Skip to content

Instantly share code, notes, and snippets.

@cristiandley
Last active January 16, 2017 09:10
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cristiandley/3475aafae1427610df0b490ad84884dd to your computer and use it in GitHub Desktop.
Save cristiandley/3475aafae1427610df0b490ad84884dd to your computer and use it in GitHub Desktop.
Trying to migrate leaflet-heatmap to react
import _ from 'lodash';
import L from 'leaflet';
import React from 'react';
import h337 from 'heatmap.js';
import { MapLayer } from 'react-leaflet';
import ReactDOM, { render } from 'react-dom';
class ReactLeafletHeatmap extends MapLayer {
constructor(props, context) {
super(props, context);
this.state = {
cfg: null,
divProps: null,
_data: null,
_max: 1,
_min: 0,
};
this.setData = this.setData.bind(this);
this._update = this._update.bind(this);
}
componentDidMount(){
const { config, data, map } = this.props;
this._map = map;
let size = map.getSize();
let initialCfg={}; initialCfg = config;
initialCfg.container = ReactDOM.findDOMNode(this);
let newState = { cfg: initialCfg };
map.getPanes().overlayPane.appendChild(initialCfg.container);
if (!this.heatmapInstance) {
this.heatmapInstance = h337.create(initialCfg);
}
map.on('moveend', this._reset, this);
this.setState(newState, () => { this.setData() });
}
componentWillReceiveProps(nextProps, nextState){
return nextProps != this.props || nextState != this.state;
}
shouldComponentUpdate(nextProps){
return nextProps != this.props;
}
/**
* -----------------------------------------
* SET DATA
* -----------------------------------------
*/
setData() {
const { data } = this.props;
const { _max, _min, _data, cfg } = this.state;
this.setState({ _max: data.max || _max, _min: data.min || _min });
var utils = {
xField: cfg.xField.toString() || 'lat',
yField: cfg.yField.toString() || 'lng',
valueField: cfg.valueField.toString() || 'value',
};
// transform data to latlngs
utils.d = [];
data.data.map((d) => {
let latlng = new L.LatLng(d[utils.xField], d[utils.yField]);
let dataObj = { latlng: latlng };
dataObj[utils.valueField] = d[utils.valueField];
if (d.radius) {
dataObj.radius = d.radius;
}
utils.d.push(dataObj);
})
this.setState({ _data: utils.d }, () => { this._draw() });
}
/**
* -----------------------------------------
* DRAW
* -----------------------------------------
*/
_draw() {
if (!this._map) { return; }
let mapPane = this._map.getPanes().mapPane;
let point = mapPane._leaflet_pos;
this._update();
}
/**
* -----------------------------------------
* UPDATE
* -----------------------------------------
*/
_update() {
const { _max, _min, _data, cfg } = this.state;
var bounds, zoom, scale;
var generatedData = { max: _max, min: _min, data: _data };
bounds = this._map.getBounds();
zoom = this._map.getZoom();
scale = Math.pow(2, zoom);
if (_data.length == 0) {
if (this.heatmapInstance) {
this.heatmapInstance.setData(generatedData);
}
return;
}
var latLngPoints = [];
var radiusMultiplier = cfg.scaleRadius ? scale : 1;
var localMax = 0; var localMin = 0;
_data.map((d)=>{
let value = d[cfg.valueField];
let latlng = d.latlng;
// no mostremos los puntos que no estan en el mapa
if (bounds.contains(latlng)) {
// local max es el maximo respecto a nuestros bounds
localMax = Math.max(value, localMax);
localMin = Math.min(value, localMin);
let point = this._map.latLngToContainerPoint(latlng);
// [cfg.xField]: Math.round(point.x),
// [cfg.yField]: Math.round(point.y),
// [cfg.valueField]: value
let latlngPoint = {
x: Math.round(point.x),
y: Math.round(point.y),
value: value
};
let radius;
if (d.radius) {
radius = d.radius * radiusMultiplier;
} else {
radius = (cfg.radius || 2) * radiusMultiplier;
}
latlngPoint.radius = radius;
latLngPoints.push(latlngPoint);
}
});
if (cfg.useLocalExtrema) {
generatedData.max = localMax;
generatedData.min = localMin;
}
generatedData.data = latLngPoints;
console.log(generatedData);
this.heatmapInstance.setData(generatedData);
}
/**
* -----------------------------------------
* RENDER
* -----------------------------------------
*/
render(){
const { map } = this.props;
const mapSize = map.getSize();
const transformProp = L.DomUtil.testProp(
['transformOrigin', 'WebkitTransformOrigin', 'msTransformOrigin']
);
const canAnimate = map.options.zoomAnimation && L.Browser.any3d;
const zoomClass = `leaflet-zoom-${canAnimate ? 'animated' : 'hide'}`;
const canvasProps = {
className: `leaflet-heatmap-layer leaflet-layer ${zoomClass}`,
style: {
[transformProp]: '50% 50%'
},
width: mapSize.x,
height: mapSize.y,
};
return (
<div ref="react-leaflet-heatmap" {...canvasProps}></div>
);
}
}
export default ReactLeafletHeatmap;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment