How to use MarkerClusterer with #googlemaps/react-wrapper - reactjs

After following this example provided by google for adding a map and markers to a react application using #googlemaps/react-wrapper, I decided to try adding marker clustering to my app. However, I am unable to get the clusters to appear.
I tried following this question/answer but no clusters have appeared despite adding new MarkerClusterer({ ref, markers }); to my code:
App.js
/*global google*/
import { useState, useEffect, useRef } from "react";
import { Wrapper } from "#googlemaps/react-wrapper";
import { MarkerClusterer } from "#googlemaps/markerclusterer";
import { createCustomEqual } from "fast-equals";
const markerList = [
{ id: "A12345", uuid: "500924cf83424aad9e7d386bbec88ef6", lat: 44.459744, lng: -73.214126, assetName: "A" },
{ id: "B09423", uuid: "500924cf83424aad9e7d386bbec88ef6", lat: 44.465291, lng: -73.190723, assetName: "A" },
{ id: "C98765", uuid: "c0385833-e483-40d1-803f-2b4c26ae3799", lat: 44.476949, lng: -73.210578, assetName: "B" },
{ id: "D99999", uuid: "c0385833-e483-40d1-803f-2b4c26ae3799", lat: 44.444572, lng: -73.208741, assetName: "B" },
{ id: "E12345", uuid: "500924cf83424aad9e7d386bbec88ef6", lat: 38.459744, lng: -81.214126, assetName: "A" },
{ id: "F09423", uuid: "500924cf83424aad9e7d386bbec88ef6", lat: 38.465291, lng: -81.190723, assetName: "A" },
{ id: "G98765", uuid: "c0385833-e483-40d1-803f-2b4c26ae3799", lat: 38.476949, lng: -81.210578, assetName: "B" },
{ id: "H99999", uuid: "c0385833-e483-40d1-803f-2b4c26ae3799", lat: 38.444572, lng: -81.208741, assetName: "B" },
]
const render = (status) => {
return <h1>{status}</h1>;
};
const App = () => {
const [zoom, setZoom] = useState(8); // initial zoom
const [center, setCenter] = useState({ lat: 44.45, lng: -73.21 });
const onIdle = (m) => {
console.log("onIdle");
};
return (
<>
<div style={{ width: "500px", height: "500px" }}>
<Wrapper
apiKey={process.env.REACT_APP_GOOGLE_MAPS_API_KEY}
render={render}
>
<Map
center={center}
onIdle={onIdle}
zoom={zoom}
style={{ flexGrow: "1", height: "100%" }}
/>
</Wrapper>
</div>
</>
);
};
const Map = ({ onIdle, children, style, ...options }) => {
const ref = useRef(null);
const [map, setMap] = useState();
useEffect(() => {
if (ref.current && !map) {
setMap(new window.google.maps.Map(ref.current, {}));
}
// Add some markers to the map.
const markers = markerList.map((m) => {
return new window.google.maps.Marker({
position: { lat: parseFloat(m.lat), lng: parseFloat(m.lng) }
//map: map,
});
});
// Add a marker clusterer to manage the markers.
new MarkerClusterer({ ref, markers });
}, [ref, map]);
useDeepCompareEffectForMaps(() => {
if (map) {
map.setOptions(options);
}
}, [map, options]);
useEffect(() => {
if (map) {
["click", "idle"].forEach((eventName) =>
google.maps.event.clearListeners(map, eventName)
);
if (onIdle) {
map.addListener("idle", () => onIdle(map));
}
}
}, [map, onIdle]);
return (
<>
<div ref={ref} style={style} />
</>
);
};
const deepCompareEqualsForMaps = createCustomEqual((deepEqual) => (a, b) => {
if (a instanceof google.maps.LatLng || b instanceof google.maps.LatLng) {
return new google.maps.LatLng(a).equals(new google.maps.LatLng(b));
}
return deepEqual(a, b);
});
function useDeepCompareMemoize(value) {
const ref = useRef();
if (!deepCompareEqualsForMaps(value, ref.current)) {
ref.current = value;
}
return ref.current;
}
function useDeepCompareEffectForMaps(callback, dependencies) {
useEffect(callback, dependencies.map(useDeepCompareMemoize));
}
export default App;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
How can I get MarkerClusterer to function with #googlemaps/react-wrapper?

Replace
new MarkerClusterer({ ref, markers });
with
new MarkerClusterer({ map, markers });
PS: The answer to the mentioned question was updated

Related

Map & Marker nothing showing white page #react-google-maps/api on localhost

