import Heatmap from 'ol/layer/Heatmap'
import VectorEventType from 'ol/source/VectorEventType'
import Point from 'ol/geom/Point'
import { getUid } from 'ol/util'
import { listen } from 'ol/events'
import { getCentroid } from '../tools/services/centroid'
/**
* @param {ol.source.Vector.VectorSourceEvent|ol.Collection.CollectionEvent} evt Event
* @return {ol.Feature} Feature
*/
function getFeatureFromEvent (evt) {
if (
(evt).feature
) {
return (evt).feature
} else if (
(evt).element
) {
return (
(evt).element
)
}
}
function getFeatureReplacement (feature, allGeomType = false) {
const geomType = feature.getGeometry() ? feature.getGeometry().getType() : null
// on garde les points tel quel
if (geomType === 'Point') {
return null
}
const newFeature = feature.clone()
if (geomType === 'GeometryCollection') {
// un seul point dans la collection: on l'utilise
const geometryPoints = newFeature.getGeometry().getGeometries().filter((geom) => geom.getType() === 'Point')
if (geometryPoints.length === 1) { newFeature.setGeometry(geometryPoints[0]) }
} else if (geomType !== 'Point' && allGeomType) {
const geomCoordinates = getCentroid(newFeature)
if (geomCoordinates) {
newFeature.setGeometry(new Point([geomCoordinates[0], geomCoordinates[1]]))
}
}
return newFeature
}
class CustomHeatmap extends Heatmap {
constructor (options) {
options = options || { }
super(options)
this.listenerKeys = []
this.originalToSourceMap = {}
this.customPendingAdd = {}
this.customPendingRemove = {}
// Heatmap.call(this, options)
const source = this.getSource()
const handleFeatureSwap = function (feature) {
const newFeature = getFeatureReplacement(feature, true)
if (newFeature) {
// garde une trace de mapping des features (au cas ou on essais d'en supprimer une via remove(feature) on reconnaitra notre copie)
this.originalToSourceMap[getUid(feature)] = newFeature
this.customPendingAdd[getUid(newFeature)] = 1
// on diffère la suppression de notre feature de la source dans le temps car c'est pas "normal"
// de supprimer une feature dans l'event d'ajout
setTimeout(() => {
this.customPendingRemove[getUid(feature)] = 1
source.removeFeature(feature)
source.addFeature(newFeature)
}, 10)
}
}
this.listenerKeys.push(
listen(
source,
VectorEventType.ADDFEATURE,
(evt) => {
const feature = getFeatureFromEvent(evt)
// Si c'est une feature qu'on est en train d'ajouter via cette méthode on ne fait rien.
if (!this.customPendingAdd[getUid(feature)]) {
handleFeatureSwap.call(this, feature)
} else {
delete this.customPendingAdd[getUid(feature)]
}
},
this
),
listen(
source,
VectorEventType.REMOVEFEATURE,
(evt) => {
// lorsque l'on supprime une feature via l'api, on vérifi si c'est pas une feature que l'on a modifié..
const feature = getFeatureFromEvent(evt)
if (this.customPendingRemove[getUid(feature)]) {
delete this.customPendingRemove[getUid(feature)]
} else {
const clonedFeature = this.originalToSourceMap[getUid(feature)]
if (clonedFeature) {
source.removeFeature(clonedFeature)
}
}
delete this.originalToSourceMap[getUid(feature)]
},
this
)
, listen(
source,
VectorEventType.CHANGEFEATURE,
(evt) => {
// lorsque l'on modifie une feature via l'api, on vérifi si c'est pas une feature que l'on a modifié..
const feature = getFeatureFromEvent(evt)
const clonedFeature = this.originalToSourceMap[getUid(feature)]
if (clonedFeature) {
// remove fera bien son travail
source.removeFeature(feature)
// puis re-ajoute la feature
source.addFeature(feature)
} else {
handleFeatureSwap.call(this, feature)
}
},
this
)
)
}
}
export default CustomHeatmap