dawarich/app/javascript/maps_v2/layers/points_layer.js
2025-11-20 22:36:58 +01:00

138 lines
3.3 KiB
JavaScript

import { BaseLayer } from './base_layer'
/**
* Points layer with toggleable clustering
*/
export class PointsLayer extends BaseLayer {
constructor(map, options = {}) {
super(map, { id: 'points', ...options })
this.clusterRadius = options.clusterRadius || 50
this.clusterMaxZoom = options.clusterMaxZoom || 14
this.clusteringEnabled = options.clustering !== false // Default to enabled
}
getSourceConfig() {
return {
type: 'geojson',
data: this.data || {
type: 'FeatureCollection',
features: []
},
cluster: this.clusteringEnabled,
clusterMaxZoom: this.clusterMaxZoom,
clusterRadius: this.clusterRadius
}
}
getLayerConfigs() {
return [
// Cluster circles
{
id: `${this.id}-clusters`,
type: 'circle',
source: this.sourceId,
filter: ['has', 'point_count'],
paint: {
'circle-color': [
'step',
['get', 'point_count'],
'#51bbd6', 10,
'#f1f075', 50,
'#f28cb1', 100,
'#ff6b6b'
],
'circle-radius': [
'step',
['get', 'point_count'],
20, 10,
30, 50,
40, 100,
50
]
}
},
// Cluster count labels
{
id: `${this.id}-count`,
type: 'symbol',
source: this.sourceId,
filter: ['has', 'point_count'],
layout: {
'text-field': '{point_count_abbreviated}',
'text-font': ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'],
'text-size': 12
},
paint: {
'text-color': '#ffffff'
}
},
// Individual points
{
id: this.id,
type: 'circle',
source: this.sourceId,
filter: ['!', ['has', 'point_count']],
paint: {
'circle-color': '#3b82f6',
'circle-radius': 6,
'circle-stroke-width': 2,
'circle-stroke-color': '#ffffff'
}
}
]
}
/**
* Toggle clustering on/off
* @param {boolean} enabled - Whether to enable clustering
*/
toggleClustering(enabled) {
if (!this.data) {
console.warn('Cannot toggle clustering: no data loaded')
return
}
this.clusteringEnabled = enabled
// Need to recreate the source with new clustering setting
// MapLibre doesn't support changing cluster setting dynamically
// So we remove and re-add the source
const currentData = this.data
const wasVisible = this.visible
// Remove all layers first
this.getLayerIds().forEach(layerId => {
if (this.map.getLayer(layerId)) {
this.map.removeLayer(layerId)
}
})
// Remove source
if (this.map.getSource(this.sourceId)) {
this.map.removeSource(this.sourceId)
}
// Re-add source with new clustering setting
this.map.addSource(this.sourceId, this.getSourceConfig())
// Re-add layers
const layers = this.getLayerConfigs()
layers.forEach(layerConfig => {
this.map.addLayer(layerConfig)
})
// Restore visibility state
this.visible = wasVisible
this.setVisibility(wasVisible)
// Update data
this.data = currentData
const source = this.map.getSource(this.sourceId)
if (source && source.setData) {
source.setData(currentData)
}
}
}