@abi-software/flatmap-viewer 2.2.11-devel.2 → 2.2.12-b.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.rst +1 -1
- package/package.json +1 -1
- package/src/controls.js +75 -31
- package/src/flatmap-viewer.js +40 -31
- package/src/info.js +5 -1
- package/src/interactions.js +95 -97
- package/src/layers.js +43 -18
- package/src/pathways.js +20 -7
- package/src/styling.js +77 -5
- package/static/flatmap-viewer.css +3 -30
package/README.rst
CHANGED
|
@@ -38,7 +38,7 @@ The map server endpoint is specified as ``MAP_ENDPOINT`` in ``src/main.js``. It
|
|
|
38
38
|
Package Installation
|
|
39
39
|
====================
|
|
40
40
|
|
|
41
|
-
* ``npm install @abi-software/flatmap-viewer@2.2.
|
|
41
|
+
* ``npm install @abi-software/flatmap-viewer@2.2.12-b.1``
|
|
42
42
|
|
|
43
43
|
Documentation
|
|
44
44
|
-------------
|
package/package.json
CHANGED
package/src/controls.js
CHANGED
|
@@ -123,7 +123,11 @@ export class PathControl
|
|
|
123
123
|
if (checked != '') {
|
|
124
124
|
this.__checkedCount += 1;
|
|
125
125
|
}
|
|
126
|
-
|
|
126
|
+
const colour = path.colour || '#440';
|
|
127
|
+
const style = path.dashed ? `background: repeating-linear-gradient(to right,${colour} 0,${colour} 6px,transparent 6px,transparent 9px);`
|
|
128
|
+
: `background: ${colour};`;
|
|
129
|
+
|
|
130
|
+
innerHTML.push(`<label for="path-${path.type}">${path.label}</label><div class="nerve-line" style="${style}"></div><input id="path-${path.type}" type="checkbox" ${checked}/>`);
|
|
127
131
|
}
|
|
128
132
|
this._legend.innerHTML = innerHTML.join('\n');
|
|
129
133
|
this.__halfCount = Math.trunc(this.__pathTypes.length/2);
|
|
@@ -228,12 +232,9 @@ export class LayerControl
|
|
|
228
232
|
{
|
|
229
233
|
this.__map = map;
|
|
230
234
|
this.__container = document.createElement('div');
|
|
231
|
-
this.__container.className = 'maplibregl-ctrl';
|
|
232
|
-
this.__container.id = 'flatmap-layer-control';
|
|
233
|
-
|
|
235
|
+
this.__container.className = 'maplibregl-ctrl flatmap-control';
|
|
234
236
|
this.__layersControl = document.createElement('div');
|
|
235
|
-
this.__layersControl.
|
|
236
|
-
this.__layersControl.className = 'flatmap-layer-grid';
|
|
237
|
+
this.__layersControl.className = 'flatmap-control-grid';
|
|
237
238
|
|
|
238
239
|
const innerHTML = [];
|
|
239
240
|
innerHTML.push(`<label for="layer-all-layers">ALL LAYERS:</label><input id="layer-all-layers" type="checkbox" checked/>`);
|
|
@@ -323,7 +324,6 @@ export class LayerControl
|
|
|
323
324
|
|
|
324
325
|
//==============================================================================
|
|
325
326
|
|
|
326
|
-
|
|
327
327
|
const SCKAN_STATES = [
|
|
328
328
|
{
|
|
329
329
|
'id': 'VALID',
|
|
@@ -338,11 +338,11 @@ const SCKAN_STATES = [
|
|
|
338
338
|
|
|
339
339
|
export class SCKANControl
|
|
340
340
|
{
|
|
341
|
-
constructor(flatmap)
|
|
341
|
+
constructor(flatmap, options={sckan: 'valid'})
|
|
342
342
|
{
|
|
343
343
|
this.__flatmap = flatmap;
|
|
344
344
|
this.__map = undefined;
|
|
345
|
-
this.
|
|
345
|
+
this.__initialState = options.sckan || 'valid';
|
|
346
346
|
}
|
|
347
347
|
|
|
348
348
|
getDefaultPosition()
|
|
@@ -356,25 +356,22 @@ export class SCKANControl
|
|
|
356
356
|
{
|
|
357
357
|
this.__map = map;
|
|
358
358
|
this.__container = document.createElement('div');
|
|
359
|
-
this.__container.className = 'maplibregl-ctrl';
|
|
360
|
-
this.__container.id = 'flatmap-layer-control';
|
|
361
|
-
|
|
359
|
+
this.__container.className = 'maplibregl-ctrl flatmap-control';
|
|
362
360
|
this.__sckan = document.createElement('div');
|
|
363
|
-
this.__sckan.
|
|
364
|
-
this.__sckan.className = 'flatmap-layer-grid';
|
|
361
|
+
this.__sckan.className = 'flatmap-control-grid';
|
|
365
362
|
|
|
366
363
|
const innerHTML = [];
|
|
367
|
-
let checked = (this.
|
|
364
|
+
let checked = (this.__initialState === 'all') ? 'checked' : '';
|
|
368
365
|
innerHTML.push(`<label for="sckan-all-paths">ALL PATHS:</label><input id="sckan-all-paths" type="checkbox" ${checked}/>`);
|
|
369
366
|
for (const state of SCKAN_STATES) {
|
|
370
|
-
checked = (this.
|
|
367
|
+
checked = (this.__initialState.toUpperCase() === state.id) ? 'checked' : '';
|
|
371
368
|
innerHTML.push(`<label for="sckan-${state.id}">${state.description}</label><input id="sckan-${state.id}" type="checkbox" ${checked}/>`);
|
|
372
369
|
}
|
|
373
370
|
this.__sckan.innerHTML = innerHTML.join('\n');
|
|
374
371
|
|
|
375
372
|
this.__sckanCount = SCKAN_STATES.length;
|
|
376
|
-
this.__checkedCount = (this.
|
|
377
|
-
: (this.
|
|
373
|
+
this.__checkedCount = (this.__initialState === 'all') ? this.__sckanCount
|
|
374
|
+
: (this.__initialState === 'none') ? 0
|
|
378
375
|
: 1;
|
|
379
376
|
this.__halfCount = Math.trunc(this.__sckanCount/2);
|
|
380
377
|
|
|
@@ -407,7 +404,8 @@ export class SCKANControl
|
|
|
407
404
|
this.__container.appendChild(this.__sckan);
|
|
408
405
|
this.__button.setAttribute('control-visible', 'true');
|
|
409
406
|
const allLayersCheckbox = document.getElementById('sckan-all-paths');
|
|
410
|
-
allLayersCheckbox.indeterminate = this.
|
|
407
|
+
allLayersCheckbox.indeterminate = (this.__checkedCount > 0)
|
|
408
|
+
&& (this.__checkedCount < this.__sckanCount);
|
|
411
409
|
this.__sckan.focus();
|
|
412
410
|
} else {
|
|
413
411
|
this.__sckan = this.__container.removeChild(this.__sckan);
|
|
@@ -430,11 +428,12 @@ export class SCKANControl
|
|
|
430
428
|
const sckanCheckbox = document.getElementById(`sckan-${state.id}`);
|
|
431
429
|
if (sckanCheckbox) {
|
|
432
430
|
sckanCheckbox.checked = event.target.checked;
|
|
433
|
-
|
|
431
|
+
this.__flatmap.enableSckanPath(state.id, event.target.checked);
|
|
432
|
+
}
|
|
434
433
|
}
|
|
435
|
-
this.__flatmap.showSckanPaths(this.__state);
|
|
436
434
|
} else if (event.target.id.startsWith('sckan-')) {
|
|
437
435
|
const sckanId = event.target.id.substring(6);
|
|
436
|
+
this.__flatmap.enableSckanPath(sckanId, event.target.checked);
|
|
438
437
|
if (event.target.checked) {
|
|
439
438
|
this.__checkedCount += 1;
|
|
440
439
|
} else {
|
|
@@ -442,24 +441,14 @@ export class SCKANControl
|
|
|
442
441
|
}
|
|
443
442
|
const allLayersCheckbox = document.getElementById('sckan-all-paths');
|
|
444
443
|
if (this.__checkedCount === 0) {
|
|
445
|
-
this.__state = 'none';
|
|
446
444
|
allLayersCheckbox.checked = false;
|
|
447
445
|
allLayersCheckbox.indeterminate = false;
|
|
448
446
|
} else if (this.__checkedCount === this.__sckanCount) {
|
|
449
|
-
this.__state = 'all';
|
|
450
447
|
allLayersCheckbox.checked = true;
|
|
451
448
|
allLayersCheckbox.indeterminate = false;
|
|
452
449
|
} 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
450
|
allLayersCheckbox.indeterminate = true;
|
|
461
451
|
}
|
|
462
|
-
this.__flatmap.showSckanPaths(this.__state);
|
|
463
452
|
}
|
|
464
453
|
}
|
|
465
454
|
event.stopPropagation();
|
|
@@ -468,6 +457,61 @@ export class SCKANControl
|
|
|
468
457
|
|
|
469
458
|
//==============================================================================
|
|
470
459
|
|
|
460
|
+
export class NerveControl
|
|
461
|
+
{
|
|
462
|
+
constructor(flatmap, options={showCentrelines: false})
|
|
463
|
+
{
|
|
464
|
+
this.__flatmap = flatmap;
|
|
465
|
+
this.__map = undefined;
|
|
466
|
+
this.__visible = options.showCentrelines || false;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
getDefaultPosition()
|
|
470
|
+
//==================
|
|
471
|
+
{
|
|
472
|
+
return 'top-right';
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
onAdd(map)
|
|
476
|
+
//========
|
|
477
|
+
{
|
|
478
|
+
this.__map = map;
|
|
479
|
+
this.__container = document.createElement('div');
|
|
480
|
+
this.__container.className = 'maplibregl-ctrl';
|
|
481
|
+
|
|
482
|
+
this.__button = document.createElement('button');
|
|
483
|
+
this.__button.id = 'map-nerve-button';
|
|
484
|
+
this.__button.className = 'control-button text-button';
|
|
485
|
+
this.__button.setAttribute('type', 'button');
|
|
486
|
+
this.__button.setAttribute('aria-label', 'Show/hide nerve centrelines');
|
|
487
|
+
this.__button.textContent = 'NERVES';
|
|
488
|
+
this.__button.title = 'Show/hide nerve centrelines';
|
|
489
|
+
this.__container.appendChild(this.__button);
|
|
490
|
+
|
|
491
|
+
this.__container.addEventListener('click', this.onClick_.bind(this));
|
|
492
|
+
return this.__container;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
onRemove()
|
|
496
|
+
//========
|
|
497
|
+
{
|
|
498
|
+
this.__container.parentNode.removeChild(this.__container);
|
|
499
|
+
this.__map = undefined;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
onClick_(event)
|
|
503
|
+
//=============
|
|
504
|
+
{
|
|
505
|
+
if (event.target.id === 'map-nerve-button') {
|
|
506
|
+
this.__visible = !this.__visible;
|
|
507
|
+
this.__flatmap.enableCentrelines(this.__visible);
|
|
508
|
+
}
|
|
509
|
+
event.stopPropagation();
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
//==============================================================================
|
|
514
|
+
|
|
471
515
|
export class BackgroundControl
|
|
472
516
|
{
|
|
473
517
|
constructor(flatmap)
|
package/src/flatmap-viewer.js
CHANGED
|
@@ -275,21 +275,24 @@ class FlatMap
|
|
|
275
275
|
}
|
|
276
276
|
|
|
277
277
|
/**
|
|
278
|
-
* @returns {Array.<{type: string, label: string, colour: string}>} an array of objects giving path types
|
|
279
|
-
*
|
|
278
|
+
* @returns {Array.<{type: string, label: string, colour: string}>} an array of objects giving the path types
|
|
279
|
+
* present in the map along with their
|
|
280
|
+
* descriptions and colours
|
|
280
281
|
*/
|
|
281
282
|
pathTypes()
|
|
282
283
|
//=========
|
|
283
284
|
{
|
|
284
|
-
|
|
285
|
+
if (this._userInteractions !== null) {
|
|
286
|
+
return this._userInteractions.pathways.pathTypes();
|
|
287
|
+
}
|
|
285
288
|
}
|
|
286
289
|
|
|
287
290
|
/**
|
|
288
291
|
* Hide or show paths of a given type.
|
|
289
292
|
*
|
|
290
|
-
* @param
|
|
291
|
-
* @param
|
|
292
|
-
*
|
|
293
|
+
* @param {string} pathType The path type
|
|
294
|
+
* @param {boolean} enable Show or hide paths of that type. Defaults to
|
|
295
|
+
* ``true`` (show)
|
|
293
296
|
*/
|
|
294
297
|
enablePath(pathType, enable=true)
|
|
295
298
|
//===============================
|
|
@@ -300,32 +303,31 @@ class FlatMap
|
|
|
300
303
|
}
|
|
301
304
|
|
|
302
305
|
/**
|
|
303
|
-
* Hide or show all paths
|
|
306
|
+
* Hide or show all paths valid in SCKAN.
|
|
304
307
|
*
|
|
305
|
-
* @param
|
|
306
|
-
* @param
|
|
307
|
-
*
|
|
308
|
+
* @param {string} sckanState Either ``valid`` or ``invalid``
|
|
309
|
+
* @param {boolean} enable Show or hide paths with that SCKAN state.
|
|
310
|
+
* Defaults to ``true`` (show)
|
|
308
311
|
*/
|
|
309
|
-
|
|
310
|
-
|
|
312
|
+
enableSckanPath(sckanState, enable=true)
|
|
313
|
+
//======================================
|
|
311
314
|
{
|
|
312
315
|
if (this._userInteractions !== null) {
|
|
313
|
-
this._userInteractions.
|
|
316
|
+
this._userInteractions.enableSckanPath(sckanState, enable);
|
|
314
317
|
}
|
|
315
318
|
}
|
|
316
319
|
|
|
317
320
|
/**
|
|
318
|
-
* Hide or show
|
|
321
|
+
* Hide or show centrelines and nodes.
|
|
319
322
|
*
|
|
320
|
-
* @param
|
|
321
|
-
*
|
|
322
|
-
* of the type(s) otherwise only hide the paths
|
|
323
|
+
* @param {boolean} enable Show or centrelines and associated nodes.
|
|
324
|
+
* Defaults to ``true`` (show)
|
|
323
325
|
*/
|
|
324
|
-
|
|
325
|
-
|
|
326
|
+
enableCentrelines(enable=true)
|
|
327
|
+
//============================
|
|
326
328
|
{
|
|
327
329
|
if (this._userInteractions !== null) {
|
|
328
|
-
this._userInteractions.
|
|
330
|
+
this._userInteractions.enableCentrelines(enable);
|
|
329
331
|
}
|
|
330
332
|
}
|
|
331
333
|
|
|
@@ -664,18 +666,25 @@ class FlatMap
|
|
|
664
666
|
}
|
|
665
667
|
}
|
|
666
668
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
+
setPaint(options=null)
|
|
670
|
+
//====================
|
|
669
671
|
{
|
|
670
672
|
options = utils.setDefaults(options, {
|
|
671
673
|
colour: true,
|
|
672
674
|
outline: true
|
|
673
675
|
});
|
|
674
676
|
if (this._userInteractions !== null) {
|
|
675
|
-
this._userInteractions.
|
|
677
|
+
this._userInteractions.setPaint(options);
|
|
676
678
|
}
|
|
677
679
|
}
|
|
678
680
|
|
|
681
|
+
setColour(options=null)
|
|
682
|
+
//=====================
|
|
683
|
+
{
|
|
684
|
+
console.log('`setColour()` is deprecated; please use `setPaint()` instead.')
|
|
685
|
+
this.setPaint(options);
|
|
686
|
+
}
|
|
687
|
+
|
|
679
688
|
//==========================================================================
|
|
680
689
|
|
|
681
690
|
/**
|
|
@@ -781,17 +790,17 @@ class FlatMap
|
|
|
781
790
|
*
|
|
782
791
|
* @param {string} anatomicalId The anatomical identifier of the feature on which
|
|
783
792
|
* to place the marker
|
|
784
|
-
* @param {string} [
|
|
785
|
-
*
|
|
786
|
-
*
|
|
793
|
+
* @param {string} [htmlElement=null] An optional parameter giving the DOM element to
|
|
794
|
+
* use as a marker. The default is a light blue,
|
|
795
|
+
* droplet-shaped SVG marker.
|
|
787
796
|
* @return {integer} The identifier for the resulting marker. -1 is returned if the
|
|
788
797
|
* map doesn't contain a feature with the given anatomical identifier
|
|
789
798
|
*/
|
|
790
|
-
addMarker(anatomicalId,
|
|
791
|
-
|
|
799
|
+
addMarker(anatomicalId, htmlElement=null)
|
|
800
|
+
//========================================
|
|
792
801
|
{
|
|
793
802
|
if (this._userInteractions !== null) {
|
|
794
|
-
return this._userInteractions.addMarker(anatomicalId,
|
|
803
|
+
return this._userInteractions.addMarker(anatomicalId, htmlElement);
|
|
795
804
|
}
|
|
796
805
|
return -1;
|
|
797
806
|
}
|
|
@@ -1272,9 +1281,9 @@ export class MapManager
|
|
|
1272
1281
|
// Note the kind of map
|
|
1273
1282
|
|
|
1274
1283
|
if ('style' in mapIndex) {
|
|
1275
|
-
mapOptions.style = mapIndex.style; // Currently ``
|
|
1284
|
+
mapOptions.style = mapIndex.style; // Currently ``anatomical`` or ``functional``
|
|
1276
1285
|
} else {
|
|
1277
|
-
mapOptions.style = 'flatmap';
|
|
1286
|
+
mapOptions.style = 'flatmap'; // Default is a generic ``flatmap``
|
|
1278
1287
|
}
|
|
1279
1288
|
|
|
1280
1289
|
// Mapmaker has changed the name of the field to indicate that indicates if
|
package/src/info.js
CHANGED
|
@@ -238,7 +238,11 @@ export class InfoControl
|
|
|
238
238
|
if (prop in feature.properties) {
|
|
239
239
|
const value = feature.properties[prop];
|
|
240
240
|
if (value !== undefined) {
|
|
241
|
-
|
|
241
|
+
if (prop === 'label') {
|
|
242
|
+
values[prop] = value.replaceAll("\n", "<br/>");
|
|
243
|
+
} else {
|
|
244
|
+
values[prop] = value;
|
|
245
|
+
}
|
|
242
246
|
}
|
|
243
247
|
}
|
|
244
248
|
});
|
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 {
|
|
41
|
-
import {BackgroundControl, LayerControl, PathControl, SCKANControl} from './controls.js';
|
|
40
|
+
import {PATHWAYS_LAYER, Pathways} from './pathways.js';
|
|
41
|
+
import {BackgroundControl, LayerControl, NerveControl, PathControl, SCKANControl} from './controls.js';
|
|
42
42
|
import {SearchControl} from './search.js';
|
|
43
43
|
import {VECTOR_TILES_SOURCE} from './styling.js';
|
|
44
44
|
|
|
@@ -118,13 +118,7 @@ export class UserInteractions
|
|
|
118
118
|
this.__annotationByMarkerId = new Map();
|
|
119
119
|
|
|
120
120
|
// Where to put labels and popups on a feature
|
|
121
|
-
this.
|
|
122
|
-
|
|
123
|
-
// MapLibre dynamically sets a transform on marker elements so in
|
|
124
|
-
// order to apply a scale transform we need to create marker icons
|
|
125
|
-
// inside the marker container <div>.
|
|
126
|
-
this._defaultMarkerHTML = new maplibre.Marker().getElement().innerHTML;
|
|
127
|
-
this._simulationMarkerHTML = new maplibre.Marker({color: '#005974'}).getElement().innerHTML;
|
|
121
|
+
this.__markerPositions = new Map();
|
|
128
122
|
|
|
129
123
|
// Fit the map to its initial position
|
|
130
124
|
|
|
@@ -139,7 +133,7 @@ export class UserInteractions
|
|
|
139
133
|
this._pathways = new Pathways(flatmap);
|
|
140
134
|
|
|
141
135
|
// The path types in this map
|
|
142
|
-
const mapPathTypes = this._pathways.pathTypes;
|
|
136
|
+
const mapPathTypes = this._pathways.pathTypes();
|
|
143
137
|
|
|
144
138
|
// Disable paths that are not initially shown
|
|
145
139
|
for (const path of mapPathTypes) {
|
|
@@ -167,9 +161,15 @@ export class UserInteractions
|
|
|
167
161
|
// Add a control to manage our layers
|
|
168
162
|
this._map.addControl(new LayerControl(flatmap, this._layerManager));
|
|
169
163
|
|
|
164
|
+
// Add a control for nerve centrelines if they are present
|
|
165
|
+
if (this._pathways.haveCentrelines) {
|
|
166
|
+
this._map.addControl(new NerveControl(flatmap, this._layerManager, {showCentrelines: false}));
|
|
167
|
+
this.enableCentrelines(false);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
170
|
// A SCKAN path control for FC maps
|
|
171
|
-
if (flatmap.options.style === '
|
|
172
|
-
this._map.addControl(new SCKANControl(flatmap));
|
|
171
|
+
if (flatmap.options.style === 'functional') {
|
|
172
|
+
this._map.addControl(new SCKANControl(flatmap, flatmap.options.layerOptions));
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
175
|
|
|
@@ -213,6 +213,12 @@ export class UserInteractions
|
|
|
213
213
|
this.__pan_zoom_enabled = false;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
get pathways()
|
|
217
|
+
//============
|
|
218
|
+
{
|
|
219
|
+
return this._pathways;
|
|
220
|
+
}
|
|
221
|
+
|
|
216
222
|
getState()
|
|
217
223
|
//========
|
|
218
224
|
{
|
|
@@ -246,11 +252,11 @@ export class UserInteractions
|
|
|
246
252
|
}
|
|
247
253
|
}
|
|
248
254
|
|
|
249
|
-
|
|
250
|
-
|
|
255
|
+
setPaint(options)
|
|
256
|
+
//===============
|
|
251
257
|
{
|
|
252
258
|
this.__colourOptions = options;
|
|
253
|
-
this._layerManager.
|
|
259
|
+
this._layerManager.setPaint(options);
|
|
254
260
|
}
|
|
255
261
|
|
|
256
262
|
getLayers()
|
|
@@ -291,7 +297,7 @@ export class UserInteractions
|
|
|
291
297
|
{
|
|
292
298
|
featureId = +featureId; // Ensure numeric
|
|
293
299
|
if (this._selectedFeatureIds.size === 0) {
|
|
294
|
-
this._layerManager.
|
|
300
|
+
this._layerManager.setPaint({...this.__colourOptions, dimmed: dim});
|
|
295
301
|
}
|
|
296
302
|
if (this._selectedFeatureIds.has(featureId)) {
|
|
297
303
|
this._selectedFeatureIds.set(featureId, this._selectedFeatureIds.get(featureId) + 1);
|
|
@@ -321,7 +327,7 @@ export class UserInteractions
|
|
|
321
327
|
}
|
|
322
328
|
}
|
|
323
329
|
if (this._selectedFeatureIds.size === 0) {
|
|
324
|
-
this._layerManager.
|
|
330
|
+
this._layerManager.setPaint({...this.__colourOptions, dimmed: false});
|
|
325
331
|
}
|
|
326
332
|
}
|
|
327
333
|
|
|
@@ -335,7 +341,7 @@ export class UserInteractions
|
|
|
335
341
|
}
|
|
336
342
|
}
|
|
337
343
|
this._selectedFeatureIds.clear();
|
|
338
|
-
this._layerManager.
|
|
344
|
+
this._layerManager.setPaint({...this.__colourOptions, dimmed: false});
|
|
339
345
|
}
|
|
340
346
|
|
|
341
347
|
activeFeaturesAtEvent_(event)
|
|
@@ -609,7 +615,7 @@ export class UserInteractions
|
|
|
609
615
|
location = this.__lastClickLngLat;
|
|
610
616
|
} else {
|
|
611
617
|
// Position popup at the feature's 'centre'
|
|
612
|
-
location = this.
|
|
618
|
+
location = this.__markerPosition(featureId, ann);
|
|
613
619
|
}
|
|
614
620
|
|
|
615
621
|
// Make sure the feature is on screen
|
|
@@ -651,9 +657,13 @@ export class UserInteractions
|
|
|
651
657
|
const tooltips = [];
|
|
652
658
|
for (const lineFeature of lineFeatures) {
|
|
653
659
|
const properties = lineFeature.properties;
|
|
654
|
-
if ('
|
|
655
|
-
|
|
656
|
-
|
|
660
|
+
if ('error' in properties) {
|
|
661
|
+
tooltips.push(`<div class="feature-error">Error: ${properties.error}</div>`)
|
|
662
|
+
}
|
|
663
|
+
if ('warning' in properties) {
|
|
664
|
+
tooltips.push(`<div class="feature-error">Warning: ${properties.warning}</div>`)
|
|
665
|
+
}
|
|
666
|
+
if ('label' in properties && (!('tooltip' in properties) || properties.tooltip)) {
|
|
657
667
|
let tooltip = '';
|
|
658
668
|
const label = properties.label;
|
|
659
669
|
const cleanLabel = (label.substr(0, 1).toUpperCase() + label.substr(1)).replaceAll("\n", "<br/>");
|
|
@@ -662,32 +672,37 @@ export class UserInteractions
|
|
|
662
672
|
}
|
|
663
673
|
}
|
|
664
674
|
}
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
}
|
|
668
|
-
return `<div class='flatmap-feature-label'>${tooltips.join('<hr/>')}</div>`;
|
|
675
|
+
return (tooltips.length === 0) ? ''
|
|
676
|
+
: `<div class='flatmap-feature-label'>${tooltips.join('<hr/>')}</div>`;
|
|
669
677
|
}
|
|
670
678
|
|
|
671
679
|
tooltipHtml_(properties, forceLabel=false)
|
|
672
680
|
//========================================
|
|
673
681
|
{
|
|
682
|
+
const tooltip = [];
|
|
683
|
+
if ('error' in properties) {
|
|
684
|
+
tooltip.push(`<div class="feature-error">Error: ${properties.error}</div>`)
|
|
685
|
+
}
|
|
686
|
+
if ('warning' in properties) {
|
|
687
|
+
tooltip.push(`<div class="feature-error">Warning: ${properties.warning}</div>`)
|
|
688
|
+
}
|
|
674
689
|
if (('label' in properties || 'hyperlink' in properties)
|
|
675
|
-
|
|
676
|
-
&& !('labelled' in properties)) {
|
|
690
|
+
&& (forceLabel || !('tooltip' in properties) || properties.tooltip)) {
|
|
677
691
|
const label = ('label' in properties) ? (properties.label.substr(0, 1).toUpperCase()
|
|
678
692
|
+ properties.label.substr(1)).replaceAll("\n", "<br/>")
|
|
679
693
|
: '';
|
|
680
694
|
if ('hyperlink' in properties) {
|
|
681
695
|
if (label === '') {
|
|
682
|
-
|
|
696
|
+
tooltip.push(`<a href='${properties.hyperlink}'>${properties.hyperlink}</a>`);
|
|
683
697
|
} else {
|
|
684
|
-
|
|
698
|
+
tooltip.push(`<a href='${properties.hyperlink}'>${label}</a></div>`);
|
|
685
699
|
}
|
|
686
700
|
} else {
|
|
687
|
-
|
|
701
|
+
tooltip.push(label);
|
|
688
702
|
}
|
|
689
703
|
}
|
|
690
|
-
return ''
|
|
704
|
+
return (tooltip.length === 0) ? ''
|
|
705
|
+
: `<div class='flatmap-feature-label'>${tooltip.join('<hr/>')}</div>`;
|
|
691
706
|
}
|
|
692
707
|
|
|
693
708
|
__featureEvent(type, feature)
|
|
@@ -976,6 +991,7 @@ export class UserInteractions
|
|
|
976
991
|
togglePaths()
|
|
977
992
|
//===========
|
|
978
993
|
{
|
|
994
|
+
console.log('Depracated API function called: togglePaths()')
|
|
979
995
|
if (this._disabledPathFeatures){
|
|
980
996
|
this.enablePathFeatures_(true, this._pathways.allFeatureIds());
|
|
981
997
|
this._disabledPathFeatures = false;
|
|
@@ -990,29 +1006,6 @@ export class UserInteractions
|
|
|
990
1006
|
this.enablePathFeatures_(enable, this._pathways.typeFeatureIds(pathType));
|
|
991
1007
|
}
|
|
992
1008
|
|
|
993
|
-
showPaths(pathTypes, enable=true)
|
|
994
|
-
//===============================
|
|
995
|
-
{
|
|
996
|
-
// Disable/enable all paths except those with `pathTypes`
|
|
997
|
-
if (Array.isArray(pathTypes)) {
|
|
998
|
-
for (const pathType of pathways.PATH_TYPES) {
|
|
999
|
-
if (pathTypes.indexOf(pathType.type) >= 0) {
|
|
1000
|
-
this.enablePath(pathType.type, enable)
|
|
1001
|
-
} else {
|
|
1002
|
-
this.enablePath(pathType.type, !enable)
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
} else {
|
|
1006
|
-
for (const pathType of pathways.PATH_TYPES) {
|
|
1007
|
-
if (pathType.type === pathTypes) {
|
|
1008
|
-
this.enablePath(pathType.type, enable)
|
|
1009
|
-
} else {
|
|
1010
|
-
this.enablePath(pathType.type, !enable)
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
1009
|
pathwaysFeatureIds(externalIds)
|
|
1017
1010
|
//=============================
|
|
1018
1011
|
{
|
|
@@ -1028,52 +1021,57 @@ export class UserInteractions
|
|
|
1028
1021
|
return this._pathways.nodePathModels(nodeId);
|
|
1029
1022
|
}
|
|
1030
1023
|
|
|
1031
|
-
|
|
1032
|
-
|
|
1024
|
+
enableCentrelines(show=true)
|
|
1025
|
+
//==========================
|
|
1033
1026
|
{
|
|
1034
|
-
this.
|
|
1027
|
+
this.enablePath('centreline', show);
|
|
1028
|
+
this._layerManager.setPaint({showCentrelines: show});
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
enableSckanPath(sckanState, enable=true)
|
|
1032
|
+
//======================================
|
|
1033
|
+
{
|
|
1034
|
+
this._layerManager.enableSckanPath(sckanState, enable);
|
|
1035
1035
|
}
|
|
1036
1036
|
|
|
1037
1037
|
//==============================================================================
|
|
1038
1038
|
|
|
1039
|
-
//
|
|
1039
|
+
// Marker handling
|
|
1040
1040
|
|
|
1041
|
-
|
|
1042
|
-
//======================================
|
|
1041
|
+
__markerPosition(featureId, annotation)
|
|
1043
1042
|
{
|
|
1044
|
-
if (this.
|
|
1045
|
-
return this.
|
|
1043
|
+
if (this.__markerPositions.has(featureId)) {
|
|
1044
|
+
return this.__markerPositions.get(featureId);
|
|
1046
1045
|
}
|
|
1047
|
-
let position = annotation.centroid;
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1046
|
+
let position = annotation.markerPosition || annotation.centroid;
|
|
1047
|
+
if (position === null || position == undefined) {
|
|
1048
|
+
// Find where to place a label or popup on a feature
|
|
1049
|
+
const features = this._map.querySourceFeatures(VECTOR_TILES_SOURCE, {
|
|
1050
|
+
'sourceLayer': this._flatmap.options.separateLayers
|
|
1051
|
+
? `${annotation['layer']}_${annotation['tile-layer']}`
|
|
1052
|
+
: annotation['tile-layer'],
|
|
1053
|
+
'filter': [
|
|
1054
|
+
'all',
|
|
1055
|
+
[ '==', ['id'], parseInt(featureId) ],
|
|
1056
|
+
[ '==', ['geometry-type'], 'Polygon' ]
|
|
1057
|
+
]
|
|
1058
|
+
});
|
|
1059
|
+
if (features.length > 0) {
|
|
1060
|
+
const feature = features[0];
|
|
1061
|
+
const polygon = feature.geometry.coordinates;
|
|
1062
|
+
// Rough heuristic. Area is in km^2; below appears to be good enough.
|
|
1063
|
+
const precision = ('area' in feature.properties)
|
|
1064
|
+
? Math.sqrt(feature.properties.area)/500000
|
|
1065
|
+
: 0.1;
|
|
1066
|
+
position = polylabel(polygon, precision);
|
|
1067
|
+
}
|
|
1066
1068
|
}
|
|
1067
|
-
this.
|
|
1069
|
+
this.__markerPositions.set(featureId, position);
|
|
1068
1070
|
return position;
|
|
1069
1071
|
}
|
|
1070
1072
|
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
// Marker handling
|
|
1074
|
-
|
|
1075
|
-
addMarker(anatomicalId, markerType='')
|
|
1076
|
-
//====================================
|
|
1073
|
+
addMarker(anatomicalId, htmlElement=null)
|
|
1074
|
+
//=======================================
|
|
1077
1075
|
{
|
|
1078
1076
|
const featureIds = this._flatmap.modelFeatureIds(anatomicalId);
|
|
1079
1077
|
let markerId = -1;
|
|
@@ -1089,19 +1087,19 @@ export class UserInteractions
|
|
|
1089
1087
|
markerId = this.__lastMarkerId;
|
|
1090
1088
|
}
|
|
1091
1089
|
|
|
1090
|
+
// MapLibre dynamically sets a transform on marker elements so in
|
|
1091
|
+
// order to apply a scale transform we need to create marker icons
|
|
1092
|
+
// inside the marker container <div>.
|
|
1093
|
+
const markerHTML = htmlElement ? new maplibre.Marker({element: htmlElement})
|
|
1094
|
+
: new maplibre.Marker();
|
|
1095
|
+
|
|
1092
1096
|
const markerElement = document.createElement('div');
|
|
1093
1097
|
const markerIcon = document.createElement('div');
|
|
1094
|
-
|
|
1095
|
-
markerIcon.innerHTML = this._simulationMarkerHTML;
|
|
1096
|
-
} else {
|
|
1097
|
-
markerIcon.innerHTML = this._defaultMarkerHTML;
|
|
1098
|
-
}
|
|
1098
|
+
markerIcon.innerHTML = markerHTML.getElement().innerHTML;
|
|
1099
1099
|
markerIcon.className = 'flatmap-marker';
|
|
1100
1100
|
markerElement.appendChild(markerIcon);
|
|
1101
1101
|
|
|
1102
|
-
const markerPosition = (annotation
|
|
1103
|
-
? this.__centralPosition(featureId, annotation)
|
|
1104
|
-
: annotation.centroid;
|
|
1102
|
+
const markerPosition = this.__markerPosition(featureId, annotation);
|
|
1105
1103
|
const marker = new maplibre.Marker(markerElement)
|
|
1106
1104
|
.setLngLat(markerPosition)
|
|
1107
1105
|
.addTo(this._map);
|
package/src/layers.js
CHANGED
|
@@ -93,14 +93,12 @@ class MapStylingLayers
|
|
|
93
93
|
: sourceLayer;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
setPaint(options)
|
|
97
97
|
{
|
|
98
|
-
|
|
99
98
|
}
|
|
100
99
|
|
|
101
100
|
setFilter(options)
|
|
102
101
|
{
|
|
103
|
-
|
|
104
102
|
}
|
|
105
103
|
}
|
|
106
104
|
|
|
@@ -124,6 +122,8 @@ class MapFeatureLayers extends MapStylingLayers
|
|
|
124
122
|
this.__addStyleLayer(style.FeatureDashLineLayer);
|
|
125
123
|
this.__addStyleLayer(style.FeatureLineLayer);
|
|
126
124
|
this.__addStyleLayer(style.FeatureBorderLayer);
|
|
125
|
+
this.__addStyleLayer(style.CentrelineNodeFillLayer);
|
|
126
|
+
this.__addStyleLayer(style.CentrelineNodeBorderLayer);
|
|
127
127
|
}
|
|
128
128
|
this.__addPathwayStyleLayers();
|
|
129
129
|
if (vectorFeatures) {
|
|
@@ -134,9 +134,9 @@ class MapFeatureLayers extends MapStylingLayers
|
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
// Make sure our
|
|
137
|
+
// Make sure our paint options are set properly, in particular raster layer visibility
|
|
138
138
|
|
|
139
|
-
this.
|
|
139
|
+
this.setPaint(this.__layerOptions);
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
__addStyleLayer(styleClass, sourceLayer=FEATURES_LAYER)
|
|
@@ -167,8 +167,8 @@ class MapFeatureLayers extends MapStylingLayers
|
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
-
|
|
171
|
-
|
|
170
|
+
setPaint(options)
|
|
171
|
+
//===============
|
|
172
172
|
{
|
|
173
173
|
for (const layer of this.__layers) {
|
|
174
174
|
const paintStyle = layer.paintStyle(options, true);
|
|
@@ -208,8 +208,8 @@ class MapRasterLayers extends MapStylingLayers
|
|
|
208
208
|
this.__map.addLayer(styleLayer.style(this.__layerOptions));
|
|
209
209
|
this.__layers.push(styleLayer);
|
|
210
210
|
}
|
|
211
|
-
// Make sure our
|
|
212
|
-
this.
|
|
211
|
+
// Make sure our paint options are set properly, in particular raster layer visibility
|
|
212
|
+
this.setPaint(this.__layerOptions);
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
addLayer(layer)
|
|
@@ -220,12 +220,12 @@ class MapRasterLayers extends MapStylingLayers
|
|
|
220
220
|
this.__map.addLayer(rasterLayer.style(this.__layerOptions));
|
|
221
221
|
this.__layers.push(rasterLayer);
|
|
222
222
|
}
|
|
223
|
-
// Make sure our
|
|
224
|
-
this.
|
|
223
|
+
// Make sure our paint options are set properly, in particular raster layer visibility
|
|
224
|
+
this.setPaint(this.__layerOptions);
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
|
|
228
|
-
|
|
227
|
+
setPaint(options)
|
|
228
|
+
//===============
|
|
229
229
|
{
|
|
230
230
|
const coloured = !('colour' in options) || options.colour;
|
|
231
231
|
for (const layer of this.__layers) {
|
|
@@ -250,7 +250,7 @@ export class LayerManager
|
|
|
250
250
|
colour: true,
|
|
251
251
|
outline: true,
|
|
252
252
|
sckan: 'valid'
|
|
253
|
-
})
|
|
253
|
+
});
|
|
254
254
|
const backgroundLayer = new style.BackgroundLayer();
|
|
255
255
|
if ('background' in flatmap.options) {
|
|
256
256
|
this.__map.addLayer(backgroundLayer.style(flatmap.options.background));
|
|
@@ -305,19 +305,19 @@ export class LayerManager
|
|
|
305
305
|
this.__layerOptions.activeRasterLayer = enable;
|
|
306
306
|
for (const mapLayer of this.__mapLayers.values()) {
|
|
307
307
|
if (mapLayer.id !== RASTER_LAYERS_ID) {
|
|
308
|
-
mapLayer.
|
|
308
|
+
mapLayer.setPaint(this.__layerOptions);
|
|
309
309
|
}
|
|
310
310
|
}
|
|
311
311
|
}
|
|
312
312
|
}
|
|
313
313
|
}
|
|
314
314
|
|
|
315
|
-
|
|
316
|
-
|
|
315
|
+
setPaint(options={})
|
|
316
|
+
//==================
|
|
317
317
|
{
|
|
318
318
|
this.__layerOptions = utils.setDefaults(options, this.__layerOptions);
|
|
319
319
|
for (const mapLayer of this.__mapLayers.values()) {
|
|
320
|
-
mapLayer.
|
|
320
|
+
mapLayer.setPaint(this.__layerOptions);
|
|
321
321
|
}
|
|
322
322
|
}
|
|
323
323
|
|
|
@@ -329,6 +329,31 @@ export class LayerManager
|
|
|
329
329
|
mapLayer.setFilter(this.__layerOptions);
|
|
330
330
|
}
|
|
331
331
|
}
|
|
332
|
+
|
|
333
|
+
enableSckanPath(sckanState, enable=true)
|
|
334
|
+
//======================================
|
|
335
|
+
{
|
|
336
|
+
const currentState = this.__layerOptions.sckan;
|
|
337
|
+
const validEnabled = ['valid', 'all'].indexOf(currentState) >= 0;
|
|
338
|
+
const invalidEnabled = ['invalid', 'all'].indexOf(currentState) >= 0;
|
|
339
|
+
let newState = sckanState.toLowerCase();
|
|
340
|
+
if (newState === 'valid') {
|
|
341
|
+
if (enable && !validEnabled) {
|
|
342
|
+
newState = invalidEnabled ? 'all' : 'valid';
|
|
343
|
+
} else if (!enable && validEnabled) {
|
|
344
|
+
newState = invalidEnabled ? 'invalid' : 'none';
|
|
345
|
+
}
|
|
346
|
+
} else if (newState === 'invalid') {
|
|
347
|
+
if (enable && !invalidEnabled) {
|
|
348
|
+
newState = validEnabled ? 'all' : 'invalid';
|
|
349
|
+
} else if (!enable && invalidEnabled) {
|
|
350
|
+
newState = validEnabled ? 'valid' : 'none';
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
if (newState !== this.__layerOptions.sckan) {
|
|
354
|
+
this.setFilter({sckan: newState});
|
|
355
|
+
}
|
|
356
|
+
}
|
|
332
357
|
}
|
|
333
358
|
|
|
334
359
|
//==============================================================================
|
package/src/pathways.js
CHANGED
|
@@ -26,19 +26,20 @@ export const PATHWAYS_LAYER = 'pathways';
|
|
|
26
26
|
|
|
27
27
|
//==============================================================================
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
const PATH_TYPES = [
|
|
30
30
|
{ type: "cns", label: "CNS", colour: "#9B1FC1"},
|
|
31
31
|
{ type: "intracardiac", label: "Local circuit neuron", colour: "#F19E38"},
|
|
32
32
|
{ type: "para-pre", label: "Parasympathetic pre-ganglionic", colour: "#3F8F4A"},
|
|
33
|
-
{ type: "para-post", label: "Parasympathetic post-ganglionic", colour: "#3F8F4A"},
|
|
33
|
+
{ type: "para-post", label: "Parasympathetic post-ganglionic", colour: "#3F8F4A", dashed: true},
|
|
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
|
-
{ type: "symp-post", label: "Sympathetic post-ganglionic", colour: "#EA3423"},
|
|
37
|
+
{ type: "symp-post", label: "Sympathetic post-ganglionic", colour: "#EA3423", dashed: true},
|
|
38
38
|
{ type: "other", label: "Other neuron type", colour: "#888"},
|
|
39
39
|
{ type: "arterial", label: "Arterial blood vessel", colour: "#F00"},
|
|
40
40
|
{ type: "venous", label: "Venous blood vessel", colour: "#2F6EBA"},
|
|
41
|
-
{ type: "centreline", label: "Nerve centrelines", colour: "#
|
|
41
|
+
{ type: "centreline", label: "Nerve centrelines", colour: "#CCC", enabled: false},
|
|
42
|
+
{ type: "error", label: "Paths with errors or warnings", colour: "#FF0"}
|
|
42
43
|
];
|
|
43
44
|
|
|
44
45
|
export const PATH_STYLE_RULES =
|
|
@@ -142,16 +143,28 @@ export class Pathways
|
|
|
142
143
|
this.__typePaths['other'].push(...paths);
|
|
143
144
|
}
|
|
144
145
|
}
|
|
146
|
+
// Nerve centrelines are a special case with their own controls
|
|
147
|
+
this.__haveCentrelines = false;
|
|
145
148
|
}
|
|
146
149
|
|
|
147
|
-
get
|
|
148
|
-
|
|
150
|
+
get haveCentrelines()
|
|
151
|
+
//===================
|
|
152
|
+
{
|
|
153
|
+
return this.__haveCentrelines;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
pathTypes()
|
|
157
|
+
//=========
|
|
149
158
|
{
|
|
150
159
|
const pathTypes = [];
|
|
151
160
|
for (const pathType of PATH_TYPES) {
|
|
152
161
|
if (pathType.type in this.__typePaths
|
|
153
162
|
&& this.__typePaths[pathType.type].length > 0) {
|
|
154
|
-
|
|
163
|
+
if (pathType.type === 'centreline') {
|
|
164
|
+
this.__haveCentrelines = true;
|
|
165
|
+
} else {
|
|
166
|
+
pathTypes.push(pathType);
|
|
167
|
+
}
|
|
155
168
|
}
|
|
156
169
|
}
|
|
157
170
|
return pathTypes;
|
package/src/styling.js
CHANGED
|
@@ -162,7 +162,8 @@ export class FeatureFillLayer extends VectorStyleLayer
|
|
|
162
162
|
'filter': [
|
|
163
163
|
'all',
|
|
164
164
|
['==', '$type', 'Polygon'],
|
|
165
|
-
['!=', 'models', 'UBERON:0013702']
|
|
165
|
+
['!=', 'models', 'UBERON:0013702'],
|
|
166
|
+
['!has', 'node']
|
|
166
167
|
],
|
|
167
168
|
'layout': {
|
|
168
169
|
'fill-sort-key': ['get', 'scale']
|
|
@@ -244,7 +245,8 @@ export class FeatureBorderLayer extends VectorStyleLayer
|
|
|
244
245
|
'type': 'line',
|
|
245
246
|
'filter': [
|
|
246
247
|
'all',
|
|
247
|
-
['==', '$type', 'Polygon']
|
|
248
|
+
['==', '$type', 'Polygon'],
|
|
249
|
+
['!has', 'node']
|
|
248
250
|
],
|
|
249
251
|
'paint': this.paintStyle(options)
|
|
250
252
|
};
|
|
@@ -287,8 +289,8 @@ export class FeatureLineLayer extends VectorStyleLayer
|
|
|
287
289
|
'line-color': [
|
|
288
290
|
'case',
|
|
289
291
|
['boolean', ['feature-state', 'selected'], false], '#0F0',
|
|
290
|
-
['has', 'colour'], ['get', 'colour'],
|
|
291
292
|
['boolean', ['feature-state', 'active'], false], coloured ? '#888' : '#CCC',
|
|
293
|
+
['has', 'colour'], ['get', 'colour'],
|
|
292
294
|
['==', ['get', 'type'], 'network'], '#AFA202',
|
|
293
295
|
options.authoring ? '#C44' : '#444'
|
|
294
296
|
],
|
|
@@ -415,7 +417,6 @@ export class PathLineLayer extends VectorStyleLayer
|
|
|
415
417
|
['boolean', ['feature-state', 'selected'], false], '#0F0',
|
|
416
418
|
['boolean', ['feature-state', 'hidden'], false], '#CCC',
|
|
417
419
|
['==', ['get', 'type'], 'bezier'], 'red',
|
|
418
|
-
['has', 'error'], '#FFFE0E',
|
|
419
420
|
['==', ['get', 'kind'], 'unknown'], '#888',
|
|
420
421
|
...PATH_STYLE_RULES,
|
|
421
422
|
'#888'
|
|
@@ -424,6 +425,7 @@ export class PathLineLayer extends VectorStyleLayer
|
|
|
424
425
|
'case',
|
|
425
426
|
['boolean', ['feature-state', 'hidden'], false], 0.05,
|
|
426
427
|
['==', ['get', 'type'], 'bezier'], 1.0,
|
|
428
|
+
['==', ['get', 'kind'], 'error'], 1.0,
|
|
427
429
|
['boolean', ['get', 'invisible'], false], 0.001,
|
|
428
430
|
['boolean', ['feature-state', 'selected'], false], 1.0,
|
|
429
431
|
['boolean', ['feature-state', 'active'], false], 1.0,
|
|
@@ -434,7 +436,7 @@ export class PathLineLayer extends VectorStyleLayer
|
|
|
434
436
|
'width', ["*", [
|
|
435
437
|
'case',
|
|
436
438
|
['==', ['get', 'type'], 'bezier'], 0.1,
|
|
437
|
-
['
|
|
439
|
+
['==', ['get', 'kind'], 'error'], 1,
|
|
438
440
|
['==', ['get', 'kind'], 'unknown'], 1,
|
|
439
441
|
['boolean', ['get', 'invisible'], false], 0.1,
|
|
440
442
|
['boolean', ['feature-state', 'selected'], false], 0.6,
|
|
@@ -568,6 +570,76 @@ export class CentrelineTrackLayer extends CentrelineLayer
|
|
|
568
570
|
|
|
569
571
|
//==============================================================================
|
|
570
572
|
|
|
573
|
+
export class CentrelineNodeFillLayer extends VectorStyleLayer
|
|
574
|
+
{
|
|
575
|
+
constructor(id, sourceLayer)
|
|
576
|
+
{
|
|
577
|
+
super(id, 'node-fill', sourceLayer);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
paintStyle(options={}, changes=false)
|
|
581
|
+
{
|
|
582
|
+
const showNodes = options.showCentrelines || false;
|
|
583
|
+
const paintStyle = {
|
|
584
|
+
'fill-color': '#AFA202',
|
|
585
|
+
'fill-opacity': showNodes ? 0.7 : 0.01
|
|
586
|
+
}
|
|
587
|
+
return super.changedPaintStyle(paintStyle, changes);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
style(options)
|
|
591
|
+
{
|
|
592
|
+
return {
|
|
593
|
+
...super.style(),
|
|
594
|
+
'type': 'fill',
|
|
595
|
+
'filter': [
|
|
596
|
+
'all',
|
|
597
|
+
['==', '$type', 'Polygon'],
|
|
598
|
+
['has', 'node']
|
|
599
|
+
],
|
|
600
|
+
'layout': {
|
|
601
|
+
'fill-sort-key': ['get', 'scale']
|
|
602
|
+
},
|
|
603
|
+
'paint': this.paintStyle(options)
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
export class CentrelineNodeBorderLayer extends VectorStyleLayer
|
|
609
|
+
{
|
|
610
|
+
constructor(id, sourceLayer)
|
|
611
|
+
{
|
|
612
|
+
super(id, 'node-border', sourceLayer);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
paintStyle(options={}, changes=false)
|
|
616
|
+
{
|
|
617
|
+
const showNodes = options.showCentrelines || false;
|
|
618
|
+
const paintStyle = {
|
|
619
|
+
'line-color': '#AFA202',
|
|
620
|
+
'line-opacity': showNodes ? 0.7 : 0.01,
|
|
621
|
+
'line-width': 0.5
|
|
622
|
+
}
|
|
623
|
+
return super.changedPaintStyle(paintStyle, changes);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
style(options)
|
|
627
|
+
{
|
|
628
|
+
return {
|
|
629
|
+
...super.style(),
|
|
630
|
+
'type': 'line',
|
|
631
|
+
'filter': [
|
|
632
|
+
'all',
|
|
633
|
+
['==', '$type', 'Polygon'],
|
|
634
|
+
['has', 'node']
|
|
635
|
+
],
|
|
636
|
+
'paint': this.paintStyle(options)
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
//==============================================================================
|
|
642
|
+
|
|
571
643
|
export class FeatureNerveLayer extends VectorStyleLayer
|
|
572
644
|
{
|
|
573
645
|
constructor(id, sourceLayer)
|
|
@@ -202,40 +202,13 @@ li.flatmap-contextmenu-item:hover {
|
|
|
202
202
|
label[for=path-all-paths] {
|
|
203
203
|
font-weight: bold;
|
|
204
204
|
}
|
|
205
|
-
.nerve-cns {
|
|
206
|
-
background: #9B1FC1;
|
|
207
|
-
}
|
|
208
|
-
.nerve-intracardiac {
|
|
209
|
-
background: #F19E38;
|
|
210
|
-
}
|
|
211
|
-
.nerve-other {
|
|
212
|
-
background: #888;
|
|
213
|
-
}
|
|
214
|
-
.nerve-para-pre {
|
|
215
|
-
background: #3F8F4A;
|
|
216
|
-
}
|
|
217
|
-
.nerve-para-post {
|
|
218
|
-
background: repeating-linear-gradient(to right,#3F8F4A 0,#3F8F4A 6px,transparent 6px,transparent 9px)
|
|
219
|
-
}
|
|
220
|
-
.nerve-sensory {
|
|
221
|
-
background: #2A62F6;
|
|
222
|
-
}
|
|
223
|
-
.nerve-somatic {
|
|
224
|
-
background: #98561D;
|
|
225
|
-
}
|
|
226
|
-
.nerve-symp-pre {
|
|
227
|
-
background: #EA3423;
|
|
228
|
-
}
|
|
229
|
-
.nerve-symp-post {
|
|
230
|
-
background: repeating-linear-gradient(to right,#EA3423 0,#EA3423 6px,transparent 6px,transparent 9px)
|
|
231
|
-
}
|
|
232
205
|
|
|
233
206
|
/* Layer control */
|
|
234
207
|
|
|
235
|
-
|
|
208
|
+
.flatmap-control {
|
|
236
209
|
text-align: right;
|
|
237
210
|
}
|
|
238
|
-
.flatmap-
|
|
211
|
+
.flatmap-control-grid {
|
|
239
212
|
margin-top: 10px;
|
|
240
213
|
display: grid;
|
|
241
214
|
grid-template-columns: 3.8fr 0.2fr;
|
|
@@ -250,7 +223,7 @@ label[for=path-all-paths] {
|
|
|
250
223
|
padding: 4px;
|
|
251
224
|
opacity: 0.8;
|
|
252
225
|
}
|
|
253
|
-
.flatmap-
|
|
226
|
+
.flatmap-control-grid input {
|
|
254
227
|
height: 1.1em;
|
|
255
228
|
}
|
|
256
229
|
label[for=layer-all-layers] {
|