I was trying to create a custom marker using Google Maps advanced markers
Data so that you can reproduce the example. Just put any image where image is being used.
const center = {
lat: 28.7041,
lng: 77.102,
};
const markers = [
{
key: "1",
coordinates: {
lat: 28.7041,
lng: 77.102,
},
marker: {
text: "BUS-001",
backgroundColor: "black",
},
},
{
key: "2",
coordinates: {
lat: 28.4557,
lng: 77.032,
},
marker: {
text: "BUS-002",
backgroundColor: "red",
},
},
{
key: "3",
coordinates: {
lat: 28.457,
lng: 77.0412,
},
marker: {
text: "BUS-003",
backgroundColor: "blue",
},
},
];
import React, { useEffect, useState } from "react";
import Typography from "@mui/material/Typography"; // Update the import statement
import busTopViewImage from "../assets/bus-top-view.png";
import { Grid } from "@mui/material";
const Map = ({ center, markers }) => {
useEffect(() => {
async function initMap() {
const { Map } = (await google.maps.importLibrary(
"maps"
)) as google.maps.MapsLibrary;
const { AdvancedMarkerElement } = (await google.maps.importLibrary(
"marker"
)) as google.maps.MarkerLibrary;
const map = new Map(document.getElementById("map-view") as HTMLElement, {
center,
zoom: 14,
mapId: "4504f8b37365c3d0",
});
let mapMarkers = [];
for (let markerData of markers) {
const markerComponent = document.createElement("div");
markerComponent.innerHTML = `
<img src="${busTopViewImage}" />
<h5 style="background-color: ${markerData.marker.backgroundColor}; color: white; border-radius: 10px; padding: 8px;">
${markerData.marker.text}
</h5>
`;
const m = new AdvancedMarkerElement({
map,
position: markerData.coordinates,
content: markerComponent,
});
mapMarkers.push(m);
}
}
initMap();
}, []);
return <div id="map-view" style={{ width: "100%", height: "100%" }}></div>;
};
export default Map;
The issue I am facing is that I want to use a React component as marker as below.
const Marker = ({ text, backgroundColor }) => {
return (
<Grid
container
justifyContent="stretch"
alignItems="center"
direction="column"
style={{
boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)",
marginBottom: "3rem",
}}
>
<img src={busTopViewImage} alt="Bus Marker" />
<Grid
item
style={{
boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)",
backgroundColor: backgroundColor,
borderRadius: "10px",
padding: "0 0.5rem",
}}
>
<Typography variant="body1" color="white">
{text}
</Typography>
</Grid>
</Grid>
);
};
To what I know about react, it uses babel to convert jsx to javascript nodes using the document.createElement
as that api wants. I want to know if there is any library/react function that can ingest this Marker
component and help me use remove that ugly markerComponent.innerHTML
in that useEffect.
If you know of any method please share an example or provide some sources of information.
I already tried the react packages available for google maps. Some only allow static images and one of them accepted the Marker but while zooming in and out didn't change the marker position.
As you can tell, you can pass DOM nodes into advanced markers like you have here:
const markerComponent = document.createElement("div");
markerComponent.innerHTML = `
<img src="${busTopViewImage}" />
<h5 style="background-color: ${markerData.marker.backgroundColor}; color: white; border-radius: 10px; padding: 8px;">
${markerData.marker.text}
</h5>
`;
const m = new AdvancedMarkerElement({
map,
position: markerData.coordinates,
content: markerComponent,
});
The only thing you're missing is to generate the HTML via React.
// Setup a React root on a virtual DOM node
const markerComponent = document.createElement("div");
// Initialize root at new DOM node
const root = ReactDOM.createRoot(el);
// Output HTML into it
root.render(<Marker ... />);
// Use it
const m = new AdvancedMarkerElement({
map,
position: markerData.coordinates,
content: markerComponent,
});
If you need to share state with the rest of the tree, you can combine this with Portals.