react-google-maps-api icon indicating copy to clipboard operation
react-google-maps-api copied to clipboard

Does this support Advanced Markers?

Open SaavanNanavati opened this issue 2 years ago • 54 comments

I want to add class names to my marker.

Advanced markers support this: https://developers.google.com/maps/documentation/javascript/advanced-markers/html-markers

But I don't see advanced markers available in the repo.

Can you confirm how can I add class names to my marker?

Thanks!

SaavanNanavati avatar Jun 30 '23 15:06 SaavanNanavati

@JustFly1984 It seems like you're really active here so just wanted to tag for visibility. Thanks.

SaavanNanavati avatar Jul 03 '23 19:07 SaavanNanavati

+1 on this. Bumping up.

dszeto avatar Sep 07 '23 22:09 dszeto

Same here ... want to use some other marker clustering lib for big datasets that works better with Advanced Markers but I can't seem to find a way to do it. My main issue is the Map ID during initialization so, +1 from me as well...

chris-iliopoulos avatar Sep 27 '23 11:09 chris-iliopoulos

So I was able to add Advanced Markers by doing the following:

  • When loading @react-google-maps/api, add `libraries: ["marker"]
  const { isLoaded } = useJsApiLoader({
    googleMapsApiKey: "<redacted>",
    libraries: ["marker"],
  });
  • In my Google Map component, I'm iterating through my locations and rendering custom Marker components:
 <GoogleMap
        center={center}
        zoom={13}
        options={options}
        mapContainerStyle={{ width: "100%", height: "100%" }}
        onLoad={onLoad}
        onBoundsChanged={handleBoundsChanged}
      >
        {mapRef.current &&
          locations.map((location) => {
            return (
              <Marker
                key={location.id}
                map={mapRef.current}
                position={{ lat: location.lat, lng: location.lng }}
              >
                <div className="marker">
                  <h2>{location.name}</h2>
                </div>
              </Marker>
            );
          })}
      </GoogleMap>

Here is the custom Marker component:

"use client";
import { FC, useRef, useEffect } from "react";
import { createRoot, Root } from "react-dom/client";

type LatLngLiteral = google.maps.LatLngLiteral;
type Map = google.maps.Map;
type AdvancedMarkerElement = google.maps.marker.AdvancedMarkerElement;

interface MarkerProps {
  map: Map;
  position: LatLngLiteral;
  children: React.ReactNode;
}

const Marker: FC<MarkerProps> = ({ map, position, children }) => {
  const markerRef = useRef<AdvancedMarkerElement>();
  const rootRef = useRef<Root>();
  useEffect(() => {
    if (!rootRef.current) {
      const container = document.createElement("div");
      rootRef.current = createRoot(container);
      markerRef.current = new google.maps.marker.AdvancedMarkerElement({
        position,
        content: container,
      });
    }
  }, []);

  useEffect(() => {
    if (!markerRef.current || !rootRef.current) return;
    rootRef.current.render(children);
    markerRef.current.position = position;
    markerRef.current.map = map;
  }, [map, position, children]);

  return <></>;
};

export default Marker;

This works by essentially translating the jsx/React node (children prop in the above Marker component) into a proper HTML dom element. Tbh I'm not the best at detailing why this works, but I got the insight from this video: https://www.youtube.com/watch?v=8kxYqoY2WwE&t=1019s&ab_channel=GoogleMapsPlatform

tcgilbert avatar Oct 30 '23 01:10 tcgilbert

"use client" is only next.js compatible

JustFly1984 avatar Oct 30 '23 12:10 JustFly1984

@tcgilbert Your PR is welcome, can you please add this component to the library? I would publish new version.

JustFly1984 avatar Oct 30 '23 12:10 JustFly1984

Hello, I get the following error image I created an ID but I don't know where to put it. Please help.

NOTE: I found the solution here - https://github.com/JustFly1984/react-google-maps-api/issues/3116

mp3por avatar Nov 15 '23 09:11 mp3por

@tcgilbert can we get that PR?

Fabioni avatar Jan 25 '24 01:01 Fabioni

I dont want to tag them but with tcgilbert's solution Im getting Illegal constructor for the line new google.maps.marker.AdvancedMarkerElement(...). I'm not using typescript, so there is that change, although I cant currently think of why that itself would matter.

bradley avatar Jan 31 '24 16:01 bradley

So I was able to add Advanced Markers by doing the following:

  • When loading @react-google-maps/api, add `libraries: ["marker"]
  const { isLoaded } = useJsApiLoader({
    googleMapsApiKey: "<redacted>",
    libraries: ["marker"],
  });
  • In my Google Map component, I'm iterating through my locations and rendering custom Marker components:
 <GoogleMap
        center={center}
        zoom={13}
        options={options}
        mapContainerStyle={{ width: "100%", height: "100%" }}
        onLoad={onLoad}
        onBoundsChanged={handleBoundsChanged}
      >
        {mapRef.current &&
          locations.map((location) => {
            return (
              <Marker
                key={location.id}
                map={mapRef.current}
                position={{ lat: location.lat, lng: location.lng }}
              >
                <div className="marker">
                  <h2>{location.name}</h2>
                </div>
              </Marker>
            );
          })}
      </GoogleMap>

