@abi-software/flatmap-viewer 2.6.0-a.1 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -36,7 +36,6 @@ import polylabel from 'polylabel';
36
36
  import {LayerManager} from './layers';
37
37
  import {PATHWAYS_LAYER, PathManager} from './pathways';
38
38
  import {VECTOR_TILES_SOURCE} from './layers/styling';
39
- import {Paths3DLayer} from './layers/paths3d'
40
39
  import {SystemsManager} from './systems';
41
40
 
42
41
  import {displayedProperties, InfoControl} from './controls/info';
@@ -102,8 +101,6 @@ function labelPosition(feature)
102
101
  if (feature.geometry.type === 'Point') {
103
102
  return feature.geometry.coordinates
104
103
  }
105
- // LineString?
106
- // Multi geometries??
107
104
  const polygon = feature.geometry.coordinates;
108
105
  // Rough heuristic. Area is in km^2; below appears to be good enough.
109
106
  const precision = ('area' in feature.properties)
@@ -134,7 +131,6 @@ export class UserInteractions
134
131
  {
135
132
  #annotationDrawControl = null
136
133
  #minimap = null
137
- #paths3dLayer = null
138
134
 
139
135
  constructor(flatmap)
140
136
  {
@@ -168,9 +164,7 @@ export class UserInteractions
168
164
 
169
165
  flatmap.setInitialPosition();
170
166
 
171
- // Add and manage our layers
172
-
173
- this._layerManager = new LayerManager(flatmap);
167
+ // Track enabled features
174
168
 
175
169
  this.__featureEnabledCount = new Map(Array.from(this._flatmap.annotations.keys()).map(k => [+k, 0]));
176
170
 
@@ -182,9 +176,16 @@ export class UserInteractions
182
176
  this.__pathManager = new PathManager(flatmap, this, featuresEnabled);
183
177
 
184
178
  // The path types in this map
179
+
185
180
  const mapPathTypes = this.__pathManager.pathTypes();
186
181
 
182
+ // Add and manage our layers. NB. this needs to after we have a
183
+ // path manager but before path enabled state is set.
184
+
185
+ this._layerManager = new LayerManager(flatmap, this);
186
+
187
187
  // Set initial enabled state of paths
188
+
188
189
  for (const path of mapPathTypes) {
189
190
  this.__pathManager.enablePathsByType(path.type, path.enabled, true);
190
191
  }
@@ -218,9 +219,6 @@ export class UserInteractions
218
219
  this._map.addControl(new NavigationControl(flatmap), position);
219
220
  }
220
221
 
221
- // Support 3D path view
222
- this.#paths3dLayer = new Paths3DLayer(flatmap, this)
223
-
224
222
  // Add various controls when running standalone
225
223
  if (flatmap.options.standalone) {
226
224
  // Add a control to search annotations if option set
@@ -268,6 +266,7 @@ export class UserInteractions
268
266
  this._map.addControl(this.#annotationDrawControl)
269
267
 
270
268
  // Handle mouse events
269
+
271
270
  this._map.on('click', this.clickEvent_.bind(this));
272
271
  this._map.on('touchend', this.clickEvent_.bind(this));
273
272
  this._map.on('mousemove', this.mouseMoveEvent_.bind(this));
@@ -301,7 +300,8 @@ export class UserInteractions
301
300
  return {
302
301
  center: this._map.getCenter().toArray(),
303
302
  zoom: this._map.getZoom(),
304
- layers: this.layers
303
+ bearing: this._map.getBearing(),
304
+ pitch: this._map.getPitch()
305
305
  };
306
306
  }
307
307
 
@@ -309,14 +309,11 @@ export class UserInteractions
309
309
  //=============
310
310
  {
311
311
  // Restore the map to a saved state
312
- const options = {};
313
- if ('center' in state) {
314
- options['center'] = state.center;
315
- }
316
- if ('zoom' in state) {
317
- options['zoom'] = state.zoom;
318
- if ('center' in state) {
319
- options['around'] = state.center;
312
+
313
+ const options = Object.assign({}, state)
314
+ if ('zoom' in options) {
315
+ if ('center' in options) {
316
+ options['around'] = options.center;
320
317
  } else {
321
318
  options['around'] = [0, 0];
322
319
  }
@@ -366,11 +363,19 @@ export class UserInteractions
366
363
  }
367
364
  }
368
365
 
369
- clearAnnotationFeature()
370
- //======================
366
+ clearAnnotationFeatures()
367
+ //=======================
371
368
  {
372
369
  if (this.#annotationDrawControl) {
373
- this.#annotationDrawControl.clearFeature()
370
+ this.#annotationDrawControl.clearFeatures()
371
+ }
372
+ }
373
+
374
+ removeAnnotationFeature()
375
+ //=======================
376
+ {
377
+ if (this.#annotationDrawControl) {
378
+ this.#annotationDrawControl.removeFeature()
374
379
  }
375
380
  }
376
381
 
@@ -386,7 +391,15 @@ export class UserInteractions
386
391
  //=======================================
387
392
  {
388
393
  if (this.#annotationDrawControl) {
389
- return this.#annotationDrawControl.getFeature(feature.id)
394
+ return this.#annotationDrawControl.refreshGeometry(feature)
395
+ }
396
+ }
397
+
398
+ changeAnnotationDrawMode(type)
399
+ //=============================
400
+ {
401
+ if (this.#annotationDrawControl) {
402
+ this.#annotationDrawControl.changeMode(type)
390
403
  }
391
404
  }
392
405
 
@@ -422,9 +435,6 @@ export class UserInteractions
422
435
  //================
423
436
  {
424
437
  this._layerManager.setPaint(options)
425
- if (this.#paths3dLayer) {
426
- this.#paths3dLayer.setPaint(options)
427
- }
428
438
  }
429
439
 
430
440
  setPaint(options)
@@ -449,9 +459,7 @@ export class UserInteractions
449
459
  enable3dPaths(enable=true)
450
460
  //========================
451
461
  {
452
- if (this.#paths3dLayer) {
453
- this.#paths3dLayer.enable(enable)
454
- }
462
+ this._layerManager.set3dMode(enable)
455
463
  }
456
464
 
457
465
  getSystems()
@@ -466,37 +474,21 @@ export class UserInteractions
466
474
  this.__systemsManager.enable(systemId, enable);
467
475
  }
468
476
 
469
- #getAnnotationProperties(featureId)
470
- //=================================
471
- {
472
- const properties = this._flatmap.annotation(featureId)
473
- if (properties) {
474
- return properties
475
- } else if (this.#annotationDrawControl) {
476
- const drawnFeature = this.#annotationDrawControl.getFeature(featureId)
477
- if (drawnFeature) {
478
- drawnFeature.properties.user_drawn = true
479
- return drawnFeature.properties
480
- }
481
- }
482
- return null
483
- }
484
-
485
477
  mapFeature(featureId)
486
478
  //===================
487
479
  {
488
- const properties = this.#getAnnotationProperties(featureId);
489
- if (properties && !properties.user_drawn) {
480
+ const ann = this._flatmap.annotation(featureId);
481
+ if (ann !== undefined) {
490
482
  return {
491
483
  id: featureId,
492
484
  source: VECTOR_TILES_SOURCE,
493
485
  sourceLayer: (this._flatmap.options.separateLayers
494
- ? `${properties['layer']}_${properties['tile-layer']}`
495
- : properties['tile-layer']).replaceAll('/', '_'),
496
- children: properties.children || []
486
+ ? `${ann['layer']}_${ann['tile-layer']}`
487
+ : ann['tile-layer']).replaceAll('/', '_'),
488
+ children: ann.children || []
497
489
  };
498
490
  }
499
- return null;
491
+ return undefined;
500
492
  }
501
493
 
502
494
  #getFeatureState(feature)
@@ -509,24 +501,20 @@ export class UserInteractions
509
501
  //===============================
510
502
  {
511
503
  this._map.removeFeatureState(feature, key)
512
- if (this.#paths3dLayer) {
513
- this.#paths3dLayer.removeFeatureState(feature.id, key)
514
- }
504
+ this._layerManager.removeFeatureState(feature, key)
515
505
  }
516
506
 
517
507
  #setFeatureState(feature, state)
518
508
  //==============================
519
509
  {
520
510
  this._map.setFeatureState(feature, state)
521
- if (this.#paths3dLayer) {
522
- this.#paths3dLayer.setFeatureState(feature.id, state)
523
- }
511
+ this._layerManager.setFeatureState(feature, state)
524
512
  }
525
513
 
526
514
  enableMapFeature(feature, enable=true)
527
515
  //====================================
528
516
  {
529
- if (feature) {
517
+ if (feature !== undefined) {
530
518
  const state = this.#getFeatureState(feature);
531
519
  if ('hidden' in state) {
532
520
  if (enable) {
@@ -559,7 +547,7 @@ export class UserInteractions
559
547
  //============================================================
560
548
  {
561
549
  const feature = this.mapFeature(featureId);
562
- if (feature) {
550
+ if (feature !== undefined) {
563
551
  this.enableFeature(featureId, enable, force);
564
552
  for (const childFeatureId of feature.children) {
565
553
  this.enableFeatureWithChildren(childFeatureId, enable, force);
@@ -571,7 +559,7 @@ export class UserInteractions
571
559
  //===========================================
572
560
  {
573
561
  const markerId = this.__markerIdByFeatureId.get(+featureId);
574
- if (markerId) {
562
+ if (markerId !== undefined) {
575
563
  const markerDiv = document.getElementById(`marker-${markerId}`);
576
564
  if (markerDiv) {
577
565
  markerDiv.style.visibility = enable ? 'visible' : 'hidden';
@@ -584,7 +572,7 @@ export class UserInteractions
584
572
  {
585
573
  if (feature.id) {
586
574
  const state = this.#getFeatureState(feature);
587
- return (state
575
+ return (state !== undefined
588
576
  && (!('hidden' in state) || !state.hidden));
589
577
  }
590
578
  return DRAW_ANNOTATION_LAYERS.includes(feature.layer.id)
@@ -599,12 +587,12 @@ export class UserInteractions
599
587
  selectFeature(featureId, dim=true)
600
588
  //================================
601
589
  {
602
- const properties = this.#getAnnotationProperties(featureId);
603
- if (properties && 'sckan' in properties) {
590
+ const ann = this._flatmap.annotation(featureId);
591
+ if (ann && 'sckan' in ann) {
604
592
  const sckanState = this._layerManager.sckanState;
605
593
  if (sckanState === 'none'
606
- || sckanState === 'valid' && !properties.sckan
607
- || sckanState === 'invalid' && properties.sckan) {
594
+ || sckanState === 'valid' && !ann.sckan
595
+ || sckanState === 'invalid' && ann.sckan) {
608
596
  return false;
609
597
  }
610
598
  }
@@ -614,15 +602,11 @@ export class UserInteractions
614
602
  if (this._selectedFeatureIds.has(featureId)) {
615
603
  this._selectedFeatureIds.set(featureId, this._selectedFeatureIds.get(featureId) + 1);
616
604
  result = true;
617
- } else if (properties.user_drawn) {
618
- if (this.#annotationDrawControl) {
619
- this.#annotationDrawControl.selectFeature(featureId, true)
620
- }
621
605
  } else {
622
606
  const feature = this.mapFeature(featureId);
623
- if (feature) {
607
+ if (feature !== undefined) {
624
608
  const state = this.#getFeatureState(feature);
625
- if (state && (!('hidden' in state) || !state.hidden)) {
609
+ if (state !== undefined && (!('hidden' in state) || !state.hidden)) {
626
610
  this.#setFeatureState(feature, { selected: true });
627
611
  this._selectedFeatureIds.set(featureId, 1);
628
612
  result = true;
@@ -645,7 +629,7 @@ export class UserInteractions
645
629
  this._selectedFeatureIds.set(featureId, references - 1);
646
630
  } else {
647
631
  const feature = this.mapFeature(featureId);
648
- if (feature) {
632
+ if (feature !== undefined) {
649
633
  this.#removeFeatureState(feature, 'selected');
650
634
  this._selectedFeatureIds.delete(+featureId);
651
635
  }
@@ -661,7 +645,7 @@ export class UserInteractions
661
645
  {
662
646
  for (const featureId of this._selectedFeatureIds.keys()) {
663
647
  const feature = this.mapFeature(featureId);
664
- if (feature) {
648
+ if (feature !== undefined) {
665
649
  this.#removeFeatureState(feature, 'selected');
666
650
  }
667
651
  }
@@ -672,7 +656,7 @@ export class UserInteractions
672
656
  activateFeature(feature)
673
657
  //======================
674
658
  {
675
- if (feature) {
659
+ if (feature !== undefined) {
676
660
  this.#setFeatureState(feature, { active: true });
677
661
  this._activeFeatures.add(feature);
678
662
  }
@@ -758,7 +742,7 @@ export class UserInteractions
758
742
  if (featureIds.length) {
759
743
  this.unselectFeatures();
760
744
  for (const featureId of featureIds) {
761
- const annotation = this.#getAnnotationProperties(featureId);
745
+ const annotation = this._flatmap.annotation(featureId);
762
746
  if (annotation) {
763
747
  if (this.selectFeature(featureId)) {
764
748
  if ('type' in annotation && annotation.type.startsWith('line')) {
@@ -806,14 +790,14 @@ export class UserInteractions
806
790
  padding.lng -= bbox[0];
807
791
  padding.lat = bbox[3] - padding.lat;
808
792
  for (const featureId of featureIds) {
809
- const annotation = this.#getAnnotationProperties(featureId);
793
+ const annotation = this._flatmap.annotation(featureId);
810
794
  if (annotation) {
811
795
  if (this.selectFeature(featureId)) {
812
796
  bbox = expandBounds(bbox, annotation.bounds, padding);
813
797
  if ('type' in annotation && annotation.type.startsWith('line')) {
814
798
  for (const pathFeatureId of this.__pathManager.lineFeatureIds([featureId])) {
815
799
  if (this.selectFeature(pathFeatureId)) {
816
- const pathAnnotation = this.#getAnnotationProperties(pathFeatureId)
800
+ const pathAnnotation = this._flatmap.annotation(pathFeatureId)
817
801
  bbox = expandBounds(bbox, pathAnnotation.bounds, padding);
818
802
  }
819
803
  }
@@ -833,11 +817,12 @@ export class UserInteractions
833
817
  showPopup(featureId, content, options={})
834
818
  //=======================================
835
819
  {
836
- const properties = this.#getAnnotationProperties(featureId);
820
+ const ann = this._flatmap.annotation(featureId);
837
821
  const drawn = options && options.annotationFeatureGeometry;
838
- if (properties || drawn) { // The feature exists or it is a drawn annotation
822
+ if (ann || drawn) { // The feature exists or it is a drawn annotation
839
823
 
840
824
  // Remove any existing popup
825
+
841
826
  if (this._currentPopup) {
842
827
  if (options && options.preserveSelection) {
843
828
  this._currentPopup.options.preserveSelection = options.preserveSelection;
@@ -846,6 +831,7 @@ export class UserInteractions
846
831
  }
847
832
 
848
833
  // Clear selection if we are not preserving it
834
+
849
835
  if (options && options.preserveSelection) {
850
836
  delete options.preserveSelection; // Don't pass to onClose()
851
837
  } else { // via the popup's options
@@ -853,9 +839,10 @@ export class UserInteractions
853
839
  }
854
840
 
855
841
  // Select the feature
842
+
856
843
  this.selectFeature(featureId);
857
844
 
858
- // Find the pop-up's position
845
+ // Find the pop-up's postion
859
846
 
860
847
  let location = null;
861
848
  if ('positionAtLastClick' in options
@@ -868,7 +855,7 @@ export class UserInteractions
868
855
  location = options.annotationFeatureGeometry;
869
856
  } else {
870
857
  // Position popup at the feature's 'centre'
871
- location = this.__markerPosition(featureId, properties);
858
+ location = this.__markerPosition(featureId, ann);
872
859
  }
873
860
 
874
861
  // Make sure the feature is on screen
@@ -884,11 +871,10 @@ export class UserInteractions
884
871
  }
885
872
  this._currentPopup.setLngLat(location);
886
873
  if (typeof content === 'object') {
887
- this._currentPopup.setDOMContent(content)
874
+ this._currentPopup.setDOMContent(content);
888
875
  } else {
889
- this._currentPopup.setText(content)
876
+ this._currentPopup.setText(content);
890
877
  }
891
- this._currentPopup.addTo(this._map)
892
878
  }
893
879
  }
894
880
 
@@ -995,13 +981,7 @@ export class UserInteractions
995
981
  #renderedFeatures(point)
996
982
  //======================
997
983
  {
998
- let features = []
999
- if (this.#paths3dLayer) {
1000
- features = this.#paths3dLayer.queryFeaturesAtPoint(point)
1001
- }
1002
- if (features.length === 0) {
1003
- features = this._map.queryRenderedFeatures(point)
1004
- }
984
+ const features = this._layerManager.featuresAtPoint(point)
1005
985
  return features.filter(feature => this.__featureEnabled(feature));
1006
986
  }
1007
987
 
@@ -1166,7 +1146,7 @@ export class UserInteractions
1166
1146
  selectionEvent_(event, feature)
1167
1147
  //=============================
1168
1148
  {
1169
- if (feature) {
1149
+ if (feature !== undefined) {
1170
1150
  const clickedFeatureId = +feature.id;
1171
1151
  const dim = !('properties' in feature
1172
1152
  && 'kind' in feature.properties
@@ -1324,33 +1304,26 @@ export class UserInteractions
1324
1304
 
1325
1305
  // Marker handling
1326
1306
 
1327
- __markerPosition(featureId, properties)
1307
+ __markerPosition(featureId, annotation)
1328
1308
  {
1329
1309
  if (this.__markerPositions.has(featureId)) {
1330
1310
  return this.__markerPositions.get(featureId);
1331
1311
  }
1332
- let position = properties.markerPosition || properties.centroid || null;
1333
- if (!position) {
1312
+ let position = annotation.markerPosition || annotation.centroid;
1313
+ if (position === null || position == undefined) {
1334
1314
  // Find where to place a label or popup on a feature
1335
- if (properties.user_drawn) {
1336
- if (this.#annotationDrawControl) {
1337
- const feature = this.#annotationDrawControl.getFeature(featureId)
1338
- position = labelPosition(feature);
1339
- }
1340
- } else {
1341
- const features = this._map.querySourceFeatures(VECTOR_TILES_SOURCE, {
1342
- 'sourceLayer': this._flatmap.options.separateLayers
1343
- ? `${properties['layer']}_${properties['tile-layer']}`
1344
- : properties['tile-layer'],
1345
- 'filter': [
1346
- 'all',
1347
- [ '==', ['id'], parseInt(featureId) ],
1348
- [ '==', ['geometry-type'], 'Polygon' ]
1349
- ]
1350
- });
1351
- if (features.length > 0) {
1352
- position = labelPosition(features[0]);
1353
- }
1315
+ const features = this._map.querySourceFeatures(VECTOR_TILES_SOURCE, {
1316
+ 'sourceLayer': this._flatmap.options.separateLayers
1317
+ ? `${annotation['layer']}_${annotation['tile-layer']}`
1318
+ : annotation['tile-layer'],
1319
+ 'filter': [
1320
+ 'all',
1321
+ [ '==', ['id'], parseInt(featureId) ],
1322
+ [ '==', ['geometry-type'], 'Polygon' ]
1323
+ ]
1324
+ });
1325
+ if (features.length > 0) {
1326
+ position = labelPosition(features[0]);
1354
1327
  }
1355
1328
  }
1356
1329
  this.__markerPositions.set(featureId, position);
@@ -1364,7 +1337,7 @@ export class UserInteractions
1364
1337
  let markerId = -1;
1365
1338
 
1366
1339
  for (const featureId of featureIds) {
1367
- const annotation = this.#getAnnotationProperties(featureId);
1340
+ const annotation = this._flatmap.annotation(featureId);
1368
1341
  if (!('markerPosition' in annotation) && !annotation.geometry.includes('Polygon')) {
1369
1342
  continue;
1370
1343
  }
@@ -1480,7 +1453,7 @@ export class UserInteractions
1480
1453
  const annotation = this.__annotationByMarkerId.get(markerId);
1481
1454
  // The marker's feature
1482
1455
  const feature = this.mapFeature(annotation.featureId);
1483
- if (feature) {
1456
+ if (feature !== undefined) {
1484
1457
  if (event.type === 'mouseenter') {
1485
1458
  // Highlight on mouse enter
1486
1459
  this.resetActiveFeatures_();