@abi-software/flatmap-viewer 2.4.4 → 2.5.0-a.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.
- package/README.rst +1 -1
- package/package.json +6 -1
- package/src/controls/paths3d.js +76 -0
- package/src/flatmap-viewer.js +15 -2
- package/src/interactions.js +26 -18
- package/src/{layers.js → layers/index.js} +2 -2
- package/src/layers/paths3d.js +170 -0
- package/src/{styling.js → layers/styling.js} +2 -2
- package/src/pathways.js +45 -0
package/README.rst
CHANGED
|
@@ -38,7 +38,7 @@ The map server endpoint is specified as ``MAP_ENDPOINT`` in ``src/main.js``. It
|
|
|
38
38
|
Package Installation
|
|
39
39
|
====================
|
|
40
40
|
|
|
41
|
-
* ``npm install @abi-software/flatmap-viewer@2.
|
|
41
|
+
* ``npm install @abi-software/flatmap-viewer@2.5.0-a.2``
|
|
42
42
|
|
|
43
43
|
Documentation
|
|
44
44
|
-------------
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abi-software/flatmap-viewer",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0-a.2",
|
|
4
4
|
"description": "Flatmap viewer using Maplibre GL",
|
|
5
5
|
"repository": "https://github.com/AnatomicMaps/flatmap-viewer.git",
|
|
6
6
|
"main": "src/main.js",
|
|
@@ -18,12 +18,17 @@
|
|
|
18
18
|
"license": "MIT",
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@babel/runtime": "^7.10.4",
|
|
21
|
+
"@deck.gl/core": "^8.9.33",
|
|
22
|
+
"@deck.gl/extensions": "^8.9.34",
|
|
23
|
+
"@deck.gl/layers": "^8.9.33",
|
|
24
|
+
"@deck.gl/mapbox": "^8.9.33",
|
|
21
25
|
"@fortawesome/fontawesome-free": "^6.4.0",
|
|
22
26
|
"@turf/area": "^6.5.0",
|
|
23
27
|
"@turf/bbox": "^6.5.0",
|
|
24
28
|
"@turf/helpers": "^6.5.0",
|
|
25
29
|
"@turf/projection": "^6.5.0",
|
|
26
30
|
"bezier-js": "^6.1.0",
|
|
31
|
+
"colord": "^2.9.3",
|
|
27
32
|
"html-es6cape": "^2.0.2",
|
|
28
33
|
"maplibre-gl": ">=3.6.0",
|
|
29
34
|
"mathjax-full": "^3.2.2",
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/******************************************************************************
|
|
2
|
+
|
|
3
|
+
Flatmap viewer and annotation tool
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2019 - 2024 David Brooks
|
|
6
|
+
|
|
7
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
you may not use this file except in compliance with the License.
|
|
9
|
+
You may obtain a copy of the License at
|
|
10
|
+
|
|
11
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
|
|
13
|
+
Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
See the License for the specific language governing permissions and
|
|
17
|
+
limitations under the License.
|
|
18
|
+
|
|
19
|
+
******************************************************************************/
|
|
20
|
+
|
|
21
|
+
export class Path3DControl
|
|
22
|
+
{
|
|
23
|
+
#button
|
|
24
|
+
#container
|
|
25
|
+
#map = null
|
|
26
|
+
#flatmap
|
|
27
|
+
|
|
28
|
+
constructor(flatmap)
|
|
29
|
+
{
|
|
30
|
+
this.#flatmap = flatmap
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getDefaultPosition()
|
|
34
|
+
//==================
|
|
35
|
+
{
|
|
36
|
+
return 'top-right'
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
onAdd(map)
|
|
40
|
+
//========
|
|
41
|
+
{
|
|
42
|
+
this.#map = map
|
|
43
|
+
this.#container = document.createElement('div')
|
|
44
|
+
this.#container.className = 'maplibregl-ctrl'
|
|
45
|
+
this.#button = document.createElement('button')
|
|
46
|
+
this.#button.className = 'control-button text-button'
|
|
47
|
+
this.#button.setAttribute('type', 'button')
|
|
48
|
+
this.#button.setAttribute('aria-label', 'Show 3D paths')
|
|
49
|
+
this.#button.textContent = '3D'
|
|
50
|
+
this.#button.title = 'Show/hide 3D paths'
|
|
51
|
+
this.#container.appendChild(this.#button)
|
|
52
|
+
this.#container.addEventListener('click', this.onClick.bind(this))
|
|
53
|
+
return this.#container
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
onRemove()
|
|
57
|
+
//========
|
|
58
|
+
{
|
|
59
|
+
this.#container.parentNode.removeChild(this.#container)
|
|
60
|
+
this.#map = undefined
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
onClick(_event)
|
|
64
|
+
//=============
|
|
65
|
+
{
|
|
66
|
+
if (this.#button.classList.contains('control-active')) {
|
|
67
|
+
this.#flatmap.enable3dPaths(false)
|
|
68
|
+
this.#button.classList.remove('control-active')
|
|
69
|
+
} else {
|
|
70
|
+
this.#flatmap.enable3dPaths(true)
|
|
71
|
+
this.#button.classList.add('control-active')
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
//==============================================================================
|
package/src/flatmap-viewer.js
CHANGED
|
@@ -170,8 +170,8 @@ class FlatMap
|
|
|
170
170
|
|
|
171
171
|
// Disable map rotation
|
|
172
172
|
|
|
173
|
-
this._map.dragRotate.disable();
|
|
174
|
-
this._map.touchZoomRotate.disableRotation();
|
|
173
|
+
//this._map.dragRotate.disable();
|
|
174
|
+
//this._map.touchZoomRotate.disableRotation();
|
|
175
175
|
|
|
176
176
|
// Add navigation controls if option set
|
|
177
177
|
|
|
@@ -898,6 +898,19 @@ class FlatMap
|
|
|
898
898
|
}
|
|
899
899
|
}
|
|
900
900
|
|
|
901
|
+
/**
|
|
902
|
+
* Show/hide 3D path view.
|
|
903
|
+
*
|
|
904
|
+
* @param {boolean} [enable=true]
|
|
905
|
+
*/
|
|
906
|
+
enable3dPaths(enable=true)
|
|
907
|
+
//========================
|
|
908
|
+
{
|
|
909
|
+
if (this._userInteractions !== null) {
|
|
910
|
+
this._userInteractions.enable3dPaths(enable)
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
|
|
901
914
|
//==========================================================================
|
|
902
915
|
|
|
903
916
|
/**
|
package/src/interactions.js
CHANGED
|
@@ -35,13 +35,15 @@ import polylabel from 'polylabel';
|
|
|
35
35
|
|
|
36
36
|
import {LayerManager} from './layers';
|
|
37
37
|
import {PATHWAYS_LAYER, PathManager} from './pathways';
|
|
38
|
-
import {VECTOR_TILES_SOURCE} from './styling';
|
|
38
|
+
import {VECTOR_TILES_SOURCE} from './layers/styling';
|
|
39
|
+
import {Paths3DLayer} from './layers/paths3d'
|
|
39
40
|
import {SystemsManager} from './systems';
|
|
40
41
|
|
|
41
42
|
import {displayedProperties, InfoControl} from './controls/info';
|
|
42
43
|
import {BackgroundControl, LayerControl, NerveControl,
|
|
43
44
|
SCKANControl} from './controls/controls';
|
|
44
45
|
import {PathControl} from './controls/paths';
|
|
46
|
+
import {Path3DControl} from './controls/paths3d'
|
|
45
47
|
import {SearchControl} from './controls/search';
|
|
46
48
|
import {SystemsControl} from './controls/systems';
|
|
47
49
|
import {TaxonsControl} from './controls/taxons';
|
|
@@ -120,6 +122,8 @@ function getRenderedLabel(properties)
|
|
|
120
122
|
|
|
121
123
|
export class UserInteractions
|
|
122
124
|
{
|
|
125
|
+
#paths3dLayer
|
|
126
|
+
|
|
123
127
|
constructor(flatmap)
|
|
124
128
|
{
|
|
125
129
|
this._flatmap = flatmap;
|
|
@@ -183,6 +187,9 @@ export class UserInteractions
|
|
|
183
187
|
// All taxons of connectivity paths are enabled by default
|
|
184
188
|
this.__enabledConnectivityTaxons = new Set(this._flatmap.taxonIdentifiers);
|
|
185
189
|
|
|
190
|
+
// Support 3D path view
|
|
191
|
+
this.#paths3dLayer = new Paths3DLayer(flatmap, this)
|
|
192
|
+
|
|
186
193
|
// Add various controls when running standalone
|
|
187
194
|
if (flatmap.options.standalone) {
|
|
188
195
|
// Add a control to search annotations if option set
|
|
@@ -214,6 +221,8 @@ export class UserInteractions
|
|
|
214
221
|
// Connectivity taxon control for AC maps
|
|
215
222
|
this._map.addControl(new TaxonsControl(flatmap));
|
|
216
223
|
}
|
|
224
|
+
|
|
225
|
+
this._map.addControl(new Path3DControl(this));
|
|
217
226
|
}
|
|
218
227
|
|
|
219
228
|
// Handle mouse events
|
|
@@ -288,6 +297,12 @@ export class UserInteractions
|
|
|
288
297
|
this._layerManager.activate(layerId, enable);
|
|
289
298
|
}
|
|
290
299
|
|
|
300
|
+
enable3dPaths(enable=true)
|
|
301
|
+
//========================
|
|
302
|
+
{
|
|
303
|
+
this.#paths3dLayer.enable(enable)
|
|
304
|
+
}
|
|
305
|
+
|
|
291
306
|
getSystems()
|
|
292
307
|
//==========
|
|
293
308
|
{
|
|
@@ -459,8 +474,8 @@ export class UserInteractions
|
|
|
459
474
|
this._layerManager.setPaint({...this.__colourOptions, dimmed: false});
|
|
460
475
|
}
|
|
461
476
|
|
|
462
|
-
|
|
463
|
-
|
|
477
|
+
activateFeature(feature)
|
|
478
|
+
//======================
|
|
464
479
|
{
|
|
465
480
|
if (feature !== undefined) {
|
|
466
481
|
this._map.setFeatureState(feature, { active: true });
|
|
@@ -515,7 +530,6 @@ export class UserInteractions
|
|
|
515
530
|
this.__clearModal();
|
|
516
531
|
this.__clearActiveMarker();
|
|
517
532
|
this.unselectFeatures();
|
|
518
|
-
this.__enablePathFeatures(this.__pathManager.allFeatureIds(), true);
|
|
519
533
|
}
|
|
520
534
|
|
|
521
535
|
clearSearchResults(reset=true)
|
|
@@ -809,7 +823,7 @@ export class UserInteractions
|
|
|
809
823
|
let tooltip = '';
|
|
810
824
|
if (displayInfo) {
|
|
811
825
|
if (!('tooltip' in features[0].properties)) {
|
|
812
|
-
this.
|
|
826
|
+
this.activateFeature(features[0]);
|
|
813
827
|
}
|
|
814
828
|
info = this._infoControl.featureInformation(features, event.lngLat);
|
|
815
829
|
}
|
|
@@ -822,11 +836,11 @@ export class UserInteractions
|
|
|
822
836
|
tooltipFeature = lineFeatures[0];
|
|
823
837
|
for (const lineFeature of lineFeatures) {
|
|
824
838
|
const lineFeatureId = +lineFeature.properties.featureId; // Ensure numeric
|
|
825
|
-
this.
|
|
839
|
+
this.activateFeature(lineFeature);
|
|
826
840
|
const lineIds = new Set(lineFeatures.map(f => f.properties.featureId));
|
|
827
841
|
for (const featureId of this.__pathManager.lineFeatureIds(lineIds)) {
|
|
828
842
|
if (+featureId !== lineFeatureId) {
|
|
829
|
-
this.
|
|
843
|
+
this.activateFeature(this.mapFeature(featureId));
|
|
830
844
|
}
|
|
831
845
|
}
|
|
832
846
|
}
|
|
@@ -876,7 +890,7 @@ export class UserInteractions
|
|
|
876
890
|
info = `<div id="info-control-info">${htmlList.join('\n')}</div>`;
|
|
877
891
|
}
|
|
878
892
|
}
|
|
879
|
-
this.
|
|
893
|
+
this.activateFeature(feature);
|
|
880
894
|
this.__activateRelatedFeatures(feature);
|
|
881
895
|
if ('hyperlink' in feature.properties) {
|
|
882
896
|
this._map.getCanvas().style.cursor = 'pointer';
|
|
@@ -996,25 +1010,19 @@ export class UserInteractions
|
|
|
996
1010
|
if ('nerveId' in feature.properties) {
|
|
997
1011
|
const nerveId = feature.properties.nerveId;
|
|
998
1012
|
if (nerveId !== feature.id) {
|
|
999
|
-
this.
|
|
1013
|
+
this.activateFeature(this.mapFeature(nerveId));
|
|
1000
1014
|
}
|
|
1001
1015
|
for (const featureId of this.__pathManager.nerveFeatureIds(nerveId)) {
|
|
1002
|
-
this.
|
|
1016
|
+
this.activateFeature(this.mapFeature(featureId));
|
|
1003
1017
|
}
|
|
1004
1018
|
}
|
|
1005
1019
|
if ('nodeId' in feature.properties) {
|
|
1006
1020
|
for (const featureId of this.__pathManager.pathFeatureIds(feature.properties.nodeId)) {
|
|
1007
|
-
this.
|
|
1021
|
+
this.activateFeature(this.mapFeature(featureId));
|
|
1008
1022
|
}
|
|
1009
1023
|
}
|
|
1010
1024
|
}
|
|
1011
1025
|
|
|
1012
|
-
enablePath(pathId, enable=true)
|
|
1013
|
-
//=============================
|
|
1014
|
-
{
|
|
1015
|
-
this.__pathManager.enablePath(pathId, enable);
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
1026
|
enablePathsBySystem(system, enable=true, force=false)
|
|
1019
1027
|
//===================================================
|
|
1020
1028
|
{
|
|
@@ -1239,7 +1247,7 @@ export class UserInteractions
|
|
|
1239
1247
|
if (event.type === 'mouseenter') {
|
|
1240
1248
|
// Highlight on mouse enter
|
|
1241
1249
|
this.resetActiveFeatures_();
|
|
1242
|
-
this.
|
|
1250
|
+
this.activateFeature(feature);
|
|
1243
1251
|
} else {
|
|
1244
1252
|
this.selectionEvent_(event, feature)
|
|
1245
1253
|
}
|
|
@@ -22,10 +22,10 @@ limitations under the License.
|
|
|
22
22
|
|
|
23
23
|
//==============================================================================
|
|
24
24
|
|
|
25
|
-
import {PATHWAYS_LAYER} from '
|
|
25
|
+
import {PATHWAYS_LAYER} from '../pathways.js';
|
|
26
|
+
import * as utils from '../utils.js';
|
|
26
27
|
|
|
27
28
|
import * as style from './styling.js';
|
|
28
|
-
import * as utils from './utils.js';
|
|
29
29
|
|
|
30
30
|
const FEATURES_LAYER = 'features';
|
|
31
31
|
const RASTER_LAYERS_NAME = 'Background image layer';
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/******************************************************************************
|
|
2
|
+
|
|
3
|
+
Flatmap viewer and annotation tool
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2019 - 2024 David Brooks
|
|
6
|
+
|
|
7
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
you may not use this file except in compliance with the License.
|
|
9
|
+
You may obtain a copy of the License at
|
|
10
|
+
|
|
11
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
|
|
13
|
+
Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
See the License for the specific language governing permissions and
|
|
17
|
+
limitations under the License.
|
|
18
|
+
|
|
19
|
+
******************************************************************************/
|
|
20
|
+
|
|
21
|
+
import {colord} from 'colord'
|
|
22
|
+
import {ArcLayer} from '@deck.gl/layers'
|
|
23
|
+
import {MapboxOverlay as DeckOverlay} from '@deck.gl/mapbox'
|
|
24
|
+
import {PathStyleExtension} from '@deck.gl/extensions'
|
|
25
|
+
|
|
26
|
+
//==============================================================================
|
|
27
|
+
|
|
28
|
+
import {pathColour} from '../pathways'
|
|
29
|
+
|
|
30
|
+
// Should this be in `pathways.js` ??
|
|
31
|
+
function pathColourRGB(pathType, alpha=255)
|
|
32
|
+
//=========================================
|
|
33
|
+
{
|
|
34
|
+
const rgb = colord(pathColour(pathType)).toRgb()
|
|
35
|
+
return [rgb.r, rgb.g, rgb.b, alpha]
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
//==============================================================================
|
|
39
|
+
|
|
40
|
+
/*
|
|
41
|
+
TODO:
|
|
42
|
+
|
|
43
|
+
* Dashed paths
|
|
44
|
+
* Control by SCKAN status
|
|
45
|
+
* Control by taxon visibility
|
|
46
|
+
* Control by visible layer
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
Also see https://alasarr.github.io/deck.gl/docs/api-reference/core/layer#updatetriggers
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
{
|
|
53
|
+
"featureId": 37,
|
|
54
|
+
"id": "ilxtr_neuron-type-keast-10",
|
|
55
|
+
"kind": "sensory",
|
|
56
|
+
"label": "L6-S1 sensory neuron innervating bladder",
|
|
57
|
+
"models": "ilxtr:neuron-type-keast-10",
|
|
58
|
+
"sckan": true,
|
|
59
|
+
"source": "https://apinatomy.org/uris/models/keast-bladder",
|
|
60
|
+
"taxons": ["NCBITaxon:10116"],
|
|
61
|
+
"tile-layer": "pathways",
|
|
62
|
+
"type": "line",
|
|
63
|
+
"bounds": [1.5454426659162825, -1.6254174813389017, 1.7478459571498208, -1.3632864333949712],
|
|
64
|
+
"markerPosition": [1.6466443115330516, -1.4943519573669364],
|
|
65
|
+
"geometry": "LineString",
|
|
66
|
+
"layer": "neural-routes",
|
|
67
|
+
"pathStartPosition": [1.7478459571498208, -1.3632864333949712],
|
|
68
|
+
"pathEndPosition": [1.5454426659162825, -1.6254174813389017]
|
|
69
|
+
}
|
|
70
|
+
*/
|
|
71
|
+
|
|
72
|
+
//==============================================================================
|
|
73
|
+
|
|
74
|
+
export class Paths3DLayer
|
|
75
|
+
{
|
|
76
|
+
#deckOverlay = null
|
|
77
|
+
#enabled = false
|
|
78
|
+
#map
|
|
79
|
+
#pathData
|
|
80
|
+
#pathManager
|
|
81
|
+
#ui
|
|
82
|
+
|
|
83
|
+
constructor(flatmap, ui)
|
|
84
|
+
{
|
|
85
|
+
this.#ui = ui
|
|
86
|
+
this.#map = flatmap.map
|
|
87
|
+
this.#pathManager = ui.pathManager
|
|
88
|
+
this.#pathManager.addWatcher(this.#pathStateChanged.bind(this))
|
|
89
|
+
this.#pathData = [...flatmap.annotations.values()]
|
|
90
|
+
.filter(ann => ann['tile-layer'] === 'pathways'
|
|
91
|
+
&& ann['geometry'] === 'LineString'
|
|
92
|
+
&& 'type' in ann && ann['type'].startsWith('line')
|
|
93
|
+
&& 'kind' in ann // && !ann['kind'].includes('arterial') && !ann['kind'].includes('venous')
|
|
94
|
+
&& 'pathStartPosition' in ann
|
|
95
|
+
&& 'pathEndPosition' in ann)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
enable(enable=true)
|
|
99
|
+
//=================
|
|
100
|
+
{
|
|
101
|
+
if (enable && !this.#enabled) {
|
|
102
|
+
this.#setDeckOverlay()
|
|
103
|
+
this.#map.addControl(this.#deckOverlay)
|
|
104
|
+
} else if (!enable && this.#enabled) {
|
|
105
|
+
if (this.#deckOverlay) {
|
|
106
|
+
this.#map.removeControl(this.#deckOverlay)
|
|
107
|
+
this.#deckOverlay = null
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
this.#enabled = enable
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
#pathStateChanged()
|
|
114
|
+
//=================
|
|
115
|
+
{
|
|
116
|
+
if (this.#deckOverlay) {
|
|
117
|
+
this.#map.removeControl(this.#deckOverlay)
|
|
118
|
+
this.#setDeckOverlay()
|
|
119
|
+
this.#map.addControl(this.#deckOverlay)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
#setDeckOverlay()
|
|
124
|
+
//===============
|
|
125
|
+
{
|
|
126
|
+
this.#deckOverlay = new DeckOverlay({
|
|
127
|
+
layers: [
|
|
128
|
+
// Need to have two layers, one with dashed lines, one without
|
|
129
|
+
//
|
|
130
|
+
// Better, one layer per pathType and set/clear layer.visible...
|
|
131
|
+
//
|
|
132
|
+
new ArcLayer({
|
|
133
|
+
id: 'arcs',
|
|
134
|
+
data: this.#pathData
|
|
135
|
+
.filter(f => this.#pathManager.pathTypeEnabled(f.kind)),
|
|
136
|
+
pickable: true,
|
|
137
|
+
autoHighlight: true,
|
|
138
|
+
numSegments: 100,
|
|
139
|
+
onHover: (i, e) => {
|
|
140
|
+
//console.log('hover', i, e)
|
|
141
|
+
if (i.object) {
|
|
142
|
+
const lineFeatureId = +i.object.featureId
|
|
143
|
+
this.#ui.activateFeature(this.#ui.mapFeature(lineFeatureId))
|
|
144
|
+
for (const featureId of this.#pathManager.lineFeatureIds([lineFeatureId])) {
|
|
145
|
+
if (+featureId !== lineFeatureId) {
|
|
146
|
+
this.#ui.activateFeature(this.#ui.mapFeature(featureId))
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
onClick: (i, e) => {
|
|
152
|
+
console.log('click', i, e)
|
|
153
|
+
},
|
|
154
|
+
// Styles
|
|
155
|
+
getSourcePosition: f => f.pathStartPosition,
|
|
156
|
+
getTargetPosition: f => f.pathEndPosition,
|
|
157
|
+
getSourceColor: f => pathColourRGB(f.kind, 160),
|
|
158
|
+
getTargetColor: f => pathColourRGB(f.kind, 160),
|
|
159
|
+
highlightColor: o => pathColourRGB(o.object.kind),
|
|
160
|
+
getWidth: 3,
|
|
161
|
+
extensions: [new PathStyleExtension({dash: true})],
|
|
162
|
+
getDashArray: [3, 2],
|
|
163
|
+
dashJustified: true,
|
|
164
|
+
dashGapPickable: true,
|
|
165
|
+
})
|
|
166
|
+
],
|
|
167
|
+
getTooltip: ({object}) => object && object.label
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -26,8 +26,8 @@ export const VECTOR_TILES_SOURCE = 'vector-tiles';
|
|
|
26
26
|
|
|
27
27
|
//==============================================================================
|
|
28
28
|
|
|
29
|
-
import {UNCLASSIFIED_TAXON_ID} from '
|
|
30
|
-
import {PATH_STYLE_RULES} from '
|
|
29
|
+
import {UNCLASSIFIED_TAXON_ID} from '../flatmap-viewer';
|
|
30
|
+
import {PATH_STYLE_RULES} from '../pathways';
|
|
31
31
|
|
|
32
32
|
//==============================================================================
|
|
33
33
|
|
package/src/pathways.js
CHANGED
|
@@ -52,6 +52,14 @@ const PATH_TYPES = [
|
|
|
52
52
|
export const PATH_STYLE_RULES =
|
|
53
53
|
PATH_TYPES.flatMap(pathType => [['==', ['get', 'kind'], pathType.type], pathType.colour]);
|
|
54
54
|
|
|
55
|
+
export const PATH_COLOURS =
|
|
56
|
+
Object.fromEntries(PATH_TYPES.flatMap(pathType => [[pathType.type, pathType.colour]]));
|
|
57
|
+
|
|
58
|
+
export function pathColour(pathType)
|
|
59
|
+
{
|
|
60
|
+
return PATH_COLOURS[pathType] || '#FF0';
|
|
61
|
+
}
|
|
62
|
+
|
|
55
63
|
//==============================================================================
|
|
56
64
|
|
|
57
65
|
export class PathManager
|
|
@@ -291,6 +299,7 @@ export class PathManager
|
|
|
291
299
|
enablePathsBySystem(system, enable, force=false)
|
|
292
300
|
//==============================================
|
|
293
301
|
{
|
|
302
|
+
let changed = false;
|
|
294
303
|
for (const pathId of system.pathIds) {
|
|
295
304
|
const path = this.__paths[pathId];
|
|
296
305
|
if (this.__pathtypeEnabled[path.pathType]
|
|
@@ -303,6 +312,7 @@ export class PathManager
|
|
|
303
312
|
for (const featureId of featureIds) {
|
|
304
313
|
this.__ui.enableFeature(featureId, enable, force);
|
|
305
314
|
}
|
|
315
|
+
changed = true
|
|
306
316
|
}
|
|
307
317
|
path.systemCount += (enable ? 1 : -1);
|
|
308
318
|
if (path.systemCount < 0) {
|
|
@@ -310,6 +320,9 @@ export class PathManager
|
|
|
310
320
|
}
|
|
311
321
|
// TODO? Show connectors and parent components of these paths??
|
|
312
322
|
}
|
|
323
|
+
if (changed) {
|
|
324
|
+
this.#notifyWatchers()
|
|
325
|
+
}
|
|
313
326
|
}
|
|
314
327
|
|
|
315
328
|
enablePathsByType(pathType, enable, force=false)
|
|
@@ -322,9 +335,16 @@ export class PathManager
|
|
|
322
335
|
this.__ui.enableFeature(featureId, enable, force);
|
|
323
336
|
}
|
|
324
337
|
this.__pathtypeEnabled[pathType] = enable;
|
|
338
|
+
this.#notifyWatchers()
|
|
325
339
|
}
|
|
326
340
|
}
|
|
327
341
|
|
|
342
|
+
pathTypeEnabled(pathType)
|
|
343
|
+
//=======================
|
|
344
|
+
{
|
|
345
|
+
return this.__pathtypeEnabled[pathType] || false
|
|
346
|
+
}
|
|
347
|
+
|
|
328
348
|
nodePathModels(nodeId)
|
|
329
349
|
//====================
|
|
330
350
|
{
|
|
@@ -352,6 +372,31 @@ export class PathManager
|
|
|
352
372
|
}
|
|
353
373
|
return nodeIds;
|
|
354
374
|
}
|
|
375
|
+
|
|
376
|
+
#lastWatcherId = 0
|
|
377
|
+
#watcherCallbacks = new Map()
|
|
378
|
+
|
|
379
|
+
addWatcher(callback)
|
|
380
|
+
//==================
|
|
381
|
+
{
|
|
382
|
+
this.#lastWatcherId += 1
|
|
383
|
+
this.#watcherCallbacks.set(this.#lastWatcherId, callback)
|
|
384
|
+
return this.#lastWatcherId
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
removeWatcher(watcherId)
|
|
388
|
+
//======================
|
|
389
|
+
{
|
|
390
|
+
this.#watcherCallbacks.delete(watcherId)
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
#notifyWatchers()
|
|
394
|
+
//===============
|
|
395
|
+
{
|
|
396
|
+
for (const callback of this.#watcherCallbacks.values()) {
|
|
397
|
+
callback()
|
|
398
|
+
}
|
|
399
|
+
}
|
|
355
400
|
}
|
|
356
401
|
|
|
357
402
|
//==============================================================================
|