react-leaflet#Popup TypeScript Examples

The following examples show how to use react-leaflet#Popup. 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: OrphanagesMap.tsx    From NLW-3.0 with MIT License 6 votes vote down vote up
function OrphanagesMap() {
  const [orphanages, setOrphanages] = useState<Orphanage[]>([]);

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

  return (
    <div id="page-map">
      <aside>
        <header>
          <img src={mapMarkerImg} alt="Happy" />

          <h2>Escolha um orfanato no mapa</h2>

          <p>Muitas crianças estão esperando a sua visita {':)'}</p>
        </header>

        <footer>
          <strong>Meia Praia</strong>
          <span>Santa Catarina</span>
        </footer>
      </aside>

      <Map
        center={[-27.1376523, -48.6087994]}
        zoom={15}
        style={{ width: '100%', height: '100%' }}
      >
        {/* <TileLayer url="https://a.tile.openstreetmap.org/{z}/{x}/{y}.png" /> */}
        <TileLayer
          url={`https://api.mapbox.com/styles/v1/mapbox/light-v10/tiles/256/{z}/{x}/{y}@2x?access_token=${process.env.REACT_APP_MAPBOX_TOKEN}`}
        />

        {orphanages.map(orphanage => (
          <Marker
            key={orphanage.id}
            icon={mapIcon}
            position={[orphanage.latitude, orphanage.longitude]}
          >
            <Popup closeButton={false} minWidth={240} maxWidth={240} className="map-popup">
              {orphanage.name}
              <Link to={`/orphanages/${orphanage.id}`}>
                <FiArrowRight size={20} color="#fff" />
              </Link>
            </Popup>
          </Marker>
        ))}
      </Map>

      <Link to="/orphanages/create" className="create-orphanage">
        <FiPlus size={32} color="#fff" />
      </Link>
    </div>
  )
}
Example #2
Source File: SidcMarker.tsx    From project-tauntaun with GNU Lesser General Public License v3.0 6 votes vote down vote up
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function SidcMarkerNonMemo(props: SidcMarkerProps) {
  const { sidc, label } = props;

  const symbol = new ms.Symbol(sidc, { size: 20 });
  const anchor = symbol.getAnchor();
  const icon = new Icon({
    iconUrl: symbol.toDataURL(),
    iconAnchor: [anchor.x, anchor.y]
  });

  return (
    <Marker {...omit(props, 'onadd', 'icon')} icon={icon}>
      {label && <Popup minWidth={100}>{label}</Popup>}
    </Marker>
  );
}
Example #3
Source File: index.tsx    From aqualink-app with MIT License 6 votes vote down vote up
SurveyPointPopup = ({
  siteId,
  point,
  classes,
}: SurveyPointPopupProps) => {
  return (
    <Popup closeButton={false} autoPan={false}>
      <Card className={classes.surveyPointPopup}>
        <Grid
          container
          alignItems="center"
          justify="space-between"
          item
          spacing={2}
        >
          <Grid title={point.name || ""} item className={classes.nameWrapper}>
            <Typography
              className={classes.name}
              variant="h6"
              color="textSecondary"
            >
              {point.name}
            </Typography>
          </Grid>
          <Grid item>
            <Link
              to={`/sites/${siteId}/points/${point.id}`}
              isIcon
              tooltipTitle="View survey point"
            />
          </Grid>
        </Grid>
      </Card>
    </Popup>
  );
}
Example #4
Source File: index.tsx    From nlw-03-omnistack with MIT License 6 votes vote down vote up
export default function OrphanagesMap() {
  return (
    <div id="page-map">
      <aside>
        <header>
          <img src={mapMarkerImg} alt="Happy" />

          <h2>Escolha um orfanato no mapa</h2>
          <p>Muitas crianças estão esperando a sua visita :)</p>
        </header>

        <footer>
          <strong>Rio do Sul</strong>
          <span>Santa Catarina</span>
        </footer>
      </aside>

      <Map>
        <Marker icon={happyMapIcon} position={[-27.2092052,-49.6401092]}>
          <Popup closeButton={false} minWidth={240} maxWidth={240} className="map-popup">
            Lar das meninas
            <Link to={`/orphanages/1`}>
              <FiArrowRight size={20} color="#fff" />
            </Link>
          </Popup>
        </Marker>
      </Map>

      <Link to="/orphanages/create" className="create-orphanage">
        <FiPlus size={32} color="#FFF" />
      </Link>
    </div>
  );
}
Example #5
Source File: OrphanagesMap.tsx    From happy with MIT License 5 votes vote down vote up
function OrphanagesMap() {
  const [orphanages, setOrphanages] = useState<Orphanage[]>([]);

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

  return (
    <div id="page-map">
      <aside>
        <header>
          <img src={mapMarkerImg} alt="Happy"/>

          <h2>Escolha um orfanato no mapa</h2>

          <p>Muitas crianças estão esperando a sua visita {':)'}</p>
        </header>

        <footer>
          <strong>Rio do Sul</strong>
          <span>Santa Catarina</span>
        </footer>
      </aside>

      <Map
        center={[-27.2092052, -49.6401092]}
        zoom={15}
        style={{ width: '100%', height: '100%'}}
      >
        <TileLayer url="https://a.tile.openstreetmap.org/{z}/{x}/{y}.png" />
        {/* <TileLayer
          url={`https://api.mapbox.com/styles/v1/mapbox/light-v10/tiles/256/{z}/{x}/{y}@2x?access_token=${process.env.REACT_APP_MAPBOX_TOKEN}`}
        /> */}

        {orphanages.map(orphanage => (
          <Marker
            key={orphanage.id}
            icon={mapIcon}
            position={[orphanage.latitude, orphanage.longitude]}
          >
            <Popup closeButton={false} minWidth={240} maxWidth={240} className="map-popup">
              {orphanage.name}
              <Link to={`/orphanages/${orphanage.id}`}>
                <FiArrowRight size={20} color="#fff" />
              </Link>
            </Popup>
          </Marker>
        ))}
      </Map>

      <Link to="/orphanages/create" className="create-orphanage">
        <FiPlus size={32} color="#fff" />
      </Link>
    </div>
  )
}
Example #6
Source File: RouteLine.tsx    From Teyvat.moe with GNU General Public License v3.0 5 votes vote down vote up
RouteLine: FunctionComponent<RouteLineProps> = ({
  route,
  editable = false,
  allowExternalMedia = false,
}) => {
  // CSS classes.
  const classes = useStyles();

  const onCopyPermalink = () => copyPermalink(route.id);

  const title = localizeField(route?.popupTitle);
  const content = localizeField(route?.popupContent);

  const eventHandlers: LeafletEventHandlerFnMap = {
    add: (event: LeafletEvent) => {
      if (editable) {
        event.target.enableEdit();
      }
    },
  };

  return (
    <TextPath
      // Options passed to the parent Polyline.
      pathOptions={{
        color: route.routeColor ?? DEFAULT_ROUTE_COLOR,
      }}
      eventHandlers={eventHandlers}
      positions={route.coordinates}
      // Attributes passed to TextPath.setText.
      text={route.routeText ?? DEFAULT_ROUTE_TEXT}
      repeat
      attributes={{
        // Attributes to apply to the text.
        dy: '6',
        fill: route.routeColor ?? DEFAULT_ROUTE_COLOR,
        class: classes.mapRouteLineText,
      }}
    >
      {/* A modern variant of MapPopupLegacy. */}
      <Popup maxWidth={540} minWidth={192} autoPan={false} keepInView={false}>
        <Box className={classes.popupContainer}>
          {title && title !== '' ? (
            <Typography className={classes.popupTitle}>{title}</Typography>
          ) : (
            <Typography className={classes.popupTitle}>
              {f('map-ui:route-id-format', { id: route.id.slice(0, 7) })}
            </Typography>
          )}
          <Box>
            <RouteMedia media={route.popupMedia ?? ''} allowExternalMedia={allowExternalMedia} />
          </Box>
          {content && content !== '' ? (
            <SafeHTML className={classes.popupContent}>{content}</SafeHTML>
          ) : null}
          {!editable ? (
            <Box className={classes.actionContainer}>
              <Tooltip title={t('map-ui:copy-permalink')}>
                <Box className={classes.innerActionContainer}>
                  <IconButton onClick={onCopyPermalink}>
                    <LinkIcon />
                  </IconButton>
                </Box>
              </Tooltip>
            </Box>
          ) : null}
        </Box>
      </Popup>
    </TextPath>
  );
}
Example #7
Source File: index.tsx    From NextLevelWeek with MIT License 5 votes vote down vote up
OrphanagesMap: React.FC = () => {
    const [orphanages, setOrphanages] = useState<IOpharnage[]>([]);

    useEffect(() => {
        api.get('/orphanages').then(res => {
            // console.log(res.data);
            setOrphanages(res.data);
        });
    }, []);

    return (
        <Container>
            <SideBar>
                <header>
                    <img src={mapMarkerImg} alt="" />

                    <h2>Escolha um orfanato no mapa</h2>
                    <p>Muitas crianças estão esperando a sua visita <span role="img" aria-label="happy">?</span></p>
                </header>

                <footer>
                    <strong>Natal</strong>
                    <span>Rio Grande do Norte</span>
                </footer>
            </SideBar>

            <Map
                center={[-5.8044209, -35.263095]}
                zoom={12}
                style={{ width: '100%', height: '100%' }}
            >
                <TileLayer url={`https://api.mapbox.com/styles/v1/mapbox/light-v10/tiles/256/{z}/{x}/{y}@2x?access_token=${process.env.REACT_APP_MAPBOX_TOKEN}`} />

                {orphanages.map(orphanage => {
                    return (
                        <Marker
                            key={orphanage.id}
                            position={[orphanage.latitude, orphanage.longitude]}
                            icon={happyMapIcon}
                        >
                            <Popup closeButton={false} minWidth={240} maxHeight={240} className="map-popup">
                                {orphanage.name}
                                <Link to={`/orphanages/${orphanage.id}`}>
                                    <FiArrowRight size={20} color="#fff" />
                                </Link>
                            </Popup>
                        </Marker>
                    );
                })}
            </Map>

            <Link to="/orphanages/create">
                <FiPlus size={32} color="#FFF" />
            </Link>
        </Container>
    );
}
Example #8
Source File: StationMarker.tsx    From metro-fare with MIT License 5 votes vote down vote up
StationPopup = ({
  stationName,
  stationId,
}: {
  stationName: string;
  stationId: METRO_STATION_ID;
}) => {
  const { t: translate } = useTranslation();
  const { trip, setTrip } = useContext(TripContext);

  const popupRef = React.useRef(null);

  const closePopupOnClick = () => {
    // @ts-ignore
    popupRef.current.leafletElement.options.leaflet.map.closePopup();
  };

  const handleSetFromTo = (
    type: "from" | "to",
    stationId: METRO_STATION_ID
  ) => {
    if (type === "from") {
      setTrip(stationId, trip.toId);
    } else {
      setTrip(trip.fromId, stationId);
    }
  };

  return (
    <Popup ref={popupRef} closeButton={false}>
      <section
        style={{ display: "flex", flexDirection: "column", width: "170px" }}
      >
        <h3>{stationName}</h3>
        <Button
          variant="contained"
          size="small"
          onClick={() => {
            handleSetFromTo("from", stationId);
            closePopupOnClick();
          }}>
          {translate("map.popup.setFrom")}
        </Button>
        <Button
          variant="contained"
          size="small"
          onClick={() => {
            handleSetFromTo("to", stationId);
            closePopupOnClick();
          }}>
          {translate("map.popup.setTo")}
        </Button>
      </section>
    </Popup>
  );
}
Example #9
Source File: OrphanagesMap.tsx    From happy with MIT License 5 votes vote down vote up
function OrphanagesMap() {

  const [orphanages, setOrphaanges] = useState<Orphanage[]>([]);

  useEffect(() => {
    api.get("/orphanages").then(res => {
      setOrphaanges(res.data);
    });
  }, []);

  return (
    <div id="page-map">
      <aside>
        <header>
          <img src={mapMakerImg} alt="Logo da plataforma Happy" />

          <h2>Escolha um orfanato no mapa</h2>
          <p>Muitas crianças estão esperando sua visita :)</p>
        </header>

        <footer>
          <strong>São Paulo</strong>
          <span>São Paulo</span>
        </footer>
      </aside>

      <Map
        center={[-23.6821604, -46.8754915]}
        zoom={10}
        style={{ width: "100%", height: "100%" }}
      >

        {/* Mapa alternativo: "https://a.tile.openstreetmap.org/{z}/{x}/{y}.png" */}
        <TileLayer
          url={
            `https://api.mapbox.com/styles/v1/mapbox/light-v10/tiles/256/{z}/{x}/{y}@2x?access_token=${process.env.REACT_APP_MAPBOX_TOKEN}`
          }
        />

        {orphanages.map(orphanage => {
          return (
            <Marker
              key={orphanage.id}
              icon={mapIcon}
              position={[orphanage.latitude, orphanage.longitude]}
            >
              <Popup
                closeButton={false}
                minWidth={240}
                maxWidth={240}
                className="map-popup"
              >
                {orphanage.name}
                <Link to={`/orphanages/${orphanage.id}`}>
                  <FiArrowRight size={20} color="#FFF" />
                </Link>
              </Popup>
            </Marker>
          )
        })}

      </Map>

      <Link to="/orphanages/create" className="create-orphanage">
        <FiPlus size={32} color="#FFF" />
      </Link>

    </div>
  );
}
Example #10
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 #11
Source File: NodeMap.tsx    From nanolooker with MIT License 5 votes vote down vote up
Markers = React.memo(({ nodes }: { nodes: NodeLocation[] }) => {
  const { t } = useTranslation();

  return (
    <>
      {nodes.map(
        (
          {
            ip,
            // @ts-ignore
            isPrincipal,
            // @ts-ignore
            alias,
            // @ts-ignore
            account,
            nodeId,
            location: { latitude, longitude, ...rest },
          },
          index,
        ) => {
          if (!latitude || !longitude) {
            // @TODO Figure out why these IP doesn't give a lat/long
            return null;
          }

          return (
            <Marker
              key={index}
              position={{ lat: latitude, lng: longitude }}
              icon={isPrincipal ? principalNodeMarker : nodeMarker}
              zIndexOffset={isPrincipal ? 10 : 1}
            >
              <Popup>
                <>
                  {alias ? (
                    <strong style={{ display: "block" }}>{alias}</strong>
                  ) : null}

                  <span className="break-word color-normal">
                    {account || nodeId}
                  </span>

                  {account ? (
                    <>
                      <br />
                      <Link to={`/account/${account}`}>
                        {t("pages.status.viewAccount")}
                      </Link>
                    </>
                  ) : null}
                </>
              </Popup>
            </Marker>
          );
        },
      )}
    </>
  );
})
Example #12
Source File: index.tsx    From MLH-Fellow-Map with MIT License 4 votes vote down vote up
IndexPage = ({
  data: { allMdx, allImageSharp, allGithubData, githubData: locationData },
}: {
  data: FellowDataQuery;
}) => {
  const githubProfiles = githubParser(allGithubData.nodes[0].data);
  const allProfiles = allMdx.nodes;

  const createClusterCustomIcon = (cluster: { getChildCount: () => void }) => {
    return L.divIcon({
      html: `<span>${cluster.getChildCount()}</span>`,
      className: 'marker-cluster-custom',
      iconSize: L.point(50, 50, true),
    });
  };

  const layers: { [k in string]: boolean } = {};
  githubProfiles.forEach((ele) => {
    layers[ele.pod_id] = true;
  });
  const [showLayers, setShowLayers] = useState(layers);
  // we likely don't want to generate this every render haha
  const markers = useMemo(() => {
    const ret: ReactElement[] = [];
    const alreadyAdded: string[] = [];
    for (const githubProfile of githubProfiles) {
      if (alreadyAdded.includes(githubProfile.username)) continue;
      alreadyAdded.push(githubProfile.username);
      const mdx = allProfiles.find(
        (profile) =>
          profile?.frontmatter?.github?.toLowerCase() ===
          githubProfile.username.toLowerCase(),
      );

      const fellow = new Fellow(
        githubProfile,
        allImageSharp,
        mdx?.frontmatter as FellowType,
        mdx?.body,
        locationData?.fields?.memberLocationMap?.find(
          (loc) =>
            loc?.name?.toLowerCase() === githubProfile.username.toLowerCase(),
        ) || undefined,
      );
      if (!showLayers[fellow.podId]) continue;
      const center = [fellow.lat, fellow.long];
      ret.push(
        <Marker
          position={center}
          key={fellow.name + fellow.lat}
          icon={
            <div className={`${fellow.podId}`}>
              <img
                src={
                  fellow.profilePictureUrl ||
                  allImageSharp.nodes.find((ele) => {
                    if (!ele || !ele.fluid) return false;
                    return ele.fluid.originalName === 'mlh.png';
                  })?.fluid?.src ||
                  'none'
                }
                className={`icon`}
              />
            </div>
          }
        >
          <Popup>
            <MapPopup fellow={fellow} />
          </Popup>
        </Marker>,
      );
    }
    console.log(ret.length);
    return (
      <MarkerClusterGroup
        showCoverageOnHover={false}
        iconCreateFunction={createClusterCustomIcon}
        maxClusterRadius={25}
      >
        {ret}
      </MarkerClusterGroup>
    );
  }, [showLayers, allImageSharp, allMdx]);

  const mapSettings = {
    center: CENTER,
    defaultBaseMap: 'OpenStreetMap',
    zoom: DEFAULT_ZOOM,
  };

  return (
    <Layout pageName="home">
      <Helmet>
        <title>MLH Fellows</title>
        <link
          href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.12.0-2/css/all.min.css"
          rel="stylesheet"
        />
      </Helmet>
      <Map {...mapSettings}>{markers}</Map>
      <Filters layers={showLayers} setLayers={setShowLayers} />
    </Layout>
  );
}
Example #13
Source File: FeatureMarker.tsx    From Teyvat.moe with GNU General Public License v3.0 4 votes vote down vote up
_FeatureMarker: FunctionComponent<FeatureMarkerProps> = ({
  marker,
  featureKey,
  icons,

  completed,
  completedAlpha,

  editable = false,
  allowExternalMedia = false,

  markFeature,
  unmarkFeature,
}) => {
  // CSS classes.
  const classes = useStyles();

  let svg = false;
  let clusterIconName = '';

  if (completed) {
    // == false sucks, but TypeScript needs it to guarantee
    // the structure of the marker icon data.
    if (icons?.done?.marker == false) {
      svg = icons?.done?.svg ?? false;
      clusterIconName = icons?.done?.clusterIcon ?? '';
    }
  } else {
    if (icons?.base?.marker == false) {
      svg = icons?.base?.svg ?? false;
      clusterIconName = icons?.base?.clusterIcon ?? '';
    }
  }

  // Build the icon for this marker. Relies on completion status.
  const icon =
    icons == null
      ? editorMarker
      : createMapIcon({
          ...(completed ? icons?.done : icons?.base),
          marker: (completed ? icons?.done?.marker : icons?.base?.marker) ?? true,
          done: !!completed,
          ext: svg ? 'svg' : 'png',
          key: (completed ? icons?.done?.key : icons?.base?.key) ?? icons?.filter ?? '',
        });

  // Build the cluster icon for the marker. Also relies on completion status.
  const clusterIcon = createClusterIcon({
    marker: (completed ? icons?.done?.marker : icons?.base?.marker) ?? true,
    extension: svg ? 'svg' : 'png',
    key: (completed ? icons?.done?.key : icons?.base?.key) ?? icons?.filter ?? '',
    clusterIcon: clusterIconName,
  });

  const onDoubleClick = (_event: LeafletEvent) => {
    // Calls on double clicks, not single clicks.

    // Mark as completed.
    if (completed) {
      unmarkFeature();
    } else {
      markFeature();
    }
  };

  const DOUBLE_CLICK_TIMEOUT = 300;

  const onCopyPermalink = () => copyPermalink(marker.id);

  const onSwitchCompleted = (value: boolean): void => {
    // If we switch to true but the marker is already completed,
    // do nothing.
    if (value === !!completed) return;

    if (value) {
      markFeature();
    } else {
      unmarkFeature();
    }
  };

  /* eslint-disable no-param-reassign */
  const eventHandlers: Record<string, LeafletEventHandlerFn> = {
    add: (event) => {
      // We will be triggering popups manually.
      event.target.off('click', event.target._openPopup);
      if (editable) {
        event.target.enableEdit();
      }
    },
    click: (event) => {
      if (event.target.clicks === undefined) event.target.clicks = 0;

      event.target.clicks += 1;

      setTimeout(() => {
        if (event.target.clicks === 1) {
          onSingleClick(event);
        }
        event.target.clicks = 0;
      }, DOUBLE_CLICK_TIMEOUT);
    },
    dblclick: (event) => {
      event.target.clicks = 0;
      onDoubleClick(event);
    },
  };
  /* eslint-enable no-param-reassign */

  const title = localizeField(marker?.popupTitle);
  const content = localizeField(marker?.popupContent);

  return (
    <ExtendedMarker
      clusterIconUrl={clusterIcon}
      completed={!!completed}
      eventHandlers={eventHandlers}
      icon={icon}
      key={marker.id}
      markerKey={`${featureKey}/${marker.id}`}
      opacity={completed ? completedAlpha : 1}
      position={marker.coordinates}
    >
      {/* A modern variant of MapPopupLegacy. */}
      <Popup maxWidth={540} minWidth={192} autoPan={false} keepInView={false}>
        <Box className={classes.popupContainer}>
          {title && title !== '' ? (
            <Typography className={classes.popupTitle}>{title}</Typography>
          ) : (
            <Typography className={classes.popupTitle}>
              {f('map-ui:marker-id-format', { id: marker.id.slice(0, 7) })}
            </Typography>
          )}
          <Box>
            <FeatureMedia media={marker.popupMedia} allowExternalMedia={allowExternalMedia} />
          </Box>
          {content && content !== '' ? (
            <SafeHTML className={classes.popupContent}>{content}</SafeHTML>
          ) : null}
          {!editable ? (
            <Box className={classes.actionContainer}>
              <Tooltip title={t('completed')}>
                <Box className={classes.innerActionContainer}>
                  <InputSwitch
                    size="small"
                    color="primary"
                    label={<AssignmentTurnedInIcon />}
                    value={Boolean(completed)}
                    onChange={onSwitchCompleted}
                  />
                </Box>
              </Tooltip>
              <Tooltip title={t('map-ui:copy-permalink')}>
                <Box className={classes.innerActionContainer}>
                  <IconButton onClick={onCopyPermalink}>
                    <LinkIcon />
                  </IconButton>
                </Box>
              </Tooltip>
            </Box>
          ) : null}
          {completed ? (
            <Typography className={classes.completedSubtitle}>
              {f('map-ui:completed-time-format', {
                time: formatUnixTimestamp(completed),
              })}
            </Typography>
          ) : null}
        </Box>
      </Popup>
    </ExtendedMarker>
  );
}
Example #14
Source File: Map.tsx    From covid19map with MIT License 4 votes vote down vote up
Map = ({
  center,
  zoom,
  markers = [],
  clusters = {},
  onMarkerClick,
  maxCases,
  outerBounds,
  innerBounds,
  location
}: {
  center: any;
  zoom: number;
  markers: any[];
  clusters: any;
  onMarkerClick: any;
  maxCases: number;
  outerBounds: any;
  innerBounds: any;
  location: any;
}) => {
  const theme = useTheme();
  const mapRef = useRef<any>(null);
  const [currentLocation, setCurrentLocation] = useState<string>();
  const [currentZoom, setCurrentZoom] = useState(100);

  useEffect(() => {
    mapRef?.current?.leafletElement.fitBounds(innerBounds);
  }, [mapRef.current]);

  useEffect(() => {
    mapRef?.current?.leafletElement.closePopup();
    setCurrentLocation('');
  }, [location]);

  const getRegionIcon = (
    className: string,
    totalCases: number,
    name: string
  ) => {
    const iconSize = 24;
    return L.divIcon({
      className: `marker ${className}`,
      iconSize: [iconSize, iconSize],
      html: `<div>${
        name === 'Managed Isolation' ? 'MIQ: ' : ''
      }${totalCases}</div>`
    });
  };

  const getClusterIcon = (className: string, totalCases: number) => {
    const normalise = totalCases / 100;
    const iconSize = 24 + normalise * 15;
    return L.divIcon({
      className: `marker ${className}`,
      iconSize: [iconSize, iconSize],
      html: `<div></div>`
    });
  };

  const onLocationClick = (name: string) => {
    setCurrentLocation(name);
    onMarkerClick(name);
  };

  const onZoomend = () => {
    if (mapRef.current) {
      setCurrentZoom(mapRef.current?.leafletElement.getZoom());
    }
  };

  return (
    <div style={{ position: 'relative' }}>
      <LeafletMap
        // onClick={() => onLocationClick('')}
        ref={mapRef}
        maxBounds={outerBounds}
        center={center}
        zoom={zoom}
        maxZoom={7}
        minZoom={5}
        zoomControl={true}
        doubleClickZoom={true}
        scrollWheelZoom={true}
        dragging={true}
        animate={true}
        easeLinearity={0.35}
        onZoomend={onZoomend}
      >
        <TileLayer
          url="//{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}{r}.png"
          attribution='&copy; <a href="//www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>'
        />
        {markers.map(
          (
            {
              name,
              latlng,
              boundary,
              totalCases,
              active,
              recovered,
              deaths,
              inHospital,
              level
            },
            i
          ) => (
            <>
              {latlng && (
                <FeatureGroup key={i}>
                  <Marker
                    position={latlng}
                    icon={getRegionIcon(
                      `region ${inHospital > 0 ? 'hospital' : ''}`,
                      active,
                      name
                    )}
                    zIndexOffset={100}
                    // onClick={() => {
                    //   onLocationClick(name);
                    //   gtag.event('Marker', 'Map', name);
                    // }}
                  />
                  <Popup>
                    <StyledPopup>
                      <div className="location">{name}</div>
                      <div className="cases">
                        {active} active case{active > 1 && 's'}
                        <br />
                        {recovered} recovered
                        <br />
                        {totalCases} total case{totalCases > 1 && 's'}
                        {deaths > 0 && (
                          <>
                            <br />
                            {deaths} death{deaths > 1 && 's'}
                          </>
                        )}
                      </div>
                      {inHospital > 0 && (
                        <div className="cases">{inHospital} in hospital</div>
                      )}
                    </StyledPopup>
                  </Popup>
                  {boundary && (
                    <Polygon
                      color={currentLocation === name ? 'white' : 'black'}
                      opacity={currentLocation === name ? 1 : 0.2}
                      weight={currentLocation === name ? 3 : 1}
                      fillColor={theme[alertColours[level - 1]]}
                      // fillOpacity={((active || 0) - -10) / (maxCases + 10 - 1)}
                      // fillOpacity={(level - 1) / (4 - 1)}
                      fillOpacity={0.8}
                      positions={boundary[0]}
                      // smoothFactor={10}
                      // onClick={() => {
                      //   onLocationClick(name);
                      //   gtag.event('Region', 'Map', name);
                      // }}
                    />
                  )}
                </FeatureGroup>
              )}
            </>
          )
        )}
        {Object.keys(clusters).map((regionName: string, j: number) =>
          Object.keys(clusters[regionName]).map(
            (clustLocName: string, k: number) => {
              const { latlng, count, items } = clusters[regionName][
                clustLocName
              ];

              return items.filter((x: any) => x.ongoing === 'Yes').length >
                0 ? (
                <Marker
                  key={k}
                  position={latlng}
                  icon={getClusterIcon('cluster', count)}
                  // onClick={() => gtag.event('Cluster', 'Map', clustLocName)}
                >
                  <Popup>
                    <StyledPopup>
                      <div className="head">
                        {clustLocName} cluster{items.length > 1 && 's'}
                      </div>
                      {items
                        .filter((x: any) => x.ongoing === 'Yes')
                        .map(
                          (
                            {
                              name,
                              totalCases
                            }: { name: string; totalCases: number },
                            l: number
                          ) => (
                            <div className="cluster-desc" key={l}>
                              <div className="location">{name}</div>
                              <div className="cases">{totalCases} cases</div>
                            </div>
                          )
                        )}
                    </StyledPopup>
                  </Popup>
                </Marker>
              ) : (
                <div key={k} />
              );
            }
          )
        )}
      </LeafletMap>
      <Styles currentZoom={currentZoom} />
    </div>
  );
}
Example #15
Source File: Maps.tsx    From roamjs-com with MIT License 4 votes vote down vote up
Markers = ({
  id,
  href,
  markers,
}: {
  id: string;
  href: string;
  markers: RoamMarker[];
}) => {
  const map = useMap();
  const mouseRef = useRef(null);
  const openMarker = (marker: LMarker) => () => {
    mouseRef.current = marker;
    marker.openPopup();
  };
  const closeMarker = (marker: LMarker) => () => {
    mouseRef.current = null;
    setTimeout(() => {
      if (mouseRef.current !== marker) {
        marker.closePopup();
      }
    }, 100);
  };
  useEffect(() => {
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore until there's a better way to grab markers
    const leafletMarkers = map._layers as { [key: string]: LMarker };
    Object.keys(leafletMarkers).forEach((k) => {
      const m = leafletMarkers[k];
      m.on({
        mouseover: openMarker(m),
        mouseout: closeMarker(m),
        click: (e) => {
          const extractedTag = extractTag(m.options.title);
          const pageUid = getPageUidByPageTitle(extractedTag);
          if (pageUid) {
            if (e.originalEvent.shiftKey) {
              openBlockInSidebar(pageUid);
            } else {
              window.roamAlphaAPI.ui.mainWindow.openPage({
                page: { uid: pageUid },
              });
            }
          }
        },
      });
    });
    const observer = new MutationObserver((mrs) => {
      mrs
        .flatMap((mr) => Array.from(mr.addedNodes))
        .filter((n) => n.nodeName === "DIV")
        .map((n) => n as HTMLDivElement)
        .map((n) =>
          n.classList.contains("leaflet-popup")
            ? n
            : n.getElementsByClassName("leaflet-popup")[0]
        )
        .filter((n) => !!n)
        .forEach((n) => {
          const marker = Object.values(leafletMarkers).find(
            (m) =>
              n
                .querySelector(".roamjs-marker-data")
                .getAttribute("data-uid") === m.options.title
          );
          n.addEventListener("mouseenter", openMarker(marker));
          n.addEventListener("mouseleave", closeMarker(marker));
        });
      mrs
        .flatMap((mr) => Array.from(mr.addedNodes))
        .map((n) =>
          n.parentElement.querySelector<HTMLAnchorElement>(".rm-alias")
        )
        .filter((n) => !!n)
        .forEach((anchor) => {
          renderAlias({
            p: anchor,
            children: anchor.innerText,
            blockUid: anchor.href.match(/\/page\/(.*)/)?.[1] || "",
          });
        });
    });
    observer.observe(document.getElementById(id), {
      childList: true,
      subtree: true,
    });
    return () => observer.disconnect();
  });
  return (
    <>
      {markers.map((m, i) => (
        <Marker
          position={[m.x, m.y]}
          icon={MarkerIcon}
          key={i}
          title={m.uid}
          riseOnHover
        >
          <Popup>
            <div
              className={"roamjs-marker-data roamjs-block-view"}
              id={`roamjs-map-marker-${m.uid}`}
              data-uid={m.uid}
              style={{ display: "flex" }}
              dangerouslySetInnerHTML={{
                __html: parseRoamMarked(m.tag),
              }}
            />
          </Popup>
        </Marker>
      ))}
    </>
  );
}
Example #16
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>;
}