dawarich/app/javascript/maps_maplibre/layers/base_layer.js
Evgenii Burmakin 8934c29fce
0.36.2 (#2007)
* fix: move foreman to global gems to fix startup crash (#1971)

* Update exporting code to stream points data to file in batches to red… (#1980)

* Update exporting code to stream points data to file in batches to reduce memory usage

* Update changelog

* Update changelog

* Feature/maplibre frontend (#1953)

* Add a plan to use MapLibre GL JS for the frontend map rendering, replacing Leaflet

* Implement phase 1

* Phases 1-3 + part of 4

* Fix e2e tests

* Phase 6

* Implement fog of war

* Phase 7

* Next step: fix specs, phase 7 done

* Use our own map tiles

* Extract v2 map logic to separate manager classes

* Update settings panel on v2 map

* Update v2 e2e tests structure

* Reimplement location search in maps v2

* Update speed routes

* Implement visits and places creation in v2

* Fix last failing test

* Implement visits merging

* Fix a routes e2e test and simplify the routes layer styling.

* Extract js to modules from maps_v2_controller.js

* Implement area creation

* Fix spec problem

* Fix some e2e tests

* Implement live mode in v2 map

* Update icons and panel

* Extract some styles

* Remove unused file

* Start adding dark theme to popups on MapLibre maps

* Make popups respect dark theme

* Move v2 maps to maplibre namespace

* Update v2 references to maplibre

* Put place, area and visit info into side panel

* Update API to use safe settings config method

* Fix specs

* Fix method name to config in SafeSettings and update usages accordingly

* Add missing public files

* Add handling for real time points

* Fix remembering enabled/disabled layers of the v2 map

* Fix lots of e2e tests

* Add settings to select map version

* Use maps/v2 as main path for MapLibre maps

* Update routing

* Update live mode

* Update maplibre controller

* Update changelog

* Remove some console.log statements

---------

Co-authored-by: Robin Tuszik <mail@robin.gg>
2025-12-06 20:54:49 +01:00

136 lines
3.3 KiB
JavaScript

/**
* Base class for all map layers
* Provides common functionality for layer management
*/
export class BaseLayer {
constructor(map, options = {}) {
this.map = map
this.id = options.id || this.constructor.name.toLowerCase()
this.sourceId = `${this.id}-source`
this.visible = options.visible !== false
this.data = null
}
/**
* Add layer to map with data
* @param {Object} data - GeoJSON or layer-specific data
*/
add(data) {
console.log(`[BaseLayer:${this.id}] add() called, visible:`, this.visible, 'features:', data?.features?.length || 0)
this.data = data
// Add source
if (!this.map.getSource(this.sourceId)) {
console.log(`[BaseLayer:${this.id}] Adding source:`, this.sourceId)
this.map.addSource(this.sourceId, this.getSourceConfig())
} else {
console.log(`[BaseLayer:${this.id}] Source already exists:`, this.sourceId)
}
// Add layers
const layers = this.getLayerConfigs()
console.log(`[BaseLayer:${this.id}] Adding ${layers.length} layer(s)`)
layers.forEach(layerConfig => {
if (!this.map.getLayer(layerConfig.id)) {
console.log(`[BaseLayer:${this.id}] Adding layer:`, layerConfig.id, 'type:', layerConfig.type)
this.map.addLayer(layerConfig)
} else {
console.log(`[BaseLayer:${this.id}] Layer already exists:`, layerConfig.id)
}
})
this.setVisibility(this.visible)
console.log(`[BaseLayer:${this.id}] Layer added successfully`)
}
/**
* Update layer data
* @param {Object} data - New data
*/
update(data) {
this.data = data
const source = this.map.getSource(this.sourceId)
if (source && source.setData) {
source.setData(data)
}
}
/**
* Remove layer from map
*/
remove() {
this.getLayerIds().forEach(layerId => {
if (this.map.getLayer(layerId)) {
this.map.removeLayer(layerId)
}
})
if (this.map.getSource(this.sourceId)) {
this.map.removeSource(this.sourceId)
}
this.data = null
}
/**
* Show layer
*/
show() {
this.visible = true
this.setVisibility(true)
}
/**
* Hide layer
*/
hide() {
this.visible = false
this.setVisibility(false)
}
/**
* Toggle layer visibility
* @param {boolean} visible - Show/hide layer
*/
toggle(visible = !this.visible) {
this.visible = visible
this.setVisibility(visible)
}
/**
* Set visibility for all layer IDs
* @param {boolean} visible
*/
setVisibility(visible) {
const visibility = visible ? 'visible' : 'none'
this.getLayerIds().forEach(layerId => {
if (this.map.getLayer(layerId)) {
this.map.setLayoutProperty(layerId, 'visibility', visibility)
}
})
}
/**
* Get source configuration (override in subclass)
* @returns {Object} MapLibre source config
*/
getSourceConfig() {
throw new Error('Must implement getSourceConfig()')
}
/**
* Get layer configurations (override in subclass)
* @returns {Array<Object>} Array of MapLibre layer configs
*/
getLayerConfigs() {
throw new Error('Must implement getLayerConfigs()')
}
/**
* Get all layer IDs for this layer
* @returns {Array<string>}
*/
getLayerIds() {
return this.getLayerConfigs().map(config => config.id)
}
}