@abi-software/flatmap-viewer 2.2.1-beta.1 → 2.2.1-beta.10
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 +2 -2
- package/package.json +2 -1
- package/src/flatmap-viewer.js +13 -1
- package/src/interactions.js +101 -70
- package/src/layers.js +42 -19
- package/src/styling.js +84 -46
package/README.rst
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Flatmap Viewer
|
|
3
3
|
==============
|
|
4
4
|
|
|
5
|
-
A viewer for anatomical flatmaps generated by `flatmap-maker <https://github.com/
|
|
5
|
+
A viewer for anatomical flatmaps generated by `flatmap-maker <https://github.com/AnatomicMaps/flatmap-maker>`_. The viewer is intended to be a component of a larger Javascript web application, although may be used standalone for local flatmap development and testing. Flatmap content is obtained from a `flatmap-server <https://github.com/AnatomicMaps/flatmap-server>`_.
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
Standalone Use
|
|
@@ -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.1-beta.
|
|
41
|
+
* ``npm install @abi-software/flatmap-viewer@2.2.1-beta.10``
|
|
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.2.1-beta.
|
|
3
|
+
"version": "2.2.1-beta.10",
|
|
4
4
|
"description": "Flatmap viewer using Maplibre GL",
|
|
5
5
|
"repository": "https://github.com/AnatomicMaps/flatmap-viewer.git",
|
|
6
6
|
"main": "src/main.js",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"@turf/area": "^6.0.1",
|
|
22
22
|
"@turf/bbox": "^6.0.1",
|
|
23
23
|
"@turf/helpers": "^6.1.4",
|
|
24
|
+
"bezier-js": "^6.1.0",
|
|
24
25
|
"maplibre-gl": ">=1.15.3",
|
|
25
26
|
"minisearch": "^2.2.1",
|
|
26
27
|
"polylabel": "^1.1.0"
|
package/src/flatmap-viewer.js
CHANGED
|
@@ -1191,6 +1191,12 @@ export class MapManager
|
|
|
1191
1191
|
mapOptions['pathControls'] = true;
|
|
1192
1192
|
}
|
|
1193
1193
|
|
|
1194
|
+
// Mapmaker's changed the name of the field to indicate that indicates if
|
|
1195
|
+
// there are raster layers
|
|
1196
|
+
if (!('image-layers' in mapIndex) && ('image_layer' in mapIndex)) {
|
|
1197
|
+
mapIndex['image-layers'] = mapIndex['image_layer'];
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1194
1200
|
// Get details about the map's layers
|
|
1195
1201
|
|
|
1196
1202
|
let mapLayers = [];
|
|
@@ -1259,7 +1265,13 @@ export class MapManager
|
|
|
1259
1265
|
outline: true
|
|
1260
1266
|
};
|
|
1261
1267
|
}
|
|
1262
|
-
|
|
1268
|
+
if ('authoring' in mapIndex) {
|
|
1269
|
+
mapOptions.layerOptions.style == 'authoring'
|
|
1270
|
+
} else if ('style' in mapIndex) {
|
|
1271
|
+
mapOptions.layerOptions.style = mapIndex.style;
|
|
1272
|
+
} else {
|
|
1273
|
+
mapOptions.layerOptions.style = 'flatmap';
|
|
1274
|
+
}
|
|
1263
1275
|
|
|
1264
1276
|
// Are features in separate vector tile source layers?
|
|
1265
1277
|
|
package/src/interactions.js
CHANGED
|
@@ -162,34 +162,6 @@ export class UserInteractions
|
|
|
162
162
|
|
|
163
163
|
this._layerManager = new LayerManager(flatmap);
|
|
164
164
|
|
|
165
|
-
// Add the map's layers
|
|
166
|
-
|
|
167
|
-
// Layers have an id, either layer-N or an assigned name
|
|
168
|
-
// Some layers might have a description. These are the selectable layers,
|
|
169
|
-
// unless they are flagged as `no-select`
|
|
170
|
-
// Selectable layers have opacity 0 unless active, in which case they have opacity 1.
|
|
171
|
-
// `no-select` layers have opacity 0.5
|
|
172
|
-
// Background layer has opacity 0.2
|
|
173
|
-
|
|
174
|
-
const layersById = new Map();
|
|
175
|
-
const layerBackgroundIds = [];
|
|
176
|
-
for (const layer of flatmap.layers) {
|
|
177
|
-
layer.backgroundLayers = [];
|
|
178
|
-
layersById.set(layer.id, layer);
|
|
179
|
-
}
|
|
180
|
-
for (const layer of flatmap.layers) {
|
|
181
|
-
if (layer.background_for) {
|
|
182
|
-
const l = layersById.get(layer.background_for);
|
|
183
|
-
l.backgroundLayers.push(layer);
|
|
184
|
-
layerBackgroundIds.push(layer.id);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
for (const layer of flatmap.layers) {
|
|
188
|
-
if (layerBackgroundIds.indexOf(layer.id) < 0) {
|
|
189
|
-
this._layerManager.addLayer(layer, flatmap.options.layerOptions);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
165
|
// Flag features that have annotations
|
|
194
166
|
// Also flag those features that are models of something
|
|
195
167
|
|
|
@@ -205,7 +177,7 @@ export class UserInteractions
|
|
|
205
177
|
// Display a context menu on right-click
|
|
206
178
|
|
|
207
179
|
this._lastContextTime = 0;
|
|
208
|
-
this._contextMenu = new ContextMenu(flatmap, this.
|
|
180
|
+
this._contextMenu = new ContextMenu(flatmap, this.__clearModal.bind(this));
|
|
209
181
|
this._map.on('contextmenu', this.contextMenuEvent_.bind(this));
|
|
210
182
|
|
|
211
183
|
// Display a context menu with a touch longer than 0.5 second
|
|
@@ -332,8 +304,8 @@ export class UserInteractions
|
|
|
332
304
|
}
|
|
333
305
|
}
|
|
334
306
|
|
|
335
|
-
|
|
336
|
-
|
|
307
|
+
__unselectFeatures()
|
|
308
|
+
//==================
|
|
337
309
|
{
|
|
338
310
|
for (const featureId of this._selectedFeatureIds.keys()) {
|
|
339
311
|
const feature = this.mapFeature_(featureId);
|
|
@@ -449,8 +421,8 @@ export class UserInteractions
|
|
|
449
421
|
this._modal = true;
|
|
450
422
|
}
|
|
451
423
|
|
|
452
|
-
|
|
453
|
-
|
|
424
|
+
__clearModal(event)
|
|
425
|
+
//=================
|
|
454
426
|
{
|
|
455
427
|
this._modal = false;
|
|
456
428
|
}
|
|
@@ -461,7 +433,7 @@ export class UserInteractions
|
|
|
461
433
|
this._contextMenu.hide();
|
|
462
434
|
const nodeId = event.target.getAttribute('featureId');
|
|
463
435
|
this.enablePathFeatures_(enable, this._pathways.pathFeatureIds(nodeId));
|
|
464
|
-
this.
|
|
436
|
+
this.__clearModal();
|
|
465
437
|
}
|
|
466
438
|
|
|
467
439
|
enablePathFeatures_(enable, featureIds)
|
|
@@ -492,9 +464,9 @@ export class UserInteractions
|
|
|
492
464
|
reset()
|
|
493
465
|
//=====
|
|
494
466
|
{
|
|
495
|
-
this.
|
|
467
|
+
this.__clearModal();
|
|
496
468
|
this.clearActiveMarker_();
|
|
497
|
-
this.
|
|
469
|
+
this.__unselectFeatures();
|
|
498
470
|
this.enablePathFeatures_(true, this._pathways.allFeatureIds());
|
|
499
471
|
this._disabledPathFeatures = false;
|
|
500
472
|
}
|
|
@@ -502,7 +474,7 @@ export class UserInteractions
|
|
|
502
474
|
clearSearchResults(reset=true)
|
|
503
475
|
//============================
|
|
504
476
|
{
|
|
505
|
-
this.
|
|
477
|
+
this.__unselectFeatures();
|
|
506
478
|
}
|
|
507
479
|
|
|
508
480
|
/**
|
|
@@ -538,7 +510,7 @@ export class UserInteractions
|
|
|
538
510
|
//========================
|
|
539
511
|
{
|
|
540
512
|
if (featureIds.length) {
|
|
541
|
-
this.
|
|
513
|
+
this.__unselectFeatures();
|
|
542
514
|
for (const featureId of featureIds) {
|
|
543
515
|
const annotation = this._flatmap.annotation(featureId);
|
|
544
516
|
if (annotation) {
|
|
@@ -571,7 +543,7 @@ export class UserInteractions
|
|
|
571
543
|
const padding = options.padding || 100;
|
|
572
544
|
if (featureIds.length) {
|
|
573
545
|
this.unhighlightFeatures_();
|
|
574
|
-
if (select) this.
|
|
546
|
+
if (select) this.__unselectFeatures();
|
|
575
547
|
let bbox = null;
|
|
576
548
|
for (const featureId of featureIds) {
|
|
577
549
|
const annotation = this._flatmap.annotation(featureId);
|
|
@@ -618,7 +590,7 @@ export class UserInteractions
|
|
|
618
590
|
|
|
619
591
|
// Highlight the feature
|
|
620
592
|
|
|
621
|
-
this.
|
|
593
|
+
this.__unselectFeatures();
|
|
622
594
|
this.selectFeature_(featureId);
|
|
623
595
|
|
|
624
596
|
// Find the pop-up's postion
|
|
@@ -640,7 +612,7 @@ export class UserInteractions
|
|
|
640
612
|
}
|
|
641
613
|
this.setModal_();
|
|
642
614
|
this._currentPopup = new maplibre.Popup(options).addTo(this._map);
|
|
643
|
-
this._currentPopup.on('close', this.
|
|
615
|
+
this._currentPopup.on('close', this.__clearPopup.bind(this));
|
|
644
616
|
this._currentPopup.setLngLat(location);
|
|
645
617
|
if (typeof content === 'object') {
|
|
646
618
|
this._currentPopup.setDOMContent(content);
|
|
@@ -650,6 +622,13 @@ export class UserInteractions
|
|
|
650
622
|
}
|
|
651
623
|
}
|
|
652
624
|
|
|
625
|
+
__clearPopup()
|
|
626
|
+
//============
|
|
627
|
+
{
|
|
628
|
+
this.__clearModal();
|
|
629
|
+
this.__unselectFeatures();
|
|
630
|
+
}
|
|
631
|
+
|
|
653
632
|
removeTooltip_()
|
|
654
633
|
//==============
|
|
655
634
|
{
|
|
@@ -659,15 +638,47 @@ export class UserInteractions
|
|
|
659
638
|
}
|
|
660
639
|
}
|
|
661
640
|
|
|
641
|
+
lineTooltip_(lineFeatures)
|
|
642
|
+
//========================
|
|
643
|
+
{
|
|
644
|
+
const tooltips = [];
|
|
645
|
+
for (const lineFeature of lineFeatures) {
|
|
646
|
+
const properties = lineFeature.properties;
|
|
647
|
+
if ('label' in properties
|
|
648
|
+
&& (!('tooltip' in properties) || properties.tooltip)
|
|
649
|
+
&& !('labelled' in properties)) {
|
|
650
|
+
let tooltip = '';
|
|
651
|
+
const label = properties.label;
|
|
652
|
+
const cleanLabel = (label.substr(0, 1).toUpperCase() + label.substr(1)).replaceAll("\n", "<br/>");
|
|
653
|
+
if (!tooltips.includes(cleanLabel)) {
|
|
654
|
+
tooltips.push(cleanLabel);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
if (tooltips.length === 0) {
|
|
659
|
+
return '';
|
|
660
|
+
}
|
|
661
|
+
return `<div class='flatmap-feature-label'>${tooltips.join('<hr/>')}</div>`;
|
|
662
|
+
}
|
|
663
|
+
|
|
662
664
|
tooltipHtml_(properties, forceLabel=false)
|
|
663
665
|
//========================================
|
|
664
666
|
{
|
|
665
|
-
if ('label' in properties
|
|
667
|
+
if (('label' in properties || 'hyperlink' in properties)
|
|
666
668
|
&& (forceLabel || !('tooltip' in properties) || properties.tooltip)
|
|
667
669
|
&& !('labelled' in properties)) {
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
670
|
+
let tooltip = '';
|
|
671
|
+
if ('label' in properties) {
|
|
672
|
+
const label = properties.label;
|
|
673
|
+
tooltip = (label.substr(0, 1).toUpperCase() + label.substr(1)).replaceAll("\n", "<br/>");
|
|
674
|
+
} else {
|
|
675
|
+
tooltip = properties.hyperlink
|
|
676
|
+
}
|
|
677
|
+
if ('hyperlink' in properties) {
|
|
678
|
+
return `<div class='flatmap-feature-label'><a href='{properties.hyperlink}'>${tooltip}</a></div>`;
|
|
679
|
+
} else {
|
|
680
|
+
return `<div class='flatmap-feature-label'>${tooltip}</div>`;
|
|
681
|
+
}
|
|
671
682
|
}
|
|
672
683
|
return '';
|
|
673
684
|
}
|
|
@@ -683,36 +694,37 @@ export class UserInteractions
|
|
|
683
694
|
return false;
|
|
684
695
|
}
|
|
685
696
|
|
|
686
|
-
|
|
687
|
-
|
|
697
|
+
__resetFeatureDisplay()
|
|
698
|
+
//=====================
|
|
688
699
|
{
|
|
689
|
-
// No tooltip when context menu is open
|
|
690
|
-
|
|
691
|
-
if (this._modal) {
|
|
692
|
-
return;
|
|
693
|
-
}
|
|
694
|
-
|
|
695
700
|
// Remove any existing tooltip
|
|
696
|
-
|
|
697
701
|
this.removeTooltip_();
|
|
698
702
|
|
|
699
703
|
// Reset cursor
|
|
700
|
-
|
|
701
704
|
this._map.getCanvas().style.cursor = 'default';
|
|
702
705
|
|
|
703
706
|
// Reset any active features
|
|
704
|
-
|
|
705
707
|
this.resetActiveFeatures_();
|
|
708
|
+
}
|
|
706
709
|
|
|
707
|
-
|
|
710
|
+
mouseMoveEvent_(event)
|
|
711
|
+
//====================
|
|
712
|
+
{
|
|
713
|
+
// No tooltip when context menu is open
|
|
714
|
+
if (this._modal) {
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
708
717
|
|
|
718
|
+
// Remove tooltip, reset active features, etc
|
|
719
|
+
this.__resetFeatureDisplay();
|
|
720
|
+
|
|
721
|
+
// Reset any info display
|
|
709
722
|
const displayInfo = (this._infoControl && this._infoControl.active);
|
|
710
723
|
if (displayInfo) {
|
|
711
724
|
this._infoControl.reset()
|
|
712
725
|
}
|
|
713
726
|
|
|
714
727
|
// Get all the features at the current point
|
|
715
|
-
|
|
716
728
|
const features = this._map.queryRenderedFeatures(event.point);
|
|
717
729
|
if (features.length === 0) {
|
|
718
730
|
this._lastFeatureMouseEntered = null;
|
|
@@ -750,18 +762,20 @@ export class UserInteractions
|
|
|
750
762
|
&& feature.properties.type.startsWith('line'))
|
|
751
763
|
|| 'centreline' in feature.properties));
|
|
752
764
|
if (lineFeatures.length > 0) {
|
|
753
|
-
|
|
754
|
-
const
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
765
|
+
tooltip = this.lineTooltip_(lineFeatures);
|
|
766
|
+
for (const lineFeature of lineFeatures) {
|
|
767
|
+
const lineFeatureId = +lineFeature.properties.featureId; // Ensure numeric
|
|
768
|
+
this.activateFeature_(lineFeature);
|
|
769
|
+
const lineIds = new Set(lineFeatures.map(f => f.properties.featureId));
|
|
770
|
+
for (const featureId of this._pathways.lineFeatureIds(lineIds)) {
|
|
771
|
+
if (+featureId !== lineFeatureId) {
|
|
772
|
+
this.activateFeature_(this.mapFeature_(featureId));
|
|
773
|
+
}
|
|
761
774
|
}
|
|
762
775
|
}
|
|
763
776
|
} else {
|
|
764
|
-
let labelledFeatures = features.filter(feature => (('
|
|
777
|
+
let labelledFeatures = features.filter(feature => (('hyperlink' in feature.properties
|
|
778
|
+
|| 'label' in feature.properties
|
|
765
779
|
|| 'node' in feature.properties)
|
|
766
780
|
&& (!('tooltip' in feature.properties)
|
|
767
781
|
|| feature.properties.tooltip)))
|
|
@@ -803,11 +817,20 @@ export class UserInteractions
|
|
|
803
817
|
}
|
|
804
818
|
info = `<div id="info-control-info">${htmlList.join('\n')}</div>`;
|
|
805
819
|
}
|
|
806
|
-
this.activateFeature_(feature);
|
|
807
820
|
if ('nerveId' in feature.properties) {
|
|
821
|
+
if (feature.properties.active) {
|
|
822
|
+
this.activateFeature_(feature);
|
|
823
|
+
} else {
|
|
824
|
+
tooltip = '';
|
|
825
|
+
}
|
|
808
826
|
if (feature.properties.nerveId !== feature.properties.featureId) {
|
|
809
827
|
this.activateNerveFeatures_(feature.properties.nerveId);
|
|
810
828
|
}
|
|
829
|
+
} else {
|
|
830
|
+
this.activateFeature_(feature);
|
|
831
|
+
}
|
|
832
|
+
if ('hyperlink' in feature.properties) {
|
|
833
|
+
this._map.getCanvas().style.cursor = 'pointer';
|
|
811
834
|
}
|
|
812
835
|
}
|
|
813
836
|
}
|
|
@@ -841,7 +864,7 @@ export class UserInteractions
|
|
|
841
864
|
{
|
|
842
865
|
const multipleSelect = event.ctrlKey || event.metaKey;
|
|
843
866
|
if (!multipleSelect) {
|
|
844
|
-
this.
|
|
867
|
+
this.__unselectFeatures();
|
|
845
868
|
}
|
|
846
869
|
if (feature !== undefined) {
|
|
847
870
|
const featureId = feature.id;
|
|
@@ -874,9 +897,17 @@ export class UserInteractions
|
|
|
874
897
|
this.clearActiveMarker_();
|
|
875
898
|
const feature = this._activeFeatures[0]
|
|
876
899
|
this.selectionEvent_(event.originalEvent, feature);
|
|
877
|
-
if (
|
|
900
|
+
if (this._modal) {
|
|
901
|
+
// Remove tooltip, reset active features, etc
|
|
902
|
+
this.__resetFeatureDisplay();
|
|
903
|
+
this.__unselectFeatures();
|
|
904
|
+
this.__clearModal();
|
|
905
|
+
} else if (feature !== undefined) {
|
|
878
906
|
this.__lastClickLngLat = event.lngLat;
|
|
879
907
|
this.__featureEvent('click', feature);
|
|
908
|
+
if ('hyperlink' in feature.properties) {
|
|
909
|
+
window.open(feature.properties.hyperlink, '_blank');
|
|
910
|
+
}
|
|
880
911
|
}
|
|
881
912
|
}
|
|
882
913
|
|
package/src/layers.js
CHANGED
|
@@ -33,7 +33,7 @@ const FEATURES_LAYER = 'features'
|
|
|
33
33
|
|
|
34
34
|
class MapFeatureLayer
|
|
35
35
|
{
|
|
36
|
-
constructor(flatmap, layer,
|
|
36
|
+
constructor(flatmap, layer, background_layers=true)
|
|
37
37
|
{
|
|
38
38
|
this.__map = flatmap.map;
|
|
39
39
|
this.__separateLayers = flatmap.options.separateLayers;
|
|
@@ -41,6 +41,7 @@ class MapFeatureLayer
|
|
|
41
41
|
this.__rasterLayers = [];
|
|
42
42
|
this.__styleLayers = [];
|
|
43
43
|
|
|
44
|
+
const layerOptions = flatmap.options.layerOptions;
|
|
44
45
|
const vectorTileSource = this.__map.getSource('vector-tiles');
|
|
45
46
|
const haveVectorLayers = (typeof vectorTileSource !== 'undefined');
|
|
46
47
|
const featuresVectorLayerId = this.__separateLayers
|
|
@@ -48,33 +49,36 @@ class MapFeatureLayer
|
|
|
48
49
|
: FEATURES_LAYER;
|
|
49
50
|
const vectorFeatures = haveVectorLayers
|
|
50
51
|
&& vectorTileSource.vectorLayerIds.indexOf(featuresVectorLayerId) >= 0;
|
|
51
|
-
if (
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const
|
|
52
|
+
if (background_layers) {
|
|
53
|
+
if (vectorFeatures) {
|
|
54
|
+
this.__addStyleLayer(style.BodyLayer, layerOptions);
|
|
55
|
+
}
|
|
56
|
+
if (flatmap.details['image-layers']) {
|
|
57
|
+
for (const raster_layer_id of layer['image-layers']) {
|
|
58
|
+
this.__addRasterLayer(raster_layer_id, layerOptions);
|
|
59
|
+
}
|
|
57
60
|
}
|
|
58
61
|
}
|
|
59
62
|
// if no image layers then make feature borders (and lines?) more visible...??
|
|
60
63
|
if (haveVectorLayers) {
|
|
61
64
|
if (vectorFeatures) {
|
|
62
|
-
this.__addStyleLayer(style.FeatureFillLayer,
|
|
63
|
-
this.__addStyleLayer(style.
|
|
64
|
-
this.__addStyleLayer(style.
|
|
65
|
+
this.__addStyleLayer(style.FeatureFillLayer, layerOptions);
|
|
66
|
+
this.__addStyleLayer(style.FeatureDashLineLayer, layerOptions);
|
|
67
|
+
this.__addStyleLayer(style.FeatureLineLayer, layerOptions);
|
|
68
|
+
this.__addStyleLayer(style.FeatureBorderLayer, layerOptions);
|
|
65
69
|
}
|
|
66
|
-
this.__addPathwayStyleLayers(
|
|
70
|
+
this.__addPathwayStyleLayers(layerOptions);
|
|
67
71
|
if (vectorFeatures) {
|
|
68
|
-
this.__addStyleLayer(style.FeatureLargeSymbolLayer,
|
|
72
|
+
this.__addStyleLayer(style.FeatureLargeSymbolLayer, layerOptions);
|
|
69
73
|
if (!flatmap.options.tooltips) {
|
|
70
|
-
this.__addStyleLayer(style.FeatureSmallSymbolLayer,
|
|
74
|
+
this.__addStyleLayer(style.FeatureSmallSymbolLayer, layerOptions);
|
|
71
75
|
}
|
|
72
76
|
}
|
|
73
77
|
}
|
|
74
78
|
|
|
75
|
-
// Make sure our
|
|
79
|
+
// Make sure our colour options are set properly, in particular raster layer visibility
|
|
76
80
|
|
|
77
|
-
this.setColour(
|
|
81
|
+
this.setColour(layerOptions);
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
get id()
|
|
@@ -147,12 +151,31 @@ export class LayerManager
|
|
|
147
151
|
this.__mapLayers = new Map;
|
|
148
152
|
this.__activeLayers = [];
|
|
149
153
|
this.__activeLayerNames = [];
|
|
154
|
+
this.__rasterLayers = [];
|
|
155
|
+
const layerOptions = flatmap.options.layerOptions;
|
|
156
|
+
const fcDiagram = ('style' in layerOptions && layerOptions.style == 'fcdiagram');
|
|
150
157
|
const backgroundLayer = new style.BackgroundLayer();
|
|
151
|
-
if (
|
|
158
|
+
if (fcDiagram) {
|
|
159
|
+
this.__map.addLayer(backgroundLayer.style('black', 1));
|
|
160
|
+
}
|
|
161
|
+
else if ('background' in flatmap.options) {
|
|
152
162
|
this.__map.addLayer(backgroundLayer.style(flatmap.options.background));
|
|
153
163
|
} else {
|
|
154
164
|
this.__map.addLayer(backgroundLayer.style('white'));
|
|
155
165
|
}
|
|
166
|
+
// Add the map's layers
|
|
167
|
+
if (fcDiagram && flatmap.details['image-layers']) {
|
|
168
|
+
for (const layer of flatmap.layers) {
|
|
169
|
+
for (const raster_layer_id of layer['image-layers']) {
|
|
170
|
+
const rasterLayer = new style.RasterLayer(raster_layer_id);
|
|
171
|
+
this.__map.addLayer(rasterLayer.style(layerOptions));
|
|
172
|
+
this.__rasterLayers.push(rasterLayer);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
for (const layer of flatmap.layers) {
|
|
177
|
+
this.addLayer(layer, !fcDiagram);
|
|
178
|
+
}
|
|
156
179
|
}
|
|
157
180
|
|
|
158
181
|
get activeLayerNames()
|
|
@@ -161,12 +184,12 @@ export class LayerManager
|
|
|
161
184
|
return this.__activeLayerNames;
|
|
162
185
|
}
|
|
163
186
|
|
|
164
|
-
addLayer(layer,
|
|
165
|
-
|
|
187
|
+
addLayer(layer, background_layers=true)
|
|
188
|
+
//=====================================
|
|
166
189
|
{
|
|
167
190
|
this.__mapLayers.set(layer.id, layer);
|
|
168
191
|
|
|
169
|
-
const layers = new MapFeatureLayer(this.__flatmap, layer,
|
|
192
|
+
const layers = new MapFeatureLayer(this.__flatmap, layer, background_layers);
|
|
170
193
|
const layerId = this.__flatmap.mapLayerId(layer.id);
|
|
171
194
|
this.__layers.set(layerId, layers);
|
|
172
195
|
}
|
package/src/styling.js
CHANGED
|
@@ -117,12 +117,12 @@ export class FeatureFillLayer extends VectorStyleLayer
|
|
|
117
117
|
const paintStyle = {
|
|
118
118
|
'fill-color': [
|
|
119
119
|
'case',
|
|
120
|
-
['boolean', ['feature-state', 'active'], false], coloured ? '#D88' : '#CCC',
|
|
121
120
|
['boolean', ['feature-state', 'selected'], false], '#0F0',
|
|
121
|
+
['has', 'colour'], ['get', 'colour'],
|
|
122
|
+
['boolean', ['feature-state', 'active'], false], coloured ? '#D88' : '#CCC',
|
|
122
123
|
['any',
|
|
123
124
|
['==', ['get', 'kind'], 'scaffold']
|
|
124
125
|
], 'white',
|
|
125
|
-
['has', 'colour'], ['get', 'colour'],
|
|
126
126
|
['has', 'node'], '#AFA202',
|
|
127
127
|
'white' // background colour? body colour ??
|
|
128
128
|
],
|
|
@@ -133,10 +133,10 @@ export class FeatureFillLayer extends VectorStyleLayer
|
|
|
133
133
|
['==', ['get', 'kind'], 'tissue'],
|
|
134
134
|
['==', ['get', 'kind'], 'cell-type'],
|
|
135
135
|
], 0.1,
|
|
136
|
-
['has', 'colour'], 0.008,
|
|
137
136
|
['has', 'node'], 0.3,
|
|
138
137
|
['boolean', ['feature-state', 'selected'], false], 1.0,
|
|
139
138
|
['boolean', ['feature-state', 'active'], false], 0.8,
|
|
139
|
+
['has', 'colour'], 0.008,
|
|
140
140
|
(coloured && !dimmed) ? 0.01 : 0.5
|
|
141
141
|
]
|
|
142
142
|
};
|
|
@@ -236,68 +236,105 @@ export class FeatureBorderLayer extends VectorStyleLayer
|
|
|
236
236
|
|
|
237
237
|
export class FeatureLineLayer extends VectorStyleLayer
|
|
238
238
|
{
|
|
239
|
-
constructor(id, sourceLayer)
|
|
239
|
+
constructor(id, sourceLayer, dashed=false)
|
|
240
240
|
{
|
|
241
|
-
|
|
241
|
+
const filterType = dashed ? 'line-dash' : 'line';
|
|
242
|
+
super(id, `feature-${filterType}`, sourceLayer);
|
|
243
|
+
this.__filter = dashed ?
|
|
244
|
+
[
|
|
245
|
+
'any',
|
|
246
|
+
['==', 'type', `line-dash`]
|
|
247
|
+
]
|
|
248
|
+
:
|
|
249
|
+
[
|
|
250
|
+
'any',
|
|
251
|
+
['has', 'centreline'],
|
|
252
|
+
['==', 'type', 'bezier'],
|
|
253
|
+
['==', 'type', `line`]
|
|
254
|
+
];
|
|
255
|
+
this.__dashed = dashed;
|
|
242
256
|
}
|
|
243
257
|
|
|
244
|
-
|
|
258
|
+
paintStyle(options)
|
|
245
259
|
{
|
|
246
260
|
const coloured = !('colour' in options) || options.colour;
|
|
261
|
+
const paintStyle = {
|
|
262
|
+
'line-color': [
|
|
263
|
+
'case',
|
|
264
|
+
['boolean', ['feature-state', 'selected'], false], '#0F0',
|
|
265
|
+
['has', 'colour'], ['get', 'colour'],
|
|
266
|
+
['boolean', ['feature-state', 'active'], false], coloured ? '#888' : '#CCC',
|
|
267
|
+
['==', ['get', 'type'], 'network'], '#AFA202',
|
|
268
|
+
['has', 'centreline'], '#888',
|
|
269
|
+
('style' in options && options.style === 'authoring') ? '#C44' : '#444'
|
|
270
|
+
],
|
|
271
|
+
'line-opacity': [
|
|
272
|
+
'case',
|
|
273
|
+
['boolean', ['feature-state', 'selected'], false], 1.0,
|
|
274
|
+
['boolean', ['feature-state', 'active'], false], 1.0,
|
|
275
|
+
0.3
|
|
276
|
+
],
|
|
277
|
+
'line-width': [
|
|
278
|
+
'let',
|
|
279
|
+
'width', [
|
|
280
|
+
'case',
|
|
281
|
+
['has', 'centreline'], 1.2,
|
|
282
|
+
['==', ['get', 'type'], 'network'], 1.2,
|
|
283
|
+
['boolean', ['feature-state', 'selected'], false], 1.2,
|
|
284
|
+
['boolean', ['feature-state', 'active'], false], 1.2,
|
|
285
|
+
('style' in options && options.style === 'authoring') ? 0.7 : 0.5
|
|
286
|
+
], [
|
|
287
|
+
'interpolate',
|
|
288
|
+
['exponential', 2],
|
|
289
|
+
['zoom'],
|
|
290
|
+
2, ["*", ['var', 'width'], ["^", 2, -0.5]],
|
|
291
|
+
7, ["*", ['var', 'width'], ["^", 2, 2.5]],
|
|
292
|
+
9, ["*", ['var', 'width'], ["^", 2, 4.0]]
|
|
293
|
+
]
|
|
294
|
+
]
|
|
295
|
+
// Need to vary width based on zoom??
|
|
296
|
+
// Or opacity??
|
|
297
|
+
};
|
|
298
|
+
if (this.__dashed) {
|
|
299
|
+
paintStyle['line-dasharray'] = [3, 2];
|
|
300
|
+
}
|
|
301
|
+
return paintStyle;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
style(options)
|
|
305
|
+
{
|
|
247
306
|
return {
|
|
248
307
|
...super.style(),
|
|
249
308
|
'type': 'line',
|
|
250
309
|
'filter': [
|
|
251
|
-
|
|
252
|
-
|
|
310
|
+
'all',
|
|
311
|
+
['==', '$type', 'LineString'],
|
|
312
|
+
this.__filter
|
|
253
313
|
// not for paths...
|
|
254
314
|
],
|
|
255
|
-
'paint':
|
|
256
|
-
'line-color': [
|
|
257
|
-
'case',
|
|
258
|
-
['boolean', ['feature-state', 'active'], false], coloured ? '#D88' : '#CCC',
|
|
259
|
-
['boolean', ['feature-state', 'selected'], false], '#0F0',
|
|
260
|
-
['==', ['get', 'type'], 'network'], '#AFA202',
|
|
261
|
-
['has', 'centreline'], '#888',
|
|
262
|
-
('authoring' in options && options.authoring) ? '#C44' : '#444'
|
|
263
|
-
],
|
|
264
|
-
'line-opacity': [
|
|
265
|
-
'case',
|
|
266
|
-
['boolean', ['feature-state', 'active'], false], 1.0,
|
|
267
|
-
0.3
|
|
268
|
-
],
|
|
269
|
-
'line-width': [
|
|
270
|
-
'let',
|
|
271
|
-
'width', [
|
|
272
|
-
'case',
|
|
273
|
-
['has', 'centreline'], 1.2,
|
|
274
|
-
['==', ['get', 'type'], 'network'], 1.2,
|
|
275
|
-
['boolean', ['feature-state', 'active'], false], 1.2,
|
|
276
|
-
('authoring' in options && options.authoring) ? 0.7 : 0.1
|
|
277
|
-
], [
|
|
278
|
-
'interpolate',
|
|
279
|
-
['exponential', 2],
|
|
280
|
-
['zoom'],
|
|
281
|
-
2, ["*", ['var', 'width'], ["^", 2, -0.5]],
|
|
282
|
-
7, ["*", ['var', 'width'], ["^", 2, 2.5]],
|
|
283
|
-
9, ["*", ['var', 'width'], ["^", 2, 4.0]]
|
|
284
|
-
]
|
|
285
|
-
]
|
|
286
|
-
// Need to vary width based on zoom??
|
|
287
|
-
// Or opacity??
|
|
288
|
-
}
|
|
315
|
+
'paint': this.paintStyle(options)
|
|
289
316
|
};
|
|
290
317
|
}
|
|
291
318
|
}
|
|
292
319
|
|
|
293
320
|
//==============================================================================
|
|
294
321
|
|
|
322
|
+
export class FeatureDashLineLayer extends FeatureLineLayer
|
|
323
|
+
{
|
|
324
|
+
constructor(id, sourceLayer)
|
|
325
|
+
{
|
|
326
|
+
super(id, sourceLayer, true);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
//==============================================================================
|
|
331
|
+
|
|
295
332
|
export class PathLineLayer extends VectorStyleLayer
|
|
296
333
|
{
|
|
297
334
|
constructor(id, sourceLayer, dashed=false)
|
|
298
335
|
{
|
|
299
336
|
const filterType = dashed ? 'line-dash' : 'line';
|
|
300
|
-
super(id, filterType
|
|
337
|
+
super(id, `path-${filterType}`, sourceLayer);
|
|
301
338
|
this.__filter = dashed ?
|
|
302
339
|
[
|
|
303
340
|
'any',
|
|
@@ -417,7 +454,8 @@ export class FeatureNerveLayer extends VectorStyleLayer
|
|
|
417
454
|
['boolean', ['feature-state', 'active'], false], '#222',
|
|
418
455
|
['boolean', ['feature-state', 'selected'], false], 'red',
|
|
419
456
|
['boolean', ['feature-state', 'hidden'], false], '#CCC',
|
|
420
|
-
'#888'
|
|
457
|
+
['boolean', ['get', 'active'], false], '#888',
|
|
458
|
+
'#FFF'
|
|
421
459
|
],
|
|
422
460
|
'line-opacity': [
|
|
423
461
|
'case',
|
|
@@ -640,14 +678,14 @@ export class BackgroundLayer
|
|
|
640
678
|
return this.__id;
|
|
641
679
|
}
|
|
642
680
|
|
|
643
|
-
style(backgroundColour)
|
|
681
|
+
style(backgroundColour, opacity=0.1)
|
|
644
682
|
{
|
|
645
683
|
return {
|
|
646
684
|
'id': this.__id,
|
|
647
685
|
'type': 'background',
|
|
648
686
|
'paint': {
|
|
649
687
|
'background-color': backgroundColour,
|
|
650
|
-
'background-opacity':
|
|
688
|
+
'background-opacity': opacity
|
|
651
689
|
}
|
|
652
690
|
};
|
|
653
691
|
}
|