react-leaflet#MapContainer TypeScript Examples

The following examples show how to use react-leaflet#MapContainer. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: CampaignMap.tsx    From project-tauntaun with GNU Lesser General Public License v3.0 5 votes vote down vote up
export function CampaignMap(props: CampaignMapProps) {
  const { mission } = MissionStateContainer.useContainer();
  const { mapType, showLegend, showRuler } = MapStateContainer.useContainer();

  const { sessionId, sessions } = SessionStateContainer.useContainer();
  const sessionData = sessions[sessionId];
  const sessionCoalition = sessionData ? sessionData.coalition : '';

  const [position, setPosition] = useState(null as ClickPosition | null);
  const center = new LatLng(props.lat, props.lng);

  const onContextMenuClick = (event: any) => {
    event.originalEvent.preventDefault();
    setPosition({
      xy: {
        x: event.originalEvent.clientX,
        y: event.originalEvent.clientY
      } as PointXY,
      latlon: event.latlng
    } as ClickPosition);
  };

  // Need to add a second layer with labels for these three basemaps.
  const layersNeedingLabels = ['Imagery', 'Gray', 'DarkGray'];
  const showLabels = layersNeedingLabels.includes(mapType);
  const labelLayerName = (mapType + 'Labels') as Basemaps;

  return (
    <div data-testid="campaign-map">
      <LegendContext.Provider value={{ legends: [] }}>
        <MapContainer
          center={center}
          zoom={props.zoom}
          preferCanvas={true}
          doubleClickZoom={false}
          inertia={false}
          zoomControl={false}
        >
          <BasemapLayer key={mapType} name={mapType} />
          {showLabels && <BasemapLayer key={labelLayerName} name={labelLayerName} />}
          <CampaignMapEventHandler
            eventHandlers={{
              contextmenu: onContextMenuClick
            }}
          />
          {sessionCoalition && (
            <React.Fragment>
              <AirportLayer airports={mission.terrain.airports} />
              {Object.keys(mission.coalition).map(key => (
                <CoalitionLayer key={key} coalition={mission.coalition[key]} />
              ))}
            </React.Fragment>
          )}
          {position && <MapContextMenu position={position} />}
          {showRuler && <Ruler />}
        </MapContainer>
        {showLegend && <Legend />}
      </LegendContext.Provider>
    </div>
  );
}
Example #2
Source File: SchoolLocationMap.tsx    From po8klasie with GNU General Public License v3.0 5 votes vote down vote up
SchoolLocationMap: FC<SchoolLocationMapProps> = ({ position }) => (
  <MapContainer center={position} zoom={13} className="w-full h-full rounded">
    <TileLayer {...tileLayerProps} />
    <Marker position={position} icon={marker} />
  </MapContainer>
)
Example #3
Source File: SchoolsMap.tsx    From po8klasie with GNU General Public License v3.0 5 votes vote down vote up
SchoolsMap: FC<SchoolsMapProps> = ({ results, onExpandToggle, isExpanded, hideExpandBtn }) => {
  const [map, setMap] = useState<LeafletMap | null>(null);
  const { searchView: searchViewConfig } = useProjectConfig();
  const { mapOptions } = searchViewConfig as SearchViewConfig;

  useEffect(() => {
    setTimeout(() => {
      if (map) map.invalidateSize();
    }, 300);
  }, [isExpanded, map]);

  useEffect(() => {
    if (map && results.length > 0) {
      const lngLatExpressions = results.map((school) => parseCoords(school));
      map.fitBounds(latLngBounds(lngLatExpressions));
    }
  }, [results, map]);

  return (
    <div className={isExpanded ? styles.mapWrapperExpanded : styles.mapWrapper}>
      <MapContainer
        className={styles.map}
        zoomControl={false}
        whenCreated={setMap}
        fullscreenControl
        {...mapOptions}
      >
        <TileLayer {...tileLayerProps} />
        {results.map(({ latitude, longitude, name, id }) => {
          if (!latitude || !longitude) return null;

          return (
            <Marker
              position={{
                lat: parseFloat(latitude),
                lng: parseFloat(longitude),
              }}
              icon={marker}
              key={id}
            >
              <Popup className={styles.markerPopup}>
                <h4>{name}</h4>
              </Popup>
            </Marker>
          );
        })}
      </MapContainer>
      {
        !hideExpandBtn && (
          <button className={styles.mapExpandButton} onClick={onExpandToggle} type="button">
            <BsChevronRight />
          </button>
        )
      }
    </div>
  );
}
Example #4
Source File: NodeMap.tsx    From nanolooker with MIT License 5 votes vote down vote up
NodeMap: React.FC<Props> = ({ nodeMonitors, isLoading }) => {
  const { t } = useTranslation();
  const [nodes, setNodes] = React.useState([] as NodeLocation[]);
  const { knownAccounts, isLoading: isKnownAccountsLoading } = React.useContext(
    KnownAccountsContext,
  );

  React.useEffect(() => {
    if (isKnownAccountsLoading || isLoading) return;

    getNodeLocations().then(nodeLocations => {
      const nodes = nodeLocations?.map(nodeLocation => {
        const nodeMonitor = nodeMonitors?.find(
          ({ rawIp }) => rawIp === nodeLocation.rawIp,
        );
        const knownAccount = nodeMonitor
          ? knownAccounts.find(({ account }) => account === nodeMonitor.account)
          : null;

        return {
          ...nodeLocation,
          ...nodeMonitor,
          ...knownAccount,
        };
      })!;

      setNodes(nodes);
    });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isLoading, isKnownAccountsLoading]);

  return (
    <>
      <Title level={3}>
        {t("pages.status.nodeLocations", {
          count: nodes.length,
        })}
      </Title>
      <div style={{ marginBottom: "12px" }}>
        <MapContainer
          center={[25, 0]}
          zoom={2}
          minZoom={2}
          style={{ height: "500px" }}
          scrollWheelZoom={false}
        >
          <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
          <Markers nodes={nodes} />
        </MapContainer>
      </div>
    </>
  );
}
Example #5
Source File: LeafletMap.tsx    From Teyvat.moe with GNU General Public License v3.0 4 votes vote down vote up
LeafletMap: FunctionComponent = () => {
  const classes = useStyles();

  const onTileLayerLoadStart = useCallback(() => {
    dispatchSetLoading('loadLeafletTiles', 'progress');
  }, []);

  const onTileLayerLoadError = useCallback(() => {
    dispatchSetLoading('loadLeafletTiles', 'error');
  }, []);

  const onTileLayerLoadSuccess = useCallback(() => {
    dispatchSetLoading('loadLeafletTiles', true);
  }, []);

  return (
    <MapContainer
      className={classes.main}
      maxBounds={MAP_BOUNDS}
      center={MAP_CENTER}
      zoom={DEFAULT_ZOOM}
      zoomDelta={0.5}
      editable
      crs={CRS.Simple}
      zoomSnap={0.5}
      maxZoom={MAXIMUM_ZOOM}
      minZoom={MINIMUM_ZOOM}
      attributionControl={false} // Override the Leaflet attribution with our own AttributionControl.
      zoomControl={false}
    >
      {/* Handles events related to the map position. */}
      <MapPositionHandler />
      {/* Handles events related to the map editing, and renders the editor controls.. */}
      <MapEditorHandler />
      {/* Controls the actual map image. */}
      <TileLayer
        onLoadSuccess={onTileLayerLoadSuccess}
        onLoadStart={onTileLayerLoadStart}
        onLoadError={onTileLayerLoadError}
      />

      <RegionLabelLayer />
      {/* <WorldBorderLayer /> */}
      <EditorLayer />

      {/* Controls the zoom buttons in the top left corner. */}
      <ZoomControl zoomInTitle="+" zoomOutTitle="-" />
      <DebugControls />

      {/* Display each visible feature. */}
      {_.map(getMapFeatureKeys(), (key) => {
        const feature = getMapFeature(key);
        if (!feature) {
          console.error(`ERROR: Feature '${key}' is not defined.`);
          return null;
        }

        return (
          <ErrorHandler key={`feature:${key}`} errorHandler={ErrorLayer}>
            <FeatureLayer mapFeature={feature} featureKey={key} />
          </ErrorHandler>
        );
      })}

      {/* Display each visible route. */}
      {_.map(getMapRouteGroupKeys(), (key) => {
        const route = getMapRouteGroup(key);
        if (!route) {
          console.error(`ERROR: Route '${key}' is not defined.`);
          return null;
        }

        return (
          <ErrorHandler key={`route:${key}`} errorHandler={ErrorLayer}>
            <RouteLayer routeKey={key} routeGroup={route} />
          </ErrorHandler>
        );
      })}
    </MapContainer>
  );
}
Example #6
Source File: Maps.tsx    From roamjs-com with MIT License 4 votes vote down vote up
Maps = ({ blockId }: { blockId: string }): JSX.Element => {
  const id = useMemo(() => `roamjs-maps-container-id-${blockId}`, [blockId]);
  const mapInstance = useRef<Map>(null);
  const initialTree = useTreeByHtmlId(blockId);
  const [height, setHeight] = useState(DEFAULT_HEIGHT);
  const fixHeight = useCallback(() => {
    setHeight(
      parseInt(
        getComputedStyle(document.getElementById(id)).width.match(
          /^(.*)px$/
        )?.[1] || `${Math.round((DEFAULT_HEIGHT * 4) / 3)}`
      ) * 0.75
    );
    mapInstance.current?.invalidateSize?.();
  }, [setHeight]);
  const initialZoom = useMemo(() => getZoom(initialTree), [initialTree]);
  const initialCenter = useMemo(() => getCenter(initialTree), [initialTree]);
  const [markers, setMarkers] = useState<RoamMarker[]>([]);
  const [loaded, setLoaded] = useState(false);
  const [filter, setFilter] = useState(getFilter(initialTree));
  const isShift = useRef(false);
  const load = useCallback(() => setLoaded(true), [setLoaded]);
  const refresh = useCallback(() => {
    const tree = getTreeByHtmlId(blockId);
    mapInstance.current.setZoom(getZoom(tree));
    mapInstance.current.panTo(getCenter(tree));
    setFilter(getFilter(tree));
    getMarkers(tree).then((newMarkers) => {
      setMarkers(newMarkers);
    });
    fixHeight();
  }, [mapInstance, setMarkers, blockId, fixHeight]);

  const [href, setHref] = useState("https://roamresearch.com");
  useEffect(() => {
    const windowHref = window.location.href;
    setHref(
      windowHref.includes("/page/")
        ? windowHref.substring(0, windowHref.indexOf("/page/"))
        : windowHref
    );
  }, [setHref]);
  const shiftKeyCallback = useCallback(
    (e: KeyboardEvent) => (isShift.current = e.shiftKey),
    [isShift]
  );
  useEffect(() => {
    if (!loaded) {
      load();
      getMarkers(initialTree).then((newMarkers) => {
        setMarkers(newMarkers);
      });
      document.addEventListener("keydown", shiftKeyCallback);
      document.addEventListener("keyup", shiftKeyCallback);
      fixHeight();
    }
  }, [load, loaded, initialTree, setMarkers, shiftKeyCallback, id, fixHeight]);
  const filteredMarkers = useMemo(
    () =>
      filter
        ? markers.filter((m) =>
            isTagOnPage({ tag: filter, title: extractTag(m.tag) })
          )
        : markers,
    [markers, filter]
  );
  const filterOnBlur = useCallback(
    (value: string) => {
      setInputSetting({
        blockUid: getUidsFromId(blockId).blockUid,
        value,
        key: "filter",
      });
      setFilter(value);
    },
    [blockId]
  );
  const whenCreated = useCallback(
    (m) => {
      mapInstance.current = m;
      mapInstance.current.invalidateSize();
    },
    [mapInstance]
  );
  return (
    <EditContainer
      blockId={blockId}
      refresh={refresh}
      Settings={
        <>
          <Label>
            Filter
            <PageInput
              value={filter}
              setValue={setFilter}
              onBlur={filterOnBlur}
            />
          </Label>
        </>
      }
    >
      <MapContainer
        center={initialCenter}
        zoom={initialZoom}
        id={id}
        style={{ height }}
        whenCreated={whenCreated}
      >
        <LayersControl position="bottomleft">
          <LayersControl.BaseLayer checked name="Streets">
            <TileLayer
              attribution='Map data &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>'
              url="https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}"
              accessToken={process.env.MAPBOX_TOKEN}
              id="mapbox/streets-v11"
            />
          </LayersControl.BaseLayer>
          <LayersControl.BaseLayer name="Outdoors">
            <TileLayer
              attribution='Map data &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>'
              url="https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}"
              accessToken={process.env.MAPBOX_TOKEN}
              id="mapbox/outdoors-v11"
            />
          </LayersControl.BaseLayer>
          <LayersControl.BaseLayer name="Light">
            <TileLayer
              attribution='Map data &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>'
              url="https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}"
              accessToken={process.env.MAPBOX_TOKEN}
              id="mapbox/light-v10"
            />
          </LayersControl.BaseLayer>
          <LayersControl.BaseLayer name="Dark">
            <TileLayer
              attribution='Map data &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>'
              url="https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}"
              accessToken={process.env.MAPBOX_TOKEN}
              id="mapbox/dark-v10"
            />
          </LayersControl.BaseLayer>
          <LayersControl.BaseLayer name="Satellite">
            <TileLayer
              attribution='Map data &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>'
              url="https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}"
              accessToken={process.env.MAPBOX_TOKEN}
              id="mapbox/satellite-v9"
            />
          </LayersControl.BaseLayer>
        </LayersControl>
        <Markers href={href} markers={filteredMarkers} id={id} />
      </MapContainer>
    </EditContainer>
  );
}
Example #7
Source File: index.tsx    From nlw-ecoleta with MIT License 4 votes vote down vote up
export function CreatePoint() {
	const [items, setItems] = useState<Item[]>([]);
	const [ufs, setUfs] = useState<string[]>([]);
	const [cities, setCities] = useState<string[]>([]);

	const [selectedItems, setSelectedItems] = useState<number[]>([]);
	const [initialPosition, setInitialPosition] = useState<[number, number]>([0, 0]);
	const [selectedFile, setSelectedFile] = useState<File>();
    
	const [formData, setFormData] = useState({
		name: '',
		email: '',
		whatsapp: '',
	});

	const [selectedUf, setSelectedUf] = useState('0');
	const [selectedCity, setSelectedCity] = useState('0');
	const [selectedPosition, setSelectedPosition] = useState<[number, number]>([0, 0]);

	const history = useNavigate();

	useEffect (() => {
		navigator.geolocation.getCurrentPosition(position => {
			const { latitude, longitude } = position.coords;
			setInitialPosition([latitude, longitude]);
		});
	}, []);

	useEffect(() => { 
		api.get('items').then(response => {
			setItems(response.data);
		});
	}, []);

	useEffect(() => { 
		axios
			.get<IBGEUFResponse[]>('https://servicodados.ibge.gov.br/api/v1/localidades/estados')
			.then(response => {
				const ufInitials = response.data.map(uf => uf.sigla);

				setUfs(ufInitials);
			});
	}, []);

	useEffect(() => {
		if(selectedUf === '0') {
			return;
		}

		axios
			.get<IBGECityResponse[]>(`https://servicodados.ibge.gov.br/api/v1/localidades/estados/${selectedUf}/municipios`)
			.then(response => {
				const cityNames = response.data.map(city => city.nome);

				setCities(cityNames);
			});
	} , [selectedUf]);

	function handleSelectUf(event: ChangeEvent<HTMLSelectElement>) {
		const uf = event.target.value;

		setSelectedUf(uf);
	}

	function handleSelectCity(event: ChangeEvent<HTMLSelectElement>) {
		const city = event.target.value;

		setSelectedCity(city);
	}

	function handleMapClick(event: LeafletMouseEvent) {
		setSelectedPosition([
			event.latlng.lat,
			event.latlng.lng,
		]);
	}

	function handleInputChange(event: ChangeEvent<HTMLInputElement>){
		const { name, value } = event.target;

		setFormData({ ...formData, [name]: value });
	}

	function handleSelectItem(id: number) {
		const alreadySelected = selectedItems.findIndex(item => item === id);

		if (alreadySelected >= 0) {
			const filteredItems = selectedItems.filter(item => item  !== id);
			setSelectedItems(filteredItems);
		}

		else {
			setSelectedItems([ ...selectedItems, id ]);
		}
	}

	async function handleSubmit(event: FormEvent) {
		event.preventDefault();

		const { name, email, whatsapp } = formData;
		const uf = selectedUf;
		const city = selectedCity;
		const [ latitude, longitude ] = selectedPosition;
		const items = selectedItems;

		const data = new FormData();

		data.append('name', name);
		data.append('email', email);
		data.append('whatsapp', whatsapp);
		data.append('uf', uf);
		data.append('city', city);
		data.append('latitude', String(latitude));
		data.append('longitude', String(longitude));
		data.append('items', items.join(','));

		if (selectedFile) {
			data.append('image', selectedFile);
		}

		await api.post('points', data);

		alert('Ponto de coleta criado.');
		history('/');
	}

	// function LocationMarker() {
	// 	const map = useMapEvents({
	// 		click() {
	// 			map.locate();
	// 		},
	// 		locationfound(e) {
	// 			setSelectedPosition(e.latlng as any);
	// 			map.flyTo(e.latlng, map.getZoom());
	// 		},
	// 	});
	
	// 	return selectedPosition === null ? null : (
	// 		<Marker position={selectedPosition} />
	// 	);
	// }

	return (
		<div id='page-create-point'>
			<header>
				<img src={ logo } alt="Ecoleta" />

				<Link to='/'>
					<FiArrowLeft />
                    Voltar para home
				</Link>
			</header>

			<form onSubmit={handleSubmit}>
				<h1>Cadastro do <br /> ponto de coleta</h1>

				<Dropzone onFileUploaded={setSelectedFile} />

				<fieldset>
					<legend>
						<h2> Dados </h2>
					</legend>

					<div className='field'> 
						<label htmlFor="name"> Nome da entidade</label>
						<input 
							type="text"
							name="name"
							id="name"
							onChange={handleInputChange}
						/>
					</div>

					<div className="field-group">
						<div className='field'> 
							<label htmlFor="email"> E-mail</label>
							<input 
								type="email"
								name="email"
								id="email"
								onChange={handleInputChange}
							/>
						</div>

						<div className='field'> 
							<label htmlFor="name"> Whatsapp</label>
							<input 
								type="text"
								name="whatsapp"
								id="whatsapp"
								onChange={handleInputChange}
							/>
						</div>
					</div>
				</fieldset>

				<fieldset>
					<legend>
						<h2> Endereço </h2>
						<span>Selecione o endereço no mapa</span>
					</legend>

					<MapContainer center={initialPosition} zoom={5} onClick={handleMapClick}>
						<TileLayer
							attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
							url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
						/>

						<Marker position={selectedPosition}></Marker>
					</MapContainer>

					<div className="field-group">
						<div className="field">
							<label htmlFor="uf"> Estado (UF)</label>
							<select 
								name="uf" 
								id="uf"  
								value={selectedUf} 
								onChange={handleSelectUf}
							>
								<option value="0"> Selecione um UF</option>
								{ufs.map(uf => (
									<option key={uf} value={uf}> {uf}</option>
								))}
							</select>
						</div>
						<div className="field">
							<label htmlFor="city"> Cidade</label>
							<select 
								name="city" 
								id="city"
								value={selectedCity}
								onChange={handleSelectCity}
							>
								<option value="0"> Selecione uma cidade</option>
								{cities.map(city => (
									<option key={city} value={city}> {city}</option>
								))}
							</select>
						</div>
					</div>
				</fieldset>

				<fieldset>
					<legend>
						<h2> Itens de coleta </h2>
						<span>Selecione um ou mais itens abaixo</span>
					</legend>

					<ul className='items-grid'>
						{items.map(item =>(
							<li 
								key={item.id} 
								onClick={() => handleSelectItem(item.id)}
								className={selectedItems.includes(item.id) ? 'selected' : ''}
							>
								<img src={item.image_url} alt={item.title}/>
								<span>{item.title}</span>
							</li>
						))}
                        
					</ul>
				</fieldset>

				<button type="submit">Cadastrar ponto de coleta</button>
			</form>
		</div>
	);
}
Example #8
Source File: MapChart.tsx    From neodash with Apache License 2.0 4 votes vote down vote up
NeoMapChart = (props: ChartProps) => {

    // Retrieve config from advanced settings
    const nodeColorProp = props.settings && props.settings.nodeColorProp ? props.settings.nodeColorProp : "color";
    const defaultNodeSize = props.settings && props.settings.defaultNodeSize ? props.settings.defaultNodeSize : "large";
    const relWidthProp = props.settings && props.settings.relWidthProp ? props.settings.relWidthProp : "width";
    const relColorProp = props.settings && props.settings.relColorProp ? props.settings.relColorProp : "color";
    const defaultRelWidth = props.settings && props.settings.defaultRelWidth ? props.settings.defaultRelWidth : 3.5;
    const defaultRelColor = props.settings && props.settings.defaultRelColor ? props.settings.defaultRelColor : "#666";
    const nodeColorScheme = props.settings && props.settings.nodeColorScheme ? props.settings.nodeColorScheme : "neodash";
    const styleRules = props.settings && props.settings.styleRules ? props.settings.styleRules : [];
    const defaultNodeColor = "grey"; // Color of nodes without labels
    const dimensions = props.dimensions ? props.dimensions : {width: 100, height: 100};

    const [data, setData] = React.useState({ nodes: [], links: [], zoom: 0, centerLatitude: 0, centerLongitude: 0 });

    // Per pixel, scaling factors for the latitude/longitude mapping function.
    const widthScale = 8.55;
    const heightScale = 6.7;

    var key = dimensions.width + "," + dimensions.height + ","+ data.centerLatitude + "," + data.centerLongitude + "," + props.fullscreen;
    useEffect(() => {
        data.centerLatitude + "," + data.centerLongitude + "," + props.fullscreen;
    }, [props.fullscreen])

    useEffect(() => {
        buildVisualizationDictionaryFromRecords(props.records);
    }, [])

    var nodes = {};
    var nodeLabels = {};
    var links = {};
    var linkTypes = {};

    // Gets all graphy objects (nodes/relationships) from the complete set of return values.
    function extractGraphEntitiesFromField(value) {
        if (value == undefined) {
            return
        }
        if (valueIsArray(value)) {
            value.forEach((v, i) => extractGraphEntitiesFromField(v));
        } else if (valueIsObject(value)) {
            if (value["label"] && value["id"]) {
                // Override for adding point nodes using a manually constructed dict.
                nodeLabels[value["label"]] = true;
                nodes[value["id"]] = {
                    id: value["id"],
                    labels: [value["label"]],
                    size: defaultNodeSize,
                    properties: value,
                    firstLabel: value["label"]
                };
            } else if (value["type"] && value["id"] && value["start"] && value["end"]) {
                // Override for adding relationships using a manually constructed dict.
                if (links[value["start"] + "," + value["end"]] == undefined) {
                    links[value["start"] + "," + value["end"]] = [];
                }
                const addItem = (arr, item) => arr.find((x) => x.id === item.id) || arr.push(item);
                addItem(links[value["start"] + "," + value["end"]], {
                    id: value["id"],
                    source: value["start"],
                    target: value["end"],
                    type: value["type"],
                    width: value[relWidthProp] ? value[relWidthProp] : defaultRelWidth,
                    color: value[relColorProp] ? value[relColorProp] : defaultRelColor,
                    properties: value
                });
            }
        } else if (valueIsNode(value)) {
            value.labels.forEach(l => nodeLabels[l] = true)
            nodes[value.identity.low] = {
                id: value.identity.low,
                labels: value.labels,
                size: defaultNodeSize,
                properties: value.properties,
                firstLabel: value.labels[0]
            };
        } else if (valueIsRelationship(value)) {
            if (links[value.start.low + "," + value.end.low] == undefined) {
                links[value.start.low + "," + value.end.low] = [];
            }
            const addItem = (arr, item) => arr.find((x) => x.id === item.id) || arr.push(item);
            addItem(links[value.start.low + "," + value.end.low], {
                id: value.identity.low,
                source: value.start.low,
                target: value.end.low,
                type: value.type,
                width: value.properties[relWidthProp] ? value.properties[relWidthProp] : defaultRelWidth,
                color: value.properties[relColorProp] ? value.properties[relColorProp] : defaultRelColor,
                properties: value.properties
            });

        } else if (valueIsPath(value)) {
            value.segments.map((segment, i) => {
                extractGraphEntitiesFromField(segment.start);
                extractGraphEntitiesFromField(segment.relationship);
                extractGraphEntitiesFromField(segment.end);
            });
        }
    }

    function buildVisualizationDictionaryFromRecords(records) {


        // Extract graph objects from result set.
        records.forEach((record, rownumber) => {
            record._fields && record._fields.forEach((field, i) => {
                extractGraphEntitiesFromField(field);
            })
        });

        // Assign proper colors & coordinates to nodes.
        const totalColors = categoricalColorSchemes[nodeColorScheme].length;
        const nodeLabelsList = Object.keys(nodeLabels);
        const nodesList = Object.values(nodes).map(node => {
            const assignPosition = (node) => {
                if (node.properties.latitude && node.properties.longitude) {
                    nodes[node.id].pos = [parseFloat(node.properties.latitude), parseFloat(node.properties.longitude)];
                    return nodes[node.id].pos;
                }
                if (node.properties.lat && node.properties.long) {
                    nodes[node.id].pos = [parseFloat(node.properties.lat), parseFloat(node.properties.long)];
                    return nodes[node.id].pos;
                }
                Object.values(node.properties).forEach(p => {
                    if (p != null && p.srid != null && p.x != null && p.y != null) {
                        if (!isNaN(p.x) && !isNaN(p.y)) {
                            nodes[node.id].pos = [p.y, p.x];
                            return [p.y, p.x];
                        }
                    }
                })
            }

            var assignedColor = node.properties[nodeColorProp] ? node.properties[nodeColorProp] :
                categoricalColorSchemes[nodeColorScheme][nodeLabelsList.indexOf(node.firstLabel) % totalColors];
           
            assignedColor = evaluateRulesOnNode(node, 'marker color', assignedColor, styleRules);
            const assignedPos = assignPosition(node);
            return update(node, { pos: node.pos ? node.pos : assignedPos, color: assignedColor ? assignedColor : defaultNodeColor });

        });

        // Assign proper curvatures to relationships.
        const linksList = Object.values(links).map(nodePair => {
            return nodePair.map((link, i) => {
                if (nodes[link.source] && nodes[link.source].pos && nodes[link.target] && nodes[link.target].pos) {
                    return update(link, { start: nodes[link.source].pos, end: nodes[link.target].pos });
                }
            });
        }).flat();

        // Calculate center latitude and center longitude:

        const latitudes = nodesList.reduce((a, b) => {
            if (b["pos"] == undefined) {
                return a;
            }
            a.push(b["pos"][0])
            return a;
        }, []);
        const longitudes = nodesList.reduce((a, b) => {
            if (b["pos"] == undefined) {
                return a;
            }
            a.push(b["pos"][1])
            return a;
        }, []);
        const maxLat = Math.max(...latitudes);
        const minLat = Math.min(...latitudes);
        const avgLat = maxLat - (maxLat - minLat) / 2.0;

        let latWidthScaleFactor = (dimensions.width ? dimensions.width : 300) / widthScale;
        let latDiff = maxLat - avgLat;
        let latProjectedWidth = latDiff / latWidthScaleFactor;
        let latZoomFit = Math.ceil(Math.log2(1.0 / latProjectedWidth));

        const maxLong = Math.min(...longitudes);
        const minLong = Math.min(...longitudes);
        const avgLong = maxLong - (maxLong - minLong) / 2.0;

        let longHeightScaleFactor = (dimensions.height ? dimensions.height : 300) / heightScale;
        let longDiff = maxLong - avgLong;
        let longProjectedHeight = longDiff / longHeightScaleFactor;
        let longZoomFit = Math.ceil(Math.log2(1.0 / longProjectedHeight));
        // Set data based on result values.
        setData({
            zoom: Math.min(latZoomFit, longZoomFit),
            centerLatitude: latitudes ? latitudes.reduce((a, b) => a + b, 0) / latitudes.length : 0,
            centerLongitude: longitudes ? longitudes.reduce((a, b) => a + b, 0) / longitudes.length : 0,
            nodes: nodesList,
            links: linksList
        });
    }

    // Render a node label tooltip
    const renderNodeLabel = (node) => {
        const selectedProp = props.selection && props.selection[node.firstLabel];
        if (selectedProp == "(id)") {
            return node.id;
        }
        if (selectedProp == "(label)") {
            return node.labels;
        }
        if (selectedProp == "(no label)") {
            return "";
        }
        return node.properties[selectedProp] ? node.properties[selectedProp].toString() : "";
    }

    var markerMarginTop = "6px";
    switch (defaultNodeSize) {
        case "large":
            markerMarginTop = "-5px";
            break;
        case "medium":
            markerMarginTop = "3px";
            break;
        default:
            break;
    }

    function createMarkers() {
        // Create markers to plot on the map

        return data.nodes.filter(node => node.pos && !isNaN(node.pos[0]) && !isNaN(node.pos[1])).map((node, i) =>
            <Marker position={node.pos} key={i}
                icon={<div style={{ color: node.color, textAlign: "center", marginTop: markerMarginTop }}>
                    <LocationOnIcon fontSize={node.size}></LocationOnIcon>
                </div>}>
                {props.selection && props.selection[node.firstLabel] && props.selection[node.firstLabel] != "(no label)" ?
                    <Tooltip direction='bottom' permanent className={"leaflet-custom-tooltip"}> {renderNodeLabel(node)}   </Tooltip>
                    : <></>}
                {createPopupFromNodeProperties(node)}
            </Marker>);
    }

    function createLines() {
        // Create lines to plot on the map.
        return data.links.filter(link => link).map((rel, i) => {
            if (rel.start && rel.end) {
                return <Polyline weight={rel.width} key={i} positions={[rel.start, rel.end]} color={rel.color}>
                    {createPopupFromRelProperties(rel)}
                </Polyline>
            }
        });
    }


    // Helper function to convert property values to string for the pop-ups.
    function convertMapPropertyToString(property) {
        if (property.srid) {
            return "(lat:" + property.y + ", long:" + property.x + ")";
        }
        return property;
    }

    function createPopupFromRelProperties(value) {
        return <Popup className={"leaflet-custom-rel-popup"}>
            <h3><b>{value.type}</b></h3>
            <table><tbody>{Object.keys(value.properties).length == 0 ? <tr><td>(No properties)</td></tr> : Object.keys(value.properties).map((k, i) => <tr key={i}><td style={{ marginRight: "10px" }} key={0}>{k.toString()}:</td><td key={1}>{value.properties[k].toString()}</td></tr>)}</tbody></table>
        </Popup>;
    }

    function createPopupFromNodeProperties(value) {
        return <Popup className={"leaflet-custom-node-popup"}>
            <h3><b>{(value.labels.length > 0) ? value.labels.map(b => b + " ") : "(No labels)"}</b></h3>
            <table><tbody>{Object.keys(value.properties).length == 0 ? <tr><td>(No properties)</td></tr> : Object.keys(value.properties).map((k, i) => <tr key={i}><td style={{ marginRight: "10px" }} key={0}>{k.toString()}:</td><td key={1}>{value.properties[k].toString()}</td></tr>)}</tbody></table>
        </Popup>;
    }




    const markers = createMarkers();
    const lines = createLines();
    const fullscreen = props.fullscreen ? props.fullscreen : true;

    // Draw the component.
    return <MapContainer key={key} style={{ width: "100%", height: "100%" }}
        center={[data.centerLatitude ? data.centerLatitude : 0, data.centerLongitude ? data.centerLongitude : 0]}
        zoom={data.zoom ? data.zoom : 0}
        maxZoom={18}
        scrollWheelZoom={false}>
        <TileLayer
            attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
            url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />
        {markers}
        {lines}
    </MapContainer>;
}
Example #9
Source File: location.admin.tsx    From ui with GNU Affero General Public License v3.0 4 votes vote down vote up
LocationAdmin: React.FC<FieldAdminProps> = (props) => {
  const { t } = useTranslation()

  return (
    <div>
      <Form.Item
        label={t('type:location:default')}
        labelCol={{ span: 6 }}
      >
        <Space>
          <Form.Item
            name={[
              props.field.name as string,
              'defaultValue',
              'lat',
            ]}
            noStyle
          >
            <InputNumber addonAfter={'LAT'} precision={7} step={0.00001} max={90} min={-90} />
          </Form.Item>

          <Form.Item
            name={[
              props.field.name as string,
              'defaultValue',
              'lng',
            ]}
            noStyle
          >
            <InputNumber addonAfter={'LNG'} precision={7} step={0.00001} max={180} min={-180} />
          </Form.Item>
        </Space>
      </Form.Item>

      <Form.Item
        label={t('type:location.initialZoom')}
        name={[
          props.field.name as string,
          'optionKeys',
          'initialZoom',
        ]}
        labelCol={{ span: 6 }}
        initialValue={1}
      >
        <InputNumber precision={0} min={1} max={18} />
      </Form.Item>

      <Form.Item
        label={t('type:location.tiles')}
        name={[
          props.field.name as string,
          'optionKeys',
          'tiles',
        ]}
        labelCol={{ span: 6 }}
        initialValue={'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'}
      >
        <Input placeholder={'https://tile.openstreetmap.org/{z}/{x}/{y}.png'} />
      </Form.Item>

      <Form.Item shouldUpdate>
        {(form) => {
          //const prefix = React.useContext(FormItemContext).prefixName
          const prefix = (form as any).prefixName

          const zoom = form.getFieldValue([
            ...prefix,
            props.field.name as string,
            'optionKeys',
            'initialZoom',
          ])

          const center = form.getFieldValue([
            ...prefix,
            props.field.name as string,
            'defaultValue',
          ])

          const tiles = form.getFieldValue([
            ...prefix,
            props.field.name as string,
            'optionKeys',
            'tiles',
          ])

          if (!tiles) {
            return <Alert message={'Tiles missing!'} />
          }

          return (
            <div>
              <MapContainer
                center={center}
                zoom={zoom}
                style={{ height: 300, width: '100%' }}
              >
                <TileLayer
                  attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
                  url={tiles}
                />
                {center?.lat && center?.lng && (
                  <DraggableMarker
                    value={center}
                    onChange={next => {
                      form.setFields([
                        {
                          name: [
                            ...prefix,
                            props.field.name as string,
                            'defaultValue',
                            'lng',
                          ],
                          value: next.lng,
                        },
                        {
                          name: [
                            ...prefix,
                            props.field.name as string,
                            'defaultValue',
                            'lat',
                          ],
                          value: next.lat,
                        },
                      ])
                    }}
                  />
                )}
              </MapContainer>
            </div>
          )
        }}
      </Form.Item>
    </div>
  )
}
Example #10
Source File: location.input.tsx    From ui with GNU Affero General Public License v3.0 4 votes vote down vote up
builder: FieldInputBuilderType = ({
  parseUrlValue,
  parseValue,
}) => function LocationInput ({
  field,
  urlValue,
}) {
  const [initialZoom, setInitialZoom] = useState<number>(13)
  const [tiles, setTiles] = useState<string>()
  const [loading, setLoading] = useState(true)

  const { t } = useTranslation()


  useEffect(() => {
    field.options.forEach((option) => {
      if (option.key === 'initialZoom') {
        try {
          setInitialZoom(JSON.parse(option.value))
        } catch (e) {
          logger('invalid initialZoom value %O', e)
        }
      }

      if (option.key === 'tiles') {
        try {
          setTiles(JSON.parse(option.value))
        } catch (e) {
          logger('invalid tiles value %O', e)
        }
      }
    })

    setLoading(false)
  }, [field])

  let initialValue: { lat: number, lng: number } = undefined

  if (field.defaultValue) {
    try {
      initialValue = parseValue(field.defaultValue)
    } catch (e) {
      logger('invalid default value %O', e)
    }
  }

  if (urlValue) {
    try {
      initialValue = parseUrlValue(urlValue)
    } catch (e) {
      logger('invalid url value %O', e)
    }
  }

  if (loading) {
    return (
      <div>
        <Spin />
      </div>
    )
  }

  if (!tiles) {
    return <Alert message={'Tiles missing!'} />
  }

  return (
    <div>
      <Form.Item>
        <Space>
          <Form.Item
            rules={[{ required: field.required, message: t('validation:valueRequired') }]}
            name={[
              field.id,
              'lat',
            ]}
            initialValue={initialValue?.lat}
            noStyle
          >
            <InputNumber addonAfter={'LAT'} precision={7} step={0.00001} max={90} min={-90} />
          </Form.Item>

          <Form.Item
            rules={[{ required: field.required, message: t('validation:valueRequired') }]}
            name={[
              field.id,
              'lng',
            ]}
            initialValue={initialValue?.lng}
            noStyle
          >
            <InputNumber addonAfter={'LNG'} precision={7} step={0.00001} max={180} min={-180} />
          </Form.Item>
        </Space>
      </Form.Item>
      <Form.Item dependencies={[[field.id, 'lat'], [field.id, 'lng']]}>
        {(form) => {
          const center = form.getFieldValue([field.id])

          return (
            <div>
              <MapContainer
                center={initialValue}
                zoom={initialZoom}
                style={{ height: 300, width: '100%' }}
              >
                <TileLayer
                  attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
                  url={tiles}
                />
                {center.lat && center.lng && (
                  <DraggableMarker
                    value={center}
                    onChange={next => {
                      form.setFields([
                        {
                          name: [
                            field.id,
                            'lng',
                          ],
                          value: next.lng,
                        },
                        {
                          name: [
                            field.id,
                            'lat',
                          ],
                          value: next.lat,
                        },
                      ])
                    }}
                  />
                )}
              </MapContainer>
            </div>
          )
        }}
      </Form.Item>
    </div>
  )
}