@abi-software/flatmap-viewer 2.3.1-b.1 → 2.3.2-b.2

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.
@@ -180,10 +180,13 @@ class FlatMap
180
180
  if (this._userInteractions === null) {
181
181
  this.setupUserInteractions_();
182
182
  } else if (this._initialState === null) {
183
+ this._map.setMinZoom(3.0);
184
+ this._map.setMaxBounds(null);
185
+ this._map.setRenderWorldCopies(true);
183
186
  this._bounds = this._map.getBounds();
184
- this._map.setMaxBounds(this._bounds);
185
- const sw = maplibregl.MercatorCoordinate.fromLngLat(this._bounds.toArray()[0]);
186
- const ne = maplibregl.MercatorCoordinate.fromLngLat(this._bounds.toArray()[1]);
187
+ const bounds = this._bounds.toArray();
188
+ const sw = maplibregl.MercatorCoordinate.fromLngLat(bounds[0]);
189
+ const ne = maplibregl.MercatorCoordinate.fromLngLat(bounds[1]);
187
190
  this.__normalised_origin = [sw.x, ne.y];
188
191
  this.__normalised_size = [ne.x - sw.x, sw.y - ne.y];
189
192
  if ('state' in this._options) {
@@ -269,7 +272,7 @@ class FlatMap
269
272
  //=========
270
273
  {
271
274
  if (this._userInteractions !== null) {
272
- return this._userInteractions.pathways.pathTypes();
275
+ return this._userInteractions.pathManager.pathTypes();
273
276
  }
274
277
  }
275
278
 
@@ -284,7 +287,7 @@ class FlatMap
284
287
  //===============================
285
288
  {
286
289
  if (this._userInteractions !== null) {
287
- this._userInteractions.enablePath(pathType, enable);
290
+ this._userInteractions.enablePathsByType(pathType, enable);
288
291
  }
289
292
  }
290
293
 
@@ -299,7 +302,7 @@ class FlatMap
299
302
  //======================================
300
303
  {
301
304
  if (this._userInteractions !== null) {
302
- this._userInteractions.enableSckanPath(sckanState, enable);
305
+ this._userInteractions.enableSckanPaths(sckanState, enable);
303
306
  }
304
307
  }
305
308
 
@@ -521,7 +524,7 @@ class FlatMap
521
524
  }
522
525
  if (featureIds.length == 0 && this._userInteractions !== null) {
523
526
  // We still haven't found a feature, so check connectivity
524
- featureIds.extend(this._userInteractions.pathwaysFeatureIds(anatomicalIds));
527
+ featureIds.extend(this._userInteractions.pathFeatureIds(anatomicalIds));
525
528
  }
526
529
  return featureIds;
527
530
  }
@@ -805,7 +808,7 @@ class FlatMap
805
808
  /**
806
809
  * Get a list of a FC flatmap's systems.
807
810
  *
808
- * @return {Array.Object.<{name: string, colour: string}>} An array with system details
811
+ * @return {Array.Object.<{id: string, name: string, colour: string, enabled: boolean}>} An array with system details
809
812
  */
810
813
  getSystems()
811
814
  //==========
@@ -816,15 +819,15 @@ class FlatMap
816
819
  }
817
820
 
818
821
  /**
819
- * @param {string} systemName The name of the system to enable
822
+ * @param {string} systemId The identifier of the system to enable
820
823
  * @param {boolean} enable Show or hide the system. Defaults to ``true`` (show)
821
824
  *
822
825
  */
823
- enableSystem(systemName, enable=true)
826
+ enableSystem(systemId, enable=true)
824
827
  //===================================
825
828
  {
826
829
  if (this._userInteractions !== null) {
827
- return this._userInteractions.enableSystem(systemName, enable);
830
+ return this._userInteractions.enableSystem(systemId, enable);
828
831
  }
829
832
  }
830
833
 
@@ -35,17 +35,17 @@ import polylabel from 'polylabel';
35
35
 
36
36
  import {Annotator} from './annotation';
37
37
  import {LayerManager} from './layers';
38
- import {PATHWAYS_LAYER, Pathways} from './pathways';
39
- import {COLOUR_ERROR, VECTOR_TILES_SOURCE} from './styling';
38
+ import {PATHWAYS_LAYER, PathManager} from './pathways';
39
+ import {VECTOR_TILES_SOURCE} from './styling';
40
40
  import {SystemsManager} from './systems';
41
41
 
42
42
  import {displayedProperties, InfoControl} from './controls/info';
