Open SaavanNanavati opened 1 year ago
@JustFly1984 It seems like you're really active here so just wanted to tag for visibility. Thanks.
+1 on this. Bumping up.
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...
So I was able to add Advanced Markers by doing the following:
const { isLoaded } = useJsApiLoader({
googleMapsApiKey: "<redacted>",
libraries: ["marker"],
});
<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
"use client" is only next.js compatible
@tcgilbert Your PR is welcome, can you please add this component to the library? I would publish new version.
Hello, I get the following error
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
@tcgilbert can we get that PR?
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.
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.
More actual the need of AdvancedMarker after deprecation warning from Google
Please implement this import
Please implement this import
Which import?
Please implement this import
Which import?
AdvancedMarker
Please implement this import
Which import?
AdvancedMarker
Seems they don't export such component. At which version are you importing that?
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.
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
@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
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 <></>;
};
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 can you please make a PR into the package?
@JustFly1984 I just tried, but I can't install the dependencies for some reason
@rex-smith use yarn@1
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.
@rex-smith hey, getting the dev setup to work also does not work for me. You could try to make the PR blindly..
If looking to do clusters with AdvancedMarkers, the docs have a useful example: https://developers.google.com/maps/documentation/javascript/marker-clustering
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
also found this lib solving most of my problems: https://visgl.github.io/react-google-maps/docs/api-reference/components/advanced-marker
@hassan-mir did you add a component from this library or completely redo the whole project?
@rex-smith Could you share a complete example - of your use of the Marker component using AdvancedMarkerElement?
@alexandermirzoyan you didn't get a fix on the warning?
@alexandermirzoyan you didn't get a fix on the warning?
Not yet, still waiting for a working solution
@hassan-mir did you add a component from this library or completely redo the whole project?
redid the Map related bits. Was already using a MapProvider, now a simpler ApiProvider, GoogleMap replaced with Map and some minor rework but think it was worth it. Still had to treat the AdvancedMarker as a HTML element to get my animation to work but libs only a few months old, hoping for a better solution soon
I solved the problem by 'stealing' the component from visgl (https://github.com/visgl/react-google-maps/blob/main/src/components/advanced-marker.tsx). 500$ for this would have been like the best hourly pay you can imagine haha.
I additionally added right-click
, clickable
and anchorAbove
. If you need further explanation, let me know.
In general the advanced markers do not feel completely mature, so you might have to fiddle around a bit, but this has nothing to do with the library here.
I did remove the possibility to use the pin component (https://github.com/visgl/react-google-maps/blob/main/src/components/pin.tsx), it did work, but I just did not need it.
The actuall contribution to make this work is just adding this to connect the two librarys.
import { MapContext } from '@react-google-maps/api';
// ...
const map = useContext(MapContext);
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
// Based on https://github.dev/visgl/react-google-maps because the original package is not maintained anymore and misses advanced markers
/* eslint-disable complexity */
import React, {
Children,
forwardRef,
useCallback,
useContext,
useEffect,
useImperativeHandle,
useMemo,
useState
} from 'react';
import { createPortal } from 'react-dom';
import type { Ref, PropsWithChildren } from 'react';
import { MapContext } from '@react-google-maps/api';
export interface AdvancedMarkerContextValue {
marker: google.maps.marker.AdvancedMarkerElement;
}
export const AdvancedMarkerContext =
React.createContext<AdvancedMarkerContextValue | null>(null);
type AdvancedMarkerEventProps = {
onClick?: (e: MouseEvent) => void;
onRightClick?: (e: MouseEvent) => void;
onDrag?: (e: google.maps.MapMouseEvent) => void;
onDragStart?: (e: google.maps.MapMouseEvent) => void;
onDragEnd?: (e: google.maps.MapMouseEvent) => void;
};
export type AdvancedMarkerProps = PropsWithChildren<
Omit<google.maps.marker.AdvancedMarkerElementOptions, 'gmpDraggable'> &
AdvancedMarkerEventProps & {
/**
* className to add a class to the advanced marker element
* Can only be used with HTML Marker content
*/
className?: string;
anchorAbove?: boolean;
draggable?: boolean;
clickable?: boolean; // right now this just deactivates the onClick handler but does not change the google maps marker behaviour
}
>;
export type AdvancedMarkerRef = google.maps.marker.AdvancedMarkerElement | null;
function useAdvancedMarker(props: AdvancedMarkerProps) {
const [marker, setMarker] =
useState<google.maps.marker.AdvancedMarkerElement | null>(null);
const [contentContainer, setContentContainer] =
useState<HTMLDivElement | null>(null);
const map = useContext(MapContext);
const markerLibrary = google.maps.marker
const {
children,
className,
anchorAbove,
onClick,
onRightClick,
onDrag,
onDragStart,
onDragEnd,
collisionBehavior,
draggable,
clickable,
position,
title,
zIndex
} = props;
const numChilds = Children.count(children);
// create marker instance and add it to the map when map becomes available
useEffect(() => {
if (!map || !markerLibrary) return;
const newMarker = new markerLibrary.AdvancedMarkerElement();
newMarker.map = map;
setMarker(newMarker);
// create container for marker content if there are children
if (numChilds > 0) {
const el = document.createElement('div');
if (!anchorAbove) el.style.transform = 'translate(0, 50%)';
if (className) el.className = className;
newMarker.content = el;
setContentContainer(el);
}
return () => {
newMarker.map = null;
setMarker(null);
setContentContainer(null);
};
// We do not want to re-render the whole marker when the className changes
// because that causes a short flickering of the marker.
// The className update is handled in the useEffect below.
// Excluding the className from the dependency array onm purpose here
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [map, markerLibrary, numChilds]);
useEffect(() => {
if ((className?.includes('translate') || className?.includes('transform')) && !anchorAbove) console.warn("not setting anchorAbove automatically set 'transform: translate(0, 50%)' to center the marker on the position. Set this to false to be able to use custom translate values.");
}, [className, anchorAbove]);
// update className of advanced marker element
useEffect(() => {
if (!contentContainer) return;
contentContainer.className = className ?? '';
}, [contentContainer, className]);
// bind all marker events
useEffect(() => {
if (!marker) return;
const gme = google.maps.event;
const controller = new AbortController();
const { signal } = controller;
// TODO fix the type mismatch for click and contextmenu events
// marker.addEventListener("gmp-click", (e: google.maps.marker.AdvancedMarkerClickEvent) => { console.log(e) }); // only available in beta and misses some properties, check https://issuetracker.google.com/issues/331684436
if (onClick && clickable) gme.addListener(marker, 'click', (e: { domEvent: PointerEvent }) => onClick(e.domEvent));
if (onRightClick && clickable) marker.content?.addEventListener('contextmenu', onRightClick, { signal }); // setting marker.addEventListener directly onces this is out of beta
if (onDrag && draggable) gme.addListener(marker, 'drag', onDrag);
if (onDragStart && draggable) gme.addListener(marker, 'dragstart', onDragStart);
if (onDragEnd && draggable) gme.addListener(marker, 'dragend', onDragEnd);
if ((onDrag || onDragStart || onDragEnd) && !draggable) {
console.warn(
'You need to set the marker to draggable to listen to drag-events.'
);
}
if ((onClick && !clickable) || (onRightClick && !clickable)) {
console.warn(
'You need to set the marker to clickable to listen to click-events.'
);
}
const m = marker;
return () => {
gme.clearInstanceListeners(m); // for addListener
controller.abort(); // for addEventListener
};
}, [marker, draggable, onClick, onDragStart, onDrag, onDragEnd, onRightClick, clickable]);
// update other marker props when changed
useEffect(() => {
if (!marker) return;
if (position !== undefined) marker.position = position;
if (draggable !== undefined) marker.gmpDraggable = draggable;
// use marker.gmpClickable once this is resolved https://issuetracker.google.com/issues/331684436
if (collisionBehavior !== undefined)
marker.collisionBehavior = collisionBehavior;
if (zIndex !== undefined) marker.zIndex = zIndex;
if (typeof title === 'string') marker.title = title;
}, [marker, position, draggable, collisionBehavior, zIndex, title, clickable]);
return [marker, contentContainer] as const;
}
const AdvancedMarkerComponent = forwardRef(
(props: AdvancedMarkerProps, ref: Ref<AdvancedMarkerRef>) => {
const { children } = props;
const [marker, contentContainer] = useAdvancedMarker(props);
const advancedMarkerContextValue: AdvancedMarkerContextValue | null =
useMemo(() => (marker ? { marker } : null), [marker]);
useImperativeHandle(ref, () => marker, [marker]);
if (!marker) {
return null;
}
// we could add other props here to the context, but lets try to achieve this with tailwind group or other means first
return (
<AdvancedMarkerContext.Provider value={advancedMarkerContextValue}>
{contentContainer !== null && createPortal(children, contentContainer)}
</AdvancedMarkerContext.Provider>
);
}
);
AdvancedMarkerComponent.displayName = 'AdvancedMarker';
export const AdvancedMarker = AdvancedMarkerComponent;
// eslint-disable-next-line react-refresh/only-export-components
export function useAdvancedMarkerRef() {
const [marker, setMarker] =
useState<google.maps.marker.AdvancedMarkerElement | null>(null);
const refCallback = useCallback((m: AdvancedMarkerRef | null) => {
setMarker(m);
}, []);
return [refCallback, marker] as const;
}
I solved the problem by 'stealing' the component from visgl (https://github.com/visgl/react-google-maps/blob/main/src/components/advanced-marker.tsx). 500$ for this would have been like the best hourly pay you can imagine haha. I additionally added
right-click
,clickable
andanchorAbove
. If you need further explanation, let me know. In general the advanced markers do not feel completely mature, so you might have to fiddle around a bit, but this has nothing to do with the library here. I did remove the possibility to use the pin component (https://github.com/visgl/react-google-maps/blob/main/src/components/pin.tsx), it did work, but I just did not need it.The actuall contribution to make this work is just adding this to connect the two librarys.
import { MapContext } from '@react-google-maps/api'; // ... const map = useContext(MapContext);
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */ // Based on https://github.dev/visgl/react-google-maps because the original package is not maintained anymore and misses advanced markers /* eslint-disable complexity */ import React, { Children, forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useMemo, useState } from 'react'; import { createPortal } from 'react-dom'; import type { Ref, PropsWithChildren } from 'react'; import { MapContext } from '@react-google-maps/api'; export interface AdvancedMarkerContextValue { marker: google.maps.marker.AdvancedMarkerElement; } export const AdvancedMarkerContext = React.createContext<AdvancedMarkerContextValue | null>(null); type AdvancedMarkerEventProps = { onClick?: (e: MouseEvent) => void; onRightClick?: (e: MouseEvent) => void; onDrag?: (e: google.maps.MapMouseEvent) => void; onDragStart?: (e: google.maps.MapMouseEvent) => void; onDragEnd?: (e: google.maps.MapMouseEvent) => void; }; export type AdvancedMarkerProps = PropsWithChildren< Omit<google.maps.marker.AdvancedMarkerElementOptions, 'gmpDraggable'> & AdvancedMarkerEventProps & { /** * className to add a class to the advanced marker element * Can only be used with HTML Marker content */ className?: string; anchorAbove?: boolean; draggable?: boolean; clickable?: boolean; // right now this just deactivates the onClick handler but does not change the google maps marker behaviour } >; export type AdvancedMarkerRef = google.maps.marker.AdvancedMarkerElement | null; function useAdvancedMarker(props: AdvancedMarkerProps) { const [marker, setMarker] = useState<google.maps.marker.AdvancedMarkerElement | null>(null); const [contentContainer, setContentContainer] = useState<HTMLDivElement | null>(null); const map = useContext(MapContext); const markerLibrary = google.maps.marker const { children, className, anchorAbove, onClick, onRightClick, onDrag, onDragStart, onDragEnd, collisionBehavior, draggable, clickable, position, title, zIndex } = props; const numChilds = Children.count(children); // create marker instance and add it to the map when map becomes available useEffect(() => { if (!map || !markerLibrary) return; const newMarker = new markerLibrary.AdvancedMarkerElement(); newMarker.map = map; setMarker(newMarker); // create container for marker content if there are children if (numChilds > 0) { const el = document.createElement('div'); if (!anchorAbove) el.style.transform = 'translate(0, 50%)'; if (className) el.className = className; newMarker.content = el; setContentContainer(el); } return () => { newMarker.map = null; setMarker(null); setContentContainer(null); }; // We do not want to re-render the whole marker when the className changes // because that causes a short flickering of the marker. // The className update is handled in the useEffect below. // Excluding the className from the dependency array onm purpose here // eslint-disable-next-line react-hooks/exhaustive-deps }, [map, markerLibrary, numChilds]); useEffect(() => { if ((className?.includes('translate') || className?.includes('transform')) && !anchorAbove) console.warn("not setting anchorAbove automatically set 'transform: translate(0, 50%)' to center the marker on the position. Set this to false to be able to use custom translate values."); }, [className, anchorAbove]); // update className of advanced marker element useEffect(() => { if (!contentContainer) return; contentContainer.className = className ?? ''; }, [contentContainer, className]); // bind all marker events useEffect(() => { if (!marker) return; const gme = google.maps.event; const controller = new AbortController(); const { signal } = controller; // TODO fix the type mismatch for click and contextmenu events // marker.addEventListener("gmp-click", (e: google.maps.marker.AdvancedMarkerClickEvent) => { console.log(e) }); // only available in beta and misses some properties, check https://issuetracker.google.com/issues/331684436 if (onClick && clickable) gme.addListener(marker, 'click', (e: { domEvent: PointerEvent }) => onClick(e.domEvent)); if (onRightClick && clickable) marker.content?.addEventListener('contextmenu', onRightClick, { signal }); // setting marker.addEventListener directly onces this is out of beta if (onDrag && draggable) gme.addListener(marker, 'drag', onDrag); if (onDragStart && draggable) gme.addListener(marker, 'dragstart', onDragStart); if (onDragEnd && draggable) gme.addListener(marker, 'dragend', onDragEnd); if ((onDrag || onDragStart || onDragEnd) && !draggable) { console.warn( 'You need to set the marker to draggable to listen to drag-events.' ); } if ((onClick && !clickable) || (onRightClick && !clickable)) { console.warn( 'You need to set the marker to clickable to listen to click-events.' ); } const m = marker; return () => { gme.clearInstanceListeners(m); // for addListener controller.abort(); // for addEventListener }; }, [marker, draggable, onClick, onDragStart, onDrag, onDragEnd, onRightClick, clickable]); // update other marker props when changed useEffect(() => { if (!marker) return; if (position !== undefined) marker.position = position; if (draggable !== undefined) marker.gmpDraggable = draggable; // use marker.gmpClickable once this is resolved https://issuetracker.google.com/issues/331684436 if (collisionBehavior !== undefined) marker.collisionBehavior = collisionBehavior; if (zIndex !== undefined) marker.zIndex = zIndex; if (typeof title === 'string') marker.title = title; }, [marker, position, draggable, collisionBehavior, zIndex, title, clickable]); return [marker, contentContainer] as const; } const AdvancedMarkerComponent = forwardRef( (props: AdvancedMarkerProps, ref: Ref<AdvancedMarkerRef>) => { const { children } = props; const [marker, contentContainer] = useAdvancedMarker(props); const advancedMarkerContextValue: AdvancedMarkerContextValue | null = useMemo(() => (marker ? { marker } : null), [marker]); useImperativeHandle(ref, () => marker, [marker]); if (!marker) { return null; } // we could add other props here to the context, but lets try to achieve this with tailwind group or other means first return ( <AdvancedMarkerContext.Provider value={advancedMarkerContextValue}> {contentContainer !== null && createPortal(children, contentContainer)} </AdvancedMarkerContext.Provider> ); } ); AdvancedMarkerComponent.displayName = 'AdvancedMarker'; export const AdvancedMarker = AdvancedMarkerComponent; // eslint-disable-next-line react-refresh/only-export-components export function useAdvancedMarkerRef() { const [marker, setMarker] = useState<google.maps.marker.AdvancedMarkerElement | null>(null); const refCallback = useCallback((m: AdvancedMarkerRef | null) => { setMarker(m); }, []); return [refCallback, marker] as const; }
OMG $500 code just in a comments hahahah.
@Fabioni thank you so much!
@Fabioni thank you so much!
could you help with this solution?
import { MapContext } from '@react-google-maps/api';
// ...
const map = useContext(MapContext);
when i need to use this part and how i can add my own icon?
Hey @pct-bchumak , as far as I know, advanced_markers have no special icon functionality, so you would just use it like any other marker content, like this:
<AdvancedMarker>
<svg></svg>
</AdvancedMarker>
<AdvancedMarker>
<i class="fa-solid fa-house"></i>
</AdvancedMarker>
@Fabioni thanks! And
import { MapContext } from '@react-google-maps/api';
// ...
const map = useContext(MapContext);
this part i need to use in map component?
@pct-bchumak this part is already included in the code of advanced marker, that I shared. It was just to clarify what I added.
Just copy and paste the big code I shared into a new file and use AdvancedMarker
as a component the same way you would use other react-google-maps components.
... I did remove the possibility to use the pin component (https://github.com/visgl/react-google-maps/blob/main/src/components/pin.tsx), it did work, but I just did not need it...
What do you mean with this removing? I couldn't find anything related to the pin-component in VISGL-advancedMarker either?
Hey @jukkahuuskonen, you are right, I actually did NOT remove it. In the following code, a React context is created so that the children of the advanced marker can access the advanced marker component.
<AdvancedMarkerContext.Provider value={advancedMarkerContextValue}>
{contentContainer !== null && createPortal(children, contentContainer)}
</AdvancedMarkerContext.Provider>
This is only used by the pin component (which you can just copy and paste from the visgl code). The pin component does
// ...
const advancedMarker = useContext(AdvancedMarkerContext)?.marker;
advancedMarker.content = pinElement.element;
I thought I changed that to the following, but apparently I did not, haha.
<>
{contentContainer !== null && createPortal(children, contentContainer)}
</>
Hey @jukkahuuskonen, you are right, I actually did NOT remove it. ...
Great, since we actually do have a use for Pin-component.
@jukkahuuskonen, nice, you can just use it from visgl :) My opinion: I think the pin component is just for convenience and somehow feels not correct because of its special treatment (it is no html, but is a js instantiated objects added to the marker object). At the end, being able to use any HTML including img and svg means there is no reason to restrict yourself with the google maps pin component in my opinion.
The way I use it is via:
<AdvancedMarker>
<svg>
<!-- my custom, more flexible and react handled pin replacement -->
</svg>
</AdvancedMarker>
@jukkahuuskonen, nice, just use it :) I think the pin component is just for convenience and somehow feels not correct because of its special treatment. At the end, being able to use any HTML including img and svg means there is no reason to restrict yourself with the google maps pin component in my opinion.
The way I use it is via:
<AdvancedMarker> <svg> <!-- my custom, more flexible and react handled pin replacement --> </svg> </AdvancedMarker>
@Fabioni Ah, just got into this advanced marker and didn't realize that the pin is just the standard pin. In that case, we'll probably be using SVG there too.
Thanks again!
Just as a note to everyone. It seems that the unlike the old google marker new advancedMarker doesn't support eg. mouseover/mouseout-events. If you are relying on those with advancedMarkers (eg to show OverlayView like in below example), you will need to move them from the marker-component itself to your custom marker component eg:
/* global google */
import { useCallback, useState } from 'react';
import { OverlayView } from '@react-google-maps/api';
import useDebounceState from 'hooks/useDebounceState';
import MySvgPin from 'shared/theme/assets/svg/MySvgPin.svg?react';
import { AdvancedMarker } from 'shared/components/Maps/AdvancedMarker';
const MyMarker = ({ latLng }) => {
const [showInfoWindow, setShowInfoWindow] = useDebounceState(false, {
timeout: 50,
onlyLast: true,
});
const handleMouseOver = useCallback(() => {
setShowInfoWindow(true);
}, [setShowInfoWindow]);
const handleMouseOut = useCallback(() => {
setShowInfoWindow(false);
}, [setShowInfoWindow]);
return (
<AdvancedMarker
// onMouseOver={handleMouseOver} MOVE THESE TO YOUR CUSTOM PIN-COMPONENT
// onMouseOut={handleMouseOut} MINE IS AN SVG, BUT SHOULD WORK WITH ANY REGULAR COMPONENT
>
<MySvgPin
onMouseOver={handleMouseOver}
onMouseOut={handleMouseOut}
/>
{showInfoWindow ? (
<OverlayView
position={latLng}
style={{ left: '100px', width: '0px', height: '0px' }}
mapPaneName={OverlayView.FLOAT_PANE}
>
<MyInfoComponent />
</OverlayView>
) : null}
</AdvancedMarker>
);
};
export default MyMarker;
Current MarkerClusterer doesn't support new advanced markers.
I rewrote those components so that they work (at least on my project) and posted them in discussion here: https://github.com/JustFly1984/react-google-maps-api/discussions/3349
If you need them in your project, feel free to experiment with them and if you have time and energy, maybe create a PR to fix them in this project.
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!