Last active
January 16, 2017 09:10
-
-
Save cristiandley/3475aafae1427610df0b490ad84884dd to your computer and use it in GitHub Desktop.
Trying to migrate leaflet-heatmap to react
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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