Here is the custom Marker component:

"use client";
import { FC, useRef, useEffect } from "react";
import { createRoot, Root } from "react-dom/client";

type LatLngLiteral = google.maps.LatLngLiteral;
type Map = google.maps.Map;
type AdvancedMarkerElement = google.maps.marker.AdvancedMarkerElement;

interface MarkerProps {
  map: Map;
  position: LatLngLiteral;
  children: React.ReactNode;
}

const Marker: FC<MarkerProps> = ({ map, position, children }) => {
  const markerRef = useRef<AdvancedMarkerElement>();
  const rootRef = useRef<Root>();
  useEffect(() => {
    if (!rootRef.current) {
      const container = document.createElement("div");
      rootRef.current = createRoot(container);
      markerRef.current = new google.maps.marker.AdvancedMarkerElement({
        position,
        content: container,
      });
    }
  }, []);

  useEffect(() => {
    if (!markerRef.current || !rootRef.current) return;
    rootRef.current.render(children);
    markerRef.current.position = position;
    markerRef.current.map = map;
  }, [map, position, children]);

  return <></>;
};

export default Marker;

This works by essentially translating the jsx/React node (children prop in the above Marker component) into a proper HTML dom element. Tbh I'm not the best at detailing why this works, but I got the insight from this video: https://www.youtube.com/watch?v=8kxYqoY2WwE&t=1019s&ab_channel=GoogleMapsPlatform

Heads up, if the mapRef is null when the component mounts, the markers will not show. Given that the ref updating won't trigger a re-render, I needed to create a new state variable (mapLoaded) to replace mapRef.current in the statement that triggers the Markers to show. Once the mapRef is set in the onLoad callback, I set mapLoaded to true.

rex-smith avatar Feb 02 '24 05:02 rex-smith

More actual the need of AdvancedMarker after deprecation warning from Google

alexandermirzoyan avatar Mar 05 '24 11:03 alexandermirzoyan

Please implement this import

karlcarstensen avatar Mar 07 '24 18:03 karlcarstensen

Please implement this import

Which import?

alexandermirzoyan avatar Mar 08 '24 07:03 alexandermirzoyan

Please implement this import

Which import?

AdvancedMarker

karlcarstensen avatar Mar 08 '24 07:03 karlcarstensen

Please implement this import

Which import?

AdvancedMarker

Seems they don't export such component. At which version are you importing that?

alexandermirzoyan avatar Mar 08 '24 07:03 alexandermirzoyan

Please implement this import

Which import?

AdvancedMarker

Seems they don't export such component. At which version are you importing that?

Right now only Marker is exported but Google has started throwing a warning because it’s depreciated. AdvancedMarker needs to be exported so that it can be used to remove the warning.

karlcarstensen avatar Mar 08 '24 07:03 karlcarstensen

Please implement this import

Which import?

AdvancedMarker

Seems they don't export such component. At which version are you importing that?

Right now only Marker is exported but Google has started throwing a warning because it’s depreciated. AdvancedMarker needs to be exported so that it can be used to remove the warning.

I am also here with the same problem :) I thought you already found that the package has exported <AdvancedMarker /> component. So let's wait for the contributors.

alexandermirzoyan avatar Mar 08 '24 07:03 alexandermirzoyan