43
43
  import {BackgroundControl, LayerControl, NerveControl,
44
- PathControl, SCKANControl} from './controls/controls';
44
+ SCKANControl} from './controls/controls';
45
+ import {PathControl} from './controls/paths';
45
46
  import {SearchControl} from './controls/search';
46
47
  import {SystemsControl} from './controls/systems';
47
48
 
48
- import * as pathways from './pathways';
49
49
  import * as utils from './utils';
50
50
 
51
51
  //==============================================================================
@@ -130,18 +130,21 @@ export class UserInteractions
130
130
 
131
131
  this._layerManager = new LayerManager(flatmap);
132
132
 
133
+ this.__featureEnabledCount = new Map(Array.from(this._flatmap.annotations.keys()).map(k => [+k, 0]));
134
+
135
+ const featuresEnabled = flatmap.options.style !== 'functional';
136
+
133
137
  // Path visibility is either controlled externally or by a local control
138
+ // FC path visiblitity is determined by system visiblity
134
139
 
135
- this._pathways = new Pathways(flatmap);
140
+ this.__pathManager = new PathManager(flatmap, this, featuresEnabled);
136
141
 
137
142
  // The path types in this map
138
- const mapPathTypes = this._pathways.pathTypes();
143
+ const mapPathTypes = this.__pathManager.pathTypes();
139
144
 
140
- // Disable paths that are not initially shown
145
+ // Set initial enabled state of paths
141
146
  for (const path of mapPathTypes) {
142
- if ('enabled' in path && !path.enabled) {
143
- this.enablePath(path.type, false);
144
- }
147
+ this.__pathManager.enablePathsByType(path.type, path.enabled, true);
145
148
  }
146
149
 
147
150
  // Add annotation capability
@@ -153,7 +156,7 @@ export class UserInteractions
153
156
 
154
157
  // Note features that are FC systems
155
158
 
156
- this.__systemsManager = new SystemsManager(this._flatmap, this);
159
+ this.__systemsManager = new SystemsManager(this._flatmap, this, featuresEnabled);
157
160
 
158
161
  // Add various controls when running standalone
159
162
 
@@ -175,9 +178,9 @@ export class UserInteractions
175
178
  this._map.addControl(new LayerControl(flatmap, this._layerManager));
176
179
 
177
180
  // Add a control for nerve centrelines if they are present
178
- if (this._pathways.haveCentrelines) {
181
+ if (this.__pathManager.haveCentrelines) {
179
182
  this._map.addControl(new NerveControl(flatmap, this._layerManager, {showCentrelines: false}));
180
- this.enableCentrelines(false);
183
+ this.enableCentrelines(false, true);
181
184
  }
182
185
 
183
186
  // SCKAN path and SYSTEMS controls for FC maps
@@ -201,10 +204,10 @@ export class UserInteractions
201
204
  this.__pan_zoom_enabled = false;
202
205
  }
203
206
 
204
- get pathways()
205
- //============
207
+ get pathManager()
208
+ //===============
206
209
  {
207
- return this._pathways;
210
+ return this.__pathManager;
208
211
  }
209
212
 
210
213
  getState()
@@ -300,32 +303,64 @@ export class UserInteractions
300
303
  return this.__systemsManager.systems;
301
304
  }
302
305
 
303
- enableSystem(systemName, enable=true)
304
- //===================================
306
+ enableSystem(systemId, enable=true)
307
+ //=================================
305
308
  {
306
- this.__systemsManager.enable(systemName, enable);
309
+ this.__systemsManager.enable(systemId, enable);
307
310
  }
308
311
 
