I recently discovered a leaflet extension that conceals map markers if they fall outside the boundaries of the current view map.
import L from 'leaflet';
L.Marker.MyMarker= L.Marker.extend({}).addInitHook(function (this: ILazyMarker) {
this.on(
'add',
function (this: ILazyMarker) {
this._updateIconVisibility = function (this: ILazyMarker) {
var map = this._map,
isVisible = map.getBounds().contains(this.getLatLng()),
wasVisible = this._wasVisible,
icon = this._icon,
iconParent = this._iconParent,
shadow = this._shadow,
shadowParent = this._shadowParent;
// keep track of parent of icon
if (!iconParent) {
iconParent = this._iconParent = icon.parentNode;
}
if (shadow && !shadowParent) {
shadowParent = this._shadowParent = shadow.parentNode;
}
// remove or add to DOM based on visibility change
if (iconParent != null && isVisible != wasVisible) {
if (isVisible) {
iconParent.appendChild(icon);
if (shadowParent != null && shadow) {
shadowParent.appendChild(shadow);
}
} else {
iconParent.removeChild(icon);
if (shadowParent != null && shadow) {
shadowParent.removeChild(shadow);
}
}
this._wasVisible = isVisible;
}
};
// update icon visibility on map size change
this._map.on('resize moveend zoomend', this._updateIconVisibility, this);
this._updateIconVisibility();
},
this,
);
});
The functionality works flawlessly, but I prefer using a Typescript class for uniformity across my project. Below is my attempt at converting it:
import L from 'leaflet';
export default class MyMarker extends L.Marker {
_wasVisible!: boolean;
_icon!: any;
_shadowParent!: any;
_iconParent!: any;
constructor(latlng: L.LatLngExpression, options?: L.MarkerOptions) {
super(latlng, options);
}
onAdd(): this {
this._map.on('resize moveend zoomend', this._updateIconVisibility, this);
this._updateIconVisibility();
return this;
}
_updateIconVisibility() {
var map = this._map,
isVisible = map.getBounds().contains(this.getLatLng()),
wasVisible = this._wasVisible,
icon = this._icon,
iconParent = this._iconParent,
shadow = this._shadow,
shadowParent = this._shadowParent;
// remember parent of icon
if (!iconParent) {
iconParent = this._iconParent = icon.parentNode;
}
if (shadow && !shadowParent) {
shadowParent = this._shadowParent = shadow.parentNode;
}
// add/remove from DOM on change
if (iconParent != null && isVisible != wasVisible) {
if (isVisible) {
iconParent.appendChild(icon);
if (shadowParent != null && shadow) {
shadowParent.appendChild(shadow);
}
} else {
iconParent.removeChild(icon);
if (shadowParent != null && shadow) {
shadowParent.removeChild(shadow);
}
}
this._wasVisible = isVisible;
}
}
}
However, when trying to use this marker class, I encounter an error for each marker added and the map fails to render:
TypeError: Cannot read property 'parentNode' of undefined
at MyMarker._updateIconVisibility (leaflet-my-marker.ts:78)
at MyMarker.onAdd (leaflet-my-marker.ts:63)
at MyMarker._layerAdd (leaflet-src.js:6567)
at NewClass.whenReady (leaflet-src.js:4428)
at NewClass.addLayer (leaflet-src.js:6629)
at NewClass.addLayer (leaflet-src.js:6780)
at VueComponent.addLayer (LLayerGroup.js:164)
at VueComponent.FirecamMarker.mounted (MyMarker.vue?6277:99)
at invokeWithErrorHandling (vue.runtime.esm.js:1854)
at callHook (vue.runtime.esm.js:4219)