Comments (16)
I found a simple solution to the clustering.
First, I'm using the google markerclusterer.js file you can download from google here:
https://developers.google.com/maps/documentation/javascript/marker-clustering
Then, I observed that the Maps component passes props to child components, including maps, and google. Both of these are needed to create the clusters. From there, I just created a "MarkerCluster" component. Full source is here
import React, {useEffect} from 'react'
import PropTypes from 'prop-types'
import MarkerClusterer from './markerclusterer'
const evtNames = [
'click',
'dblclick',
'dragend',
'mousedown',
'mouseout',
'mouseover',
'mouseup',
'recenter',
]
const markerCluster = (props) => {
const {map, google, markers} = props
const handleEvent = ({event, marker, entry}) => {
if (props[event]) {
props[event]({
props: props,
marker: marker,
event: event,
entry: entry
})
}
}
// This hook works like ComponentWillMount
// The hook isn't really needed, this whole thing worked without it,
// I added the hook so that I could implement a cleanup function
useEffect(() => {
if (map && markers) {
const mapMarkers = markers.map((marker) => {
const entry = new google.maps.Marker({
position: {
lat: marker.position.lat,
lng: marker.position.lng
},
map: map,
name: marker.name
})
evtNames.forEach(e => {
entry.addListener(e, () => handleEvent({
event: e,
marker: marker,
entry: entry
}))
})
return entry
})
const clusterer = new MarkerClusterer(map, mapMarkers, {imagePath: '/static/images/maps/m'})
// Cleanup function. Note, this is only returned if we create the markers
return () => {
//console.log('Cleaning up markers')
clusterer.clearMarkers()
}
}
}, [map, google, markers])
// Do we need to render anything??
return (null)
}
markerCluster.propTypes = {
map: PropTypes.object,
google: PropTypes.object,
markers: PropTypes.arrayOf(PropTypes.shape({
position: PropTypes.shape({
lat: PropTypes.number.isRequired,
lng: PropTypes.number.isRequired,
}).isRequired,
name: PropTypes.string.isRequired,
})),
}
export default markerCluster
Then in your map implemtation, something like this:
<Map google={google}>
<MarkerCluster
markers={markers}
click={this.onMarkerClick}
mouseover={this.onMouseOver}
mouseout={this.onMouseOut}
/>
</Map>
I used the same technique found in the Marker component to map handlers to the markers that are created, and I pass enough information back so handlers can do what is needed. I probably pass too much... but, it works.
This could probably be added to the library pretty easily ;-)
from google-maps-react.
Something like this.
The 'parent' component:
/**
* This component requires the 3rd party HOC to add the <script> tag dynamically and pass the google (google.maps) object to the subcomponent.
*/
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { GoogleApiWrapper } from 'google-maps-react';
import GoogleMap from 'Feature/Locations/code/Patterns/Molecules/GoogleMap';
class GoogleMapContainer extends Component {
render() {
return (
<GoogleMap
google={this.props.google}
{...this.props}
/>
);
}
}
GoogleMapContainer.propTypes = {
google: PropTypes.objectOf(PropTypes.any),
settings: PropTypes.objectOf(PropTypes.any),
};
GoogleMapContainer.defaultProps = {
google: null,
settings: null,
};
export default GoogleApiWrapper(props => ({
apiKey: props.settings.apiKey,
}
))(GoogleMapContainer);
The child component, <GoogleMap>
.
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import MarkerClusterer from 'node-js-marker-clusterer';
class GoogleMap extends Component {
componentDidMount() {
this.loadMap();
}
componentDidUpdate(prevProps) {
if (prevProps.google !== this.props.google || prevProps.locations !== this.props.locations) {
this.loadMap();
}
}
loadMap() {
if (this.props && this.props.google) {
const { google } = this.props;
const node = this.mapRef;
const mapConfig = Object.assign({}, {
center: { lat: this.props.settings.defaultLatitude, lng: this.props.settings.defaultLongitude },
zoom: this.props.settings.zoom,
mapTypeControl: false,
streetViewControl: false,
gestureHandling: 'cooperative',
});
this.map = new google.maps.Map(node, mapConfig);
const infowindow = new google.maps.InfoWindow({
content: this.props.labels.loading,
});
const markers = this.props.locations.map((location) => {
const marker = new google.maps.Marker({
position: { lat: location.lat, lng: location.lng },
map: this.map,
content: `<div class="c-maps__callout">
...
</div>`,
icon: '/static/assets/icon-mapmarker.png',
});
if (location.isOpen) {
setTimeout(() => {
infowindow.setContent(marker.content);
infowindow.open(this.map, marker);
}, 1000);
}
google.maps.event.addListener(marker, 'click', () => {
infowindow.setContent(marker.content);
infowindow.open(this.map, marker);
});
return marker;
});
return new MarkerClusterer(
this.map,
markers,
{
styles: [{
width: 40,
height: 40,
url: '/static/assets/icon-markercluster1.png',
textColor: 'white',
}],
},
);
}
return {};
}
render() {
return (
<div
className="c-maps"
ref={(e) => {
this.mapRef = e;
}}
/>
);
}
}
from google-maps-react.
You need to instantiate the google map. You can't do this from your compiled code, since node does not expose global variables, so I add the logic to my template. Here is my initialization code
<script type="text/javascript">
function createMap(location) {
var mapOptions = {
center: location['center'],
zoom: location.zoom_level
};
return new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
}
function initMap() {
var location = {{ location|safe }};
var map = createMap(location);
if ('polymap'.indexOf(location['type']) !== -1) {
createPolyMap(map, location);
} else {
createCircleMap(map, location);
}
}
function createPolyMap(map, options) {
var polyPath = new google.maps.Polygon({
paths: options['paths'],
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.35
});
polyPath.setMap(map);
return polyPath;
}
function createCircleMap(map, options) {
var radius = options['radius'];
return new google.maps.Circle({
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.35,
center: options['center'],
map: map,
radius: radius
});
}
function createMarker(map, latLong, title, desc) {
return new google.maps.Marker({
position: latLong,
map: map,
title: title,
desc: desc
});
}
</script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key={{ GOOGLE_MAP_API_KEY }}&callback=initMap" type="text/javascript"></script>
You will need to secure an API key, which can cost you money, but this is generally a few cents, or a few dollars until you get to high traffic. Hopefully, by then you won't care.
from google-maps-react.
+1
from google-maps-react.
Use this: https://www.npmjs.com/package/node-js-marker-clusterer
Works for me.
import MarkerClusterer from 'node-js-marker-clusterer';
const mc = new MarkerClusterer(
this.map, // from new google.maps.Map();
markers, // from const markers = locations.map()
{
styles: [{
width: 40,
height: 40,
url: '/assets/icon-markercluster.png',
textColor: 'white',
}],
},
);
from google-maps-react.
@joriscolours do you have a sample?
from google-maps-react.
@scyrizales I used it here: https://www.vanlanschot.nl/contact/kantoren
from google-maps-react.
@joriscolours Hi. I have a question. Could you please show us a code snippet, how did you use this Cluster with this plugin. Thank you.
from google-maps-react.
By the way @joriscolours, I was able to find it from your page, just a little unminifying action :D
To be clear with anyone, in order to use MarkerClusterer, you need to stop using the Marker component exposed by this google-maps-react
from google-maps-react.
@kutenai nice. thanks for the solution.
from google-maps-react.
@kutenai i tried the same but I am getting an error
Uncaught TypeError: _markerclusterer__WEBPACK_IMPORTED_MODULE_2___default.a is not a constructor
at markercluster.js:57
from google-maps-react.
Hi @kutenai,
The link for the markerclusterer.js from https://developers.google.com/maps/documentation/javascript/marker-clustering isn't available at this point in time. I have used this file instead Archive which I assume is the same file you were talking about. However, I am getting an error that tells me that in the markerclusterer.js
file that google is undefined
. Is it because the file I have found is not the same as the one you have used? or is there an underlying problem elsewhere?
from google-maps-react.
You need to instantiate the google map. You can't do this from your compiled code, since node does not expose global variables, so I add the logic to my template. Here is my initialization code
<script type="text/javascript"> function createMap(location) { var mapOptions = { center: location['center'], zoom: location.zoom_level }; return new google.maps.Map(document.getElementById("map-canvas"), mapOptions); } function initMap() { var location = {{ location|safe }}; var map = createMap(location); if ('polymap'.indexOf(location['type']) !== -1) { createPolyMap(map, location); } else { createCircleMap(map, location); } } function createPolyMap(map, options) { var polyPath = new google.maps.Polygon({ paths: options['paths'], strokeColor: '#FF0000', strokeOpacity: 0.8, strokeWeight: 2, fillColor: '#FF0000', fillOpacity: 0.35 }); polyPath.setMap(map); return polyPath; } function createCircleMap(map, options) { var radius = options['radius']; return new google.maps.Circle({ strokeColor: '#FF0000', strokeOpacity: 0.8, strokeWeight: 2, fillColor: '#FF0000', fillOpacity: 0.35, center: options['center'], map: map, radius: radius }); } function createMarker(map, latLong, title, desc) { return new google.maps.Marker({ position: latLong, map: map, title: title, desc: desc }); } </script> <script async defer src="https://maps.googleapis.com/maps/api/js?key={{ GOOGLE_MAP_API_KEY }}&callback=initMap" type="text/javascript"></script>
You will need to secure an API key, which can cost you money, but this is generally a few cents, or a few dollars until you get to high traffic. Hopefully, by then you won't care.
Hi @kutenai , may I know where did you put the initialization code? Where is this "template" located? Thank you!
from google-maps-react.
Is it possible to cluster with Marker component?
from google-maps-react.
Hi @kutenai I implemented google-maps-react and its working fine but I need to implement clustering please let me know what is the best way to implement it. Thanks
from google-maps-react.
@kutenai Is it possible to cluster with Marker component?
from google-maps-react.
Related Issues (20)
- How can I hide api key when inspecting on network? HOT 1
- cors error HOT 1
- prop-types should be a proper dependency
- Circle dragend event
- Unable to get marker coordinates on drag HOT 1
- Hide labels.text config on init Map
- is it possible to load geojson HOT 1
- Pin Drag Method Of Google map
- npm ERR ! HOT 1
- React cant compile anymore
- Please Update npmjs.com package to 2.0.8 its still 2.0.6 HOT 13
- Draw a route on the map HOT 1
- How to get the Current Zoom value on the Map? Is there any function to that?
- What is the difference between bounds and marginBounds?
- getting blank page maps not rendered
- Property 'children' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<InfoWindow> & Readonly<IInfoWindowProps>'
- Exposing Google Map API key HOT 2
- Style the marker
- Updated version published as @peacechen/google-maps-react
- Custom styles not beign applied to map HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from google-maps-react.