@abi-software/flatmap-viewer 2.2.0-beta.9 → 2.2.1-beta.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 +3 -3
- package/src/flatmap-viewer.js +32 -11
- package/src/interactions.js +27 -10
- package/src/layers.js +34 -14
- package/src/search.js +1 -1
- package/src/styling.js +115 -65
- package/src/utils.js +15 -0
- package/static/flatmap-viewer.css +4 -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``
|
|
41
|
+
* ``npm install @abi-software/flatmap-viewer@2.2.1-beta.2``
|
|
42
42
|
|
|
43
43
|
Documentation
|
|
44
44
|
-------------
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abi-software/flatmap-viewer",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.1-beta.2",
|
|
4
4
|
"description": "Flatmap viewer using Maplibre GL",
|
|
5
|
-
"repository": "https://github.com/
|
|
5
|
+
"repository": "https://github.com/AnatomicMaps/flatmap-viewer.git",
|
|
6
6
|
"main": "src/main.js",
|
|
7
7
|
"files": [
|
|
8
8
|
"src",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"@turf/area": "^6.0.1",
|
|
22
22
|
"@turf/bbox": "^6.0.1",
|
|
23
23
|
"@turf/helpers": "^6.1.4",
|
|
24
|
-
"maplibre-gl": "
|
|
24
|
+
"maplibre-gl": ">=1.15.3",
|
|
25
25
|
"minisearch": "^2.2.1",
|
|
26
26
|
"polylabel": "^1.1.0"
|
|
27
27
|
},
|
package/src/flatmap-viewer.js
CHANGED
|
@@ -45,6 +45,10 @@ import * as utils from './utils.js';
|
|
|
45
45
|
|
|
46
46
|
//==============================================================================
|
|
47
47
|
|
|
48
|
+
const MAP_MAKER_SEPARATE_LAYERS_VERSION = 1.4;
|
|
49
|
+
|
|
50
|
+
//==============================================================================
|
|
51
|
+
|
|
48
52
|
/**
|
|
49
53
|
* Maps are not created directly but instead are created and loaded by
|
|
50
54
|
* :meth:`LoadMap` of :class:`MapManager`.
|
|
@@ -629,9 +633,10 @@ class FlatMap
|
|
|
629
633
|
}
|
|
630
634
|
}
|
|
631
635
|
|
|
632
|
-
setColour(options=
|
|
633
|
-
|
|
636
|
+
setColour(options=null)
|
|
637
|
+
//=====================
|
|
634
638
|
{
|
|
639
|
+
options = utils.setDefaultOptions(options, {colour: true, outline: true});
|
|
635
640
|
if (this._userInteractions !== null) {
|
|
636
641
|
this._userInteractions.setColour(options);
|
|
637
642
|
}
|
|
@@ -962,9 +967,10 @@ class FlatMap
|
|
|
962
967
|
* @param {boolean} [options.highlight=false] Highlight the features zoomed to
|
|
963
968
|
* @param {number} [options.padding=100] Padding around the composite bounding box
|
|
964
969
|
*/
|
|
965
|
-
zoomToFeatures(externalIds, options=
|
|
966
|
-
|
|
970
|
+
zoomToFeatures(externalIds, options=null)
|
|
971
|
+
//=======================================
|
|
967
972
|
{
|
|
973
|
+
options = utils.setDefaultOptions(options, {select: true, highlight: false, padding:100});
|
|
968
974
|
if (this._userInteractions !== null) {
|
|
969
975
|
const featureIds = this.modelFeatureIdList(externalIds);
|
|
970
976
|
this._userInteractions.zoomToFeatures(featureIds, options);
|
|
@@ -999,9 +1005,15 @@ export class MapManager
|
|
|
999
1005
|
{
|
|
1000
1006
|
return await this._initialisingMutex.dispatch(async () => {
|
|
1001
1007
|
if (!this._initialised) {
|
|
1002
|
-
this._mapList =
|
|
1008
|
+
this._mapList = [];
|
|
1009
|
+
const maps = await this._mapServer.loadJSON('');
|
|
1003
1010
|
// Check map schema version (set by mapmaker) and
|
|
1004
1011
|
// remove maps we can't view (giving a console warning...)
|
|
1012
|
+
for (const map of maps) {
|
|
1013
|
+
// Are features in separate vector tile source layers?
|
|
1014
|
+
map.separateLayers = ('version' in map && map.version >= MAP_MAKER_SEPARATE_LAYERS_VERSION);
|
|
1015
|
+
this._mapList.push(map);
|
|
1016
|
+
}
|
|
1005
1017
|
this._initialised = true;
|
|
1006
1018
|
}
|
|
1007
1019
|
});
|
|
@@ -1058,7 +1070,9 @@ export class MapManager
|
|
|
1058
1070
|
let latestMap = null;
|
|
1059
1071
|
let lastCreatedTime = '';
|
|
1060
1072
|
for (const map of this._mapList) {
|
|
1061
|
-
if (mapDescribes === map.
|
|
1073
|
+
if (mapDescribes === (('taxon' in map) ? map.taxon
|
|
1074
|
+
: ('describes' in map) ? map.describes
|
|
1075
|
+
: map.id)
|
|
1062
1076
|
|| mapDescribes === map.id
|
|
1063
1077
|
|| mapDescribes === map.source) {
|
|
1064
1078
|
if ('created' in map) {
|
|
@@ -1085,7 +1099,9 @@ export class MapManager
|
|
|
1085
1099
|
return flatmap;
|
|
1086
1100
|
}
|
|
1087
1101
|
}
|
|
1088
|
-
if ('
|
|
1102
|
+
if ('taxon' in identifier) {
|
|
1103
|
+
mapDescribes = identifier.taxon;
|
|
1104
|
+
} else if ('describes' in identifier) {
|
|
1089
1105
|
mapDescribes = identifier.describes;
|
|
1090
1106
|
}
|
|
1091
1107
|
} else {
|
|
@@ -1102,8 +1118,8 @@ export class MapManager
|
|
|
1102
1118
|
* or a taxon identifier of the species that the map represents. The
|
|
1103
1119
|
* latest version of a map is loaded unless it has been identified
|
|
1104
1120
|
* by ``source`` (see below).
|
|
1105
|
-
* @arg identifier.
|
|
1106
|
-
*
|
|
1121
|
+
* @arg identifier.taxon {string} The taxon identifier of the map. This is specified as metadata
|
|
1122
|
+
* in the map's source file.)
|
|
1107
1123
|
* @arg identifier.source {string} The URL of the source file from which the map has
|
|
1108
1124
|
* been generated. If given then this exact map will be
|
|
1109
1125
|
* loaded.
|
|
@@ -1138,7 +1154,7 @@ export class MapManager
|
|
|
1138
1154
|
*
|
|
1139
1155
|
* const humanMap2 = mapManager.loadMap('NCBITaxon:9606', 'div-2');
|
|
1140
1156
|
*
|
|
1141
|
-
* const humanMap3 = mapManager.loadMap({
|
|
1157
|
+
* const humanMap3 = mapManager.loadMap({taxon: 'NCBITaxon:9606'}, 'div-3');
|
|
1142
1158
|
*
|
|
1143
1159
|
* const humanMap4 = mapManager.loadMap(
|
|
1144
1160
|
* {source: 'https://models.physiomeproject.org/workspace/585/rawfile/650adf9076538a4bf081609df14dabddd0eb37e7/Human_Body.pptx'},
|
|
@@ -1151,7 +1167,7 @@ export class MapManager
|
|
|
1151
1167
|
try {
|
|
1152
1168
|
const map = await this.findMap_(identifier);
|
|
1153
1169
|
if (map === null) {
|
|
1154
|
-
reject(`Unknown map
|
|
1170
|
+
reject(`Unknown map: ${JSON.stringify(identifier)}`);
|
|
1155
1171
|
};
|
|
1156
1172
|
|
|
1157
1173
|
// Load the maps index file
|
|
@@ -1243,6 +1259,11 @@ export class MapManager
|
|
|
1243
1259
|
outline: true
|
|
1244
1260
|
};
|
|
1245
1261
|
}
|
|
1262
|
+
mapOptions.layerOptions.authoring = ('authoring' in mapIndex && mapIndex.authoring);
|
|
1263
|
+
|
|
1264
|
+
// Are features in separate vector tile source layers?
|
|
1265
|
+
|
|
1266
|
+
mapOptions.separateLayers = map.separateLayers;
|
|
1246
1267
|
|
|
1247
1268
|
// Display the map
|
|
1248
1269
|
|
package/src/interactions.js
CHANGED
|
@@ -224,6 +224,7 @@ export class UserInteractions
|
|
|
224
224
|
this._map.on('mousemove', this.mouseMoveEvent_.bind(this));
|
|
225
225
|
this._lastFeatureMouseEntered = null;
|
|
226
226
|
this._lastFeatureModelsMouse = null;
|
|
227
|
+
this.__lastClickLngLat = null;
|
|
227
228
|
|
|
228
229
|
// Handle pan/zoom events
|
|
229
230
|
this._map.on('move', this.panZoomEvent_.bind(this, 'pan'));
|
|
@@ -284,7 +285,9 @@ export class UserInteractions
|
|
|
284
285
|
return {
|
|
285
286
|
id: featureId,
|
|
286
287
|
source: VECTOR_TILES_SOURCE,
|
|
287
|
-
sourceLayer:
|
|
288
|
+
sourceLayer: this._flatmap.options.separateLayers
|
|
289
|
+
? `${ann['layer']}_${ann['tile-layer']}`
|
|
290
|
+
: ann['tile-layer']
|
|
288
291
|
};
|
|
289
292
|
}
|
|
290
293
|
|
|
@@ -559,9 +562,10 @@ export class UserInteractions
|
|
|
559
562
|
* @param {boolean} [options.highlight=false] Highlight the features zoomed to
|
|
560
563
|
* @param {number} [options.padding=100] Padding around the composite bounding box
|
|
561
564
|
*/
|
|
562
|
-
zoomToFeatures(featureIds, options=
|
|
563
|
-
|
|
565
|
+
zoomToFeatures(featureIds, options=null)
|
|
566
|
+
//======================================
|
|
564
567
|
{
|
|
568
|
+
options = utils.setDefaultOptions(options, {select: true, highlight: false, padding:100});
|
|
565
569
|
const select = (options.select === true);
|
|
566
570
|
const highlight = (options.highlight === true);
|
|
567
571
|
const padding = options.padding || 100;
|
|
@@ -617,9 +621,17 @@ export class UserInteractions
|
|
|
617
621
|
this.unselectFeatures_();
|
|
618
622
|
this.selectFeature_(featureId);
|
|
619
623
|
|
|
620
|
-
//
|
|
624
|
+
// Find the pop-up's postion
|
|
621
625
|
|
|
622
|
-
|
|
626
|
+
let location = null;
|
|
627
|
+
if ('positionAtLastClick' in options
|
|
628
|
+
&& options.positionAtLastClick
|
|
629
|
+
&& this.__lastClickLngLat !== null) {
|
|
630
|
+
location = this.__lastClickLngLat;
|
|
631
|
+
} else {
|
|
632
|
+
// Position popup at the feature's 'centre'
|
|
633
|
+
location = this.__centralPosition(featureId, ann);
|
|
634
|
+
}
|
|
623
635
|
|
|
624
636
|
// Make sure the feature is on screen
|
|
625
637
|
|
|
@@ -655,7 +667,7 @@ export class UserInteractions
|
|
|
655
667
|
&& !('labelled' in properties)) {
|
|
656
668
|
const label = properties.label;
|
|
657
669
|
const capitalisedLabel = label.substr(0, 1).toUpperCase() + label.substr(1);
|
|
658
|
-
return `<div class='flatmap-feature-label'>${capitalisedLabel}</div>`;
|
|
670
|
+
return `<div class='flatmap-feature-label'>${capitalisedLabel.replaceAll("\n", "<br/>")}</div>`;
|
|
659
671
|
}
|
|
660
672
|
return '';
|
|
661
673
|
}
|
|
@@ -734,8 +746,9 @@ export class UserInteractions
|
|
|
734
746
|
}
|
|
735
747
|
info = this._infoControl.featureInformation(features, event.lngLat);
|
|
736
748
|
}
|
|
737
|
-
const lineFeatures = features.filter(feature => ('type' in feature.properties
|
|
738
|
-
&& feature.properties.type.startsWith('line'))
|
|
749
|
+
const lineFeatures = features.filter(feature => (('type' in feature.properties
|
|
750
|
+
&& feature.properties.type.startsWith('line'))
|
|
751
|
+
|| 'centreline' in feature.properties));
|
|
739
752
|
if (lineFeatures.length > 0) {
|
|
740
753
|
const lineFeature = lineFeatures[0];
|
|
741
754
|
const lineFeatureId = +lineFeature.properties.featureId; // Ensure numeric
|
|
@@ -748,7 +761,8 @@ export class UserInteractions
|
|
|
748
761
|
}
|
|
749
762
|
}
|
|
750
763
|
} else {
|
|
751
|
-
let labelledFeatures = features.filter(feature => ('label' in feature.properties
|
|
764
|
+
let labelledFeatures = features.filter(feature => (('label' in feature.properties
|
|
765
|
+
|| 'node' in feature.properties)
|
|
752
766
|
&& (!('tooltip' in feature.properties)
|
|
753
767
|
|| feature.properties.tooltip)))
|
|
754
768
|
.sort((a, b) => (a.properties.area - b.properties.area));
|
|
@@ -861,6 +875,7 @@ export class UserInteractions
|
|
|
861
875
|
const feature = this._activeFeatures[0]
|
|
862
876
|
this.selectionEvent_(event.originalEvent, feature);
|
|
863
877
|
if (feature !== undefined) {
|
|
878
|
+
this.__lastClickLngLat = event.lngLat;
|
|
864
879
|
this.__featureEvent('click', feature);
|
|
865
880
|
}
|
|
866
881
|
}
|
|
@@ -918,7 +933,9 @@ export class UserInteractions
|
|
|
918
933
|
}
|
|
919
934
|
let position = annotation.centroid;
|
|
920
935
|
const features = this._map.querySourceFeatures(VECTOR_TILES_SOURCE, {
|
|
921
|
-
'sourceLayer':
|
|
936
|
+
'sourceLayer': this._flatmap.options.separateLayers
|
|
937
|
+
? `${annotation['layer']}_${annotation['tile-layer']}`
|
|
938
|
+
: annotation['tile-layer'],
|
|
922
939
|
'filter': [
|
|
923
940
|
'all',
|
|
924
941
|
[ '==', ['id'], parseInt(featureId) ],
|
package/src/layers.js
CHANGED
|
@@ -27,6 +27,8 @@ import {PATHWAYS_LAYER} from './pathways.js';
|
|
|
27
27
|
import * as style from './styling.js';
|
|
28
28
|
import * as utils from './utils.js';
|
|
29
29
|
|
|
30
|
+
const FEATURES_LAYER = 'features'
|
|
31
|
+
|
|
30
32
|
//==============================================================================
|
|
31
33
|
|
|
32
34
|
class MapFeatureLayer
|
|
@@ -34,12 +36,19 @@ class MapFeatureLayer
|
|
|
34
36
|
constructor(flatmap, layer, options)
|
|
35
37
|
{
|
|
36
38
|
this.__map = flatmap.map;
|
|
39
|
+
this.__separateLayers = flatmap.options.separateLayers;
|
|
37
40
|
this.__id = layer.id;
|
|
38
41
|
this.__rasterLayers = [];
|
|
39
42
|
this.__styleLayers = [];
|
|
40
43
|
|
|
41
|
-
const
|
|
42
|
-
|
|
44
|
+
const vectorTileSource = this.__map.getSource('vector-tiles');
|
|
45
|
+
const haveVectorLayers = (typeof vectorTileSource !== 'undefined');
|
|
46
|
+
const featuresVectorLayerId = this.__separateLayers
|
|
47
|
+
? `${this.__id}_${FEATURES_LAYER}`
|
|
48
|
+
: FEATURES_LAYER;
|
|
49
|
+
const vectorFeatures = haveVectorLayers
|
|
50
|
+
&& vectorTileSource.vectorLayerIds.indexOf(featuresVectorLayerId) >= 0;
|
|
51
|
+
if (vectorFeatures) {
|
|
43
52
|
this.__addStyleLayer(style.BodyLayer, options);
|
|
44
53
|
}
|
|
45
54
|
if (flatmap.details['image_layer']) {
|
|
@@ -49,13 +58,18 @@ class MapFeatureLayer
|
|
|
49
58
|
}
|
|
50
59
|
// if no image layers then make feature borders (and lines?) more visible...??
|
|
51
60
|
if (haveVectorLayers) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
61
|
+
if (vectorFeatures) {
|
|
62
|
+
this.__addStyleLayer(style.FeatureFillLayer, options);
|
|
63
|
+
this.__addStyleLayer(style.FeatureDashLineLayer, options);
|
|
64
|
+
this.__addStyleLayer(style.FeatureLineLayer, options);
|
|
65
|
+
this.__addStyleLayer(style.FeatureBorderLayer, options);
|
|
66
|
+
}
|
|
55
67
|
this.__addPathwayStyleLayers(options);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
68
|
+
if (vectorFeatures) {
|
|
69
|
+
this.__addStyleLayer(style.FeatureLargeSymbolLayer, options);
|
|
70
|
+
if (!flatmap.options.tooltips) {
|
|
71
|
+
this.__addStyleLayer(style.FeatureSmallSymbolLayer, options);
|
|
72
|
+
}
|
|
59
73
|
}
|
|
60
74
|
}
|
|
61
75
|
|
|
@@ -81,9 +95,12 @@ class MapFeatureLayer
|
|
|
81
95
|
__addPathwayStyleLayers(options)
|
|
82
96
|
//==============================
|
|
83
97
|
{
|
|
98
|
+
const pathwaysVectorLayerId = this.__separateLayers
|
|
99
|
+
? `${this.__id}_${PATHWAYS_LAYER}`
|
|
100
|
+
: PATHWAYS_LAYER;
|
|
84
101
|
if (this.__map.getSource('vector-tiles')
|
|
85
102
|
.vectorLayerIds
|
|
86
|
-
.indexOf(
|
|
103
|
+
.indexOf(pathwaysVectorLayerId) >= 0) {
|
|
87
104
|
this.__addStyleLayer(style.PathLineLayer, options, PATHWAYS_LAYER);
|
|
88
105
|
this.__addStyleLayer(style.PathDashlineLayer, options, PATHWAYS_LAYER);
|
|
89
106
|
this.__addStyleLayer(style.NervePolygonBorder, options, PATHWAYS_LAYER);
|
|
@@ -92,10 +109,12 @@ class MapFeatureLayer
|
|
|
92
109
|
}
|
|
93
110
|
}
|
|
94
111
|
|
|
95
|
-
__addStyleLayer(styleClass, options, sourceLayer=
|
|
96
|
-
|
|
112
|
+
__addStyleLayer(styleClass, options, sourceLayer=FEATURES_LAYER)
|
|
113
|
+
//==============================================================
|
|
97
114
|
{
|
|
98
|
-
const
|
|
115
|
+
const layerId = `${this.__id}_${sourceLayer}`;
|
|
116
|
+
const source = this.__separateLayers ? layerId : sourceLayer;
|
|
117
|
+
const styleLayer = new styleClass(layerId, source);
|
|
99
118
|
this.__map.addLayer(styleLayer.style(options));
|
|
100
119
|
this.__styleLayers.push(styleLayer);
|
|
101
120
|
}
|
|
@@ -188,9 +207,10 @@ export class LayerManager
|
|
|
188
207
|
}
|
|
189
208
|
}
|
|
190
209
|
|
|
191
|
-
setColour(options=
|
|
192
|
-
|
|
210
|
+
setColour(options=null)
|
|
211
|
+
//=====================
|
|
193
212
|
{
|
|
213
|
+
options = utils.setDefaultOptions(options, {colour: true, outline: true});
|
|
194
214
|
for (const layer of this.__layers.values()) {
|
|
195
215
|
layer.setColour(options)
|
|
196
216
|
}
|
package/src/search.js
CHANGED
|
@@ -180,7 +180,7 @@ export class SearchIndex
|
|
|
180
180
|
let results = [];
|
|
181
181
|
text = text.trim()
|
|
182
182
|
if (text.length > 2 && ["'", '"'].indexOf(text.slice(0, 1)) >= 0) {
|
|
183
|
-
text = (text.slice(0, 1)
|
|
183
|
+
text = text.replaceAll(text.slice(0, 1), '');
|
|
184
184
|
results = this._searchEngine.search(text, {prefix: true, combineWith: 'AND'});
|
|
185
185
|
} else if (text.length > 1) {
|
|
186
186
|
results = this._searchEngine.search(text, {prefix: true});
|
package/src/styling.js
CHANGED
|
@@ -28,9 +28,9 @@ export const VECTOR_TILES_SOURCE = 'vector-tiles';
|
|
|
28
28
|
|
|
29
29
|
class VectorStyleLayer
|
|
30
30
|
{
|
|
31
|
-
constructor(
|
|
31
|
+
constructor(id, suffix, sourceLayer)
|
|
32
32
|
{
|
|
33
|
-
this.__id = `${
|
|
33
|
+
this.__id = `${id}_${suffix}`;
|
|
34
34
|
this.__sourceLayer = sourceLayer;
|
|
35
35
|
this.__lastPaintStyle = {};
|
|
36
36
|
}
|
|
@@ -78,9 +78,9 @@ class VectorStyleLayer
|
|
|
78
78
|
|
|
79
79
|
export class BodyLayer extends VectorStyleLayer
|
|
80
80
|
{
|
|
81
|
-
constructor(
|
|
81
|
+
constructor(id, sourceLayer)
|
|
82
82
|
{
|
|
83
|
-
super(
|
|
83
|
+
super(id, 'body', sourceLayer);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
style(options)
|
|
@@ -105,9 +105,9 @@ export class BodyLayer extends VectorStyleLayer
|
|
|
105
105
|
|
|
106
106
|
export class FeatureFillLayer extends VectorStyleLayer
|
|
107
107
|
{
|
|
108
|
-
constructor(
|
|
108
|
+
constructor(id, sourceLayer)
|
|
109
109
|
{
|
|
110
|
-
super(
|
|
110
|
+
super(id, 'fill', sourceLayer);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
paintStyle(options, changes=false)
|
|
@@ -117,13 +117,13 @@ export class FeatureFillLayer extends VectorStyleLayer
|
|
|
117
117
|
const paintStyle = {
|
|
118
118
|
'fill-color': [
|
|
119
119
|
'case',
|
|
120
|
-
['
|
|
121
|
-
['==', ['get', 'kind'], 'scaffold'],
|
|
122
|
-
['==', ['get', 'kind'], 'tissue'],
|
|
123
|
-
['==', ['get', 'kind'], 'cell-type']
|
|
124
|
-
], "white",
|
|
125
|
-
['boolean', ['feature-state', 'selected'], false], '#0F0',
|
|
120
|
+
['has', 'colour'], ['get', 'colour'],
|
|
126
121
|
['boolean', ['feature-state', 'active'], false], coloured ? '#D88' : '#CCC',
|
|
122
|
+
['boolean', ['feature-state', 'selected'], false], '#0F0',
|
|
123
|
+
['any',
|
|
124
|
+
['==', ['get', 'kind'], 'scaffold']
|
|
125
|
+
], 'white',
|
|
126
|
+
['has', 'node'], '#AFA202',
|
|
127
127
|
'white' // background colour? body colour ??
|
|
128
128
|
],
|
|
129
129
|
'fill-opacity': [
|
|
@@ -131,10 +131,12 @@ export class FeatureFillLayer extends VectorStyleLayer
|
|
|
131
131
|
['any',
|
|
132
132
|
['==', ['get', 'kind'], 'scaffold'],
|
|
133
133
|
['==', ['get', 'kind'], 'tissue'],
|
|
134
|
-
['==', ['get', 'kind'], 'cell-type']
|
|
134
|
+
['==', ['get', 'kind'], 'cell-type'],
|
|
135
135
|
], 0.1,
|
|
136
|
+
['has', 'node'], 0.3,
|
|
136
137
|
['boolean', ['feature-state', 'selected'], false], 1.0,
|
|
137
138
|
['boolean', ['feature-state', 'active'], false], 0.8,
|
|
139
|
+
['has', 'colour'], 0.008,
|
|
138
140
|
(coloured && !dimmed) ? 0.01 : 0.5
|
|
139
141
|
]
|
|
140
142
|
};
|
|
@@ -163,9 +165,9 @@ export class FeatureFillLayer extends VectorStyleLayer
|
|
|
163
165
|
|
|
164
166
|
export class FeatureBorderLayer extends VectorStyleLayer
|
|
165
167
|
{
|
|
166
|
-
constructor(
|
|
168
|
+
constructor(id, sourceLayer)
|
|
167
169
|
{
|
|
168
|
-
super(
|
|
170
|
+
super(id, 'border', sourceLayer);
|
|
169
171
|
}
|
|
170
172
|
|
|
171
173
|
paintStyle(options, changes=false)
|
|
@@ -180,6 +182,10 @@ export class FeatureBorderLayer extends VectorStyleLayer
|
|
|
180
182
|
lineColour.push(['boolean', ['feature-state', 'active'], false]);
|
|
181
183
|
lineColour.push('blue');
|
|
182
184
|
}
|
|
185
|
+
lineColour.push(['has', 'colour']);
|
|
186
|
+
lineColour.push(['get', 'colour']);
|
|
187
|
+
lineColour.push(['has', 'node']);
|
|
188
|
+
lineColour.push('#AFA202');
|
|
183
189
|
lineColour.push('#444');
|
|
184
190
|
|
|
185
191
|
const lineOpacity = [
|
|
@@ -230,9 +236,66 @@ export class FeatureBorderLayer extends VectorStyleLayer
|
|
|
230
236
|
|
|
231
237
|
export class FeatureLineLayer extends VectorStyleLayer
|
|
232
238
|
{
|
|
233
|
-
constructor(
|
|
239
|
+
constructor(id, sourceLayer, dashed=false)
|
|
240
|
+
{
|
|
241
|
+
const filterType = dashed ? 'line-dash' : 'line';
|
|
242
|
+
super(id, `divider-${filterType}`, sourceLayer);
|
|
243
|
+
this.__filter = dashed ?
|
|
244
|
+
[
|
|
245
|
+
'any',
|
|
246
|
+
['==', 'type', `line-dash`]
|
|
247
|
+
]
|
|
248
|
+
:
|
|
249
|
+
[
|
|
250
|
+
'any',
|
|
251
|
+
['==', 'type', 'bezier'],
|
|
252
|
+
['==', 'type', `line`]
|
|
253
|
+
];
|
|
254
|
+
this.__dashed = dashed;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
paintStyle(options)
|
|
234
258
|
{
|
|
235
|
-
|
|
259
|
+
const coloured = !('colour' in options) || options.colour;
|
|
260
|
+
const paintStyle = {
|
|
261
|
+
'line-color': [
|
|
262
|
+
'case',
|
|
263
|
+
['has', 'colour'], ['get', 'colour'],
|
|
264
|
+
['boolean', ['feature-state', 'active'], false], coloured ? '#D88' : '#CCC',
|
|
265
|
+
['boolean', ['feature-state', 'selected'], false], '#0F0',
|
|
266
|
+
['==', ['get', 'type'], 'network'], '#AFA202',
|
|
267
|
+
['has', 'centreline'], '#888',
|
|
268
|
+
('authoring' in options && options.authoring) ? '#C44' : '#444'
|
|
269
|
+
],
|
|
270
|
+
'line-opacity': [
|
|
271
|
+
'case',
|
|
272
|
+
['boolean', ['feature-state', 'active'], false], 1.0,
|
|
273
|
+
0.3
|
|
274
|
+
],
|
|
275
|
+
'line-width': [
|
|
276
|
+
'let',
|
|
277
|
+
'width', [
|
|
278
|
+
'case',
|
|
279
|
+
['has', 'centreline'], 1.2,
|
|
280
|
+
['==', ['get', 'type'], 'network'], 1.2,
|
|
281
|
+
['boolean', ['feature-state', 'active'], false], 1.2,
|
|
282
|
+
('authoring' in options && options.authoring) ? 0.7 : 0.5
|
|
283
|
+
], [
|
|
284
|
+
'interpolate',
|
|
285
|
+
['exponential', 2],
|
|
286
|
+
['zoom'],
|
|
287
|
+
2, ["*", ['var', 'width'], ["^", 2, -0.5]],
|
|
288
|
+
7, ["*", ['var', 'width'], ["^", 2, 2.5]],
|
|
289
|
+
9, ["*", ['var', 'width'], ["^", 2, 4.0]]
|
|
290
|
+
]
|
|
291
|
+
]
|
|
292
|
+
// Need to vary width based on zoom??
|
|
293
|
+
// Or opacity??
|
|
294
|
+
};
|
|
295
|
+
if (this.__dashed) {
|
|
296
|
+
paintStyle['line-dasharray'] = [3, 2];
|
|
297
|
+
}
|
|
298
|
+
return paintStyle;
|
|
236
299
|
}
|
|
237
300
|
|
|
238
301
|
style(options)
|
|
@@ -241,47 +304,34 @@ export class FeatureLineLayer extends VectorStyleLayer
|
|
|
241
304
|
...super.style(),
|
|
242
305
|
'type': 'line',
|
|
243
306
|
'filter': [
|
|
244
|
-
|
|
245
|
-
|
|
307
|
+
'all',
|
|
308
|
+
['==', '$type', 'LineString'],
|
|
309
|
+
this.__filter
|
|
246
310
|
// not for paths...
|
|
247
311
|
],
|
|
248
|
-
'paint':
|
|
249
|
-
'line-color': [
|
|
250
|
-
'case',
|
|
251
|
-
['==', ['get', 'type'], 'network'], '#AFA202',
|
|
252
|
-
'#444'
|
|
253
|
-
],
|
|
254
|
-
'line-opacity': 0.3,
|
|
255
|
-
'line-width': [
|
|
256
|
-
'let',
|
|
257
|
-
'width', [
|
|
258
|
-
'case',
|
|
259
|
-
['==', ['get', 'type'], 'network'], 1.2,
|
|
260
|
-
0.1
|
|
261
|
-
], [
|
|
262
|
-
'interpolate',
|
|
263
|
-
['exponential', 2],
|
|
264
|
-
['zoom'],
|
|
265
|
-
2, ["*", ['var', 'width'], ["^", 2, -0.5]],
|
|
266
|
-
7, ["*", ['var', 'width'], ["^", 2, 2.5]],
|
|
267
|
-
9, ["*", ['var', 'width'], ["^", 2, 4.0]]
|
|
268
|
-
]
|
|
269
|
-
]
|
|
270
|
-
// Need to vary width based on zoom??
|
|
271
|
-
// Or opacity??
|
|
272
|
-
}
|
|
312
|
+
'paint': this.paintStyle(options)
|
|
273
313
|
};
|
|
274
314
|
}
|
|
275
315
|
}
|
|
276
316
|
|
|
277
317
|
//==============================================================================
|
|
278
318
|
|
|
319
|
+
export class FeatureDashLineLayer extends FeatureLineLayer
|
|
320
|
+
{
|
|
321
|
+
constructor(id, sourceLayer)
|
|
322
|
+
{
|
|
323
|
+
super(id, sourceLayer, true);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
//==============================================================================
|
|
328
|
+
|
|
279
329
|
export class PathLineLayer extends VectorStyleLayer
|
|
280
330
|
{
|
|
281
|
-
constructor(
|
|
331
|
+
constructor(id, sourceLayer, dashed=false)
|
|
282
332
|
{
|
|
283
333
|
const filterType = dashed ? 'line-dash' : 'line';
|
|
284
|
-
super(
|
|
334
|
+
super(id, filterType, sourceLayer);
|
|
285
335
|
this.__filter = dashed ?
|
|
286
336
|
[
|
|
287
337
|
'any',
|
|
@@ -312,7 +362,7 @@ export class PathLineLayer extends VectorStyleLayer
|
|
|
312
362
|
['==', ['get', 'kind'], 'sensory'], '#2A62F6',
|
|
313
363
|
['==', ['get', 'kind'], 'symp-post'], '#EA3423',
|
|
314
364
|
['==', ['get', 'kind'], 'symp-pre'], '#EA3423',
|
|
315
|
-
'
|
|
365
|
+
'#888'
|
|
316
366
|
],
|
|
317
367
|
'line-opacity': [
|
|
318
368
|
'case',
|
|
@@ -321,7 +371,7 @@ export class PathLineLayer extends VectorStyleLayer
|
|
|
321
371
|
['boolean', ['feature-state', 'selected'], false], 1.0,
|
|
322
372
|
['boolean', ['feature-state', 'active'], false], 0.8,
|
|
323
373
|
['boolean', ['feature-state', 'hidden'], false], 0.1,
|
|
324
|
-
dimmed ? 0.1 : 0.
|
|
374
|
+
dimmed ? 0.1 : 0.4
|
|
325
375
|
],
|
|
326
376
|
'line-width': [
|
|
327
377
|
'let',
|
|
@@ -330,7 +380,7 @@ export class PathLineLayer extends VectorStyleLayer
|
|
|
330
380
|
['==', ['get', 'type'], 'bezier'], 0.1,
|
|
331
381
|
['boolean', ['get', 'invisible'], false], 0.1,
|
|
332
382
|
['boolean', ['feature-state', 'selected'], false], 1.2,
|
|
333
|
-
['boolean', ['feature-state', 'active'], false],
|
|
383
|
+
['boolean', ['feature-state', 'active'], false], 0.9,
|
|
334
384
|
0.8
|
|
335
385
|
], [
|
|
336
386
|
'interpolate',
|
|
@@ -370,9 +420,9 @@ export class PathLineLayer extends VectorStyleLayer
|
|
|
370
420
|
|
|
371
421
|
export class PathDashlineLayer extends PathLineLayer
|
|
372
422
|
{
|
|
373
|
-
constructor(
|
|
423
|
+
constructor(id, sourceLayer)
|
|
374
424
|
{
|
|
375
|
-
super(
|
|
425
|
+
super(id, sourceLayer, true);
|
|
376
426
|
}
|
|
377
427
|
}
|
|
378
428
|
|
|
@@ -380,9 +430,9 @@ export class PathDashlineLayer extends PathLineLayer
|
|
|
380
430
|
|
|
381
431
|
export class FeatureNerveLayer extends VectorStyleLayer
|
|
382
432
|
{
|
|
383
|
-
constructor(
|
|
433
|
+
constructor(id, sourceLayer)
|
|
384
434
|
{
|
|
385
|
-
super(
|
|
435
|
+
super(id, 'nerve-path', sourceLayer);
|
|
386
436
|
}
|
|
387
437
|
|
|
388
438
|
style(options)
|
|
@@ -433,9 +483,9 @@ export class FeatureNerveLayer extends VectorStyleLayer
|
|
|
433
483
|
|
|
434
484
|
export class NervePolygonBorder extends VectorStyleLayer
|
|
435
485
|
{
|
|
436
|
-
constructor(
|
|
486
|
+
constructor(id, sourceLayer)
|
|
437
487
|
{
|
|
438
|
-
super(
|
|
488
|
+
super(id, 'nerve-border', sourceLayer);
|
|
439
489
|
}
|
|
440
490
|
|
|
441
491
|
style(options)
|
|
@@ -477,9 +527,9 @@ export class NervePolygonBorder extends VectorStyleLayer
|
|
|
477
527
|
|
|
478
528
|
export class NervePolygonFill extends VectorStyleLayer
|
|
479
529
|
{
|
|
480
|
-
constructor(
|
|
530
|
+
constructor(id, sourceLayer)
|
|
481
531
|
{
|
|
482
|
-
super(
|
|
532
|
+
super(id, 'nerve-fill', sourceLayer);
|
|
483
533
|
}
|
|
484
534
|
|
|
485
535
|
style(options)
|
|
@@ -527,9 +577,9 @@ export class NervePolygonFill extends VectorStyleLayer
|
|
|
527
577
|
|
|
528
578
|
export class FeatureLargeSymbolLayer extends VectorStyleLayer
|
|
529
579
|
{
|
|
530
|
-
constructor(
|
|
580
|
+
constructor(id, sourceLayer)
|
|
531
581
|
{
|
|
532
|
-
super(
|
|
582
|
+
super(id, 'large-symbol', sourceLayer);
|
|
533
583
|
}
|
|
534
584
|
|
|
535
585
|
style(options)
|
|
@@ -571,9 +621,9 @@ export class FeatureLargeSymbolLayer extends VectorStyleLayer
|
|
|
571
621
|
|
|
572
622
|
export class FeatureSmallSymbolLayer extends VectorStyleLayer
|
|
573
623
|
{
|
|
574
|
-
constructor(
|
|
624
|
+
constructor(id, sourceLayer)
|
|
575
625
|
{
|
|
576
|
-
super(
|
|
626
|
+
super(id, 'small-symbol', sourceLayer);
|
|
577
627
|
}
|
|
578
628
|
|
|
579
629
|
style(options)
|
|
@@ -614,7 +664,7 @@ export class FeatureSmallSymbolLayer extends VectorStyleLayer
|
|
|
614
664
|
|
|
615
665
|
export class BackgroundLayer
|
|
616
666
|
{
|
|
617
|
-
constructor(
|
|
667
|
+
constructor()
|
|
618
668
|
{
|
|
619
669
|
this.__id = 'background';
|
|
620
670
|
}
|
|
@@ -627,7 +677,7 @@ export class BackgroundLayer
|
|
|
627
677
|
style(backgroundColour)
|
|
628
678
|
{
|
|
629
679
|
return {
|
|
630
|
-
'id':
|
|
680
|
+
'id': this.__id,
|
|
631
681
|
'type': 'background',
|
|
632
682
|
'paint': {
|
|
633
683
|
'background-color': backgroundColour,
|
|
@@ -641,9 +691,9 @@ export class BackgroundLayer
|
|
|
641
691
|
|
|
642
692
|
export class RasterLayer
|
|
643
693
|
{
|
|
644
|
-
constructor(
|
|
694
|
+
constructor(id)
|
|
645
695
|
{
|
|
646
|
-
this.__id =
|
|
696
|
+
this.__id = id;
|
|
647
697
|
}
|
|
648
698
|
|
|
649
699
|
get id()
|
package/src/utils.js
CHANGED
|
@@ -109,3 +109,18 @@ export function normaliseId(id)
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
//==============================================================================
|
|
112
|
+
|
|
113
|
+
export function setDefaultOptions(options, defaultOptions)
|
|
114
|
+
{
|
|
115
|
+
if (options === undefined || options === null) {
|
|
116
|
+
return defaultOptions;
|
|
117
|
+
}
|
|
118
|
+
for (const [key, value] of Object.entries(defaultOptions)) {
|
|
119
|
+
if (!(key in options)) {
|
|
120
|
+
options[key] = value;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return options;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
//==============================================================================
|