import React from 'react'
import { GoogleMap, Marker, useJsApiLoader } from '#react-google-maps/api';
const containerStyle = {
width: '95%',
height: '550px'
};
const center = {
lat: 27.8103,
lng: 70.4125
};
function Map(props) {
const { isLoaded } = useJsApiLoader({
id: 'google-map-script',
googleMapsApiKey: "API KEY"
})
const [map, setMap] = React.useState(null)
const onLoad = React.useCallback(function callback(map) {
const bounds = new window.google.maps.LatLngBounds({
lat: props.lat,
lng: props.lng
});
map.fitBounds(bounds);
setMap(map)
}, [])
const onUnmount = React.useCallback(function callback(map) {
setMap(null)
}, [])
return isLoaded ? (
<GoogleMap
mapContainerStyle={containerStyle}
center={center}
zoom={20}
onLoad={onLoad}
onUnmount={onUnmount}>
<></>
<Marker onLoad={onLoad} position={center} />
</GoogleMap>
) : <></>
}
export default Map
I tried pinning the marker to the location but the map is now not showing as the marker is not showing. Totally blank page

React google maps/api: How to focus on the marker position with zoom based on search results?

I need to focus on the marker based on dynamic search results. As far as I understood from other discussions, what I need is to make a use of panTo function.
I gave a try, and it works partially.
Here is the code example and the codesandbox link
Note: Provide your Google Maps key in .env file to test the codesandbox.
Map.js
import { GoogleMap, LoadScript, Marker } from "#react-google-maps/api";
import React, { useEffect } from "react";
const containerStyle = {
width: "100%",
height: "500px"
};
const center = { lat: 45.4211, lng: -75.6903 };
const Maps = ({ filteredPark }) => {
const key = process.env.REACT_APP_GOOGLE_KEY; //test with your key please
if (!key) {
throw new Error("Google token is not set");
}
const mapRef = React.useRef();
const onMapLoad = React.useCallback((map) => {
mapRef.current = map;
}, []);
const panTo = React.useCallback(({ lat, lng }) => {
mapRef?.current?.panTo({ lat, lng });
mapRef?.current?.setZoom(18);
}, []);
useEffect(() => {
filteredPark.map((a) => {
const lat = a.coordinates[1];
const lng = a.coordinates[0];
return panTo({ lat, lng });
});
}, [filteredPark, panTo]);
return (
<div style={{ width: "100%", height: "100%" }}>
<LoadScript googleMapsApiKey={key}>
<GoogleMap
mapContainerStyle={containerStyle}
center={center}
zoom={6}
onLoad={onMapLoad}
>
{filteredPark &&
filteredPark.map((park) => (
<Marker
key={park.PARK_ID}
position={{
lat: park.coordinates[1],
lng: park.coordinates[0]
}}
/>
))}
</GoogleMap>
</LoadScript>
</div>
);
};
export default React.memo(Maps);
custom search hook component
import { useMemo } from "react";
import * as parkData from "./data/skateboard-parks.json";
const useParkFIlter = (DESCRIPT_1) => {
const gridRows = parkData.features.map((park) => park.properties);
const filteredParks = useMemo(() => {
return (
gridRows &&
gridRows.filter((dispo) =>
dispo.DESCRIPT_1.toLowerCase().includes(DESCRIPT_1.toLowerCase())
)
);
}, [DESCRIPT_1, gridRows]);
return [filteredParks];
};
export default useParkFIlter;
Any help will be appreciated.
I have made changes in your code. If it doesn't work, do let me know.
import { GoogleMap, LoadScript, Marker } from "#react-google-maps/api";
import React, { useEffect } from "react";
const containerStyle = {
width: "100%",
height: "500px"
};
const center = { lat: 45.4211, lng: -75.6903 };
const Maps = ({ filteredPark }) => {
const key = process.env.REACT_APP_GOOGLE_KEY; //test with your key please
if (!key) {
throw new Error("Google token is not set");
}
//const mapRef = React.useRef();
const [mapInstance, setMapInstance] = useState(null);
const[zoom, setZoom] = useState(6);
const onMapLoad = React.useCallback((map) => {
//mapRef.current = map;
setMapInstance(map);
}, []);
//const panTo = React.useCallback(({ lat, lng }) => {
//mapRef?.current?.panTo({ lat, lng });
//mapRef?.current?.setZoom(18);
//}, []);
useEffect(()=>{
if(mapInstance){
mapInstance.panTo({ lat, lng });
setZoom(18);
}
},[mapInstance]);
useEffect(() => {
filteredPark.map((a) => {
const lat = a.coordinates[1];
const lng = a.coordinates[0];
return panTo({ lat, lng });
});
}, [filteredPark, panTo]);
return (
<div style={{ width: "100%", height: "100%" }}>
<LoadScript googleMapsApiKey={key}>
<GoogleMap
mapContainerStyle={containerStyle}
center={center}
//zoom={6}
zoom={zoom}
onLoad={onMapLoad}
>
{filteredPark &&
filteredPark.map((park) => (
<Marker
key={park.PARK_ID}
position={{
lat: park.coordinates[1],
lng: park.coordinates[0]
}}
/>
))}
</GoogleMap>
</LoadScript>
</div>
);
};
export default React.memo(Maps);

