Am using leaflet library with angular 8 and I have succesufully plotted heatmap from values ( longitude , latitude , count that i pass ).
What i want to add time-dimension to the current heatmap to have animation when i hit play arrow of the play/pause bar .
i have found plenty of ressources showing the result :
The code of mine is :
mapview.component.html
<div leaflet class="map"
(leafletMapReady)="onMapReady($event)"
[leafletZoom]="zoom"
[leafletCenter]="center"
[leafletLayers]="layers"
[leafletLayersControl]="layersControl">
mapview.component.ts
import {
ChangeDetectorRef,
Component,
EventEmitter,
Input,
OnChanges,
OnDestroy,
OnInit,
Output,
SimpleChanges
} from '@angular/core';
import * as L from 'leaflet';
import {latLng, Layer, tileLayer} from 'leaflet';
import 'leaflet.markercluster';
import {LeafletLayersModel} from '../../models/leaflet-layers.model';
import {Subject} from 'rxjs';
import 'leaflet-extra-markers/';
import 'leaflet-timedimension/dist/leaflet.timedimension.min.js'
import * as HeatmapOverlay from 'leaflet-heatmap';
import * as TimeDimension from 'leaflet-timedimension';
@Component({
selector: 'app-mapview',
templateUrl: './mapview.component.html',
styleUrls: ['./mapview.component.scss']
})
export class MapviewComponent implements OnInit, OnChanges, OnDestroy {
private destroy$: Subject<boolean> = new Subject<boolean>();
@Input() mapData: any;
@Input() showLegend: boolean;
@Input() showTeamLegend: boolean;
@Output() mapUpdate = new EventEmitter<boolean>();
@Input() teamData: any;
@Input() type: string; // to identify from which component the map is called
labels = [];
legend: any;
public map: L.Map;
timeDimension:true;
// Open Street Map and Open Cycle Map definitions
LAYER_OCM = {
id: 'opencyclemap',
name: 'Open Cycle Map',
enabled: false,
layer: tileLayer('http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png', {
maxZoom: 18,
minZoom: 1,
attribution: 'Open Cycle Map'
})
};
LAYER_OSM = {
id: 'openstreetmap',
name: 'Open Street Map',
enabled: true,
layer: tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18,
minZoom: 1,
attribution: 'Open Street Map'
}),
};
// Form model object
model = new LeafletLayersModel(
[this.LAYER_OSM, this.LAYER_OCM],
this.LAYER_OSM.id
// , [ this.circle, this.polygon, this.square, this.geoJSON ]
);
// Values to bind to Leaflet Directive
layers: Layer[];
layersControl = {
baseLayers: {
'Open Street Map': this.LAYER_OSM.layer,
/*
'Open Cycle Map': this.LAYER_OCM.layer
*/
},
};
center;
zoom;
markers = L.markerClusterGroup();
constructor(
private cdRef: ChangeDetectorRef,
) {
this.apply();
}
ngOnInit() {
}
/** On change update the mapData */
ngOnChanges(changes: SimpleChanges) {
const mapData = JSON.parse(this.mapData);
if (mapData.features) {
this.removeLayers();
this.displayMapData();
}
}
ngOnDestroy(): void {
this.destroy$.next(true);
this.destroy$.unsubscribe();
}
/** To apply the map and update the layers */
apply() {
this.zoom = 5;
this.center = latLng(48.856613,
2.352222);
// Get the active base layer
const baseLayer = this.model.baseLayers.find((l: any) => (l.id === this.model.baseLayer));
// Get all the active overlay layers
const newLayers = this.model.overlayLayers
.filter((l: any) => l.enabled)
.map((l: any) => l.layer);
newLayers.unshift(baseLayer.layer);
this.layers = newLayers;
this.layers = [...this.layers];
}
/** Method executed when the map is ready */
onMapReady(map: L.Map) {
//L.timeDimension({timeDimension : true}).addTo(map);
this.map = map;
setTimeout(() => {
map.invalidateSize();
}, 500);
this.cdRef.detectChanges();
}
/** To display the map data */
private displayMapData() {
this.markers = L.markerClusterGroup({
showCoverageOnHover: false,
});
const mapDataObj = JSON.parse(this.mapData);
if (mapDataObj && mapDataObj.features.length) {
mapDataObj.features.forEach((data) => {
if (data.geometry && data.geometry.type === 'ExtraMarkers') {
this.center = latLng(mapDataObj.features[0].geometry.coordinates[0],
mapDataObj.features[0].geometry.coordinates[1]);
this.displayExtraMarkers(data);
} else if (data[0] && data[0].geometry && data[0].geometry.type === 'Polygon') {
this.center = latLng(mapDataObj.features[0][0].geometry.coordinates[0][0][1],
mapDataObj.features[0][0].geometry.coordinates[0][0][0]);
this.displayZone(data);
} else if (data.geometry && data.geometry.type === 'Polyline') {
this.center = latLng(mapDataObj.features[0].geometry.coordinates[0][0],
mapDataObj.features[0].geometry.coordinates[0][1]);
this.displayPolyline(data);
} else if (data.geometry && data.geometry.type === 'heatMap') {
this.displayHeatMap(data);
} else if (data.geometry && data.geometry.type === 'animatedHeatMap') {
//this.displayAnimatedHeatMap(data);
this.displayAnimatedHeatMap1(data);
} else if (data.geometry && data.geometry.type === 'bubbleMap') {
this.center = latLng(mapDataObj.features[0].geometry.coordinates[0],
mapDataObj.features[0].geometry.coordinates[1]);
this.displayBubble(data);
}
});
this.layers.push(this.markers);
}
}
/** To display extra markers */
private displayExtraMarkers(data) {
const icon = L.ExtraMarkers.icon(data.properties.options);
const marker = L.marker([data.geometry.coordinates[0], data.geometry.coordinates[1]], {icon});
const info = data.properties.info;
if (info) {
let popup = '';
if (info.title) {
popup += `<div style="text-align: center; bottom: 13px; border-bottom: solid 2px #1c2831; position: relative;">
<span class="name" style="color: #25aae1; "> ${info.title} </span>
</div>`;
}
marker.bindPopup(popup, {className: 'popupCustom'});
}
this.markers.addLayer(marker);
}
/** To display a polyline */
private displayPolyline(data) {
const marker = L.polyline(data.geometry.coordinates, data.properties.options);
marker.on('click', () => {
marker.bringToFront(); // to highlight the itinerary with mouse click
});
const info = data.properties.info;
if (info) {
let popup = '';
if (info.label) {
popup += `<div style="text-align: center; bottom: 13px; border-bottom: solid 2px #1c2831; position: relative;">
<span class="name" style="color: #25aae1; ">${info.label}</span>
</div>`;
}
marker.bindPopup(popup, {className: 'popupCustom'});
}
this.layers.push(marker);
}
/** To display a zone */
private displayZone(zone) {
zone[0].geometry.type = 'Polygon';
const info = zone[0].properties.options;
let zoneToAdd = new L.GeoJSON(zone, {
style: () => {
return {
fillColor: '#d0cfd1', // to fill zone with color
color: '#6b6a6c', // to fill Boundaries
fillOpacity: 0.3
};
}
});
if (info) {
let popup = '';
if (info.label) {
popup += `<div style="text-align: center; bottom: 13px; border-bottom: solid 2px #1c2831; position: relative;">
<span class="name" style="color: #25aae1; "> ${info.label} </span>
</div>`;
}
zoneToAdd.bindPopup(popup, {className: 'popupCustom'});
}
// On zones hover => change style
zoneToAdd.on('mouseover', function () {
this.setStyle({
fillOpacity: 0.6
});
});
zoneToAdd.on('mouseout', function () {
this.setStyle({
fillOpacity: 0.3
});
});
this.layers.push(zoneToAdd);
}
/** To display a bubble for the bubble maps */
private displayBubble(data) {
const marker = L.circleMarker([data.geometry.coordinates[0], data.geometry.coordinates[1]], {
fillColor: '#03a9f4',
fillOpacity: 0.6,
radius: data.geometry.coordinates[2]
});
const info = data.properties.info;
if (info) {
let popup = '';
if (info.title) {
popup += `<div style="text-align: center; bottom: 13px; border-bottom: solid 2px #1c2831; position: relative;">
<span class="name" style="color: #25aae1; "> ${info.title} </span>
</div>`;
}
marker.bindPopup(popup, {className: 'popupCustom'});
}
this.layers.push(marker);
}
/** To display the heat map */
private displayHeatMap(data) {
let heatmapLayer = new HeatmapOverlay(data.cfg);
this.layers.push(heatmapLayer);
heatmapLayer.setData({
max: 8,
data: data.rows
});
this.center = latLng(data.rows[0][data.cfg.latField],
data.rows[0][data.cfg.lngField]);
}
framesDelay(animatedHeatmapLayer, data, i) {
return new Promise(resolve => {
if (data && data.rows.length) {
setTimeout(() => {
resolve(
animatedHeatmapLayer.addData(data.rows[i])
)
}, 1000);
}
});
}
async asyncCall(animatedHeatmapLayer, data, length) {
let i = 1;
while (i < length) {
const result = await this.framesDelay(animatedHeatmapLayer, data, i);
i++
}
}
/** To display the animated heat map */
displayAnimatedHeatMap(data) {
let dates = ['2014-09-30', '2015-11-12', '2015-10-10', '2016-01-01', '2016-02-01'];
let animatedHeatmapLayer = new HeatmapOverlay(data.cfg);
// let player = new TimeDimension.Player({}).addTo(animatedHeat