309
- enableFeatureWithChildren(featureId, enable=true)
310
- //===============================================
312
+ mapFeature(featureId)
313
+ //===================
314
+ {
315
+ const ann = this._flatmap.annotation(featureId);
316
+ if (ann !== undefined) {
317
+ return {
318
+ id: featureId,
319
+ source: VECTOR_TILES_SOURCE,
320
+ sourceLayer: (this._flatmap.options.separateLayers
321
+ ? `${ann['layer']}_${ann['tile-layer']}`
322
+ : ann['tile-layer']).replaceAll('/', '_'),
323
+ children: ann.children || []
324
+ };
325
+ }
326
+ return undefined;
327
+ }
328
+
329
+ enableMapFeature(feature, enable=true)
330
+ //====================================
311
331
  {
312
- const feature = this.mapFeature(featureId);
313
332
  if (feature !== undefined) {
314
- this.enableFeature(feature, enable);
315
- for (const childFeatureId of feature.children) {
316
- this.enableFeatureWithChildren(childFeatureId, enable);
333
+ if (enable) {
334
+ this._map.removeFeatureState(feature, 'hidden');
335
+ } else {
336
+ this._map.setFeatureState(feature, { 'hidden': true });
317
337
  }
338
+ this.__enableFeatureMarker(feature.id, enable);
318
339
  }
319
340
  }
320
341
 
321
- __enableFeatureWithParents(featureId, enable=true)
342
+ enableFeature(featureId, enable=true, force=false)
322
343
  //================================================
344
+ {
345
+ const enabledCount = this.__featureEnabledCount.get(+featureId)
346
+ if (force || enable && enabledCount === 0 || !enable && enabledCount == 1) {
347
+ this.enableMapFeature(this.mapFeature(featureId), enable)
348
+ }
349
+ if (force) {
350
+ this.__featureEnabledCount.set(+featureId, enable ? 1 : 0);
351
+ } else {
352
+ this.__featureEnabledCount.set(+featureId, enabledCount + (enable ? 1 : -1));
353
+ }
354
+ }
355
+
356
+ enableFeatureWithChildren(featureId, enable=true, force=false)
357
+ //============================================================
323
358
  {
324
359
  const feature = this.mapFeature(featureId);
325
360
  if (feature !== undefined) {
326
- this.enableFeature(feature, enable);
327
- for (const childFeatureId of feature.parents) {
328
- this.__enableFeatureWithParents(childFeatureId, enable);
361
+ this.enableFeature(featureId, enable, force);
362
+ for (const childFeatureId of feature.children) {
363
+ this.enableFeatureWithChildren(childFeatureId, enable, force);
329
364
  }
330
365
  }
331
366
  }
@@ -342,19 +377,6 @@ export class UserInteractions
342
377
  }
343
378
  }
344
379
 
345
- enableFeature(feature, enable=true)
346
- //=================================
347
- {
348
- if (feature !== undefined) {
349
- if (enable) {
350
- this._map.removeFeatureState(feature, 'hidden');
351
- } else {
352
- this._map.setFeatureState(feature, { 'hidden': true });
353
- }
354
- this.__enableFeatureMarker(feature.id, enable);
355
- }
356
- }
357
-
358
380
  __featureEnabled(feature)
359
381
  //=======================
360
382
  {
@@ -363,23 +385,6 @@ export class UserInteractions
363
385
  && (!('hidden' in state) || !state.hidden));
364
386
  }
365
387
 
366
- mapFeature(featureId)
367
- //===================
368
- {
369
- const ann = this._flatmap.annotation(featureId);
370
- if (ann !== undefined) {
371
- return {
372
- id: featureId,
373
- source: VECTOR_TILES_SOURCE,
374
- sourceLayer: (this._flatmap.options.separateLayers
375
- ? `${ann['layer']}_${ann['tile-layer']}`
376
- : ann['tile-layer']).replaceAll('/', '_'),
377
- children: ann.children || []
378
- };
379
- }
380
- return undefined;
381
- }
382
-
383
388
  featureSelected_(featureId)
384
389
  //=========================
385
390
  {
@@ -507,7 +512,7 @@ export class UserInteractions
507
512
  this.__clearModal();
508
513
  this.__clearActiveMarker();
509
514
  this.unselectFeatures();
510
- this.__enablePathFeatures(this._pathways.allFeatureIds(), true);
515
+ this.__enablePathFeatures(this.__pathManager.allFeatureIds(), true);
511
516
  }
512
517
 
513
518
  clearSearchResults(reset=true)
