@abi-software/flatmap-viewer 2.2.10-devel.2 → 2.2.11-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/package.json +2 -2
- package/src/controls.js +174 -22
- package/src/flatmap-viewer.js +65 -18
- package/src/interactions.js +48 -35
- package/src/layers.js +67 -37
- package/src/main.js +1 -5
- package/src/pathways.js +21 -2
- package/src/styling.js +183 -67
- package/static/flatmap-viewer.css +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abi-software/flatmap-viewer",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.11-b.1",
|
|
4
4
|
"description": "Flatmap viewer using Maplibre GL",
|
|
5
5
|
"repository": "https://github.com/AnatomicMaps/flatmap-viewer.git",
|
|
6
6
|
"main": "src/main.js",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"@turf/helpers": "^6.1.4",
|
|
24
24
|
"@turf/projection": "^6.5.0",
|
|
25
25
|
"bezier-js": "^6.1.0",
|
|
26
|
-
"maplibre-gl": ">=
|
|
26
|
+
"maplibre-gl": ">=2.4.0",
|
|
27
27
|
"minisearch": "^2.2.1",
|
|
28
28
|
"polylabel": "^1.1.0"
|
|
29
29
|
},
|
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
|
|
|
@@ -91,10 +90,11 @@ export class NavigationControl
|
|
|
91
90
|
|
|
92
91
|
export class PathControl
|
|
93
92
|
{
|
|
94
|
-
constructor(flatmap)
|
|
93
|
+
constructor(flatmap, pathTypes)
|
|
95
94
|
{
|
|
96
95
|
this._flatmap = flatmap;
|
|
97
96
|
this._map = undefined;
|
|
97
|
+
this.__pathTypes = pathTypes;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
getDefaultPosition()
|
|
@@ -117,12 +117,16 @@ export class PathControl
|
|
|
117
117
|
|
|
118
118
|
const innerHTML = [];
|
|
119
119
|
innerHTML.push(`<label for="path-all-paths">ALL PATHS:</label><div class="nerve-line"></div><input id="path-all-paths" type="checkbox" checked/>`);
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
this.__checkedCount = 0;
|
|
121
|
+
for (const path of this.__pathTypes) {
|
|
122
|
+
const checked = !('enabled' in path) || path.enabled ? 'checked' : '';
|
|
123
|
+
if (checked != '') {
|
|
124
|
+
this.__checkedCount += 1;
|
|
125
|
+
}
|
|
126
|
+
innerHTML.push(`<label for="path-${path.type}">${path.label}</label><div class="nerve-line nerve-${path.type}"></div><input id="path-${path.type}" type="checkbox" ${checked}/>`);
|
|
122
127
|
}
|
|
123
128
|
this._legend.innerHTML = innerHTML.join('\n');
|
|
124
|
-
this.
|
|
125
|
-
this.__halfCount = Math.trunc(this.__checkedCount/2);
|
|
129
|
+
this.__halfCount = Math.trunc(this.__pathTypes.length/2);
|
|
126
130
|
|
|
127
131
|
this._button = document.createElement('button');
|
|
128
132
|
this._button.id = 'nerve-key-button';
|
|
@@ -152,6 +156,9 @@ export class PathControl
|
|
|
152
156
|
if (this._button.getAttribute('control-visible') === 'false') {
|
|
153
157
|
this._container.appendChild(this._legend);
|
|
154
158
|
this._button.setAttribute('control-visible', 'true');
|
|
159
|
+
const allPathsCheckbox = document.getElementById('path-all-paths');
|
|
160
|
+
allPathsCheckbox.indeterminate = this.__checkedCount < this.__pathTypes.length
|
|
161
|
+
&& this.__checkedCount > 0;
|
|
155
162
|
this._legend.focus();
|
|
156
163
|
} else {
|
|
157
164
|
this._legend = this._container.removeChild(this._legend);
|
|
@@ -164,11 +171,11 @@ export class PathControl
|
|
|
164
171
|
event.target.indeterminate = false;
|
|
165
172
|
}
|
|
166
173
|
if (event.target.checked) {
|
|
167
|
-
this.__checkedCount =
|
|
174
|
+
this.__checkedCount = this.__pathTypes.length;
|
|
168
175
|
} else {
|
|
169
176
|
this.__checkedCount = 0;
|
|
170
177
|
}
|
|
171
|
-
for (const path of
|
|
178
|
+
for (const path of this.__pathTypes) {
|
|
172
179
|
const pathCheckbox = document.getElementById(`path-${path.type}`);
|
|
173
180
|
if (pathCheckbox) {
|
|
174
181
|
pathCheckbox.checked = event.target.checked;
|
|
@@ -187,7 +194,7 @@ export class PathControl
|
|
|
187
194
|
if (this.__checkedCount === 0) {
|
|
188
195
|
allPathsCheckbox.checked = false;
|
|
189
196
|
allPathsCheckbox.indeterminate = false;
|
|
190
|
-
} else if (this.__checkedCount ===
|
|
197
|
+
} else if (this.__checkedCount === this.__pathTypes.length) {
|
|
191
198
|
allPathsCheckbox.checked = true;
|
|
192
199
|
allPathsCheckbox.indeterminate = false;
|
|
193
200
|
} else {
|
|
@@ -206,7 +213,7 @@ export class LayerControl
|
|
|
206
213
|
constructor(flatmap, layerManager)
|
|
207
214
|
{
|
|
208
215
|
this.__flatmap = flatmap;
|
|
209
|
-
this.
|
|
216
|
+
this.__layers = layerManager.layers;
|
|
210
217
|
this.__map = undefined;
|
|
211
218
|
}
|
|
212
219
|
|
|
@@ -224,18 +231,18 @@ export class LayerControl
|
|
|
224
231
|
this.__container.className = 'maplibregl-ctrl';
|
|
225
232
|
this.__container.id = 'flatmap-layer-control';
|
|
226
233
|
|
|
227
|
-
this.
|
|
228
|
-
this.
|
|
229
|
-
this.
|
|
234
|
+
this.__layersControl = document.createElement('div');
|
|
235
|
+
this.__layersControl.id = 'layer-control-text';
|
|
236
|
+
this.__layersControl.className = 'flatmap-layer-grid';
|
|
230
237
|
|
|
231
238
|
const innerHTML = [];
|
|
232
239
|
innerHTML.push(`<label for="layer-all-layers">ALL LAYERS:</label><input id="layer-all-layers" type="checkbox" checked/>`);
|
|
233
|
-
for (const layer of this.
|
|
240
|
+
for (const layer of this.__layers) {
|
|
234
241
|
innerHTML.push(`<label for="layer-${layer.id}">${layer.description}</label><input id="layer-${layer.id}" type="checkbox" checked/>`);
|
|
235
242
|
}
|
|
236
|
-
this.
|
|
243
|
+
this.__layersControl.innerHTML = innerHTML.join('\n');
|
|
237
244
|
|
|
238
|
-
this.__layersCount = this.
|
|
245
|
+
this.__layersCount = this.__layers;
|
|
239
246
|
this.__checkedCount = this.__layersCount;
|
|
240
247
|
this.__halfCount = Math.trunc(this.__checkedCount/2);
|
|
241
248
|
|
|
@@ -265,11 +272,11 @@ export class LayerControl
|
|
|
265
272
|
{
|
|
266
273
|
if (event.target.id === 'map-layers-button') {
|
|
267
274
|
if (this.__button.getAttribute('control-visible') === 'false') {
|
|
268
|
-
this.__container.appendChild(this.
|
|
275
|
+
this.__container.appendChild(this.__layersControl);
|
|
269
276
|
this.__button.setAttribute('control-visible', 'true');
|
|
270
|
-
this.
|
|
277
|
+
this.__layersControl.focus();
|
|
271
278
|
} else {
|
|
272
|
-
this.
|
|
279
|
+
this.__layersControl = this.__container.removeChild(this.__layersControl);
|
|
273
280
|
this.__button.setAttribute('control-visible', 'false');
|
|
274
281
|
}
|
|
275
282
|
} else if (event.target.tagName === 'INPUT') {
|
|
@@ -283,16 +290,16 @@ export class LayerControl
|
|
|
283
290
|
} else {
|
|
284
291
|
this.__checkedCount = 0;
|
|
285
292
|
}
|
|
286
|
-
for (const layer of this.
|
|
293
|
+
for (const layer of this.__layers) {
|
|
287
294
|
const layerCheckbox = document.getElementById(`layer-${layer.id}`);
|
|
288
295
|
if (layerCheckbox) {
|
|
289
296
|
layerCheckbox.checked = event.target.checked;
|
|
290
|
-
this.
|
|
297
|
+
this.__flatmap.enableLayer(layer.id, event.target.checked);
|
|
291
298
|
}
|
|
292
299
|
}
|
|
293
300
|
} else if (event.target.id.startsWith('layer-')) {
|
|
294
301
|
const layerId = event.target.id.substring(6);
|
|
295
|
-
this.
|
|
302
|
+
this.__flatmap.enableLayer(layerId, event.target.checked);
|
|
296
303
|
if (event.target.checked) {
|
|
297
304
|
this.__checkedCount += 1;
|
|
298
305
|
} else {
|
|
@@ -316,6 +323,151 @@ export class LayerControl
|
|
|
316
323
|
|
|
317
324
|
//==============================================================================
|
|
318
325
|
|
|
326
|
+
|
|
327
|
+
const SCKAN_STATES = [
|
|
328
|
+
{
|
|
329
|
+
'id': 'VALID',
|
|
330
|
+
'description': 'Path consistent with SCKAN'
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
'id': 'INVALID',
|
|
334
|
+
'description': 'Path inconsistent with SCKAN'
|
|
335
|
+
}
|
|
336
|
+
];
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
export class SCKANControl
|
|
340
|
+
{
|
|
341
|
+
constructor(flatmap)
|
|
342
|
+
{
|
|
343
|
+
this.__flatmap = flatmap;
|
|
344
|
+
this.__map = undefined;
|
|
345
|
+
this.__state = 'valid';
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
getDefaultPosition()
|
|
349
|
+
//==================
|
|
350
|
+
{
|
|
351
|
+
return 'top-right';
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
onAdd(map)
|
|
355
|
+
//========
|
|
356
|
+
{
|
|
357
|
+
this.__map = map;
|
|
358
|
+
this.__container = document.createElement('div');
|
|
359
|
+
this.__container.className = 'maplibregl-ctrl';
|
|
360
|
+
this.__container.id = 'flatmap-layer-control';
|
|
361
|
+
|
|
362
|
+
this.__sckan = document.createElement('div');
|
|
363
|
+
this.__sckan.id = 'sckan-control-text';
|
|
364
|
+
this.__sckan.className = 'flatmap-layer-grid';
|
|
365
|
+
|
|
366
|
+
const innerHTML = [];
|
|
367
|
+
let checked = (this.__state === 'all') ? 'checked' : '';
|
|
368
|
+
innerHTML.push(`<label for="sckan-all-paths">ALL PATHS:</label><input id="sckan-all-paths" type="checkbox" ${checked}/>`);
|
|
369
|
+
for (const state of SCKAN_STATES) {
|
|
370
|
+
checked = (this.__state.toUpperCase() === state.id) ? 'checked' : '';
|
|
371
|
+
innerHTML.push(`<label for="sckan-${state.id}">${state.description}</label><input id="sckan-${state.id}" type="checkbox" ${checked}/>`);
|
|
372
|
+
}
|
|
373
|
+
this.__sckan.innerHTML = innerHTML.join('\n');
|
|
374
|
+
|
|
375
|
+
this.__sckanCount = SCKAN_STATES.length;
|
|
376
|
+
this.__checkedCount = (this.__state === 'all') ? this.__sckanCount
|
|
377
|
+
: (this.__state === 'none') ? 0
|
|
378
|
+
: 1;
|
|
379
|
+
this.__halfCount = Math.trunc(this.__sckanCount/2);
|
|
380
|
+
|
|
381
|
+
this.__button = document.createElement('button');
|
|
382
|
+
this.__button.id = 'map-sckan-button';
|
|
383
|
+
this.__button.className = 'control-button text-button';
|
|
384
|
+
this.__button.setAttribute('type', 'button');
|
|
385
|
+
this.__button.setAttribute('aria-label', 'Show/hide valid SCKAN paths');
|
|
386
|
+
this.__button.setAttribute('control-visible', 'false');
|
|
387
|
+
this.__button.textContent = 'SCKAN';
|
|
388
|
+
this.__button.title = 'Show/hide valid SCKAN paths';
|
|
389
|
+
this.__container.appendChild(this.__button);
|
|
390
|
+
|
|
391
|
+
this.__container.addEventListener('click', this.onClick_.bind(this));
|
|
392
|
+
return this.__container;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
onRemove()
|
|
396
|
+
//========
|
|
397
|
+
{
|
|
398
|
+
this.__container.parentNode.removeChild(this.__container);
|
|
399
|
+
this.__map = undefined;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
onClick_(event)
|
|
403
|
+
//=============
|
|
404
|
+
{
|
|
405
|
+
if (event.target.id === 'map-sckan-button') {
|
|
406
|
+
if (this.__button.getAttribute('control-visible') === 'false') {
|
|
407
|
+
this.__container.appendChild(this.__sckan);
|
|
408
|
+
this.__button.setAttribute('control-visible', 'true');
|
|
409
|
+
const allLayersCheckbox = document.getElementById('sckan-all-paths');
|
|
410
|
+
allLayersCheckbox.indeterminate = this.__state.toLowerCase().includes('valid');
|
|
411
|
+
this.__sckan.focus();
|
|
412
|
+
} else {
|
|
413
|
+
this.__sckan = this.__container.removeChild(this.__sckan);
|
|
414
|
+
this.__button.setAttribute('control-visible', 'false');
|
|
415
|
+
}
|
|
416
|
+
} else if (event.target.tagName === 'INPUT') {
|
|
417
|
+
if (event.target.id === 'sckan-all-paths') {
|
|
418
|
+
if (event.target.indeterminate) {
|
|
419
|
+
event.target.checked = (this.__checkedCount >= this.__halfCount);
|
|
420
|
+
event.target.indeterminate = false;
|
|
421
|
+
}
|
|
422
|
+
if (event.target.checked) {
|
|
423
|
+
this.__state = 'all';
|
|
424
|
+
this.__checkedCount = this.__sckanCount;
|
|
425
|
+
} else {
|
|
426
|
+
this.__state = 'none';
|
|
427
|
+
this.__checkedCount = 0;
|
|
428
|
+
}
|
|
429
|
+
for (const state of SCKAN_STATES) {
|
|
430
|
+
const sckanCheckbox = document.getElementById(`sckan-${state.id}`);
|
|
431
|
+
if (sckanCheckbox) {
|
|
432
|
+
sckanCheckbox.checked = event.target.checked;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
this.__flatmap.showSckanPaths(this.__state);
|
|
436
|
+
} else if (event.target.id.startsWith('sckan-')) {
|
|
437
|
+
const sckanId = event.target.id.substring(6);
|
|
438
|
+
if (event.target.checked) {
|
|
439
|
+
this.__checkedCount += 1;
|
|
440
|
+
} else {
|
|
441
|
+
this.__checkedCount -= 1;
|
|
442
|
+
}
|
|
443
|
+
const allLayersCheckbox = document.getElementById('sckan-all-paths');
|
|
444
|
+
if (this.__checkedCount === 0) {
|
|
445
|
+
this.__state = 'none';
|
|
446
|
+
allLayersCheckbox.checked = false;
|
|
447
|
+
allLayersCheckbox.indeterminate = false;
|
|
448
|
+
} else if (this.__checkedCount === this.__sckanCount) {
|
|
449
|
+
this.__state = 'all';
|
|
450
|
+
allLayersCheckbox.checked = true;
|
|
451
|
+
allLayersCheckbox.indeterminate = false;
|
|
452
|
+
} else {
|
|
453
|
+
if (event.target.checked) {
|
|
454
|
+
this.__state = sckanId;
|
|
455
|
+
} else if (sckanId === 'VALID') {
|
|
456
|
+
this.__state = 'invalid';
|
|
457
|
+
} else {
|
|
458
|
+
this.__state = 'valid';
|
|
459
|
+
}
|
|
460
|
+
allLayersCheckbox.indeterminate = true;
|
|
461
|
+
}
|
|
462
|
+
this.__flatmap.showSckanPaths(this.__state);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
event.stopPropagation();
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
//==============================================================================
|
|
470
|
+
|
|
319
471
|
export class BackgroundControl
|
|
320
472
|
{
|
|
321
473
|
constructor(flatmap)
|
package/src/flatmap-viewer.js
CHANGED
|
@@ -314,6 +314,21 @@ class FlatMap
|
|
|
314
314
|
}
|
|
315
315
|
}
|
|
316
316
|
|
|
317
|
+
/**
|
|
318
|
+
* Hide or show all paths valid in SCKAN.
|
|
319
|
+
*
|
|
320
|
+
* @param {string} validity Either ``VALID`` or ``INVALID``
|
|
321
|
+
* @param {boolean} [enable=true] If ``true`` then only show the paths
|
|
322
|
+
* of the type(s) otherwise only hide the paths
|
|
323
|
+
*/
|
|
324
|
+
showSckanPaths(state='valid')
|
|
325
|
+
//===========================
|
|
326
|
+
{
|
|
327
|
+
if (this._userInteractions !== null) {
|
|
328
|
+
this._userInteractions.showSckanPaths(state);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
317
332
|
/**
|
|
318
333
|
* Load images and patterns/textures referenced in style rules.
|
|
319
334
|
*
|
|
@@ -428,12 +443,6 @@ class FlatMap
|
|
|
428
443
|
return `${this.__uuid}-${this._mapNumber}`;
|
|
429
444
|
}
|
|
430
445
|
|
|
431
|
-
get activeLayerNames()
|
|
432
|
-
//====================
|
|
433
|
-
{
|
|
434
|
-
return this._userInteractions.activeLayerNames;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
446
|
get annotations()
|
|
438
447
|
//===============
|
|
439
448
|
{
|
|
@@ -739,6 +748,34 @@ class FlatMap
|
|
|
739
748
|
|
|
740
749
|
//==========================================================================
|
|
741
750
|
|
|
751
|
+
/**
|
|
752
|
+
* Get a list of the flatmap's layers.
|
|
753
|
+
*
|
|
754
|
+
* @return {Array.Object.<{id: string, description: string, enabled: boolean}>} An array with layer details
|
|
755
|
+
*/
|
|
756
|
+
getLayers()
|
|
757
|
+
//=========
|
|
758
|
+
{
|
|
759
|
+
if (this._userInteractions !== null) {
|
|
760
|
+
return this._userInteractions.getLayers();
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
/**
|
|
765
|
+
* @param {string} layerId The layer identifier to enable
|
|
766
|
+
* @param {boolean} enable Show or hide the layer. Defaults to ``true`` (show)
|
|
767
|
+
*
|
|
768
|
+
*/
|
|
769
|
+
enableLayer(layerId, enable=true)
|
|
770
|
+
//===============================
|
|
771
|
+
{
|
|
772
|
+
if (this._userInteractions !== null) {
|
|
773
|
+
return this._userInteractions.enableLayer(layerId, enable);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
//==========================================================================
|
|
778
|
+
|
|
742
779
|
/**
|
|
743
780
|
* Add a marker to the map.
|
|
744
781
|
*
|
|
@@ -836,13 +873,21 @@ class FlatMap
|
|
|
836
873
|
'label',
|
|
837
874
|
'models',
|
|
838
875
|
'nodeId',
|
|
839
|
-
'source'
|
|
876
|
+
'source',
|
|
877
|
+
'hyperlinks'
|
|
878
|
+
];
|
|
879
|
+
const jsonProperties = [
|
|
880
|
+
'hyperlinks'
|
|
840
881
|
];
|
|
841
882
|
for (const property of exportedProperties) {
|
|
842
883
|
if (property in properties) {
|
|
843
884
|
const value = properties[property];
|
|
844
885
|
if (value !== undefined) {
|
|
845
|
-
|
|
886
|
+
if (jsonProperties.indexOf(property) >= 0) {
|
|
887
|
+
data[property] = JSON.parse(properties[property])
|
|
888
|
+
} else {
|
|
889
|
+
data[property] = properties[property];
|
|
890
|
+
}
|
|
846
891
|
}
|
|
847
892
|
}
|
|
848
893
|
}
|
|
@@ -1168,13 +1213,12 @@ export class MapManager
|
|
|
1168
1213
|
* @arg options {Object} Configurable options for the map.
|
|
1169
1214
|
* @arg options.background {string} Background colour of flatmap. Defaults to ``white``.
|
|
1170
1215
|
* @arg options.debug {boolean} Enable debugging mode.
|
|
1171
|
-
* @arg options.featureInfo {boolean} Show information about features as a tooltip. The tooltip is active
|
|
1172
|
-
* on selected features and, for non-selected features, when the
|
|
1173
|
-
* ``info`` control is enabled. More details are shown in debug mode.
|
|
1174
1216
|
* @arg options.fullscreenControl {boolean} Add a ``Show full screen`` button to the map.
|
|
1175
1217
|
* @arg options.layerOptions {Object} Options to control colour and outlines of features
|
|
1176
1218
|
* @arg options.layerOptions.colour {boolean} Use colour fill (if available) for features. Defaults to ``true``.
|
|
1177
1219
|
* @arg options.layerOptions.outline {boolean} Show the border of features. Defaults to ``true``.
|
|
1220
|
+
* @arg options.layerOptions.sckan {string} Show neuron paths known to SCKAN: values are ``valid`` (default),
|
|
1221
|
+
* ``invalid``, ``all`` or ``none``.
|
|
1178
1222
|
* @arg options.minimap {boolean|Object} Display a MiniMap of the flatmap. Defaults to ``false``.
|
|
1179
1223
|
* @arg options.minimap.position {string} The minimap's position: ``bottom-left`` (default), ``bottom-right``,
|
|
1180
1224
|
* ``top-left`` or ``top-right``.
|
|
@@ -1185,9 +1229,9 @@ export class MapManager
|
|
|
1185
1229
|
* @arg options.maxZoom {number} The maximum zoom level of the map.
|
|
1186
1230
|
* @arg options.minZoom {number} The minimum zoom level of the map.
|
|
1187
1231
|
* @arg options.navigationControl {boolean} Add navigation controls (zoom buttons) to the map.
|
|
1188
|
-
* @arg options.pathControl {boolean} Add buttons to control pathways including via a color-coded legend.
|
|
1189
|
-
* @arg options.searchable {boolean} Add a control to search for features on a map.
|
|
1190
1232
|
* @arg options.showPosition {boolean} Show ``position`` of tooltip.
|
|
1233
|
+
* @arg options.standalone {boolean} Viewer is running ``standalone``, as opposed to integrated into
|
|
1234
|
+
* another application so show a number of controls. Defaults to ``false``.
|
|
1191
1235
|
* @example
|
|
1192
1236
|
* const humanMap1 = mapManager.loadMap('humanV1', 'div-1');
|
|
1193
1237
|
*
|
|
@@ -1225,6 +1269,14 @@ export class MapManager
|
|
|
1225
1269
|
mapOptions['bounds'] = mapIndex['bounds'];
|
|
1226
1270
|
}
|
|
1227
1271
|
|
|
1272
|
+
// Note the kind of map
|
|
1273
|
+
|
|
1274
|
+
if ('style' in mapIndex) {
|
|
1275
|
+
mapOptions.style = mapIndex.style; // Currently ``flatmap`` or ``fcdiagram``
|
|
1276
|
+
} else {
|
|
1277
|
+
mapOptions.style = 'flatmap';
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1228
1280
|
// Mapmaker has changed the name of the field to indicate that indicates if
|
|
1229
1281
|
// there are raster layers
|
|
1230
1282
|
if (!('image-layers' in mapIndex) && ('image_layer' in mapIndex)) {
|
|
@@ -1300,11 +1352,6 @@ export class MapManager
|
|
|
1300
1352
|
};
|
|
1301
1353
|
}
|
|
1302
1354
|
mapOptions.layerOptions.authoring = ('authoring' in mapIndex) ? mapIndex.authoring : false;
|
|
1303
|
-
if ('style' in mapIndex) {
|
|
1304
|
-
mapOptions.layerOptions.style = mapIndex.style;
|
|
1305
|
-
} else {
|
|
1306
|
-
mapOptions.layerOptions.style = 'flatmap';
|
|
1307
|
-
}
|
|
1308
1355
|
|
|
1309
1356
|
// Are features in separate vector tile source layers?
|
|
1310
1357
|
|
package/src/interactions.js
CHANGED
|
@@ -37,8 +37,8 @@ import {ContextMenu} from './contextmenu.js';
|
|
|
37
37
|
import {displayedProperties} from './info.js';
|
|
38
38
|
import {InfoControl} from './info.js';
|
|
39
39
|
import {LayerManager} from './layers.js';
|
|
40
|
-
import {PATHWAYS_LAYER, Pathways} from './pathways.js';
|
|
41
|
-
import {BackgroundControl, LayerControl, PathControl} from './controls.js';
|
|
40
|
+
import {PATH_TYPES, PATHWAYS_LAYER, Pathways} from './pathways.js';
|
|
41
|
+
import {BackgroundControl, LayerControl, PathControl, SCKANControl} from './controls.js';
|
|
42
42
|
import {SearchControl} from './search.js';
|
|
43
43
|
import {VECTOR_TILES_SOURCE} from './styling.js';
|
|
44
44
|
|
|
@@ -130,46 +130,47 @@ export class UserInteractions
|
|
|
130
130
|
|
|
131
131
|
flatmap.setInitialPosition();
|
|
132
132
|
|
|
133
|
-
// Add a control to search annotations if option set
|
|
134
|
-
|
|
135
|
-
if (flatmap.options.searchable) {
|
|
136
|
-
this._map.addControl(new SearchControl(flatmap));
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Show information about features
|
|
140
|
-
|
|
141
|
-
if (flatmap.options.featureInfo || flatmap.options.searchable) {
|
|
142
|
-
this._infoControl = new InfoControl(flatmap);
|
|
143
|
-
if (flatmap.options.featureInfo) {
|
|
144
|
-
this._map.addControl(this._infoControl);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
133
|
// Add and manage our layers
|
|
149
134
|
|
|
150
135
|
this._layerManager = new LayerManager(flatmap);
|
|
151
136
|
|
|
152
|
-
//
|
|
137
|
+
// Path visibility is either controlled externally or by a local control
|
|
153
138
|
|
|
154
|
-
|
|
155
|
-
|
|
139
|
+
this._pathways = new Pathways(flatmap);
|
|
140
|
+
|
|
141
|
+
// The path types in this map
|
|
142
|
+
const mapPathTypes = this._pathways.pathTypes;
|
|
143
|
+
|
|
144
|
+
// Disable paths that are not initially shown
|
|
145
|
+
for (const path of mapPathTypes) {
|
|
146
|
+
if ('enabled' in path && !path.enabled) {
|
|
147
|
+
this.enablePath(path.type, false);
|
|
148
|
+
}
|
|
156
149
|
}
|
|
157
150
|
|
|
158
|
-
//
|
|
159
|
-
// or by our local controls
|
|
151
|
+
// Add various controls when running standalone
|
|
160
152
|
|
|
161
|
-
|
|
153
|
+
if (flatmap.options.standalone) {
|
|
154
|
+
// Add a control to search annotations if option set
|
|
155
|
+
this._map.addControl(new SearchControl(flatmap));
|
|
162
156
|
|
|
163
|
-
|
|
157
|
+
// Show information about features
|
|
158
|
+
this._infoControl = new InfoControl(flatmap);
|
|
159
|
+
this._map.addControl(this._infoControl);
|
|
164
160
|
|
|
165
|
-
|
|
166
|
-
this._map.addControl(new
|
|
167
|
-
}
|
|
161
|
+
// Control background colour (NB. this depends on having map layers created)
|
|
162
|
+
this._map.addControl(new BackgroundControl(flatmap));
|
|
168
163
|
|
|
169
|
-
|
|
164
|
+
// Add a control to manage our paths
|
|
165
|
+
this._map.addControl(new PathControl(flatmap, mapPathTypes));
|
|
170
166
|
|
|
171
|
-
|
|
167
|
+
// Add a control to manage our layers
|
|
172
168
|
this._map.addControl(new LayerControl(flatmap, this._layerManager));
|
|
169
|
+
|
|
170
|
+
// A SCKAN path control for FC maps
|
|
171
|
+
if (flatmap.options.style === 'fcdiagram') {
|
|
172
|
+
this._map.addControl(new SCKANControl(flatmap));
|
|
173
|
+
}
|
|
173
174
|
}
|
|
174
175
|
|
|
175
176
|
// Flag features that have annotations
|
|
@@ -220,7 +221,7 @@ export class UserInteractions
|
|
|
220
221
|
return {
|
|
221
222
|
center: this._map.getCenter().toArray(),
|
|
222
223
|
zoom: this._map.getZoom(),
|
|
223
|
-
layers: this.
|
|
224
|
+
layers: this.layers
|
|
224
225
|
};
|
|
225
226
|
}
|
|
226
227
|
|
|
@@ -252,10 +253,16 @@ export class UserInteractions
|
|
|
252
253
|
this._layerManager.setColour(options);
|
|
253
254
|
}
|
|
254
255
|
|
|
255
|
-
|
|
256
|
-
|
|
256
|
+
getLayers()
|
|
257
|
+
//=========
|
|
257
258
|
{
|
|
258
|
-
return this._layerManager.
|
|
259
|
+
return this._layerManager.layers;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
enableLayer(layerId, enable=true)
|
|
263
|
+
//===============================
|
|
264
|
+
{
|
|
265
|
+
this._layerManager.activate(layerId, enable);
|
|
259
266
|
}
|
|
260
267
|
|
|
261
268
|
mapFeature_(featureId)
|
|
@@ -672,9 +679,9 @@ export class UserInteractions
|
|
|
672
679
|
: '';
|
|
673
680
|
if ('hyperlink' in properties) {
|
|
674
681
|
if (label === '') {
|
|
675
|
-
return `<div class='flatmap-feature-label'><a href='{properties.hyperlink}'>${properties.hyperlink}</a></div>`;
|
|
682
|
+
return `<div class='flatmap-feature-label'><a href='${properties.hyperlink}'>${properties.hyperlink}</a></div>`;
|
|
676
683
|
} else {
|
|
677
|
-
return `<div class='flatmap-feature-label'><a href='{properties.hyperlink}'>${
|
|
684
|
+
return `<div class='flatmap-feature-label'><a href='${properties.hyperlink}'>${label}</a></div>`;
|
|
678
685
|
}
|
|
679
686
|
} else {
|
|
680
687
|
return `<div class='flatmap-feature-label'>${label}</div>`;
|
|
@@ -1021,6 +1028,12 @@ export class UserInteractions
|
|
|
1021
1028
|
return this._pathways.nodePathModels(nodeId);
|
|
1022
1029
|
}
|
|
1023
1030
|
|
|
1031
|
+
showSckanPaths(state='valid')
|
|
1032
|
+
//===========================
|
|
1033
|
+
{
|
|
1034
|
+
this._layerManager.setFilter({sckan: state});
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1024
1037
|
//==============================================================================
|
|
1025
1038
|
|
|
1026
1039
|
// Find where to place a label or popup on a feature
|
package/src/layers.js
CHANGED
|
@@ -35,12 +35,13 @@ const RASTER_LAYERS_ID = 'background-image-layer';
|
|
|
35
35
|
|
|
36
36
|
class MapStylingLayers
|
|
37
37
|
{
|
|
38
|
-
constructor(flatmap,
|
|
38
|
+
constructor(flatmap, layer, options)
|
|
39
39
|
{
|
|
40
40
|
this.__map = flatmap.map;
|
|
41
|
-
this.__id =
|
|
42
|
-
this.
|
|
41
|
+
this.__id = layer.id;
|
|
42
|
+
this.__description = layer.description;
|
|
43
43
|
this.__active = true;
|
|
44
|
+
this.__layers = [];
|
|
44
45
|
this.__layerOptions = options;
|
|
45
46
|
this.__separateLayers = flatmap.options.separateLayers;
|
|
46
47
|
}
|
|
@@ -51,6 +52,12 @@ class MapStylingLayers
|
|
|
51
52
|
return this.__id;
|
|
52
53
|
}
|
|
53
54
|
|
|
55
|
+
get description()
|
|
56
|
+
//===============
|
|
57
|
+
{
|
|
58
|
+
return this.__description;
|
|
59
|
+
}
|
|
60
|
+
|
|
54
61
|
get active()
|
|
55
62
|
//==========
|
|
56
63
|
{
|
|
@@ -85,6 +92,16 @@ class MapStylingLayers
|
|
|
85
92
|
return this.__separateLayers ? `${this.__id}_${sourceLayer}`
|
|
86
93
|
: sourceLayer;
|
|
87
94
|
}
|
|
95
|
+
|
|
96
|
+
setColour(options)
|
|
97
|
+
{
|
|
98
|
+
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
setFilter(options)
|
|
102
|
+
{
|
|
103
|
+
|
|
104
|
+
}
|
|
88
105
|
}
|
|
89
106
|
|
|
90
107
|
//==============================================================================
|
|
@@ -93,7 +110,7 @@ class MapFeatureLayers extends MapStylingLayers
|
|
|
93
110
|
{
|
|
94
111
|
constructor(flatmap, layer, options)
|
|
95
112
|
{
|
|
96
|
-
super(flatmap, layer
|
|
113
|
+
super(flatmap, layer, options);
|
|
97
114
|
const vectorTileSource = this.__map.getSource('vector-tiles');
|
|
98
115
|
const haveVectorLayers = (typeof vectorTileSource !== 'undefined');
|
|
99
116
|
|
|
@@ -108,7 +125,7 @@ class MapFeatureLayers extends MapStylingLayers
|
|
|
108
125
|
this.__addStyleLayer(style.FeatureLineLayer);
|
|
109
126
|
this.__addStyleLayer(style.FeatureBorderLayer);
|
|
110
127
|
}
|
|
111
|
-
this.__addPathwayStyleLayers(
|
|
128
|
+
this.__addPathwayStyleLayers();
|
|
112
129
|
if (vectorFeatures) {
|
|
113
130
|
this.__addStyleLayer(style.FeatureLargeSymbolLayer);
|
|
114
131
|
if (!flatmap.options.tooltips) {
|
|
@@ -138,8 +155,12 @@ class MapFeatureLayers extends MapStylingLayers
|
|
|
138
155
|
if (this.__map.getSource('vector-tiles')
|
|
139
156
|
.vectorLayerIds
|
|
140
157
|
.indexOf(pathwaysVectorSource) >= 0) {
|
|
158
|
+
this.__addStyleLayer(style.CentrelineEdgeLayer, PATHWAYS_LAYER);
|
|
159
|
+
this.__addStyleLayer(style.CentrelineTrackLayer, PATHWAYS_LAYER);
|
|
160
|
+
|
|
141
161
|
this.__addStyleLayer(style.PathLineLayer, PATHWAYS_LAYER);
|
|
142
162
|
this.__addStyleLayer(style.PathDashlineLayer, PATHWAYS_LAYER);
|
|
163
|
+
|
|
143
164
|
this.__addStyleLayer(style.NervePolygonBorder, PATHWAYS_LAYER);
|
|
144
165
|
this.__addStyleLayer(style.NervePolygonFill, PATHWAYS_LAYER);
|
|
145
166
|
this.__addStyleLayer(style.FeatureNerveLayer, PATHWAYS_LAYER);
|
|
@@ -156,6 +177,17 @@ class MapFeatureLayers extends MapStylingLayers
|
|
|
156
177
|
}
|
|
157
178
|
}
|
|
158
179
|
}
|
|
180
|
+
|
|
181
|
+
setFilter(options)
|
|
182
|
+
//================
|
|
183
|
+
{
|
|
184
|
+
for (const layer of this.__layers) {
|
|
185
|
+
const filter = layer.makeFilter(options);
|
|
186
|
+
if (filter !== null) {
|
|
187
|
+
this.__map.setFilter(layer.id, filter, {validate: true});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
159
191
|
}
|
|
160
192
|
|
|
161
193
|
//==============================================================================
|
|
@@ -164,7 +196,11 @@ class MapRasterLayers extends MapStylingLayers
|
|
|
164
196
|
{
|
|
165
197
|
constructor(flatmap, options, bodyLayerId=null)
|
|
166
198
|
{
|
|
167
|
-
|
|
199
|
+
const rasterLayer = {
|
|
200
|
+
id: RASTER_LAYERS_ID,
|
|
201
|
+
description: RASTER_LAYERS_NAME
|
|
202
|
+
};
|
|
203
|
+
super(flatmap, rasterLayer, options);
|
|
168
204
|
if (bodyLayerId !== null) {
|
|
169
205
|
const layerId = `${bodyLayerId}_${FEATURES_LAYER}`;
|
|
170
206
|
const source = flatmap.options.separateLayers ? layerId : FEATURES_LAYER;
|
|
@@ -209,11 +245,11 @@ export class LayerManager
|
|
|
209
245
|
{
|
|
210
246
|
this.__flatmap = flatmap;
|
|
211
247
|
this.__map = flatmap.map;
|
|
212
|
-
this.__layers = new Map;
|
|
213
248
|
this.__mapLayers = new Map;
|
|
214
249
|
this.__layerOptions = utils.setDefaults(flatmap.options.layerOptions, {
|
|
215
250
|
colour: true,
|
|
216
|
-
outline: true
|
|
251
|
+
outline: true,
|
|
252
|
+
sckan: 'valid'
|
|
217
253
|
});;
|
|
218
254
|
const backgroundLayer = new style.BackgroundLayer();
|
|
219
255
|
if ('background' in flatmap.options) {
|
|
@@ -234,44 +270,29 @@ export class LayerManager
|
|
|
234
270
|
for (const layer of flatmap.layers) {
|
|
235
271
|
rasterLayers.addLayer(layer);
|
|
236
272
|
}
|
|
237
|
-
this.__layers.set(RASTER_LAYERS_ID, {
|
|
238
|
-
id: RASTER_LAYERS_ID,
|
|
239
|
-
description: RASTER_LAYERS_NAME
|
|
240
|
-
});
|
|
241
273
|
this.__mapLayers.set(RASTER_LAYERS_ID, rasterLayers);
|
|
242
274
|
} else {
|
|
243
275
|
this.__layerOptions.activeRasterLayer = false;
|
|
244
276
|
}
|
|
245
277
|
for (const layer of flatmap.layers) {
|
|
246
|
-
|
|
278
|
+
this.__mapLayers.set(layer.id, new MapFeatureLayers(this.__flatmap,
|
|
279
|
+
layer,
|
|
280
|
+
this.__layerOptions));
|
|
247
281
|
}
|
|
248
282
|
}
|
|
249
283
|
|
|
250
|
-
get activeLayerNames()
|
|
251
|
-
//====================
|
|
252
|
-
{
|
|
253
|
-
const activeNames = [];
|
|
254
|
-
for (const mapLayer of this.__mapLayers.values()) {
|
|
255
|
-
if (mapLayer.active) {
|
|
256
|
-
activeNames.push(mapLayer.id);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
return activeNames;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
__addFeatureLayer(layer)
|
|
263
|
-
//======================
|
|
264
|
-
{
|
|
265
|
-
this.__layers.set(layer.id, layer);
|
|
266
|
-
this.__mapLayers.set(layer.id, new MapFeatureLayers(this.__flatmap,
|
|
267
|
-
layer,
|
|
268
|
-
this.__layerOptions));
|
|
269
|
-
}
|
|
270
|
-
|
|
271
284
|
get layers()
|
|
272
285
|
//==========
|
|
273
286
|
{
|
|
274
|
-
|
|
287
|
+
const layers = [];
|
|
288
|
+
for (const mapLayer of this.__mapLayers.values()) {
|
|
289
|
+
layers.push({
|
|
290
|
+
id: mapLayer.id,
|
|
291
|
+
description: mapLayer.description,
|
|
292
|
+
enabled: mapLayer.active
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
return layers;
|
|
275
296
|
}
|
|
276
297
|
|
|
277
298
|
activate(layerId, enable=true)
|
|
@@ -291,14 +312,23 @@ export class LayerManager
|
|
|
291
312
|
}
|
|
292
313
|
}
|
|
293
314
|
|
|
294
|
-
setColour(options=
|
|
295
|
-
|
|
315
|
+
setColour(options={})
|
|
316
|
+
//===================
|
|
296
317
|
{
|
|
297
318
|
this.__layerOptions = utils.setDefaults(options, this.__layerOptions);
|
|
298
319
|
for (const mapLayer of this.__mapLayers.values()) {
|
|
299
320
|
mapLayer.setColour(this.__layerOptions);
|
|
300
321
|
}
|
|
301
322
|
}
|
|
323
|
+
|
|
324
|
+
setFilter(options={})
|
|
325
|
+
//===================
|
|
326
|
+
{
|
|
327
|
+
this.__layerOptions = utils.setDefaults(options, this.__layerOptions);
|
|
328
|
+
for (const mapLayer of this.__mapLayers.values()) {
|
|
329
|
+
mapLayer.setFilter(this.__layerOptions);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
302
332
|
}
|
|
303
333
|
|
|
304
334
|
//==============================================================================
|
package/src/main.js
CHANGED
|
@@ -57,14 +57,10 @@ export async function standaloneViewer(map_endpoint=null, options={})
|
|
|
57
57
|
const mapOptions = Object.assign({
|
|
58
58
|
tooltips: true,
|
|
59
59
|
background: defaultBackground,
|
|
60
|
-
backgroundControl: true,
|
|
61
60
|
debug: false,
|
|
62
61
|
minimap: false,
|
|
63
|
-
searchable: true,
|
|
64
|
-
featureInfo: true,
|
|
65
62
|
showPosition: false,
|
|
66
|
-
|
|
67
|
-
layerControl: true
|
|
63
|
+
standalone: true
|
|
68
64
|
}, options);
|
|
69
65
|
|
|
70
66
|
function loadMap(id, taxon, sex)
|
package/src/pathways.js
CHANGED
|
@@ -28,16 +28,22 @@ export const PATHWAYS_LAYER = 'pathways';
|
|
|
28
28
|
|
|
29
29
|
export const PATH_TYPES = [
|
|
30
30
|
{ type: "cns", label: "CNS", colour: "#9B1FC1"},
|
|
31
|
-
{ type: "
|
|
31
|
+
{ type: "intracardiac", label: "Local circuit neuron", colour: "#F19E38"},
|
|
32
32
|
{ type: "para-pre", label: "Parasympathetic pre-ganglionic", colour: "#3F8F4A"},
|
|
33
33
|
{ type: "para-post", label: "Parasympathetic post-ganglionic", colour: "#3F8F4A"},
|
|
34
34
|
{ type: "sensory", label: "Sensory (afferent) neuron", colour: "#2A62F6"},
|
|
35
35
|
{ type: "somatic", label: "Somatic lower motor", colour: "#98561D"},
|
|
36
36
|
{ type: "symp-pre", label: "Sympathetic pre-ganglionic", colour: "#EA3423"},
|
|
37
37
|
{ type: "symp-post", label: "Sympathetic post-ganglionic", colour: "#EA3423"},
|
|
38
|
-
{ type: "other", label: "Other neuron type", colour: "#888"}
|
|
38
|
+
{ type: "other", label: "Other neuron type", colour: "#888"},
|
|
39
|
+
{ type: "arterial", label: "Arterial blood vessel", colour: "#F00"},
|
|
40
|
+
{ type: "venous", label: "Venous blood vessel", colour: "#2F6EBA"},
|
|
41
|
+
{ type: "centreline", label: "Nerve centrelines", colour: "#2F6EBA", enabled: false}
|
|
39
42
|
];
|
|
40
43
|
|
|
44
|
+
export const PATH_STYLE_RULES =
|
|
45
|
+
PATH_TYPES.flatMap(pathType => [['==', ['get', 'kind'], pathType.type], pathType.colour]);
|
|
46
|
+
|
|
41
47
|
//==============================================================================
|
|
42
48
|
|
|
43
49
|
function reverseMap(mapping)
|
|
@@ -138,6 +144,19 @@ export class Pathways
|
|
|
138
144
|
}
|
|
139
145
|
}
|
|
140
146
|
|
|
147
|
+
get pathTypes()
|
|
148
|
+
//=============
|
|
149
|
+
{
|
|
150
|
+
const pathTypes = [];
|
|
151
|
+
for (const pathType of PATH_TYPES) {
|
|
152
|
+
if (pathType.type in this.__typePaths
|
|
153
|
+
&& this.__typePaths[pathType.type].length > 0) {
|
|
154
|
+
pathTypes.push(pathType);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return pathTypes;
|
|
158
|
+
}
|
|
159
|
+
|
|
141
160
|
addPathsToFeatureSet_(paths, featureSet)
|
|
142
161
|
//======================================
|
|
143
162
|
{
|
package/src/styling.js
CHANGED
|
@@ -26,6 +26,10 @@ export const VECTOR_TILES_SOURCE = 'vector-tiles';
|
|
|
26
26
|
|
|
27
27
|
//==============================================================================
|
|
28
28
|
|
|
29
|
+
import {PATH_STYLE_RULES} from './pathways.js';
|
|
30
|
+
|
|
31
|
+
//==============================================================================
|
|
32
|
+
|
|
29
33
|
class VectorStyleLayer
|
|
30
34
|
{
|
|
31
35
|
constructor(id, suffix, sourceLayer)
|
|
@@ -40,6 +44,11 @@ class VectorStyleLayer
|
|
|
40
44
|
return this.__id;
|
|
41
45
|
}
|
|
42
46
|
|
|
47
|
+
makeFilter(options)
|
|
48
|
+
{
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
43
52
|
paintStyle(options, changes=false)
|
|
44
53
|
{
|
|
45
54
|
return {};
|
|
@@ -130,7 +139,8 @@ export class FeatureFillLayer extends VectorStyleLayer
|
|
|
130
139
|
'fill-opacity': [
|
|
131
140
|
'case',
|
|
132
141
|
['boolean', ['feature-state', 'selected'], false], 0.7,
|
|
133
|
-
['has', '
|
|
142
|
+
['has', 'opacity'], ['get', 'opacity'],
|
|
143
|
+
['has', 'colour'], 1.0,
|
|
134
144
|
['boolean', ['feature-state', 'active'], false], 0.7,
|
|
135
145
|
['has', 'node'], 0.3,
|
|
136
146
|
['any',
|
|
@@ -179,7 +189,7 @@ export class FeatureBorderLayer extends VectorStyleLayer
|
|
|
179
189
|
const activeRasterLayer = 'activeRasterLayer' in options && options.activeRasterLayer;
|
|
180
190
|
const lineColour = [ 'case' ];
|
|
181
191
|
lineColour.push(['boolean', ['feature-state', 'selected'], false]);
|
|
182
|
-
lineColour.push('
|
|
192
|
+
lineColour.push('black');
|
|
183
193
|
if (coloured && outlined) {
|
|
184
194
|
lineColour.push(['boolean', ['feature-state', 'active'], false]);
|
|
185
195
|
lineColour.push('blue');
|
|
@@ -245,26 +255,32 @@ export class FeatureBorderLayer extends VectorStyleLayer
|
|
|
245
255
|
|
|
246
256
|
export class FeatureLineLayer extends VectorStyleLayer
|
|
247
257
|
{
|
|
248
|
-
constructor(id, sourceLayer,
|
|
258
|
+
constructor(id, sourceLayer, options={})
|
|
249
259
|
{
|
|
260
|
+
const dashed = ('dashed' in options && options.dashed);
|
|
250
261
|
const filterType = dashed ? 'line-dash' : 'line';
|
|
251
262
|
super(id, `feature-${filterType}`, sourceLayer);
|
|
252
|
-
this.
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
263
|
+
this.__dashed = dashed;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
makeFilter(options={})
|
|
267
|
+
{
|
|
268
|
+
return this.__dashed ? [
|
|
269
|
+
'all',
|
|
270
|
+
['==', '$type', 'LineString'],
|
|
271
|
+
['==', 'type', `line-dash`]
|
|
272
|
+
] : [
|
|
273
|
+
'all',
|
|
274
|
+
['==', '$type', 'LineString'],
|
|
258
275
|
[
|
|
259
276
|
'any',
|
|
260
|
-
['has', 'centreline'],
|
|
261
277
|
['==', 'type', 'bezier'],
|
|
262
278
|
['==', 'type', `line`]
|
|
263
|
-
]
|
|
264
|
-
|
|
279
|
+
]
|
|
280
|
+
];
|
|
265
281
|
}
|
|
266
282
|
|
|
267
|
-
paintStyle(options)
|
|
283
|
+
paintStyle(options, changes=false)
|
|
268
284
|
{
|
|
269
285
|
const coloured = !('colour' in options) || options.colour;
|
|
270
286
|
const paintStyle = {
|
|
@@ -274,7 +290,6 @@ export class FeatureLineLayer extends VectorStyleLayer
|
|
|
274
290
|
['has', 'colour'], ['get', 'colour'],
|
|
275
291
|
['boolean', ['feature-state', 'active'], false], coloured ? '#888' : '#CCC',
|
|
276
292
|
['==', ['get', 'type'], 'network'], '#AFA202',
|
|
277
|
-
['has', 'centreline'], '#888',
|
|
278
293
|
options.authoring ? '#C44' : '#444'
|
|
279
294
|
],
|
|
280
295
|
'line-opacity': [
|
|
@@ -288,7 +303,6 @@ export class FeatureLineLayer extends VectorStyleLayer
|
|
|
288
303
|
'let',
|
|
289
304
|
'width', [
|
|
290
305
|
'case',
|
|
291
|
-
['has', 'centreline'], 1.2,
|
|
292
306
|
['==', ['get', 'type'], 'network'], 1.2,
|
|
293
307
|
['boolean', ['feature-state', 'selected'], false], 1.2,
|
|
294
308
|
['boolean', ['feature-state', 'active'], false], 1.2,
|
|
@@ -308,7 +322,7 @@ export class FeatureLineLayer extends VectorStyleLayer
|
|
|
308
322
|
if (this.__dashed) {
|
|
309
323
|
paintStyle['line-dasharray'] = [3, 2];
|
|
310
324
|
}
|
|
311
|
-
return paintStyle;
|
|
325
|
+
return super.changedPaintStyle(paintStyle, changes);
|
|
312
326
|
}
|
|
313
327
|
|
|
314
328
|
style(options)
|
|
@@ -316,12 +330,7 @@ export class FeatureLineLayer extends VectorStyleLayer
|
|
|
316
330
|
return {
|
|
317
331
|
...super.style(),
|
|
318
332
|
'type': 'line',
|
|
319
|
-
'filter':
|
|
320
|
-
'all',
|
|
321
|
-
['==', '$type', 'LineString'],
|
|
322
|
-
this.__filter
|
|
323
|
-
// not for paths...
|
|
324
|
-
],
|
|
333
|
+
'filter': this.makeFilter(options),
|
|
325
334
|
'paint': this.paintStyle(options)
|
|
326
335
|
};
|
|
327
336
|
}
|
|
@@ -333,7 +342,7 @@ export class FeatureDashLineLayer extends FeatureLineLayer
|
|
|
333
342
|
{
|
|
334
343
|
constructor(id, sourceLayer)
|
|
335
344
|
{
|
|
336
|
-
super(id, sourceLayer, true);
|
|
345
|
+
super(id, sourceLayer, {dashed: true});
|
|
337
346
|
}
|
|
338
347
|
}
|
|
339
348
|
|
|
@@ -341,25 +350,63 @@ export class FeatureDashLineLayer extends FeatureLineLayer
|
|
|
341
350
|
|
|
342
351
|
export class PathLineLayer extends VectorStyleLayer
|
|
343
352
|
{
|
|
344
|
-
constructor(id, sourceLayer,
|
|
353
|
+
constructor(id, sourceLayer, options={})
|
|
345
354
|
{
|
|
355
|
+
const dashed = ('dashed' in options && options.dashed);
|
|
346
356
|
const filterType = dashed ? 'line-dash' : 'line';
|
|
347
357
|
super(id, `path-${filterType}`, sourceLayer);
|
|
348
|
-
this.
|
|
349
|
-
|
|
358
|
+
this.__dashed = dashed;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
makeFilter(options={})
|
|
362
|
+
{
|
|
363
|
+
const sckanState = !'sckan' in options ? 'all'
|
|
364
|
+
: options.sckan.toLowerCase();
|
|
365
|
+
const sckan_filter =
|
|
366
|
+
sckanState == 'none' ? [
|
|
367
|
+
['!has', 'sckan']
|
|
368
|
+
] :
|
|
369
|
+
sckanState == 'valid' ? [[
|
|
350
370
|
'any',
|
|
351
|
-
['
|
|
352
|
-
|
|
353
|
-
|
|
371
|
+
['!has', 'sckan'],
|
|
372
|
+
[
|
|
373
|
+
'all',
|
|
374
|
+
['has', 'sckan'],
|
|
375
|
+
['==', 'sckan', true]
|
|
376
|
+
]
|
|
377
|
+
]] :
|
|
378
|
+
sckanState == 'invalid' ? [[
|
|
379
|
+
'any',
|
|
380
|
+
['!has', 'sckan'],
|
|
381
|
+
[
|
|
382
|
+
'all',
|
|
383
|
+
['has', 'sckan'],
|
|
384
|
+
['!=', 'sckan', true]
|
|
385
|
+
]
|
|
386
|
+
]] :
|
|
387
|
+
[ ];
|
|
388
|
+
|
|
389
|
+
return this.__dashed ? [
|
|
390
|
+
'all',
|
|
391
|
+
['==', '$type', 'LineString'],
|
|
392
|
+
['==', 'type', `line-dash`],
|
|
393
|
+
...sckan_filter
|
|
394
|
+
] : [
|
|
395
|
+
'all',
|
|
396
|
+
['==', '$type', 'LineString'],
|
|
354
397
|
[
|
|
355
398
|
'any',
|
|
356
399
|
['==', 'type', 'bezier'],
|
|
357
|
-
[
|
|
358
|
-
|
|
359
|
-
|
|
400
|
+
[
|
|
401
|
+
'all',
|
|
402
|
+
['==', 'type', `line`],
|
|
403
|
+
...sckan_filter
|
|
404
|
+
]
|
|
405
|
+
]
|
|
406
|
+
];
|
|
360
407
|
}
|
|
361
408
|
|
|
362
|
-
paintStyle(options, changes=false)
|
|
409
|
+
paintStyle(options={}, changes=false)
|
|
363
410
|
{
|
|
364
411
|
const dimmed = 'dimmed' in options && options.dimmed;
|
|
365
412
|
const paintStyle = {
|
|
@@ -368,40 +415,34 @@ export class PathLineLayer extends VectorStyleLayer
|
|
|
368
415
|
['boolean', ['feature-state', 'selected'], false], '#0F0',
|
|
369
416
|
['boolean', ['feature-state', 'hidden'], false], '#CCC',
|
|
370
417
|
['==', ['get', 'type'], 'bezier'], 'red',
|
|
371
|
-
['
|
|
418
|
+
['has', 'error'], '#FFFE0E',
|
|
372
419
|
['==', ['get', 'kind'], 'unknown'], '#888',
|
|
373
|
-
|
|
374
|
-
['==', ['get', 'kind'], 'lcn'], '#F19E38',
|
|
375
|
-
['==', ['get', 'kind'], 'para-post'], '#3F8F4A',
|
|
376
|
-
['==', ['get', 'kind'], 'para-pre'], '#3F8F4A',
|
|
377
|
-
['==', ['get', 'kind'], 'somatic'], '#98561D',
|
|
378
|
-
['==', ['get', 'kind'], 'sensory'], '#2A62F6',
|
|
379
|
-
['==', ['get', 'kind'], 'symp-post'], '#EA3423',
|
|
380
|
-
['==', ['get', 'kind'], 'symp-pre'], '#EA3423',
|
|
420
|
+
...PATH_STYLE_RULES,
|
|
381
421
|
'#888'
|
|
382
422
|
],
|
|
383
423
|
'line-opacity': [
|
|
384
424
|
'case',
|
|
385
|
-
['boolean', ['feature-state', 'hidden'], false], 0.
|
|
425
|
+
['boolean', ['feature-state', 'hidden'], false], 0.05,
|
|
386
426
|
['==', ['get', 'type'], 'bezier'], 1.0,
|
|
387
427
|
['boolean', ['get', 'invisible'], false], 0.001,
|
|
388
428
|
['boolean', ['feature-state', 'selected'], false], 1.0,
|
|
389
|
-
['boolean', ['feature-state', 'active'], false], 0
|
|
390
|
-
dimmed ? 0.1 : 0.
|
|
429
|
+
['boolean', ['feature-state', 'active'], false], 1.0,
|
|
430
|
+
dimmed ? 0.1 : 0.8
|
|
391
431
|
],
|
|
392
432
|
'line-width': [
|
|
393
433
|
'let',
|
|
394
|
-
'width', [
|
|
434
|
+
'width', ["*", [
|
|
395
435
|
'case',
|
|
396
436
|
['==', ['get', 'type'], 'bezier'], 0.1,
|
|
397
|
-
['
|
|
437
|
+
['has', 'error'], 1,
|
|
398
438
|
['==', ['get', 'kind'], 'unknown'], 1,
|
|
399
439
|
['boolean', ['get', 'invisible'], false], 0.1,
|
|
400
|
-
['boolean', ['feature-state', 'selected'], false],
|
|
440
|
+
['boolean', ['feature-state', 'selected'], false], 0.6,
|
|
401
441
|
['boolean', ['feature-state', 'active'], false], 0.9,
|
|
402
|
-
0.
|
|
403
|
-
],
|
|
404
|
-
'
|
|
442
|
+
0.6
|
|
443
|
+
],
|
|
444
|
+
['case', ['has', 'stroke-width'], ['get', 'stroke-width'], 1.0]],
|
|
445
|
+
['interpolate',
|
|
405
446
|
['exponential', 2],
|
|
406
447
|
['zoom'],
|
|
407
448
|
2, ["*", ['var', 'width'], ["^", 2, -0.5]],
|
|
@@ -411,21 +452,17 @@ export class PathLineLayer extends VectorStyleLayer
|
|
|
411
452
|
]
|
|
412
453
|
};
|
|
413
454
|
if (this.__dashed) {
|
|
414
|
-
paintStyle['line-dasharray'] = [
|
|
455
|
+
paintStyle['line-dasharray'] = [1, 1];
|
|
415
456
|
}
|
|
416
457
|
return super.changedPaintStyle(paintStyle, changes);
|
|
417
458
|
}
|
|
418
459
|
|
|
419
|
-
style(options)
|
|
460
|
+
style(options={})
|
|
420
461
|
{
|
|
421
462
|
return {
|
|
422
463
|
...super.style(),
|
|
423
464
|
'type': 'line',
|
|
424
|
-
'filter':
|
|
425
|
-
'all',
|
|
426
|
-
['==', '$type', 'LineString'],
|
|
427
|
-
this.__filter
|
|
428
|
-
],
|
|
465
|
+
'filter': this.makeFilter(options),
|
|
429
466
|
'layout': {
|
|
430
467
|
'line-cap': 'butt'
|
|
431
468
|
},
|
|
@@ -440,8 +477,93 @@ export class PathDashlineLayer extends PathLineLayer
|
|
|
440
477
|
{
|
|
441
478
|
constructor(id, sourceLayer)
|
|
442
479
|
{
|
|
443
|
-
super(id, sourceLayer, true);
|
|
480
|
+
super(id, sourceLayer, {dashed: true});
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
//==============================================================================
|
|
485
|
+
|
|
486
|
+
class CentrelineLayer extends VectorStyleLayer
|
|
487
|
+
{
|
|
488
|
+
constructor(id, type, sourceLayer)
|
|
489
|
+
{
|
|
490
|
+
super(id, `centreline-${type}`, sourceLayer);
|
|
491
|
+
this.__type = type;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
paintStyle(options, changes=false)
|
|
495
|
+
{
|
|
496
|
+
const coloured = !('colour' in options) || options.colour;
|
|
497
|
+
const paintStyle = {
|
|
498
|
+
'line-color': (this.__type == 'edge') ? '#000' : [
|
|
499
|
+
'case',
|
|
500
|
+
['boolean', ['feature-state', 'selected'], false], '#0F0',
|
|
501
|
+
['boolean', ['feature-state', 'active'], false], '#444',
|
|
502
|
+
'#CCC'
|
|
503
|
+
],
|
|
504
|
+
'line-opacity': [
|
|
505
|
+
'case',
|
|
506
|
+
['boolean', ['feature-state', 'hidden'], false], 0.01,
|
|
507
|
+
['boolean', ['feature-state', 'selected'], false], 1.0,
|
|
508
|
+
['boolean', ['feature-state', 'active'], false], 1.0,
|
|
509
|
+
0.8
|
|
510
|
+
],
|
|
511
|
+
'line-width': [
|
|
512
|
+
'let',
|
|
513
|
+
'width',
|
|
514
|
+
(this.__type == 'edge') ? 1.6 : 1.2,
|
|
515
|
+
[
|
|
516
|
+
'interpolate',
|
|
517
|
+
['exponential', 2],
|
|
518
|
+
['zoom'],
|
|
519
|
+
2, ["*", ['var', 'width'], ["^", 2, -0.5]],
|
|
520
|
+
7, ["*", ['var', 'width'], ["^", 2, 2.5]],
|
|
521
|
+
9, ["*", ['var', 'width'], ["^", 2, 4.0]]
|
|
522
|
+
]
|
|
523
|
+
]
|
|
524
|
+
// Need to vary width based on zoom??
|
|
525
|
+
// Or opacity??
|
|
526
|
+
};
|
|
527
|
+
return super.changedPaintStyle(paintStyle, changes);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
style(options)
|
|
531
|
+
{
|
|
532
|
+
return {
|
|
533
|
+
...super.style(),
|
|
534
|
+
'type': 'line',
|
|
535
|
+
'filter': [
|
|
536
|
+
'all',
|
|
537
|
+
['==', '$type', 'LineString'],
|
|
538
|
+
['==', 'kind', 'centreline']
|
|
539
|
+
],
|
|
540
|
+
'paint': this.paintStyle(options),
|
|
541
|
+
'layout': {
|
|
542
|
+
'line-cap': 'square',
|
|
543
|
+
'line-join': 'bevel'
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
export class CentrelineEdgeLayer extends CentrelineLayer
|
|
551
|
+
{
|
|
552
|
+
constructor(id, sourceLayer)
|
|
553
|
+
{
|
|
554
|
+
super(id, 'edge', sourceLayer);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
export class CentrelineTrackLayer extends CentrelineLayer
|
|
560
|
+
{
|
|
561
|
+
constructor(id, sourceLayer)
|
|
562
|
+
{
|
|
563
|
+
super(id, 'track', sourceLayer);
|
|
444
564
|
}
|
|
565
|
+
|
|
566
|
+
|
|
445
567
|
}
|
|
446
568
|
|
|
447
569
|
//==============================================================================
|
|
@@ -461,6 +583,7 @@ export class FeatureNerveLayer extends VectorStyleLayer
|
|
|
461
583
|
'filter': [
|
|
462
584
|
'all',
|
|
463
585
|
['==', '$type', 'LineString'],
|
|
586
|
+
['!=', 'kind', 'centreline'],
|
|
464
587
|
['==', 'type', 'nerve']
|
|
465
588
|
],
|
|
466
589
|
'paint': {
|
|
@@ -570,14 +693,7 @@ export class NervePolygonFill extends VectorStyleLayer
|
|
|
570
693
|
'case',
|
|
571
694
|
['==', ['get', 'kind'], 'bezier-end'], 'red',
|
|
572
695
|
['==', ['get', 'kind'], 'bezier-control'], 'green',
|
|
573
|
-
|
|
574
|
-
['==', ['get', 'kind'], 'lcn'], '#F19E38',
|
|
575
|
-
['==', ['get', 'kind'], 'para-post'], '#3F8F4A',
|
|
576
|
-
['==', ['get', 'kind'], 'para-pre'], '#3F8F4A',
|
|
577
|
-
['==', ['get', 'kind'], 'somatic'], '#98561D',
|
|
578
|
-
['==', ['get', 'kind'], 'sensory'], '#2A62F6',
|
|
579
|
-
['==', ['get', 'kind'], 'symp-post'], '#EA3423',
|
|
580
|
-
['==', ['get', 'kind'], 'symp-pre'], '#EA3423',
|
|
696
|
+
...PATH_STYLE_RULES,
|
|
581
697
|
'white'
|
|
582
698
|
],
|
|
583
699
|
'fill-opacity': [
|