|
1 |
| -import { bounds, point } from 'leaflet'; |
| 1 | +import { bounds, point, extend } from 'leaflet'; |
2 | 2 |
|
| 3 | +import { featureLayer } from './mapml/layers/FeatureLayer.js'; |
| 4 | +import { featureRenderer } from './mapml/features/featureRenderer.js'; |
3 | 5 | import { Util } from './mapml/utils/Util.js';
|
4 | 6 | import proj4 from 'proj4';
|
5 | 7 |
|
@@ -180,6 +182,9 @@ export class HTMLFeatureElement extends HTMLElement {
|
180 | 182 | this._parentEl.parentElement?.hasAttribute('data-moving')
|
181 | 183 | )
|
182 | 184 | return;
|
| 185 | + if (this._parentEl.nodeName === 'MAP-LINK') { |
| 186 | + this._createOrGetFeatureLayer(); |
| 187 | + } |
183 | 188 | // use observer to monitor the changes in mapFeature's subtree
|
184 | 189 | // (i.e. map-properties, map-featurecaption, map-coordinates)
|
185 | 190 | this._observer = new MutationObserver((mutationList) => {
|
@@ -256,17 +261,97 @@ export class HTMLFeatureElement extends HTMLElement {
|
256 | 261 |
|
257 | 262 | addFeature(layerToAddTo) {
|
258 | 263 | this._featureLayer = layerToAddTo;
|
259 |
| - let parentLayer = this.getLayerEl(); |
260 | 264 | // "synchronize" the event handlers between map-feature and <g>
|
261 | 265 | if (!this.querySelector('map-geometry')) return;
|
262 | 266 | let fallbackCS = this._getFallbackCS();
|
263 |
| - let content = parentLayer.src ? parentLayer.shadowRoot : parentLayer; |
264 | 267 | this._geometry = layerToAddTo.createGeometry(this, fallbackCS); // side effect: extends `this` with this._groupEl if successful, points to svg g element that renders to map SD
|
265 | 268 | if (!this._geometry) return;
|
| 269 | + this._geometry._layerEl = this.getLayerEl(); |
266 | 270 | layerToAddTo.addLayer(this._geometry);
|
267 | 271 | this._setUpEvents();
|
268 | 272 | }
|
| 273 | + isFirst() { |
| 274 | + // Get the previous element sibling |
| 275 | + const prevSibling = this.previousElementSibling; |
| 276 | + |
| 277 | + // If there's no previous sibling, return true |
| 278 | + if (!prevSibling) { |
| 279 | + return true; |
| 280 | + } |
| 281 | + |
| 282 | + // Compare the node names (tag names) - return true if they're different |
| 283 | + return this.nodeName !== prevSibling.nodeName; |
| 284 | + } |
| 285 | + getPrevious() { |
| 286 | + // Check if this is the first element of a sequence |
| 287 | + if (this.isFirst()) { |
| 288 | + return null; // No previous element available |
| 289 | + } |
| 290 | + |
| 291 | + // Since we know it's not the first, we can safely return the previous element sibling |
| 292 | + return this.previousElementSibling; |
| 293 | + } |
| 294 | + _createOrGetFeatureLayer() { |
| 295 | + if (this.isFirst() && this._parentEl._templatedLayer) { |
| 296 | + const parentElement = this._parentEl; |
269 | 297 |
|
| 298 | + let map = parentElement.getMapEl()._map; |
| 299 | + |
| 300 | + // Create a new FeatureLayer |
| 301 | + this._featureLayer = featureLayer(null, { |
| 302 | + // pass the vector layer a renderer of its own, otherwise leaflet |
| 303 | + // puts everything into the overlayPane |
| 304 | + renderer: featureRenderer(), |
| 305 | + // pass the vector layer the container for the parent into which |
| 306 | + // it will append its own container for rendering into |
| 307 | + pane: parentElement._templatedLayer.getContainer(), |
| 308 | + // the bounds will be static, fixed, constant for the lifetime of the layer |
| 309 | + layerBounds: parentElement.getBounds(), |
| 310 | + zoomBounds: this._getZoomBounds(), |
| 311 | + projection: map.options.projection, |
| 312 | + mapEl: parentElement.getMapEl(), |
| 313 | + onEachFeature: function (properties, geometry) { |
| 314 | + if (properties) { |
| 315 | + const popupOptions = { |
| 316 | + autoClose: false, |
| 317 | + autoPan: true, |
| 318 | + maxHeight: map.getSize().y * 0.5 - 50, |
| 319 | + maxWidth: map.getSize().x * 0.7, |
| 320 | + minWidth: 165 |
| 321 | + }; |
| 322 | + var c = document.createElement('div'); |
| 323 | + c.classList.add('mapml-popup-content'); |
| 324 | + c.insertAdjacentHTML('afterbegin', properties.innerHTML); |
| 325 | + geometry.bindPopup(c, popupOptions); |
| 326 | + } |
| 327 | + } |
| 328 | + }); |
| 329 | + // this is used by DebugOverlay testing "multipleExtents.test.js |
| 330 | + // but do we really need or want each feature to have the bounds of the |
| 331 | + // map link? tbd |
| 332 | + extend(this._featureLayer.options, { |
| 333 | + _leafletLayer: Object.assign(this._featureLayer, { |
| 334 | + _layerEl: this.getLayerEl() |
| 335 | + }) |
| 336 | + }); |
| 337 | + |
| 338 | + this.addFeature(this._featureLayer); |
| 339 | + |
| 340 | + // add featureLayer to TemplatedFeaturesOrTilesLayer of the parentElement |
| 341 | + if ( |
| 342 | + parentElement._templatedLayer && |
| 343 | + parentElement._templatedLayer.addLayer |
| 344 | + ) { |
| 345 | + parentElement._templatedLayer.addLayer(this._featureLayer); |
| 346 | + } |
| 347 | + } else { |
| 348 | + // get the previous feature's layer |
| 349 | + this._featureLayer = this.getPrevious()?._featureLayer; |
| 350 | + if (this._featureLayer) { |
| 351 | + this.addFeature(this._featureLayer); |
| 352 | + } |
| 353 | + } |
| 354 | + } |
270 | 355 | _setUpEvents() {
|
271 | 356 | ['click', 'focus', 'blur', 'keyup', 'keydown'].forEach((name) => {
|
272 | 357 | // when <g> is clicked / focused / blurred
|
|
0 commit comments