Created
May 9, 2018 11:41
-
-
Save rpdiss/5e63816e30a1fb0ec252be0fcceb6078 to your computer and use it in GitHub Desktop.
leaflet heatmapjs plugin port to ts
This file contains 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 L from "leaflet"; | |
import 'heatmap.js'; | |
/** | |
* author: Rafał Piekarski | |
* email: noopek@gmail.com | |
* this was made only cuz of need | |
* for personal usage feel free to email | |
* me with some improvements | |
* | |
* remember to npm/yarn heatmap.js and leaflet ! | |
* gl bois! | |
*/ | |
declare var window: { | |
h337: { | |
create: Function, | |
register: Function, | |
} | |
}; | |
export namespace HeatOverlayRP { | |
export interface HTMLElementEx extends HTMLElement { | |
_leaflet_pos?: L.Point; | |
} | |
export interface HeatData { | |
latlng: L.LatLng; | |
radius: any; | |
} | |
export interface HeatPoint { | |
x: Number; | |
y: Number; | |
radius?: Number; | |
} | |
export interface HeatOverlayRP { | |
constructor(options?: L.LayerOptions); | |
addTo(map: L.Map | L.LayerGroup): this; | |
onAdd(map: L.Map): this; | |
onRemove(map: L.Map): this; | |
setData(data: Array<HeatData>); | |
} | |
export class HeatOverlayRP extends L.Layer implements HeatOverlayRP { | |
private heatData: Array<HeatData>; | |
private el: HTMLElement; | |
private min: Number; | |
private max: Number; | |
private cfg: any; | |
private map: L.Map; | |
private x: Number; | |
private y: Number; | |
private heatmap; | |
constructor(config: L.LayerOptions) { | |
super(); | |
this.cfg = config; | |
this.el = L.DomUtil.create('div', 'leaflet-zoom-hide'); | |
this.heatData = []; | |
this.min = 0; | |
this.max = 1; | |
this.cfg.container = this.el; | |
} | |
public onAdd(map: L.Map) { | |
let size = map.getSize(); | |
this.map = map; | |
this.x = size.x; | |
this.y = size.y; | |
this.el.style.width = `${size.x}px`; | |
this.el.style.height = `${size.y}px`; | |
this.el.style.position = 'absolute'; | |
this.map.getPanes().overlayPane.appendChild(this.el); | |
if (!this.heatmap) { | |
this.heatmap = window.h337.create(this.cfg); | |
} | |
map.on('moveend', this.reset, this); | |
this.draw(); | |
return this; | |
} | |
public addTo(map: L.Map) { | |
map.addLayer(this); | |
return this; | |
} | |
public onRemove(map: L.Map) { | |
map.getPanes().overlayPane.removeChild(this.el); | |
map.off('moveend', this.reset, this); | |
return this; | |
} | |
private draw() { | |
if (!this.map) return; | |
let mapPane: HTMLElementEx = this.map.getPanes().mapPane; | |
let point = mapPane._leaflet_pos; | |
this.el.style[CSS_TRANSFORM] = `translate(${-Math.round(point.x)}px, ${-Math.round(point.y)}px)`; | |
this.update(); | |
} | |
private update() { | |
let bounds: L.LatLngBounds = this.map.getBounds(); | |
let generatedData = {max: this.max, min: this.min, data: []}; | |
let zoom = this.map.getZoom(); | |
let scale = Math.pow(2, zoom); | |
if (this.heatData.length == 0) { | |
if (this.heatmap) { | |
this.heatmap.setData(generatedData); | |
} | |
return; | |
} | |
let latLngPoints = []; | |
let radiusMultiplier: any = this.cfg.scaleRadius ? scale : 1; | |
let localMax: number = 0; | |
let localMin: number = 0; | |
let valueField = this.cfg.valueField; | |
let len = this.heatData.length; | |
while (len--) { | |
let entry = this.heatData[len]; | |
let value = entry[valueField]; | |
let latlng = entry.latlng; | |
if (!bounds.contains(latlng)) { | |
continue; | |
} | |
localMax = Math.max(value, localMax); | |
localMin = Math.min(value, localMin); | |
let point: L.Point = this.map.latLngToContainerPoint(latlng); | |
let latlngPoint: HeatPoint = {x: Math.round(point.x), y: Math.round(point.y)}; | |
latlngPoint[valueField] = value; | |
let radius; | |
if (entry.radius) { | |
radius = entry.radius * radiusMultiplier; | |
} else { | |
radius = (this.cfg.radius || 2) * radiusMultiplier; | |
} | |
console.log(radius, this.cfg.radius, radiusMultiplier); | |
latlngPoint.radius = radius; | |
latLngPoints.push(latlngPoint); | |
} | |
if (this.cfg.useLocalExtrema) { | |
generatedData.max = localMax; | |
generatedData.min = localMin; | |
} | |
generatedData.data = latLngPoints; | |
this.heatmap.setData(generatedData); | |
} | |
setData(data: Array<HeatData>) { | |
let len = data.length; | |
let d = []; | |
while (len--) { | |
d.push(data[len]); | |
} | |
this.heatData = d; | |
this.draw(); | |
} | |
private reset() { | |
let size = this.map.getSize(); | |
if (this.x !== size.x || this.y !== size.y) { | |
this.x = size.x; | |
this.y = size.y; | |
this.el.style.width = this.x + 'px'; | |
this.el.style.height = this.y + 'px'; | |
this.heatmap._renderer.setDimensions(this.x, this.y); | |
} | |
this.draw(); | |
} | |
} | |
export const CSS_TRANSFORM = (() => { | |
let div = document.createElement('div'); | |
let props = [ | |
'transform', | |
'WebkitTransform', | |
'MozTransform', | |
'OTransform', | |
'msTransform' | |
]; | |
for (let i = 0; i < props.length; i++) { | |
const prop = props[i]; | |
if (div.style[prop] !== undefined) { | |
return prop; | |
} | |
} | |
return props[0]; | |
})() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment