@abi-software/flatmap-viewer 2.2.7 → 2.3.0-a.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.
- package/README.rst +1 -1
- package/package.json +1 -1
- package/src/controls.js +7 -7
- package/src/flatmap-viewer.js +16 -11
- package/src/info.js +0 -7
- package/src/interactions.js +80 -65
- package/src/pathways.js +35 -13
- package/src/styling.js +11 -6
- package/static/flatmap-viewer.css +6 -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.2.
|
|
41
|
+
* ``npm install @abi-software/flatmap-viewer@2.2.8``
|
|
42
42
|
|
|
43
43
|
Documentation
|
|
44
44
|
-------------
|
package/package.json
CHANGED
package/src/controls.js
CHANGED
|
@@ -22,7 +22,6 @@ limitations under the License.
|
|
|
22
22
|
|
|
23
23
|
//==============================================================================
|
|
24
24
|
|
|
25
|
-
import * as pathways from './pathways.js';
|
|
26
25
|
|
|
27
26
|
//==============================================================================
|
|
28
27
|
|
|
@@ -77,10 +76,11 @@ export class NavigationControl
|
|
|
77
76
|
|
|
78
77
|
export class PathControl
|
|
79
78
|
{
|
|
80
|
-
constructor(flatmap)
|
|
79
|
+
constructor(flatmap, pathways)
|
|
81
80
|
{
|
|
82
81
|
this._flatmap = flatmap;
|
|
83
82
|
this._map = undefined;
|
|
83
|
+
this.__pathTypes = pathways.pathTypes;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
getDefaultPosition()
|
|
@@ -103,11 +103,11 @@ export class PathControl
|
|
|
103
103
|
|
|
104
104
|
const innerHTML = [];
|
|
105
105
|
innerHTML.push(`<label for="path-all-paths">ALL PATHS:</label><input id="path-all-paths" type="checkbox" checked/><div class="nerve-line"></div>`);
|
|
106
|
-
for (const path of
|
|
106
|
+
for (const path of this.__pathTypes) {
|
|
107
107
|
innerHTML.push(`<label for="path-${path.type}">${path.label}</label><input id="path-${path.type}" type="checkbox" checked/><div class="nerve-line nerve-${path.type}"></div>`);
|
|
108
108
|
}
|
|
109
109
|
this._legend.innerHTML = innerHTML.join('\n');
|
|
110
|
-
this.__checkedCount =
|
|
110
|
+
this.__checkedCount = this.__pathTypes.length;
|
|
111
111
|
this.__halfCount = Math.trunc(this.__checkedCount/2);
|
|
112
112
|
|
|
113
113
|
this._button = document.createElement('button');
|
|
@@ -150,11 +150,11 @@ export class PathControl
|
|
|
150
150
|
event.target.indeterminate = false;
|
|
151
151
|
}
|
|
152
152
|
if (event.target.checked) {
|
|
153
|
-
this.__checkedCount =
|
|
153
|
+
this.__checkedCount = this.__pathTypes.length;
|
|
154
154
|
} else {
|
|
155
155
|
this.__checkedCount = 0;
|
|
156
156
|
}
|
|
157
|
-
for (const path of
|
|
157
|
+
for (const path of this.__pathTypes) {
|
|
158
158
|
const pathCheckbox = document.getElementById(`path-${path.type}`);
|
|
159
159
|
if (pathCheckbox) {
|
|
160
160
|
pathCheckbox.checked = event.target.checked;
|
|
@@ -173,7 +173,7 @@ export class PathControl
|
|
|
173
173
|
if (this.__checkedCount === 0) {
|
|
174
174
|
allPathsCheckbox.checked = false;
|
|
175
175
|
allPathsCheckbox.indeterminate = false;
|
|
176
|
-
} else if (this.__checkedCount ===
|
|
176
|
+
} else if (this.__checkedCount === this.__pathTypes.length) {
|
|
177
177
|
allPathsCheckbox.checked = true;
|
|
178
178
|
allPathsCheckbox.indeterminate = false;
|
|
179
179
|
} else {
|
package/src/flatmap-viewer.js
CHANGED
|
@@ -58,7 +58,8 @@ class FlatMap
|
|
|
58
58
|
constructor(container, mapBaseUrl, mapDescription, resolve)
|
|
59
59
|
{
|
|
60
60
|
this._baseUrl = mapBaseUrl;
|
|
61
|
-
this.
|
|
61
|
+
this.__id = mapDescription.id;
|
|
62
|
+
this.__uuid = mapDescription.uuid;
|
|
62
63
|
this._details = mapDescription.details;
|
|
63
64
|
this._created = mapDescription.created;
|
|
64
65
|
this.__taxon = mapDescription.taxon;
|
|
@@ -75,7 +76,7 @@ class FlatMap
|
|
|
75
76
|
this.__idToAnnotation = new Map();
|
|
76
77
|
this.__datasetToFeatureIds = new Map();
|
|
77
78
|
this.__modelToFeatureIds = new Map();
|
|
78
|
-
this.
|
|
79
|
+
this.__mapSourceToFeatureIds = new Map();
|
|
79
80
|
for (const [featureId, annotation] of Object.entries(mapDescription.annotations)) {
|
|
80
81
|
this.__addAnnotation(featureId, annotation);
|
|
81
82
|
this.__searchIndex.indexMetadata(featureId, annotation);
|
|
@@ -280,7 +281,9 @@ class FlatMap
|
|
|
280
281
|
pathTypes()
|
|
281
282
|
//=========
|
|
282
283
|
{
|
|
283
|
-
|
|
284
|
+
if (this._userInteractions !== null) {
|
|
285
|
+
return this._userInteractions.pathTypes();
|
|
286
|
+
}
|
|
284
287
|
}
|
|
285
288
|
|
|
286
289
|
/**
|
|
@@ -354,7 +357,7 @@ class FlatMap
|
|
|
354
357
|
//==============
|
|
355
358
|
{
|
|
356
359
|
if (url.startsWith('/')) {
|
|
357
|
-
return `${this._baseUrl}flatmap/${this.
|
|
360
|
+
return `${this._baseUrl}flatmap/${this.__uuid}${url}`; // We don't want embedded `{` and `}` characters escaped
|
|
358
361
|
} else if (!url.startsWith('http://') && !url.startsWith('https://')) {
|
|
359
362
|
console.log(`Invalid URL (${url}) in map's sources`);
|
|
360
363
|
}
|
|
@@ -402,7 +405,7 @@ class FlatMap
|
|
|
402
405
|
get id()
|
|
403
406
|
//======
|
|
404
407
|
{
|
|
405
|
-
return this.
|
|
408
|
+
return this.__uuid;
|
|
406
409
|
}
|
|
407
410
|
|
|
408
411
|
/**
|
|
@@ -424,7 +427,7 @@ class FlatMap
|
|
|
424
427
|
get uniqueId()
|
|
425
428
|
//============
|
|
426
429
|
{
|
|
427
|
-
return `${this.
|
|
430
|
+
return `${this.__uuid}-${this._mapNumber}`;
|
|
428
431
|
}
|
|
429
432
|
|
|
430
433
|
get activeLayerNames()
|
|
@@ -466,7 +469,7 @@ class FlatMap
|
|
|
466
469
|
this.__idToAnnotation.set(featureId, ann);
|
|
467
470
|
this.__updateFeatureIdMap('dataset', this.__datasetToFeatureIds, ann);
|
|
468
471
|
this.__updateFeatureIdMap('models', this.__modelToFeatureIds, ann);
|
|
469
|
-
this.__updateFeatureIdMap('source', this.
|
|
472
|
+
this.__updateFeatureIdMap('source', this.__mapSourceToFeatureIds, ann);
|
|
470
473
|
}
|
|
471
474
|
|
|
472
475
|
modelFeatureIds(anatomicalId)
|
|
@@ -490,7 +493,7 @@ class FlatMap
|
|
|
490
493
|
if (featureIds.length == 0) {
|
|
491
494
|
// We couldn't find a feature by anatomical id, so check dataset and source
|
|
492
495
|
featureIds.extend(this.__datasetToFeatureIds.get(anatomicalIds));
|
|
493
|
-
featureIds.extend(this.
|
|
496
|
+
featureIds.extend(this.__mapSourceToFeatureIds.get(anatomicalIds));
|
|
494
497
|
}
|
|
495
498
|
if (featureIds.length == 0 && this._userInteractions !== null) {
|
|
496
499
|
// We still haven't found a feature, so check connectivity
|
|
@@ -634,7 +637,7 @@ class FlatMap
|
|
|
634
637
|
return {
|
|
635
638
|
taxon: this.__taxon,
|
|
636
639
|
biologicalSex: this.__biologicalSex,
|
|
637
|
-
|
|
640
|
+
uuid: this.__uuid
|
|
638
641
|
};
|
|
639
642
|
}
|
|
640
643
|
|
|
@@ -1086,7 +1089,8 @@ export class MapManager
|
|
|
1086
1089
|
latestMap_(identifier)
|
|
1087
1090
|
//====================
|
|
1088
1091
|
{
|
|
1089
|
-
const mapDescribes = (
|
|
1092
|
+
const mapDescribes = (identifier.constructor.name === "String") ? identifier
|
|
1093
|
+
: ('uuid' in identifier) ? identifier.uuid
|
|
1090
1094
|
: ('taxon' in identifier) ? identifier.taxon
|
|
1091
1095
|
: null;
|
|
1092
1096
|
if (mapDescribes === null) {
|
|
@@ -1300,7 +1304,8 @@ export class MapManager
|
|
|
1300
1304
|
this._mapNumber += 1;
|
|
1301
1305
|
const flatmap = new FlatMap(container, this._mapServer.url(),
|
|
1302
1306
|
{
|
|
1303
|
-
id:
|
|
1307
|
+
id: map,
|
|
1308
|
+
uuid: mapId,
|
|
1304
1309
|
details: mapIndex,
|
|
1305
1310
|
taxon: map.taxon,
|
|
1306
1311
|
biologicalSex: map.biologicalSex,
|
package/src/info.js
CHANGED
|
@@ -247,13 +247,6 @@ export class InfoControl
|
|
|
247
247
|
}
|
|
248
248
|
|
|
249
249
|
const htmlList = [];
|
|
250
|
-
|
|
251
|
-
if (this._flatmap.options.showPosition) {
|
|
252
|
-
const position = location;
|
|
253
|
-
htmlList.push(`<span class="info-name">Position:</span>`);
|
|
254
|
-
htmlList.push(`<span class="info-value">(${position.lng}, ${position.lat})</span>`);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
250
|
for (const values of displayValues.values()) {
|
|
258
251
|
for (const prop of displayedProperties) {
|
|
259
252
|
if (prop in values) {
|
package/src/interactions.js
CHANGED
|
@@ -151,8 +151,7 @@ export class UserInteractions
|
|
|
151
151
|
|
|
152
152
|
if (flatmap.options.pathControls) {
|
|
153
153
|
// Add controls to manage our pathways
|
|
154
|
-
|
|
155
|
-
this._map.addControl(new PathControl(flatmap));
|
|
154
|
+
this._map.addControl(new PathControl(flatmap, this._pathways));
|
|
156
155
|
}
|
|
157
156
|
|
|
158
157
|
// Manage our layers
|
|
@@ -164,10 +163,8 @@ export class UserInteractions
|
|
|
164
163
|
|
|
165
164
|
for (const [id, ann] of flatmap.annotations) {
|
|
166
165
|
const feature = this.mapFeature_(id);
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
this._map.setFeatureState(feature, { 'annotation-error': true });
|
|
170
|
-
console.log(`Annotation error, ${ann.layer}: ${ann.error} (${ann.text})`);
|
|
166
|
+
if (feature !== undefined) {
|
|
167
|
+
this._map.setFeatureState(feature, { 'annotated': true });
|
|
171
168
|
}
|
|
172
169
|
}
|
|
173
170
|
|
|
@@ -251,13 +248,15 @@ export class UserInteractions
|
|
|
251
248
|
//====================
|
|
252
249
|
{
|
|
253
250
|
const ann = this._flatmap.annotation(featureId);
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
251
|
+
if (ann !== undefined) {
|
|
252
|
+
return {
|
|
253
|
+
id: featureId,
|
|
254
|
+
source: VECTOR_TILES_SOURCE,
|
|
255
|
+
sourceLayer: this._flatmap.options.separateLayers
|
|
256
|
+
? `${ann['layer']}_${ann['tile-layer']}`
|
|
257
|
+
: ann['tile-layer']
|
|
258
|
+
};
|
|
259
|
+
}
|
|
261
260
|
}
|
|
262
261
|
|
|
263
262
|
featureSelected_(featureId)
|
|
@@ -277,8 +276,10 @@ export class UserInteractions
|
|
|
277
276
|
this._selectedFeatureIds.set(featureId, this._selectedFeatureIds.get(featureId) + 1);
|
|
278
277
|
} else {
|
|
279
278
|
const feature = this.mapFeature_(featureId);
|
|
280
|
-
|
|
281
|
-
|
|
279
|
+
if (feature !== undefined) {
|
|
280
|
+
this._map.setFeatureState(feature, { 'selected': true });
|
|
281
|
+
this._selectedFeatureIds.set(featureId, 1);
|
|
282
|
+
}
|
|
282
283
|
}
|
|
283
284
|
}
|
|
284
285
|
|
|
@@ -292,8 +293,10 @@ export class UserInteractions
|
|
|
292
293
|
this._selectedFeatureIds.set(featureId, references - 1);
|
|
293
294
|
} else {
|
|
294
295
|
const feature = this.mapFeature_(featureId);
|
|
295
|
-
|
|
296
|
-
|
|
296
|
+
if (feature !== undefined) {
|
|
297
|
+
this._map.removeFeatureState(feature, 'selected');
|
|
298
|
+
this._selectedFeatureIds.delete(+featureId);
|
|
299
|
+
}
|
|
297
300
|
}
|
|
298
301
|
}
|
|
299
302
|
if (this._selectedFeatureIds.size === 0) {
|
|
@@ -306,7 +309,9 @@ export class UserInteractions
|
|
|
306
309
|
{
|
|
307
310
|
for (const featureId of this._selectedFeatureIds.keys()) {
|
|
308
311
|
const feature = this.mapFeature_(featureId);
|
|
309
|
-
|
|
312
|
+
if (feature !== undefined) {
|
|
313
|
+
this._map.removeFeatureState(feature, 'selected');
|
|
314
|
+
}
|
|
310
315
|
}
|
|
311
316
|
this._selectedFeatureIds.clear();
|
|
312
317
|
this._layerManager.setColour({...this.__colourOptions, dimmed: false});
|
|
@@ -318,7 +323,8 @@ export class UserInteractions
|
|
|
318
323
|
// Get the features covering the event's point that are in the active layers
|
|
319
324
|
|
|
320
325
|
return this._map.queryRenderedFeatures(event.point).filter(f => {
|
|
321
|
-
return (this.
|
|
326
|
+
return (this.__enabledFeature(f)
|
|
327
|
+
&& this.activeLayerNames.indexOf(f.sourceLayer) >= 0)
|
|
322
328
|
&& ('featureId' in f.properties);
|
|
323
329
|
}
|
|
324
330
|
);
|
|
@@ -327,8 +333,10 @@ export class UserInteractions
|
|
|
327
333
|
__activateFeature(feature)
|
|
328
334
|
//=======================
|
|
329
335
|
{
|
|
330
|
-
|
|
331
|
-
|
|
336
|
+
if (feature !== undefined) {
|
|
337
|
+
this._map.setFeatureState(feature, { active: true });
|
|
338
|
+
this._activeFeatures.push(feature);
|
|
339
|
+
}
|
|
332
340
|
}
|
|
333
341
|
|
|
334
342
|
resetActiveFeatures_()
|
|
@@ -617,17 +625,14 @@ export class UserInteractions
|
|
|
617
625
|
const tooltips = [];
|
|
618
626
|
for (const lineFeature of lineFeatures) {
|
|
619
627
|
const properties = lineFeature.properties;
|
|
620
|
-
if (
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
if (!tooltips.includes(cleanLabel)) {
|
|
629
|
-
tooltips.push(cleanLabel);
|
|
630
|
-
}
|
|
628
|
+
if ('label' in properties
|
|
629
|
+
&& (!('tooltip' in properties) || properties.tooltip)
|
|
630
|
+
&& !('labelled' in properties)) {
|
|
631
|
+
let tooltip = '';
|
|
632
|
+
const label = properties.label;
|
|
633
|
+
const cleanLabel = (label.substr(0, 1).toUpperCase() + label.substr(1)).replaceAll("\n", "<br/>");
|
|
634
|
+
if (!tooltips.includes(cleanLabel)) {
|
|
635
|
+
tooltips.push(cleanLabel);
|
|
631
636
|
}
|
|
632
637
|
}
|
|
633
638
|
}
|
|
@@ -662,13 +667,11 @@ export class UserInteractions
|
|
|
662
667
|
__featureEvent(type, feature)
|
|
663
668
|
//===========================
|
|
664
669
|
{
|
|
665
|
-
if (
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
return this._flatmap.featureEvent(type, feature.properties);
|
|
671
|
-
}
|
|
670
|
+
if (feature.sourceLayer === PATHWAYS_LAYER) { // I suspect this is never true as source layer
|
|
671
|
+
// names are like `neural_routes_pathways`
|
|
672
|
+
return this._flatmap.featureEvent(type, this._pathways.pathProperties(feature));
|
|
673
|
+
} else if ('properties' in feature) {
|
|
674
|
+
return this._flatmap.featureEvent(type, feature.properties);
|
|
672
675
|
}
|
|
673
676
|
return false;
|
|
674
677
|
}
|
|
@@ -704,7 +707,8 @@ export class UserInteractions
|
|
|
704
707
|
}
|
|
705
708
|
|
|
706
709
|
// Get all the features at the current point
|
|
707
|
-
const features = this._map.queryRenderedFeatures(event.point)
|
|
710
|
+
const features = this._map.queryRenderedFeatures(event.point)
|
|
711
|
+
.filter(feature => this.__enabledFeature(feature));
|
|
708
712
|
if (features.length === 0) {
|
|
709
713
|
this._lastFeatureMouseEntered = null;
|
|
710
714
|
this._lastFeatureModelsMouse = null;
|
|
@@ -742,17 +746,13 @@ export class UserInteractions
|
|
|
742
746
|
&& feature.properties.type.startsWith('line')) ));
|
|
743
747
|
if (lineFeatures.length > 0) {
|
|
744
748
|
tooltip = this.lineTooltip_(lineFeatures);
|
|
745
|
-
const
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
for (const featureId of this._pathways.lineFeatureIds(lineIds)) {
|
|
753
|
-
if (+featureId !== lineFeatureId) {
|
|
754
|
-
this.__activateFeature(this.mapFeature_(featureId));
|
|
755
|
-
}
|
|
749
|
+
for (const lineFeature of lineFeatures) {
|
|
750
|
+
const lineFeatureId = +lineFeature.properties.featureId; // Ensure numeric
|
|
751
|
+
this.__activateFeature(lineFeature);
|
|
752
|
+
const lineIds = new Set(lineFeatures.map(f => f.properties.featureId));
|
|
753
|
+
for (const featureId of this._pathways.lineFeatureIds(lineIds)) {
|
|
754
|
+
if (+featureId !== lineFeatureId) {
|
|
755
|
+
this.__activateFeature(this.mapFeature_(featureId));
|
|
756
756
|
}
|
|
757
757
|
}
|
|
758
758
|
}
|
|
@@ -874,7 +874,12 @@ export class UserInteractions
|
|
|
874
874
|
//================
|
|
875
875
|
{
|
|
876
876
|
this.clearActiveMarker_();
|
|
877
|
-
const
|
|
877
|
+
const clickedFeatures = this._map.queryRenderedFeatures(event.point)
|
|
878
|
+
.filter(feature => this.__enabledFeature(feature));
|
|
879
|
+
if (clickedFeatures.length == 0){
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
const clickedFeature = clickedFeatures[0];
|
|
878
883
|
const originalEvent = event.originalEvent;
|
|
879
884
|
if (clickedFeature === undefined || this._activeFeatures.length === 1) {
|
|
880
885
|
this.selectionEvent_(originalEvent, clickedFeature);
|
|
@@ -920,7 +925,8 @@ export class UserInteractions
|
|
|
920
925
|
//=======================
|
|
921
926
|
{
|
|
922
927
|
const state = this._map.getFeatureState(feature);
|
|
923
|
-
return
|
|
928
|
+
return (state !== undefined
|
|
929
|
+
&& (!('hidden' in state) || !state.hidden));
|
|
924
930
|
}
|
|
925
931
|
|
|
926
932
|
enablePaths_(enable, event)
|
|
@@ -937,11 +943,13 @@ export class UserInteractions
|
|
|
937
943
|
{
|
|
938
944
|
for (const featureId of featureIds) {
|
|
939
945
|
const feature = this.mapFeature_(featureId);
|
|
940
|
-
if (
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
946
|
+
if (feature !== undefined) {
|
|
947
|
+
if (enable) {
|
|
948
|
+
this._map.removeFeatureState(feature, 'hidden');
|
|
949
|
+
} else {
|
|
950
|
+
this._map.setFeatureState(feature, { 'hidden': true });
|
|
951
|
+
this._disabledPathFeatures = true;
|
|
952
|
+
}
|
|
945
953
|
}
|
|
946
954
|
}
|
|
947
955
|
}
|
|
@@ -957,6 +965,12 @@ export class UserInteractions
|
|
|
957
965
|
}
|
|
958
966
|
}
|
|
959
967
|
|
|
968
|
+
pathTypes()
|
|
969
|
+
//=========
|
|
970
|
+
{
|
|
971
|
+
return this._pathways.pathTypes;
|
|
972
|
+
}
|
|
973
|
+
|
|
960
974
|
enablePath(pathType, enable=true)
|
|
961
975
|
//===============================
|
|
962
976
|
{
|
|
@@ -1149,14 +1163,15 @@ export class UserInteractions
|
|
|
1149
1163
|
const annotation = this.__annotationByMarkerId.get(markerId);
|
|
1150
1164
|
// The marker's feature
|
|
1151
1165
|
const feature = this.mapFeature_(annotation.featureId);
|
|
1152
|
-
if (
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1166
|
+
if (feature !== undefined) {
|
|
1167
|
+
if (event.type === 'mouseenter') {
|
|
1168
|
+
// Highlight on mouse enter
|
|
1169
|
+
this.resetActiveFeatures_();
|
|
1170
|
+
this.__activateFeature(feature);
|
|
1171
|
+
} else {
|
|
1172
|
+
this.selectionEvent_(event, feature)
|
|
1173
|
+
}
|
|
1158
1174
|
}
|
|
1159
|
-
|
|
1160
1175
|
// Show tooltip
|
|
1161
1176
|
const html = this.tooltipHtml_(annotation, true);
|
|
1162
1177
|
this.__showToolTip(html, marker.getLngLat());
|
package/src/pathways.js
CHANGED
|
@@ -26,16 +26,18 @@ export const PATHWAYS_LAYER = 'pathways';
|
|
|
26
26
|
|
|
27
27
|
//==============================================================================
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
29
|
+
const PATH_TYPES = {
|
|
30
|
+
"cns": {label: "CNS", colour: "#9B1FC1"},
|
|
31
|
+
"lcn": {label: "Local circuit neuron", colour: "#F19E38"},
|
|
32
|
+
"para-pre": {label: "Parasympathetic pre-ganglionic", colour: "#3F8F4A"},
|
|
33
|
+
"para-post": {label: "Parasympathetic post-ganglionic", colour: "#3F8F4A"},
|
|
34
|
+
"sensory": {label: "Sensory (afferent) neuron", colour: "#2A62F6"},
|
|
35
|
+
"somatic": {label: "Somatic lower motor", colour: "#98561D"},
|
|
36
|
+
"symp-pre": {label: "Sympathetic pre-ganglionic", colour: "#EA3423"},
|
|
37
|
+
"symp-post": {label: "Sympathetic post-ganglionic", colour: "#EA3423"},
|
|
38
|
+
"other": {label: "Other neuron type", colour: "#888"},
|
|
39
|
+
"centreline": {label: "Nerve centrelines", colour: "#CC0"}
|
|
40
|
+
};
|
|
39
41
|
|
|
40
42
|
//==============================================================================
|
|
41
43
|
|
|
@@ -120,7 +122,27 @@ export class Pathways
|
|
|
120
122
|
}
|
|
121
123
|
this._allFeatureIds = featureIds;
|
|
122
124
|
|
|
123
|
-
|
|
125
|
+
// Map unknown path types to ``other``
|
|
126
|
+
this.__typePaths = {};
|
|
127
|
+
this.__typePaths['other'] = [];
|
|
128
|
+
this.__knownPathTypes = [];
|
|
129
|
+
for (const [pathType, paths] of Object.entries(flatmap.pathways['type-paths'])) {
|
|
130
|
+
if (pathType in PATH_TYPES && pathType !== 'other') {
|
|
131
|
+
this.__typePaths[pathType] = paths;
|
|
132
|
+
this.__knownPathTypes.push({'type': pathType, ...PATH_TYPES[pathType]});
|
|
133
|
+
} else {
|
|
134
|
+
this.__typePaths['other'].push(...paths);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if ('other' in this.__typePaths) {
|
|
138
|
+
this.__knownPathTypes.push({'type': 'other', ...PATH_TYPES['other']});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
get pathTypes()
|
|
143
|
+
//=============
|
|
144
|
+
{
|
|
145
|
+
return this.__knownPathTypes;
|
|
124
146
|
}
|
|
125
147
|
|
|
126
148
|
addPathsToFeatureSet_(paths, featureSet)
|
|
@@ -253,8 +275,8 @@ export class Pathways
|
|
|
253
275
|
//======================
|
|
254
276
|
{
|
|
255
277
|
const featureIds = new Set();
|
|
256
|
-
if (pathType in this.
|
|
257
|
-
this.addPathsToFeatureSet_(this.
|
|
278
|
+
if (pathType in this.__typePaths) {
|
|
279
|
+
this.addPathsToFeatureSet_(this.__typePaths[pathType], featureIds);
|
|
258
280
|
}
|
|
259
281
|
return featureIds;
|
|
260
282
|
}
|
package/src/styling.js
CHANGED
|
@@ -346,7 +346,8 @@ export class PathLineLayer extends VectorStyleLayer
|
|
|
346
346
|
[
|
|
347
347
|
'any',
|
|
348
348
|
['==', 'type', 'bezier'],
|
|
349
|
-
['==', '
|
|
349
|
+
['==', 'kind', 'centreline'],
|
|
350
|
+
['==', 'type', 'line']
|
|
350
351
|
];
|
|
351
352
|
this.__dashed = dashed;
|
|
352
353
|
}
|
|
@@ -369,22 +370,25 @@ export class PathLineLayer extends VectorStyleLayer
|
|
|
369
370
|
['==', ['get', 'kind'], 'sensory'], '#2A62F6',
|
|
370
371
|
['==', ['get', 'kind'], 'symp-post'], '#EA3423',
|
|
371
372
|
['==', ['get', 'kind'], 'symp-pre'], '#EA3423',
|
|
373
|
+
['==', ['get', 'kind'], 'centreline'], '#CC0',
|
|
372
374
|
'#888'
|
|
373
375
|
],
|
|
374
376
|
'line-opacity': [
|
|
375
377
|
'case',
|
|
378
|
+
['boolean', ['feature-state', 'hidden'], false], 0.1,
|
|
376
379
|
['==', ['get', 'type'], 'bezier'], 1.0,
|
|
377
380
|
['boolean', ['get', 'invisible'], false], 0.001,
|
|
378
381
|
['boolean', ['feature-state', 'selected'], false], 1.0,
|
|
379
382
|
['boolean', ['feature-state', 'active'], false], 0.8,
|
|
380
|
-
['
|
|
381
|
-
dimmed ? 0.1 : 0.
|
|
383
|
+
['==', ['get', 'kind'], 'centreline'], 0.2,
|
|
384
|
+
dimmed ? 0.1 : 0.5
|
|
382
385
|
],
|
|
383
386
|
'line-width': [
|
|
384
387
|
'let',
|
|
385
388
|
'width', [
|
|
386
389
|
'case',
|
|
387
390
|
['==', ['get', 'type'], 'bezier'], 0.1,
|
|
391
|
+
['==', ['get', 'kind'], 'centreline'], 2,
|
|
388
392
|
['==', ['get', 'kind'], 'error'], 1,
|
|
389
393
|
['==', ['get', 'kind'], 'unknown'], 1,
|
|
390
394
|
['boolean', ['get', 'invisible'], false], 0.1,
|
|
@@ -452,22 +456,23 @@ export class FeatureNerveLayer extends VectorStyleLayer
|
|
|
452
456
|
'filter': [
|
|
453
457
|
'all',
|
|
454
458
|
['==', '$type', 'LineString'],
|
|
459
|
+
['!=', 'kind', 'centreline'],
|
|
455
460
|
['==', 'type', 'nerve']
|
|
456
461
|
],
|
|
457
462
|
'paint': {
|
|
458
463
|
'line-color': [
|
|
459
464
|
'case',
|
|
465
|
+
['boolean', ['feature-state', 'hidden'], false], '#CCC',
|
|
460
466
|
['boolean', ['feature-state', 'active'], false], '#222',
|
|
461
467
|
['boolean', ['feature-state', 'selected'], false], 'red',
|
|
462
|
-
['boolean', ['feature-state', 'hidden'], false], '#CCC',
|
|
463
468
|
'#888'
|
|
464
469
|
],
|
|
465
470
|
'line-opacity': [
|
|
466
471
|
'case',
|
|
467
|
-
['boolean', ['feature-state', 'active'], false], 0.9,
|
|
468
|
-
['boolean', ['feature-state', 'selected'], false], 0.9,
|
|
469
472
|
['boolean', ['feature-state', 'hidden'], false], 0.3,
|
|
470
473
|
['boolean', ['get', 'invisible'], false], 0.001,
|
|
474
|
+
['boolean', ['feature-state', 'active'], false], 0.9,
|
|
475
|
+
['boolean', ['feature-state', 'selected'], false], 0.9,
|
|
471
476
|
0.9
|
|
472
477
|
],
|
|
473
478
|
'line-dasharray': [2, 1],
|
|
@@ -198,12 +198,18 @@ li.flatmap-contextmenu-item:hover {
|
|
|
198
198
|
label[for=path-all-paths] {
|
|
199
199
|
font-weight: bold;
|
|
200
200
|
}
|
|
201
|
+
.nerve-centreline {
|
|
202
|
+
background: #CC0;
|
|
203
|
+
}
|
|
201
204
|
.nerve-cns {
|
|
202
205
|
background: #9B1FC1;
|
|
203
206
|
}
|
|
204
207
|
.nerve-lcn {
|
|
205
208
|
background: #F19E38;
|
|
206
209
|
}
|
|
210
|
+
.nerve-other {
|
|
211
|
+
background: #888;
|
|
212
|
+
}
|
|
207
213
|
.nerve-para-pre {
|
|
208
214
|
background: #3F8F4A;
|
|
209
215
|
}
|