@rex-smith Hey! Can you show the code of the Google map and Marker component in full? I don't quite understand what you have changed.

barabanoveugene avatar Mar 11 '24 16:03 barabanoveugene

@barabanoveugene

  1. Here's the marker component
const Marker = ({
  map,
  position,
  children,
  onClick,
}: MarkerProps) => {
  const markerRef = useRef<AdvancedMarkerElement>();
  const rootRef = useRef<Root>();
  useEffect(() => {
    if (!rootRef.current) {
      const container = document.createElement("div");
      rootRef.current = createRoot(container);
      markerRef.current = new google.maps.marker.AdvancedMarkerElement({
        position,
        content: container,
      });
    }
  }, [position]);

  useEffect(() => {
    if (!markerRef.current || !rootRef.current) return;
    rootRef.current.render(children);
    markerRef.current.position = position;
    markerRef.current.map = map;
    const clickListener = markerRef.current.addListener("click", onClick);
    return () => {
      clickListener.remove();
    };
  }, [map, position, children, onClick]);

  return <></>;
};
  1. Here's the GoogleMap component and onLoad function where the mapRef is initialized. In hindsight, I'm not sure why I didn't just hold the map in state rather than using a ref and keeping "mapLoaded" in state. In the GoogleMap component example, the map is just put into state with setMap(map) instead of mapRef.current = map below. That's how I see it in the example people have been basing this off of too https://github.com/leighhalliday/google-maps-threejs/blob/main/pages/markers.js (although without using the GoogleMap component from this library). In these cases, "map" just replaces "mapLoaded" where I have it below.
const [mapLoaded, setMapLoaded] = useState(false);
const mapRef = useRef<google.maps.Map | null>(null);
const onLoad = useCallback(
    (map: google.maps.Map) => {
      mapRef.current = map;
      setMapLoaded(true);
    },
  );

 <GoogleMap
        center={center}
        zoom={13}
        options={options}
        onLoad={onLoad}
      >
        {mapLoaded &&
          locations.map((location) => {
            return (
              <Marker
                key={location.id}
                map={mapRef.current}
                position={{ lat: location.lat, lng: location.lng }}
              >
                <div className="marker">
                  <h2>{location.name}</h2>
                </div>
              </Marker>
            );
          })}
      </GoogleMap>

rex-smith avatar Mar 11 '24 22:03 rex-smith

@rex-smith can you please make a PR into the package?

JustFly1984 avatar Mar 11 '24 23:03 JustFly1984

@JustFly1984 I just tried, but I can't install the dependencies for some reason

image

rex-smith avatar Mar 13 '24 17:03 rex-smith

@rex-smith use yarn@1

JustFly1984 avatar Mar 14 '24 23:03 JustFly1984

So implementation is fine, however it is missing many of the events and even will not support the clusters, I am using this package in a medium size project, and now google api started throwing error that, they deprecated the markers.

So AdvancedMarker with cluster and events supports are must have features.

lovedeep5 avatar Mar 18 '24 11:03 lovedeep5

@rex-smith hey, getting the dev setup to work also does not work for me. You could try to make the PR blindly..

Fabioni avatar Mar 22 '24 18:03 Fabioni

If looking to do clusters with AdvancedMarkers, the docs have a useful example: https://developers.google.com/maps/documentation/javascript/marker-clustering

hassan-mir avatar Apr 03 '24 01:04 hassan-mir

I'm waiting till I get 500$ to my opencollective to implement AdvancedMarker into this library. Currently got 100$. If you guys croudfund this issue, I'll release new version with AdvancedMarker

JustFly1984 avatar Apr 03 '24 02:04 JustFly1984

also found this lib solving most of my problems: https://visgl.github.io/react-google-maps/docs/api-reference/components/advanced-marker

hassan-mir avatar Apr 04 '24 01:04 hassan-mir

@hassan-mir did you add a component from this library or completely redo the whole project?

pct-bchumak avatar Apr 04 '24 08:04 pct-bchumak

@rex-smith Could you share a complete example - of your use of the Marker component using AdvancedMarkerElement?

pct-bchumak avatar Apr 04 '24 09:04 pct-bchumak

@alexandermirzoyan you didn't get a fix on the warning?

pct-bchumak avatar Apr 04 '24 09:04 pct-bchumak