@abi-software/flatmap-viewer 2.3.0-b.2 → 2.3.1-b.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/annotation.js +123 -8
- package/src/flatmap-viewer.js +0 -14
- package/src/interactions.js +51 -85
- package/src/pathways.js +2 -2
- package/src/styling.js +10 -6
- package/src/systems.js +7 -1
- package/static/css/flatmap-viewer.css +12 -0
- package/src/controls/newcontrols.js +0 -617
- package/src/editor.js +0 -198
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.3.
|
|
41
|
+
* ``npm install @abi-software/flatmap-viewer@2.3.1-b.1``
|
|
42
42
|
|
|
43
43
|
Documentation
|
|
44
44
|
-------------
|
package/package.json
CHANGED
package/src/annotation.js
CHANGED
|
@@ -82,9 +82,10 @@ function stopSpinner(panel)
|
|
|
82
82
|
|
|
83
83
|
export class Annotator
|
|
84
84
|
{
|
|
85
|
-
constructor(flatmap)
|
|
85
|
+
constructor(flatmap, ui)
|
|
86
86
|
{
|
|
87
87
|
this.__flatmap = flatmap;
|
|
88
|
+
this.__ui = ui;
|
|
88
89
|
this.__haveAnnotation = false;
|
|
89
90
|
this.__user = undefined;
|
|
90
91
|
this.__savedStatusMessage = '';
|
|
@@ -444,20 +445,134 @@ export class Annotator
|
|
|
444
445
|
});
|
|
445
446
|
}
|
|
446
447
|
|
|
447
|
-
|
|
448
|
-
|
|
448
|
+
__chooseFeatureProperties(features, callback)
|
|
449
|
+
//===========================================
|
|
449
450
|
{
|
|
450
|
-
this.
|
|
451
|
+
this.__ui.selectFeature(features[0].id);
|
|
452
|
+
|
|
453
|
+
// Feature chooser is only for multiple selections
|
|
454
|
+
if (features.length === 1
|
|
455
|
+
|| features[0].properties['cd-class'] !== 'celldl:Connection'
|
|
456
|
+
|| (features.length === 2
|
|
457
|
+
&& features[1].properties['cd-class'] !== 'celldl:Connection')) {
|
|
458
|
+
callback(features[0].properties);
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
const featureList = [];
|
|
462
|
+
const featureProperties = new Map();
|
|
463
|
+
const featureSeen = new Set();
|
|
464
|
+
let selected = 'selected'; // Select the first entry
|
|
465
|
+
for (const feature of features) {
|
|
466
|
+
if (feature.properties['cd-class'] !== 'celldl:Connection'
|
|
467
|
+
|| feature.properties['id'] == undefined
|
|
468
|
+
|| featureSeen.has(feature.properties['id'])) {
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
const mapFeature = this.__ui.mapFeature(feature.id);
|
|
472
|
+
const annotated = (mapFeature !== undefined)
|
|
473
|
+
? this.__ui._map.getFeatureState(mapFeature)['annotated']
|
|
474
|
+
: false;
|
|
475
|
+
let label = '';
|
|
476
|
+
if (feature.properties.models) {
|
|
477
|
+
label = ` -- ${feature.properties.label.split('\n')[0]} (${feature.properties.models})`;
|
|
478
|
+
}
|
|
479
|
+
featureList.push(`<option value="${feature.id}" ${selected}>${annotated ? '*' : ' '} ${feature.properties.id} -- ${feature.properties.kind}${label}</option>`);
|
|
480
|
+
featureProperties.set(+feature.id, feature.properties);
|
|
481
|
+
featureSeen.add(feature.properties['id']);
|
|
482
|
+
selected = '';
|
|
483
|
+
}
|
|
484
|
+
if (featureList.length == 0) {
|
|
485
|
+
callback(undefined);
|
|
486
|
+
return;
|
|
487
|
+
} else if (featureList.length == 1) {
|
|
488
|
+
callback(featureProperties.values().next().value);
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
const panelContent = `
|
|
492
|
+
<div id="annotation-feature-selection">
|
|
493
|
+
<div>
|
|
494
|
+
<label for="annotation-feature-selector">Select feature:</label>
|
|
495
|
+
<select id="annotation-feature-selector" size="${Math.min(featureList.length, 7)}">
|
|
496
|
+
${featureList.join('\n')}
|
|
497
|
+
</select>
|
|
498
|
+
</div>
|
|
499
|
+
<div id="annotation-feature-buttons">
|
|
500
|
+
<input id="annotation-feature-cancel" type="button" value="Cancel"/>
|
|
501
|
+
<input id="annotation-feature-annotate" type="button" value="Annotate"/>
|
|
502
|
+
</div>
|
|
503
|
+
</div>`;
|
|
504
|
+
this.__panel = jsPanel.create({
|
|
505
|
+
theme: 'light',
|
|
506
|
+
border: '2px solid #080',
|
|
507
|
+
borderRadius: '.5rem',
|
|
508
|
+
panelSize: 'auto auto',
|
|
509
|
+
position: 'left-top',
|
|
510
|
+
content: panelContent,
|
|
511
|
+
data: features[0].properties,
|
|
512
|
+
closeOnEscape: true,
|
|
513
|
+
closeOnBackdrop: false,
|
|
514
|
+
headerTitle: 'Select feature to annotate',
|
|
515
|
+
headerControls: 'closeonly xs',
|
|
516
|
+
callback: ((panel) => {
|
|
517
|
+
const selector = document.getElementById('annotation-feature-selector');
|
|
518
|
+
selector.onchange = (e) => {
|
|
519
|
+
if (e.target.value !== '') {
|
|
520
|
+
this.__ui.unselectFeatures();
|
|
521
|
+
this.__ui.selectFeature(e.target.value);
|
|
522
|
+
this.__panel.options.data = featureProperties.get(+e.target.value);
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
selector.ondblclick = (e) => {
|
|
526
|
+
if (e.target.value !== '') {
|
|
527
|
+
const properties = this.__panel.options.data;
|
|
528
|
+
this.__panel.close();
|
|
529
|
+
callback(properties);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
selector.focus();
|
|
533
|
+
document.getElementById('annotation-feature-cancel')
|
|
534
|
+
.onclick = (e) => {
|
|
535
|
+
this.__panel.close();
|
|
536
|
+
callback(undefined);
|
|
537
|
+
};
|
|
538
|
+
document.getElementById('annotation-feature-annotate')
|
|
539
|
+
.onclick = (e) => {
|
|
540
|
+
const properties = this.__panel.options.data;
|
|
541
|
+
this.__panel.close();
|
|
542
|
+
callback(properties);
|
|
543
|
+
};
|
|
544
|
+
}).bind(this)
|
|
545
|
+
});
|
|
546
|
+
document.addEventListener('jspanelcloseduser', (e) => { callback(undefined) }, false);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
annotate(features, closedCallback)
|
|
550
|
+
//================================
|
|
551
|
+
{
|
|
552
|
+
// provide a list of features so dialog needs to first provide selection list
|
|
553
|
+
// and highlight current one as user scrolls...
|
|
451
554
|
|
|
555
|
+
this.__chooseFeatureProperties(features, (featureProperties) => {
|
|
556
|
+
if (featureProperties) {
|
|
557
|
+
this.__annotateFeature(featureProperties, closedCallback);
|
|
558
|
+
} else {
|
|
559
|
+
closedCallback();
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
__annotateFeature(featureProperties, callback)
|
|
565
|
+
//============================================
|
|
566
|
+
{
|
|
567
|
+
this.__currentFeatureId = featureProperties['id'];
|
|
452
568
|
if (this.__currentFeatureId === undefined) {
|
|
453
|
-
|
|
569
|
+
callback();
|
|
454
570
|
return;
|
|
455
571
|
}
|
|
456
|
-
|
|
457
572
|
const panelContent = [];
|
|
458
573
|
panelContent.push('<div id="flatmap-annotation-panel">');
|
|
459
574
|
panelContent.push(' <div id="flatmap-annotation-feature">');
|
|
460
|
-
panelContent.push(...this.__featureHtml(
|
|
575
|
+
panelContent.push(...this.__featureHtml(featureProperties));
|
|
461
576
|
panelContent.push(' </div>');
|
|
462
577
|
panelContent.push(' <form id="flatmap-annotation-form"></form>');
|
|
463
578
|
panelContent.push(' <div id="flatmap-annotation-existing"></div>');
|
|
@@ -517,7 +632,7 @@ export class Annotator
|
|
|
517
632
|
});
|
|
518
633
|
|
|
519
634
|
// should we warn if unsaved changes when closing??
|
|
520
|
-
document.addEventListener('jspanelclosed',
|
|
635
|
+
document.addEventListener('jspanelclosed', callback, false);
|
|
521
636
|
}
|
|
522
637
|
|
|
523
638
|
async annotated_features()
|
package/src/flatmap-viewer.js
CHANGED
|
@@ -260,20 +260,6 @@ class FlatMap
|
|
|
260
260
|
this._map.zoomOut();
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
-
/**
|
|
264
|
-
* Toggle the visibility of paths on the map.zoomIn
|
|
265
|
-
*
|
|
266
|
-
* * If some paths are hidden then all paths are made visible.
|
|
267
|
-
* * If all paths are visible then they are all hidden.
|
|
268
|
-
*/
|
|
269
|
-
togglePaths()
|
|
270
|
-
//===========
|
|
271
|
-
{
|
|
272
|
-
if (this._userInteractions !== null) {
|
|
273
|
-
this._userInteractions.togglePaths();
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
263
|
/**
|
|
278
264
|
* @returns {Array.<{type: string, label: string, colour: string}>} an array of objects giving the path types
|
|
279
265
|
* present in the map along with their
|
package/src/interactions.js
CHANGED
|
@@ -104,8 +104,6 @@ export class UserInteractions
|
|
|
104
104
|
this._infoControl = null;
|
|
105
105
|
this._tooltip = null;
|
|
106
106
|
|
|
107
|
-
this._disabledPathFeatures = false;
|
|
108
|
-
|
|
109
107
|
this._inQuery = false;
|
|
110
108
|
this._modal = false;
|
|
111
109
|
|
|
@@ -247,7 +245,7 @@ export class UserInteractions
|
|
|
247
245
|
{
|
|
248
246
|
// Add annotation capability
|
|
249
247
|
|
|
250
|
-
this.__annotator = new Annotator(this._flatmap);
|
|
248
|
+
this.__annotator = new Annotator(this._flatmap, this);
|
|
251
249
|
const annotated_features = await this.__annotator.annotated_features();
|
|
252
250
|
|
|
253
251
|
// Flag features that have annotations
|
|
@@ -357,6 +355,14 @@ export class UserInteractions
|
|
|
357
355
|
}
|
|
358
356
|
}
|
|
359
357
|
|
|
358
|
+
__featureEnabled(feature)
|
|
359
|
+
//=======================
|
|
360
|
+
{
|
|
361
|
+
const state = this._map.getFeatureState(feature);
|
|
362
|
+
return (state !== undefined
|
|
363
|
+
&& (!('hidden' in state) || !state.hidden));
|
|
364
|
+
}
|
|
365
|
+
|
|
360
366
|
mapFeature(featureId)
|
|
361
367
|
//===================
|
|
362
368
|
{
|
|
@@ -380,8 +386,8 @@ export class UserInteractions
|
|
|
380
386
|
return this._selectedFeatureIds.has(+featureId);
|
|
381
387
|
}
|
|
382
388
|
|
|
383
|
-
|
|
384
|
-
|
|
389
|
+
selectFeature(featureId, dim=true)
|
|
390
|
+
//================================
|
|
385
391
|
{
|
|
386
392
|
featureId = +featureId; // Ensure numeric
|
|
387
393
|
if (this._selectedFeatureIds.size === 0) {
|
|
@@ -398,8 +404,8 @@ export class UserInteractions
|
|
|
398
404
|
}
|
|
399
405
|
}
|
|
400
406
|
|
|
401
|
-
|
|
402
|
-
|
|
407
|
+
unselectFeature(featureId)
|
|
408
|
+
//========================
|
|
403
409
|
{
|
|
404
410
|
featureId = +featureId; // Ensure numeric
|
|
405
411
|
if (this._selectedFeatureIds.has(featureId)) {
|
|
@@ -419,8 +425,8 @@ export class UserInteractions
|
|
|
419
425
|
}
|
|
420
426
|
}
|
|
421
427
|
|
|
422
|
-
|
|
423
|
-
|
|
428
|
+
unselectFeatures()
|
|
429
|
+
//================
|
|
424
430
|
{
|
|
425
431
|
for (const featureId of this._selectedFeatureIds.keys()) {
|
|
426
432
|
const feature = this.mapFeature(featureId);
|
|
@@ -433,7 +439,7 @@ export class UserInteractions
|
|
|
433
439
|
}
|
|
434
440
|
|
|
435
441
|
__activateFeature(feature)
|
|
436
|
-
|
|
442
|
+
//========================
|
|
437
443
|
{
|
|
438
444
|
if (feature !== undefined) {
|
|
439
445
|
this._map.setFeatureState(feature, { active: true });
|
|
@@ -499,16 +505,15 @@ export class UserInteractions
|
|
|
499
505
|
//=====
|
|
500
506
|
{
|
|
501
507
|
this.__clearModal();
|
|
502
|
-
this.
|
|
503
|
-
this.
|
|
504
|
-
this.
|
|
505
|
-
this._disabledPathFeatures = false;
|
|
508
|
+
this.__clearActiveMarker();
|
|
509
|
+
this.unselectFeatures();
|
|
510
|
+
this.__enablePathFeatures(this._pathways.allFeatureIds(), true);
|
|
506
511
|
}
|
|
507
512
|
|
|
508
513
|
clearSearchResults(reset=true)
|
|
509
514
|
//============================
|
|
510
515
|
{
|
|
511
|
-
this.
|
|
516
|
+
this.unselectFeatures();
|
|
512
517
|
}
|
|
513
518
|
|
|
514
519
|
/**
|
|
@@ -544,14 +549,14 @@ export class UserInteractions
|
|
|
544
549
|
//========================
|
|
545
550
|
{
|
|
546
551
|
if (featureIds.length) {
|
|
547
|
-
this.
|
|
552
|
+
this.unselectFeatures();
|
|
548
553
|
for (const featureId of featureIds) {
|
|
549
554
|
const annotation = this._flatmap.annotation(featureId);
|
|
550
555
|
if (annotation) {
|
|
551
|
-
this.
|
|
556
|
+
this.selectFeature(featureId);
|
|
552
557
|
if ('type' in annotation && annotation.type.startsWith('line')) {
|
|
553
558
|
for (const pathFeatureId of this._pathways.lineFeatureIds([featureId])) {
|
|
554
|
-
this.
|
|
559
|
+
this.selectFeature(pathFeatureId);
|
|
555
560
|
}
|
|
556
561
|
}
|
|
557
562
|
}
|
|
@@ -588,7 +593,7 @@ export class UserInteractions
|
|
|
588
593
|
const highlight = (options.highlight === true);
|
|
589
594
|
if (featureIds.length) {
|
|
590
595
|
this.unhighlightFeatures_();
|
|
591
|
-
if (select) this.
|
|
596
|
+
if (select) this.unselectFeatures();
|
|
592
597
|
let bbox = null;
|
|
593
598
|
if (options.noZoomIn) {
|
|
594
599
|
const bounds = this._map.getBounds().toArray();
|
|
@@ -598,7 +603,7 @@ export class UserInteractions
|
|
|
598
603
|
const annotation = this._flatmap.annotation(featureId);
|
|
599
604
|
if (annotation) {
|
|
600
605
|
if (select) {
|
|
601
|
-
this.
|
|
606
|
+
this.selectFeature(featureId);
|
|
602
607
|
} else if (highlight) {
|
|
603
608
|
this.highlightFeature_(featureId);
|
|
604
609
|
}
|
|
@@ -606,7 +611,7 @@ export class UserInteractions
|
|
|
606
611
|
if ('type' in annotation && annotation.type.startsWith('line')) {
|
|
607
612
|
for (const pathFeatureId of this._pathways.lineFeatureIds([featureId])) {
|
|
608
613
|
if (select) {
|
|
609
|
-
this.
|
|
614
|
+
this.selectFeature(pathFeatureId);
|
|
610
615
|
} else if (highlight) {
|
|
611
616
|
this.highlightFeature_(pathFeatureId);
|
|
612
617
|
}
|
|
@@ -639,8 +644,8 @@ export class UserInteractions
|
|
|
639
644
|
|
|
640
645
|
// Highlight the feature
|
|
641
646
|
|
|
642
|
-
this.
|
|
643
|
-
this.
|
|
647
|
+
this.unselectFeatures();
|
|
648
|
+
this.selectFeature(featureId);
|
|
644
649
|
|
|
645
650
|
// Find the pop-up's postion
|
|
646
651
|
|
|
@@ -675,7 +680,7 @@ export class UserInteractions
|
|
|
675
680
|
//============
|
|
676
681
|
{
|
|
677
682
|
this.__clearModal();
|
|
678
|
-
this.
|
|
683
|
+
this.unselectFeatures();
|
|
679
684
|
}
|
|
680
685
|
|
|
681
686
|
removeTooltip_()
|
|
@@ -785,7 +790,7 @@ export class UserInteractions
|
|
|
785
790
|
|
|
786
791
|
// Get all the features at the current point
|
|
787
792
|
const features = this._map.queryRenderedFeatures(event.point)
|
|
788
|
-
.filter(feature => this.
|
|
793
|
+
.filter(feature => this.__featureEnabled(feature));
|
|
789
794
|
if (features.length === 0) {
|
|
790
795
|
this._lastFeatureMouseEntered = null;
|
|
791
796
|
this._lastFeatureModelsMouse = null;
|
|
@@ -931,27 +936,27 @@ export class UserInteractions
|
|
|
931
936
|
break;
|
|
932
937
|
}
|
|
933
938
|
}
|
|
934
|
-
this.
|
|
939
|
+
this.unselectFeatures();
|
|
935
940
|
if (selecting) {
|
|
936
941
|
for (const feature of this._activeFeatures) {
|
|
937
|
-
this.
|
|
942
|
+
this.selectFeature(feature.id, dim);
|
|
938
943
|
}
|
|
939
944
|
}
|
|
940
945
|
} else {
|
|
941
946
|
const clickedSelected = this.featureSelected_(clickedFeatureId);
|
|
942
947
|
for (const feature of this._activeFeatures) {
|
|
943
948
|
if (clickedSelected) {
|
|
944
|
-
this.
|
|
949
|
+
this.unselectFeature(feature.id);
|
|
945
950
|
} else {
|
|
946
|
-
this.
|
|
951
|
+
this.selectFeature(feature.id, dim);
|
|
947
952
|
}
|
|
948
953
|
}
|
|
949
954
|
}
|
|
950
955
|
}
|
|
951
956
|
}
|
|
952
957
|
|
|
953
|
-
__annotationEvent(
|
|
954
|
-
|
|
958
|
+
__annotationEvent(features)
|
|
959
|
+
//=========================
|
|
955
960
|
{
|
|
956
961
|
if (!this.__annotator) {
|
|
957
962
|
return;
|
|
@@ -962,15 +967,12 @@ export class UserInteractions
|
|
|
962
967
|
// Remove any tooltip
|
|
963
968
|
this.removeTooltip_();
|
|
964
969
|
|
|
965
|
-
// Select the feature
|
|
966
|
-
this.selectFeature_(feature.id);
|
|
967
|
-
|
|
968
970
|
// Don't respond to mouse events while the dialog is open
|
|
969
971
|
this.setModal_();
|
|
970
972
|
|
|
971
973
|
// The annotation dialog...
|
|
972
|
-
this.__annotator.annotate(
|
|
973
|
-
this.
|
|
974
|
+
this.__annotator.annotate(features, () => {
|
|
975
|
+
this.unselectFeatures();
|
|
974
976
|
this.__clearModal();
|
|
975
977
|
});
|
|
976
978
|
}
|
|
@@ -982,25 +984,25 @@ export class UserInteractions
|
|
|
982
984
|
return;
|
|
983
985
|
}
|
|
984
986
|
|
|
985
|
-
this.
|
|
987
|
+
this.__clearActiveMarker();
|
|
986
988
|
const clickedFeatures = this._map.queryRenderedFeatures(event.point)
|
|
987
|
-
.filter(feature => this.
|
|
989
|
+
.filter(feature => this.__featureEnabled(feature));
|
|
988
990
|
if (clickedFeatures.length == 0){
|
|
989
|
-
this.
|
|
991
|
+
this.unselectFeatures();
|
|
990
992
|
return;
|
|
991
993
|
}
|
|
992
|
-
const clickedFeature = clickedFeatures[0];
|
|
993
994
|
const originalEvent = event.originalEvent;
|
|
994
995
|
if (originalEvent.altKey) {
|
|
995
|
-
this.__annotationEvent(
|
|
996
|
+
this.__annotationEvent(clickedFeatures);
|
|
996
997
|
return;
|
|
997
998
|
}
|
|
998
999
|
|
|
1000
|
+
const clickedFeature = clickedFeatures[0];
|
|
999
1001
|
this.selectionEvent_(originalEvent, clickedFeature);
|
|
1000
1002
|
if (this._modal) {
|
|
1001
1003
|
// Remove tooltip, reset active features, etc
|
|
1002
1004
|
this.__resetFeatureDisplay();
|
|
1003
|
-
this.
|
|
1005
|
+
this.unselectFeatures();
|
|
1004
1006
|
this.__clearModal();
|
|
1005
1007
|
} else if (clickedFeature !== undefined) {
|
|
1006
1008
|
this.__lastClickLngLat = event.lngLat;
|
|
@@ -1026,54 +1028,18 @@ export class UserInteractions
|
|
|
1026
1028
|
}
|
|
1027
1029
|
}
|
|
1028
1030
|
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
{
|
|
1032
|
-
const state = this._map.getFeatureState(feature);
|
|
1033
|
-
return (state !== undefined
|
|
1034
|
-
&& (!('hidden' in state) || !state.hidden));
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
enablePaths_(enable, event)
|
|
1038
|
-
//=========================
|
|
1039
|
-
{
|
|
1040
|
-
const nodeId = event.target.getAttribute('featureId');
|
|
1041
|
-
this.enablePathFeatures_(enable, this._pathways.pathFeatureIds(nodeId));
|
|
1042
|
-
this.__clearModal();
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
enablePathFeatures_(enable, featureIds)
|
|
1046
|
-
//=====================================
|
|
1031
|
+
__enablePathFeatures(featureIds, enable)
|
|
1032
|
+
//======================================
|
|
1047
1033
|
{
|
|
1048
1034
|
for (const featureId of featureIds) {
|
|
1049
|
-
|
|
1050
|
-
if (feature !== undefined) {
|
|
1051
|
-
if (enable) {
|
|
1052
|
-
this._map.removeFeatureState(feature, 'hidden');
|
|
1053
|
-
} else {
|
|
1054
|
-
this._map.setFeatureState(feature, { 'hidden': true });
|
|
1055
|
-
this._disabledPathFeatures = true;
|
|
1056
|
-
}
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
|
|
1061
|
-
togglePaths()
|
|
1062
|
-
//===========
|
|
1063
|
-
{
|
|
1064
|
-
console.log('Depracated API function called: togglePaths()')
|
|
1065
|
-
if (this._disabledPathFeatures){
|
|
1066
|
-
this.enablePathFeatures_(true, this._pathways.allFeatureIds());
|
|
1067
|
-
this._disabledPathFeatures = false;
|
|
1068
|
-
} else {
|
|
1069
|
-
this.enablePathFeatures_(false, this._pathways.allFeatureIds());
|
|
1035
|
+
this.enableFeature(this.mapFeature(featureId), enable);
|
|
1070
1036
|
}
|
|
1071
1037
|
}
|
|
1072
1038
|
|
|
1073
1039
|
enablePath(pathType, enable=true)
|
|
1074
1040
|
//===============================
|
|
1075
1041
|
{
|
|
1076
|
-
this.
|
|
1042
|
+
this.__enablePathFeatures(this._pathways.typeFeatureIds(pathType), enable);
|
|
1077
1043
|
}
|
|
1078
1044
|
|
|
1079
1045
|
pathwaysFeatureIds(externalIds)
|
|
@@ -1278,7 +1244,7 @@ export class UserInteractions
|
|
|
1278
1244
|
event.stopPropagation();
|
|
1279
1245
|
}
|
|
1280
1246
|
|
|
1281
|
-
|
|
1247
|
+
__clearActiveMarker()
|
|
1282
1248
|
//==================
|
|
1283
1249
|
{
|
|
1284
1250
|
if (this.__activeMarker !== null) {
|
|
@@ -1292,7 +1258,7 @@ export class UserInteractions
|
|
|
1292
1258
|
{
|
|
1293
1259
|
const marker = this.__activeMarker;
|
|
1294
1260
|
if (markerId !== this.__markerIdByMarker.get(marker)) {
|
|
1295
|
-
this.
|
|
1261
|
+
this.__clearActiveMarker();
|
|
1296
1262
|
return false;
|
|
1297
1263
|
}
|
|
1298
1264
|
|
|
@@ -1311,7 +1277,7 @@ export class UserInteractions
|
|
|
1311
1277
|
element.innerHTML = content;
|
|
1312
1278
|
}
|
|
1313
1279
|
|
|
1314
|
-
element.addEventListener('click', e => this.
|
|
1280
|
+
element.addEventListener('click', e => this.__clearActiveMarker());
|
|
1315
1281
|
|
|
1316
1282
|
this._tooltip = new maplibre.Popup({
|
|
1317
1283
|
closeButton: false,
|
package/src/pathways.js
CHANGED
|
@@ -37,8 +37,8 @@ const PATH_TYPES = [
|
|
|
37
37
|
{ type: "symp-pre", label: "Sympathetic pre-ganglionic", colour: "#EA3423"},
|
|
38
38
|
{ type: "symp-post", label: "Sympathetic post-ganglionic", colour: "#EA3423", dashed: true},
|
|
39
39
|
{ type: "other", label: "Other neuron type", colour: "#888"},
|
|
40
|
-
{ type: "arterial", label: "Arterial blood vessel", colour: "#F00"},
|
|
41
|
-
{ type: "venous", label: "Venous blood vessel", colour: "#2F6EBA"},
|
|
40
|
+
{ type: "arterial", label: "Arterial blood vessel", colour: "#F00", enabled: false},
|
|
41
|
+
{ type: "venous", label: "Venous blood vessel", colour: "#2F6EBA", enabled: false},
|
|
42
42
|
{ type: "centreline", label: "Nerve centrelines", colour: "#CCC", enabled: false},
|
|
43
43
|
{ type: "error", label: "Paths with errors or warnings", colour: "#FF0"}
|
|
44
44
|
];
|
package/src/styling.js
CHANGED
|
@@ -33,6 +33,7 @@ import {PATH_STYLE_RULES} from './pathways.js';
|
|
|
33
33
|
const COLOUR_ACTIVE = 'blue';
|
|
34
34
|
const COLOUR_ANNOTATED = '#0F0';
|
|
35
35
|
const COLOUR_SELECTED = '#0F0';
|
|
36
|
+
const COLOUR_HIDDEN = '#D8D8D8';
|
|
36
37
|
|
|
37
38
|
const CENTRELINE_ACTIVE = '#444';
|
|
38
39
|
const CENTRELINE_COLOUR = '#CCC';
|
|
@@ -135,14 +136,13 @@ export class FeatureFillLayer extends VectorStyleLayer
|
|
|
135
136
|
|
|
136
137
|
paintStyle(options, changes=false)
|
|
137
138
|
{
|
|
138
|
-
const ghostColour = '#D8D8D8'; // Function of BG colour?
|
|
139
139
|
const coloured = !('colour' in options) || options.colour;
|
|
140
140
|
const dimmed = 'dimmed' in options && options.dimmed;
|
|
141
141
|
const paintStyle = {
|
|
142
142
|
'fill-color': [
|
|
143
143
|
'case',
|
|
144
144
|
['boolean', ['feature-state', 'selected'], false], COLOUR_SELECTED,
|
|
145
|
-
['boolean', ['feature-state', 'hidden'], false],
|
|
145
|
+
['boolean', ['feature-state', 'hidden'], false], COLOUR_HIDDEN,
|
|
146
146
|
['has', 'colour'], ['get', 'colour'],
|
|
147
147
|
['boolean', ['feature-state', 'active'], false], coloured ? '#D88' : '#CCC',
|
|
148
148
|
'white' // background colour? body colour ??
|
|
@@ -195,6 +195,8 @@ export class FeatureBorderLayer extends VectorStyleLayer
|
|
|
195
195
|
const dimmed = 'dimmed' in options && options.dimmed;
|
|
196
196
|
const activeRasterLayer = 'activeRasterLayer' in options && options.activeRasterLayer;
|
|
197
197
|
const lineColour = [ 'case' ];
|
|
198
|
+
lineColour.push(['boolean', ['feature-state', 'hidden'], false]);
|
|
199
|
+
lineColour.push(COLOUR_HIDDEN);
|
|
198
200
|
lineColour.push(['boolean', ['feature-state', 'selected'], false]);
|
|
199
201
|
lineColour.push(FEATURE_SELECTED_BORDER);
|
|
200
202
|
if (coloured && outlined) {
|
|
@@ -298,6 +300,7 @@ export class FeatureLineLayer extends VectorStyleLayer
|
|
|
298
300
|
const paintStyle = {
|
|
299
301
|
'line-color': [
|
|
300
302
|
'case',
|
|
303
|
+
['boolean', ['feature-state', 'hidden'], false], COLOUR_HIDDEN,
|
|
301
304
|
['boolean', ['feature-state', 'selected'], false], COLOUR_SELECTED,
|
|
302
305
|
['boolean', ['feature-state', 'active'], false], coloured ? '#888' : '#CCC',
|
|
303
306
|
['has', 'colour'], ['get', 'colour'],
|
|
@@ -306,6 +309,7 @@ export class FeatureLineLayer extends VectorStyleLayer
|
|
|
306
309
|
],
|
|
307
310
|
'line-opacity': [
|
|
308
311
|
'case',
|
|
312
|
+
['boolean', ['feature-state', 'hidden'], false], 0.01,
|
|
309
313
|
['boolean', ['feature-state', 'selected'], false], 1.0,
|
|
310
314
|
['has', 'colour'], 1.0,
|
|
311
315
|
['boolean', ['feature-state', 'active'], false], 1.0,
|
|
@@ -499,7 +503,7 @@ export class PathLineLayer extends VectorStyleLayer
|
|
|
499
503
|
'line-color': [
|
|
500
504
|
'case',
|
|
501
505
|
['boolean', ['feature-state', 'selected'], false], COLOUR_SELECTED,
|
|
502
|
-
['boolean', ['feature-state', 'hidden'], false],
|
|
506
|
+
['boolean', ['feature-state', 'hidden'], false], COLOUR_HIDDEN,
|
|
503
507
|
['==', ['get', 'type'], 'bezier'], 'red',
|
|
504
508
|
['==', ['get', 'kind'], 'unknown'], '#888',
|
|
505
509
|
...PATH_STYLE_RULES,
|
|
@@ -507,7 +511,7 @@ export class PathLineLayer extends VectorStyleLayer
|
|
|
507
511
|
],
|
|
508
512
|
'line-opacity': [
|
|
509
513
|
'case',
|
|
510
|
-
['boolean', ['feature-state', 'hidden'], false], 0.
|
|
514
|
+
['boolean', ['feature-state', 'hidden'], false], 0.01,
|
|
511
515
|
['==', ['get', 'type'], 'bezier'], 1.0,
|
|
512
516
|
['==', ['get', 'kind'], 'error'], 1.0,
|
|
513
517
|
['boolean', ['get', 'invisible'], false], 0.001,
|
|
@@ -523,7 +527,7 @@ export class PathLineLayer extends VectorStyleLayer
|
|
|
523
527
|
['==', ['get', 'kind'], 'error'], 1,
|
|
524
528
|
['==', ['get', 'kind'], 'unknown'], 1,
|
|
525
529
|
['boolean', ['get', 'invisible'], false], 0.1,
|
|
526
|
-
['boolean', ['feature-state', 'selected'], false], 0
|
|
530
|
+
['boolean', ['feature-state', 'selected'], false], 2.0,
|
|
527
531
|
['boolean', ['feature-state', 'active'], false], 0.9,
|
|
528
532
|
0.6
|
|
529
533
|
],
|
|
@@ -745,7 +749,7 @@ export class FeatureNerveLayer extends VectorStyleLayer
|
|
|
745
749
|
'paint': {
|
|
746
750
|
'line-color': [
|
|
747
751
|
'case',
|
|
748
|
-
['boolean', ['feature-state', 'hidden'], false],
|
|
752
|
+
['boolean', ['feature-state', 'hidden'], false], COLOUR_HIDDEN,
|
|
749
753
|
['boolean', ['feature-state', 'active'], false], NERVE_ACTIVE,
|
|
750
754
|
['boolean', ['feature-state', 'selected'], false], NERVE_SELECTED,
|
|
751
755
|
'#888'
|
package/src/systems.js
CHANGED
|
@@ -35,7 +35,8 @@ export class SystemsManager
|
|
|
35
35
|
id: ann.name.replaceAll(' ', '_'),
|
|
36
36
|
colour: ann.colour,
|
|
37
37
|
featureIds: [ ann.featureId ],
|
|
38
|
-
enabled: enabled
|
|
38
|
+
enabled: enabled,
|
|
39
|
+
pathIds: ('path-ids' in ann) ? ann['path-ids'] : []
|
|
39
40
|
});
|
|
40
41
|
}
|
|
41
42
|
for (const childId of ann['children']) {
|
|
@@ -86,6 +87,11 @@ export class SystemsManager
|
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
system.enabled = enable;
|
|
90
|
+
|
|
91
|
+
// Enable/disable all paths associated with the system
|
|
92
|
+
for (const pathId of system.pathIds) {
|
|
93
|
+
this.__ui.enableFeature(this.__ui.mapFeature(pathId), enable);
|
|
94
|
+
}
|
|
89
95
|
}
|
|
90
96
|
}
|
|
91
97
|
}
|
|
@@ -342,6 +342,18 @@ label[for=layer-all-layers] {
|
|
|
342
342
|
background-color: #BBB;
|
|
343
343
|
}
|
|
344
344
|
|
|
345
|
+
#annotation-feature-selection
|
|
346
|
+
{
|
|
347
|
+
display: flex;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
#annotation-feature-buttons
|
|
351
|
+
{
|
|
352
|
+
float: right;
|
|
353
|
+
padding-top: 10px;
|
|
354
|
+
padding-bottom: 10px;
|
|
355
|
+
}
|
|
356
|
+
|
|
345
357
|
.jsPanel-title {
|
|
346
358
|
font-size: 1.4em !important;
|
|
347
359
|
font-weight: bold !important;
|