This is my first time contributing to open source. I have some examples from a project that I wanted to leave for anyone searching how to implement a Heatmap, Markers, or Infowindows. If anyone would like to contribute more examples, please feel free to submit a pull request. If I did anything incorrectly, please don't hesitate to contact me at john.[email protected]. Again this is my first time contributing and I invite feedback whether constructive or positive.
I'm submitting this as an issue per instructions I received via an email conversation with the maintainer.
@tomchentw should this issue be closed or remain open?
Thank you for the issue posting, were you interested in some of this making it over to the main README.md ? I'm trying to understand the intent. If so, some of this is really good, are you comfortable making a pull request with the changes?
If this is new, feel free to email me [email protected] or Tom or post here and we can walk through the process!
Thank you again,
should this issue be closed or remain open?
Let's leave it open for now.
Hey @JohnBinning , I've migrated the codebase to v8.0.0 so that it's easier to write docs with react-styleguidist. Yeah I definitely need some examples for HeadmapLayer:
https://tomchentw.github.io/react-google-maps/#heatmaplayer
Could you forked my repo and add new docs following the react-styleguidist, and submit a PR?
I'm currently making a heatmap with this component and can add some documentation soon if / when I get it working.
@selipso 馃憤
Have some working code for the Heatmap component that I've used in another project. Here's what I have after some refactoring. Would appreciate any comments / suggestions before I fork and create a PR. Even better if someone can try running it and let me know how it goes.
The Heatmap Wrapper Component is a wrapper around the Core Map Component, which was created with the help of the existing documentation. In this wrapper component, you can pass in heatmap data with properties lat, lng, and weight. You can also make requests to a backend and provide an optional callback function if you want to know the new center and bounds every time the map is moved.
Each time new data is passed into the heatmapRawData props of the wrapper component, the Core Map component will automatically update its state and fire the onMove callback in the wrapper component once finished. This is to separate the data parsing / handling from the rendering of the data to the HeatmapLayer.
After adding your own logic to the wrapper, you can just render the component in your app with <Heatmap/> and provide an optional initial zoom and initial center.
The Core Map Component (map.js)
/* global google */
import React from 'react';
import { compose, withProps, lifecycle } from "recompose";
import {
withGoogleMap,
GoogleMap,
Marker,
} from "react-google-maps";
import SearchBox from "react-google-maps/lib/components/places/SearchBox";
import HeatmapLayer from 'react-google-maps/lib/components/visualization/HeatmapLayer';
export const DataLoadingHeatmap = compose(
withProps({
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
lifecycle({
componentWillMount() {
const refs = {}
this.setState({
bounds: null,
center: this.props.center,
data: this.props.heatmapRawData,
markers: [],
mapData: [],
onMapMounted: ref => {
refs.map = ref;
},
onBoundsChanged: () => {
this.setState({
bounds: refs.map.getBounds(),
center: refs.map.getCenter(),
}, function() {
if (this.props.onMove) {
this.props.onMove(this.state.bounds, this.state.center);
}
});
},
},
componentWillReceiveProps(nextProps) {
var filteredData = [];
if (nextProps.heatmapRawData !== this.state.data) {
this.setState({
data: nextProps.heatmapRawData
});
for (var i = 0; i < nextProps.heatmapRawData.length; i++) {
const point = nextProps.heatmapRawData[i];
const htmapPoint = {
location: new google.maps.LatLng(
point.lat,
point.lng
),
weight: point.weight
};
filteredData.push(htmapPoint);
}
// after loop is done, update heatmap data
this.setState({mapData: filteredData});
}
},
}),
withGoogleMap
)(props =>
<GoogleMap
ref={props.onMapMounted}
defaultZoom={props.zoom}
center={props.center}
onBoundsChanged={props.onBoundsChanged}
>
<HeatmapLayer
data={props.mapData}
options={{radius: 20}}
/>
</GoogleMap>
);
The Heatmap Wrapper Component
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { DataLoadingHeatmap } from './map';
export default class Heatmap extends Component {
constructor(props) {
super(props);
// Initialize state
const {lat, lng} = this.props.initialCenter;
this.updateData = this.updateData.bind(this);
this.state = {
currentLocation: {
lat: lat,
lng: lng
},
mapData: [
{lat: 37.782, lng: -122.447, weight: 0.5},
{lat: 37.782, lng: -122.443, weight: 2},
{lat: 37.782, lng: -122.441, weight: 3},
{lat: 37.782, lng: -122.439, weight: 2},
{lat: 37.782, lng: -122.435, weight: 0.5},
{lat: 37.785, lng: -122.447, weight: 3},
{lat: 37.785, lng: -122.445, weight: 2},
{lat: 37.785, lng: -122.441, weight: 0.5},
{lat: 37.785, lng: -122.437, weight: 2},
{lat: 37.785, lng: -122.435, weight: 3}
],
}
}
// You can find out the new position after map is moved
// by assigning a callback to the onMove prop.
// In this example, the callback function is updateData.
// You can also make backend requests in the updateData function.
// Note that updateData() is not optimized to minimize requests
// and the onMove event handler is fired a lot!
// You can optionally set a timeout on the request inside updateData
// for better optimization
updateData(newBounds, newCenter) {
// Uncomment to pass new data to heatmap
/* this.setState({
mapData: [
{lat: 37.785, lng: -122.447, weight: 3},
{lat: 37.785, lng: -122.445, weight: 2},
{lat: 37.785, lng: -122.441, weight: 0.5},
{lat: 37.785, lng: -122.437, weight: 2}
]
});*/
}
render() {
return (
<DataLoadingHeatmap
zoom={12}
onMove={this.updateData}
heatmapRawData={this.state.mapData}
>
</DataLoadingHeatmap>
);
}
}
Heatmap.defaultProps = {
// San Francisco by default
initialCenter: {
lat: 37.774929,
lng: -122.419416
}
};
Heatmap.propTypes = {
zoom: PropTypes.number,
initialCenter: PropTypes.object
};
I noticed that a lot of people here are confused about a basic thing as fitBounds to markers when initializing map is. Can we put working demo in example page as well?
Hello. Does anyone have an example of heat map using react and ES6?
Thanks.
Most helpful comment
Have some working code for the Heatmap component that I've used in another project. Here's what I have after some refactoring. Would appreciate any comments / suggestions before I fork and create a PR. Even better if someone can try running it and let me know how it goes.
The Heatmap Wrapper Component is a wrapper around the Core Map Component, which was created with the help of the existing documentation. In this wrapper component, you can pass in heatmap data with properties
lat,lng, andweight. You can also make requests to a backend and provide an optional callback function if you want to know the new center and bounds every time the map is moved.Each time new data is passed into the
heatmapRawDataprops of the wrapper component, the Core Map component will automatically update its state and fire theonMovecallback in the wrapper component once finished. This is to separate the data parsing / handling from the rendering of the data to the HeatmapLayer.After adding your own logic to the wrapper, you can just render the component in your app with
<Heatmap/>and provide an optional initial zoom and initial center.The Core Map Component (
map.js)The Heatmap Wrapper Component