@@ -531,7 +536,7 @@ export class UserInteractions
531
536
  if (annotation) {
532
537
  this.highlightFeature_(featureId);
533
538
  if ('type' in annotation && annotation.type.startsWith('line')) {
534
- for (const pathFeatureId of this._pathways.lineFeatureIds([featureId])) {
539
+ for (const pathFeatureId of this.__pathManager.lineFeatureIds([featureId])) {
535
540
  this.highlightFeature_(pathFeatureId);
536
541
  }
537
542
  }
@@ -555,7 +560,7 @@ export class UserInteractions
555
560
  if (annotation) {
556
561
  this.selectFeature(featureId);
557
562
  if ('type' in annotation && annotation.type.startsWith('line')) {
558
- for (const pathFeatureId of this._pathways.lineFeatureIds([featureId])) {
563
+ for (const pathFeatureId of this.__pathManager.lineFeatureIds([featureId])) {
559
564
  this.selectFeature(pathFeatureId);
560
565
  }
561
566
  }
@@ -609,7 +614,7 @@ export class UserInteractions
609
614
  }
610
615
  bbox = expandBounds(bbox, annotation.bounds);
611
616
  if ('type' in annotation && annotation.type.startsWith('line')) {
612
- for (const pathFeatureId of this._pathways.lineFeatureIds([featureId])) {
617
+ for (const pathFeatureId of this.__pathManager.lineFeatureIds([featureId])) {
613
618
  if (select) {
614
619
  this.selectFeature(pathFeatureId);
615
620
  } else if (highlight) {
@@ -751,7 +756,7 @@ export class UserInteractions
751
756
  {
752
757
  if (feature.sourceLayer === PATHWAYS_LAYER) { // I suspect this is never true as source layer
753
758
  // names are like `neural_routes_pathways`
754
- return this._flatmap.featureEvent(type, this._pathways.pathProperties(feature));
759
+ return this._flatmap.featureEvent(type, this.__pathManager.pathProperties(feature));
755
760
  } else if ('properties' in feature) {
756
761
  return this._flatmap.featureEvent(type, feature.properties);
757
762
  }
@@ -826,13 +831,15 @@ export class UserInteractions
826
831
  const lineFeatures = features.filter(feature => ('centreline' in feature.properties
827
832
  || ('type' in feature.properties
828
833
  && feature.properties.type.startsWith('line')) ));
834
+ let tooltipFeature = null;
829
835
  if (lineFeatures.length > 0) {
830
836
  tooltip = this.lineTooltip_(lineFeatures);
837
+ tooltipFeature = lineFeatures[0];
831
838
  for (const lineFeature of lineFeatures) {
832
839
  const lineFeatureId = +lineFeature.properties.featureId; // Ensure numeric
833
840
  this.__activateFeature(lineFeature);
834
841
  const lineIds = new Set(lineFeatures.map(f => f.properties.featureId));
835
- for (const featureId of this._pathways.lineFeatureIds(lineIds)) {
842
+ for (const featureId of this.__pathManager.lineFeatureIds(lineIds)) {
836
843
  if (+featureId !== lineFeatureId) {
837
844
  this.__activateFeature(this.mapFeature(featureId));
838
845
  }
@@ -855,6 +862,7 @@ export class UserInteractions
855
862
  }
856
863
  const feature = labelledFeatures[0];
857
864
  tooltip = this.tooltipHtml_(feature.properties);
865
+ tooltipFeature = feature;
858
866
  if (this._flatmap.options.debug) { // Do this when Info on and not debug??
859
867
  const debugProperties = [
860
868
  'featureId',
@@ -893,11 +901,11 @@ export class UserInteractions
893
901
  if (displayInfo || this._flatmap.options.debug) {
894
902
  this._infoControl.show(info);
895
903
  }
896
- this.__showToolTip(tooltip, event.lngLat);
904
+ this.__showToolTip(tooltip, event.lngLat, tooltipFeature);
897
905
  }
898
906
 
899
- __showToolTip(html, lngLat)
900
- //=========================
907
+ __showToolTip(html, lngLat, feature=null)
908
+ //=======================================
901
909
  {
902
910
  // Show a tooltip
903
911
  if (html !== '') {
@@ -911,7 +919,10 @@ export class UserInteractions
911
919
  const pt = turf.point(lngLat.toArray());
912
920
  const gps = turfProjection.toMercator(pt);
913
921
  const coords = gps.geometry.coordinates;
914
- html = `<span>${JSON.stringify(coords)}</span><br/>${html}`;
922
+ const header = (feature === null)
923
+ ? JSON.stringify(coords)
924
+ : `${JSON.stringify(coords)} (${feature.id} ${feature.properties['id']})`;
925
+ html = `<span>${header}</span><br/>${html}`;
915
926
  }
916
927
  this._tooltip
917
928
  .setLngLat(lngLat)
@@ -1017,57 +1028,65 @@ export class UserInteractions
1017
1028
  //================================
1018
1029
  {
1019
1030
  if ('nerveId' in feature.properties) {
1020
- for (const featureId of this._pathways.nerveFeatureIds(feature.properties.nerveId)) {
1031
+ const nerveId = feature.properties.nerveId;
1032
+ if (nerveId !== feature.id) {
1033
+ this.__activateFeature(this.mapFeature(nerveId));
1034
+ }
1035
+ for (const featureId of this.__pathManager.nerveFeatureIds(nerveId)) {
1021
1036
  this.__activateFeature(this.mapFeature(featureId));
1022
1037
  }
1023
1038
  }
1024
1039
  if ('nodeId' in feature.properties) {
1025
- for (const featureId of this._pathways.nodeFeatureIds(feature.properties.nodeId)) {
1040
+ for (const featureId of this.__pathManager.nodeFeatureIds(feature.properties.nodeId)) {
1026
1041
  this.__activateFeature(this.mapFeature(featureId));
1027
1042
  }
1028
1043
  }
1029
1044
  }
1030
1045
 
1031
- __enablePathFeatures(featureIds, enable)
1032
- //======================================
1046
+ enablePath(pathId, enable=true)
1047
+ //=============================
1033
1048
  {
1034
- for (const featureId of featureIds) {
1035
- this.enableFeature(this.mapFeature(featureId), enable);
1036
- }
1049
+ this.__pathManager.enablePath(pathId, enable);
1037
1050
  }
1038
1051
 
1039
- enablePath(pathType, enable=true)
1040
- //===============================
1052
+ enablePathsBySystem(system, enable=true, force=false)
1053
+ //===================================================
1041
1054
  {
1042
- this.__enablePathFeatures(this._pathways.typeFeatureIds(pathType), enable);
1055
+ this.__pathManager.enablePathsBySystem(system, enable, force);
1043
1056
  }
1044
1057
 
1045
- pathwaysFeatureIds(externalIds)
1046
- //=============================
1058
+ enablePathsByType(pathType, enable=true)
1059
+ //======================================
1060
+ {
1061
+ this.__pathManager.enablePathsByType(pathType, enable);
1062
+ }
1063
+
1064
+ pathFeatureIds(externalIds)
1065
+ //=========================
1047
1066
  {
1048
1067
  const featureIds = new utils.List();
1049
- featureIds.extend(this._pathways.connectivityModelFeatureIds(externalIds));
1050
- featureIds.extend(this._pathways.pathModelFeatureIds(externalIds));
1068
+ featureIds.extend(this.__pathManager.connectivityModelFeatureIds(externalIds));
1069
+ featureIds.extend(this.__pathManager.pathModelFeatureIds(externalIds));
1051
1070
  return featureIds;
1052
1071
  }
1053
1072
 
1054
1073
  nodePathModels(nodeId)
1055
1074
  //====================
1056
1075
  {
1057
- return this._pathways.nodePathModels(nodeId);
1076
+ return this.__pathManager.nodePathModels(nodeId);
1058
1077
  }
1059
1078
 
1060
- enableCentrelines(show=true)
1061
- //==========================
1079
+ enableCentrelines(enable=true, force=false)
1080
+ //=========================================
1062
1081
  {
1063
- this.enablePath('centreline', show);
1064
- this._layerManager.setPaint({showCentrelines: show});
1082
+ this.__pathManager.enablePathsByType('centreline', enable, force);
1083
+ this._layerManager.setPaint({showCentrelines: enable});
1065
1084
  }
1066
1085
 
1067
- enableSckanPath(sckanState, enable=true)
1068
- //======================================
1086
+ enableSckanPaths(sckanState, enable=true)
1087
+ //=======================================
1069
1088
  {
1070
- this._layerManager.enableSckanPath(sckanState, enable);
1089
+ this._layerManager.enableSckanPaths(sckanState, enable);
1071
1090
  }
1072
1091
 
1073
1092
  //==============================================================================
package/src/layers.js CHANGED
@@ -165,6 +165,9 @@ class MapFeatureLayers extends MapStylingLayers
165
165
  this.__addStyleLayer(style.NervePolygonBorder, PATHWAYS_LAYER);
166
166
  this.__addStyleLayer(style.NervePolygonFill, PATHWAYS_LAYER);
167
167
  this.__addStyleLayer(style.FeatureNerveLayer, PATHWAYS_LAYER);
168
+
169
+ this.__addStyleLayer(style.PathHighlightLayer, PATHWAYS_LAYER);
170
+ this.__addStyleLayer(style.PathDashHighlightLayer, PATHWAYS_LAYER);
168
171
  }
169
172
  }
170
173
 
@@ -331,8 +334,8 @@ export class LayerManager
331
334
  }
332
335
  }
333
336
 
334
- enableSckanPath(sckanState, enable=true)
335
- //======================================
337
+ enableSckanPaths(sckanState, enable=true)
338
+ //=======================================
336
339
  {
337
340
  const currentState = this.__layerOptions.sckan;
338
341
  const validEnabled = ['valid', 'all'].indexOf(currentState) >= 0;