How to Draw Polyline on mapmyindia using React?

I am just exploring Mapmyindia.
I have gone through the basic location display on the map.
I am not getting how to display polyline on map.
code for location
app.js
import "./App.css";
import SideBar from "./componants/SideBar";
import Map from "mapmyindia-react";
// import MapmyIndia, { MapMarker } from "react-mapmyindia";
function App() {
return (
<div className="App">
Hello
<Map
markers={[
{
position: [21.1588329, 72.7688111],
draggable: true,
zoom: 15,
title: "Marker title",
onClick: (e) => {
console.log("clicked ");
},
onDragend: (e) => {
console.log("dragged");
},
onMouseover: (e) => {
console.log("Mouse over");
},
},
]}
/>
{/* <Map /> */}
<SideBar></SideBar>
</div>
);
}
export default App;
Which result this
Now, Please help with drawing polyline.
I guess you're using the npm package for maps. If you go through the library's code in gitHub, you can see the owner has only added marker functionality. You can simply copy the code from there and add it manually to your project and then add the polyline functionality and then pass the data as props from your app.js file like you're doing for markers.
renderPolylines = () => {
const { polylines = [] } = this.props;
if (!this.map) {
return;
}
polylines.map(m => {
if (m?.position && Array.isArray(m.position)) {
const { position, color, weight, opacity } = m;
let points = [];
position.map(p => {
const { lat, lng } = p;
const center = new L.LatLng(lat, lng);
points.push(
new L.LatLng(center.lat, center.lng))/*array of wgs points*/
})
const polyline = new L.Polyline(points, { color, weight, opacity });
this.map.addLayer(polyline);
this.polylines.push(polyline);
}
});
};
Props for rendering polyline from app.js
polylines = {[
{
position: [
{
lat: 18.5014,
lng: 73.805,
},
{
lat: 18.5414,
lng: 73.855,
},
{
lat: 18.5514,
lng: 73.855,
},
{
lat: 18.5614,
lng: 73.855,
},
],
color: "red",
weight: 4,
opacity: 0.5,
},
]}

How to Fit Boundaries and Center React Google Maps

I am new to React Google Maps. I am using this library to create a map with several locations and trying fit the boundaries and center it. I have used this example.
After I populate the map, I want the map to change its center based on the places which have been populated rather than the default center. I am unable to achieve this. The following is my code.
import React, { useState, useEffect } from "react"
import {
GoogleMap,
LoadScript,
Marker,
InfoWindow,
} from "#react-google-maps/api"
const Map = () => {
const mapStyles = {
height: "400px",
width: "100%",
}
const defaultCenter = {
lat: 39.76866069032195,
lng: -86.15818042985295,
}
const locations = [
{
name: "Location 1",
location: {
lat: 41.3954,
lng: 2.162,
},
},
{
name: "Location 2",
location: {
lat: 41.3917,
lng: 2.1649,
},
},
{
name: "Location 3",
location: {
lat: 41.3773,
lng: 2.1585,
},
},
{
name: "Location 4",
location: {
lat: 41.3797,
lng: 2.1682,
},
},
{
name: "Location 5",
location: {
lat: 41.4055,
lng: 2.1915,
},
},
]
const [selected, setSelected] = useState({})
const [map, setMap] = useState(null)
const onSelect = item => {
setSelected(item)
}
const Somefunction = map => {
const bounds = new window.google.maps.LatLngBounds()
locations.map((location, i) => {
bounds.extend(new window.google.maps.LatLng(location.lat, location.lng))
})
map.fitBounds(bounds)
setMap(map)
}
return (
<div className="map-container">
<LoadScript googleMapsApiKey="YOUR_API_KEY">
<GoogleMap
mapContainerStyle={mapStyles}
zoom={13}
center={defaultCenter}
onLoad={map => {
const bounds = new window.google.maps.LatLngBounds()
map.fitBounds(bounds)
setMap(map)
}}
>
{locations.map(item => {
return (
<Marker
key={item.name}
position={item.location}
onClick={() => onSelect(item)}
/>
)
})}
{selected.location && (
<InfoWindow
position={selected.location}
clickable={true}
onCloseClick={() => setSelected({})}
>
<p>{selected.name}</p>
</InfoWindow>
)}
</GoogleMap>
</LoadScript>
</div>
)
}
export default Map
With the current code, the map gets centered in some bizarre location and not in the middle of the 5 locations listed above.
I would also appreciate if someone can shed light on how to change the zoom level for different screen size automatically.
The problem I see in the use of functional components is that it is not as flexible as using class based components in terms of this kind of implementation. To be more precise, it would be more beneficial to make use of the react life cycles such as ComponentDidMount which you can only do when using class based components.
Furthermore, you may want to stay away from using 3rd party packages/libraries and instead implement it locally by dynamically adding the script. That way, you would be able to follow Google's official documentation instead of the the 3rd party's. The following is a sample I made to demonstrate this as well as making use of the bounds:
StackBlitz sample: https://stackblitz.com/edit/react-bounds-65524739
or
App.js
import React, { Component } from "react";
import { render } from "react-dom";
import Map from "./components/map";
import "./style.css";
class App extends Component {
render() {
return (
<Map
id="myMap"
options={{
center: { lat: 39.76866069032195, lng: -86.15818042985295 },
zoom: 8
}}
/>
);
}
}
export default App;
map.js
import React, { Component } from "react";
import { render } from "react-dom";
class Map extends Component {
constructor(props) {
super(props);
this.state = {
map: "",
locations: [
{
name: "Location 1",
location: {
lat: 41.3954,
lng: 2.162
}
},
{
name: "Location 2",
location: {
lat: 41.3917,
lng: 2.1649
}
},
{
name: "Location 3",
location: {
lat: 41.3773,
lng: 2.1585
}
},
{
name: "Location 4",
location: {
lat: 41.3797,
lng: 2.1682
}
},
{
name: "Location 5",
location: {
lat: 41.4055,
lng: 2.1915
}
}
]
};
}
onScriptLoad() {
const map = new window.google.maps.Map(
document.getElementById(this.props.id),
this.props.options
);
this.addMarker(map);
}
addMarker(map) {
const bounds = new window.google.maps.LatLngBounds();
this.state.locations.map((location, i) => {
new google.maps.Marker({
position: location.location,
map: map
});
bounds.extend(
new window.google.maps.LatLng(
location.location.lat,
location.location.lng
)
);
});
map.fitBounds(bounds);
}
componentDidMount() {
if (!window.google) {
var s = document.createElement("script");
s.type = "text/javascript";
s.src = `https://maps.google.com/maps/api/js?key=YOUR_API_KEY`;
var x = document.getElementsByTagName("script")[0];
x.parentNode.insertBefore(s, x);
// Below is important.
//We cannot access google.maps until it's finished loading
s.addEventListener("load", e => {
this.onScriptLoad();
});
} else {
this.onScriptLoad();
}
}
render() {
return <div className="map" id={this.props.id} />;
}
}
export default Map;

Limit the number of clicks on map using React

I am using the Google Maps API and I want to limit the number of markers on the map (limit: 10). I couldn't find anything related to it in the API docs
neither I can find any similar source to solve my problem.
Here is my code:
import React from "react";
import {
GoogleMap,
useLoadScript,
Marker,
} from "#react-google-maps/api";
const mapContainerStyle = {
height: "50vh",
width: "100vw",
};
const options = {
zoomControl: false,
scrollwheel: false,
draggable: false
};
const center = {
lat: 34.155834,
lng: -119.202789,
};
export default function App() {
const { isLoaded, loadError } = useLoadScript({
googleMapsApiKey: "AIzaSyCpaQDSgGTCetTR0uz42RyV80cByaGaYLs",
});
const [markers, setMarkers] = React.useState([]);
const onMapClick =
React.useCallback((e) => {
setMarkers((current) =>
[
...current,
{
lat: e.latLng.lat(),
lng: e.latLng.lng(),
},
]);
}, []);
const mapRef = React.useRef();
const onMapLoad = React.useCallback((map) => {
mapRef.current = map;
}, []);
if (loadError) return "Error";
if (!isLoaded) return "Loading...";
return (
<div>
<GoogleMap
id="map"
mapContainerStyle={mapContainerStyle}
zoom={14}
center={center}
options={options}
onClick={onMapClick}
onLoad={onMapLoad}
>
{markers.map((marker) => (
<Marker
key={`${marker.lat}-${marker.lng}`}
position={{ lat: marker.lat, lng: marker.lng }}
onClick={() => {
console.log("clicked")
}}
/>
))}
</GoogleMap>
</div>
);
}
How do I set the number of clicks up to 10?
You could do something like this. You may also want to call another function before returning current to perform some other update to alert the user they are maxed out on markers.
const onMapClick = React.useCallback((e) => {
setMarkers((current) => {
if (current.length < 10) {
return [
...current,
{
lat: e.latLng.lat(),
lng: e.latLng.lng()
}
];
} else {
return current;
};
});
}, []);

Resources