@abi-software/flatmap-viewer 2.4.0-a.2 → 2.4.1-b.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.rst +1 -1
- package/package.json +2 -2
- package/src/contextmenu.js +2 -2
- package/src/controls/minimap.js +2 -2
- package/src/controls/systems.js +1 -1
- package/src/flatmap-viewer.js +53 -8
- package/src/interactions.js +33 -18
- package/src/styling.js +23 -13
- package/src/utils.js +5 -1
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.4.
|
|
41
|
+
* ``npm install @abi-software/flatmap-viewer@2.4.1-b.1``
|
|
42
42
|
|
|
43
43
|
Documentation
|
|
44
44
|
-------------
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abi-software/flatmap-viewer",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.1-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",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"bezier-js": "^6.1.0",
|
|
27
27
|
"html-es6cape": "^2.0.2",
|
|
28
28
|
"jspanel4": "^4.16.1",
|
|
29
|
-
"maplibre-gl": ">=
|
|
29
|
+
"maplibre-gl": ">=3.0.0",
|
|
30
30
|
"minisearch": "^2.2.1",
|
|
31
31
|
"polylabel": "^1.1.0"
|
|
32
32
|
},
|
package/src/contextmenu.js
CHANGED
|
@@ -22,7 +22,7 @@ limitations under the License.
|
|
|
22
22
|
|
|
23
23
|
//==============================================================================
|
|
24
24
|
|
|
25
|
-
import
|
|
25
|
+
import maplibregl from 'maplibre-gl';
|
|
26
26
|
|
|
27
27
|
//==============================================================================
|
|
28
28
|
|
|
@@ -64,7 +64,7 @@ export class ContextMenu
|
|
|
64
64
|
this._flatmap = flatmap;
|
|
65
65
|
this._map = flatmap.map;
|
|
66
66
|
this._closeCallback = closeCallback;
|
|
67
|
-
this._popup = new
|
|
67
|
+
this._popup = new maplibregl.Popup({
|
|
68
68
|
closeButton: true,
|
|
69
69
|
closeOnClick: true,
|
|
70
70
|
className: 'flatmap-contextmenu-popup',
|
package/src/controls/minimap.js
CHANGED
|
@@ -45,7 +45,7 @@ limitations under the License.
|
|
|
45
45
|
|
|
46
46
|
//==============================================================================
|
|
47
47
|
|
|
48
|
-
import
|
|
48
|
+
import maplibregl from 'maplibre-gl';
|
|
49
49
|
|
|
50
50
|
//==============================================================================
|
|
51
51
|
|
|
@@ -146,7 +146,7 @@ export class MinimapControl
|
|
|
146
146
|
|
|
147
147
|
// Create the actual minimap
|
|
148
148
|
|
|
149
|
-
this._miniMap = new
|
|
149
|
+
this._miniMap = new maplibregl.Map({
|
|
150
150
|
attributionControl: false,
|
|
151
151
|
container: container,
|
|
152
152
|
style: map.getStyle(),
|
package/src/controls/systems.js
CHANGED
package/src/flatmap-viewer.js
CHANGED
|
@@ -79,6 +79,7 @@ class FlatMap
|
|
|
79
79
|
this.__modelToFeatureIds = new Map();
|
|
80
80
|
this.__mapSourceToFeatureIds = new Map();
|
|
81
81
|
this.__annIdToFeatureId = new Map();
|
|
82
|
+
this.__taxonToFeatureIds = new Map();
|
|
82
83
|
|
|
83
84
|
for (const [featureId, annotation] of Object.entries(mapDescription.annotations)) {
|
|
84
85
|
this.__addAnnotation(featureId, annotation);
|
|
@@ -331,6 +332,26 @@ class FlatMap
|
|
|
331
332
|
}
|
|
332
333
|
}
|
|
333
334
|
|
|
335
|
+
/**
|
|
336
|
+
* Show or hide connectivity features observed in particular species.
|
|
337
|
+
*
|
|
338
|
+
* @param {string | Array.<string>} taxonId(s) A single taxon identifier
|
|
339
|
+
* or an array of identifiers.
|
|
340
|
+
* @param {boolean} enable Show or hide connectivity paths and features.
|
|
341
|
+
* Defaults to ``true`` (show)
|
|
342
|
+
*/
|
|
343
|
+
enableConnectivityByTaxonIds(taxonIds, enable=true)
|
|
344
|
+
//=================================================
|
|
345
|
+
{
|
|
346
|
+
if (this._userInteractions !== null) {
|
|
347
|
+
if (Array.isArray(taxonIds)) {
|
|
348
|
+
this._userInteractions.enableConnectivityByTaxonIds(taxonIds, enable);
|
|
349
|
+
} else {
|
|
350
|
+
this._userInteractions.enableConnectivityByTaxonIds([taxonIds], enable);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
334
355
|
/**
|
|
335
356
|
* Hide or show centrelines and nodes.
|
|
336
357
|
*
|
|
@@ -511,16 +532,28 @@ class FlatMap
|
|
|
511
532
|
}
|
|
512
533
|
}
|
|
513
534
|
|
|
535
|
+
__updateFeatureIdMapEntry(propertyId, featureIdMap, featureId)
|
|
536
|
+
//======================================================
|
|
537
|
+
{
|
|
538
|
+
const featureIds = featureIdMap.get(propertyId);
|
|
539
|
+
if (featureIds) {
|
|
540
|
+
featureIds.push(featureId);
|
|
541
|
+
} else {
|
|
542
|
+
featureIdMap.set(propertyId, [featureId]);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
514
546
|
__updateFeatureIdMap(property, featureIdMap, annotation)
|
|
515
547
|
//======================================================
|
|
516
548
|
{
|
|
517
549
|
if (property in annotation) {
|
|
518
|
-
const
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
550
|
+
const propertyId = annotation[property];
|
|
551
|
+
if (Array.isArray(propertyId)) {
|
|
552
|
+
for (const id of propertyId) {
|
|
553
|
+
this.__updateFeatureIdMapEntry(id, featureIdMap, annotation.featureId);
|
|
554
|
+
}
|
|
522
555
|
} else {
|
|
523
|
-
|
|
556
|
+
this.__updateFeatureIdMapEntry(propertyId, featureIdMap, annotation.featureId)
|
|
524
557
|
}
|
|
525
558
|
}
|
|
526
559
|
}
|
|
@@ -533,6 +566,7 @@ class FlatMap
|
|
|
533
566
|
this.__updateFeatureIdMap('dataset', this.__datasetToFeatureIds, ann);
|
|
534
567
|
this.__updateFeatureIdMap('models', this.__modelToFeatureIds, ann);
|
|
535
568
|
this.__updateFeatureIdMap('source', this.__mapSourceToFeatureIds, ann);
|
|
569
|
+
this.__updateFeatureIdMap('taxons', this.__taxonToFeatureIds, ann);
|
|
536
570
|
this.__annIdToFeatureId.set(ann.id, featureId);
|
|
537
571
|
}
|
|
538
572
|
|
|
@@ -610,6 +644,17 @@ class FlatMap
|
|
|
610
644
|
return [...this.__modelToFeatureIds.keys()]
|
|
611
645
|
}
|
|
612
646
|
|
|
647
|
+
/**
|
|
648
|
+
* The taxon identifiers of species which the map's connectivity has been observed in.
|
|
649
|
+
*
|
|
650
|
+
* @type {string|Array.<string>}
|
|
651
|
+
*/
|
|
652
|
+
get taxonIdentifiers()
|
|
653
|
+
//====================
|
|
654
|
+
{
|
|
655
|
+
return [...this.__taxonToFeatureIds.keys()]
|
|
656
|
+
}
|
|
657
|
+
|
|
613
658
|
/**
|
|
614
659
|
* Datasets associated with the map.
|
|
615
660
|
*
|
|
@@ -817,7 +862,7 @@ class FlatMap
|
|
|
817
862
|
/**
|
|
818
863
|
* Get a list of the flatmap's layers.
|
|
819
864
|
*
|
|
820
|
-
* @return {Array
|
|
865
|
+
* @return {Array.<{id: string, description: string, enabled: boolean}>} An array with layer details
|
|
821
866
|
*/
|
|
822
867
|
getLayers()
|
|
823
868
|
//=========
|
|
@@ -845,7 +890,7 @@ class FlatMap
|
|
|
845
890
|
/**
|
|
846
891
|
* Get a list of a FC flatmap's systems.
|
|
847
892
|
*
|
|
848
|
-
* @return {Array
|
|
893
|
+
* @return {Array.<{id: string, name: string, colour: string, enabled: boolean}>} An array with system details
|
|
849
894
|
*/
|
|
850
895
|
getSystems()
|
|
851
896
|
//==========
|
|
@@ -970,7 +1015,7 @@ class FlatMap
|
|
|
970
1015
|
'models',
|
|
971
1016
|
'nodeId',
|
|
972
1017
|
'source',
|
|
973
|
-
'
|
|
1018
|
+
'taxons',
|
|
974
1019
|
'hyperlinks'
|
|
975
1020
|
];
|
|
976
1021
|
const jsonProperties = [
|
package/src/interactions.js
CHANGED
|
@@ -22,7 +22,7 @@ limitations under the License.
|
|
|
22
22
|
|
|
23
23
|
//==============================================================================
|
|
24
24
|
|
|
25
|
-
import
|
|
25
|
+
import maplibregl from 'maplibre-gl';
|
|
26
26
|
|
|
27
27
|
import {default as turfArea} from '@turf/area';
|
|
28
28
|
import {default as turfBBox} from '@turf/bbox';
|
|
@@ -80,12 +80,13 @@ function bounds(feature)
|
|
|
80
80
|
|
|
81
81
|
//==============================================================================
|
|
82
82
|
|
|
83
|
-
function expandBounds(bbox1, bbox2)
|
|
84
|
-
|
|
83
|
+
function expandBounds(bbox1, bbox2, padding)
|
|
84
|
+
//==========================================
|
|
85
85
|
{
|
|
86
|
-
return (bbox1 === null) ? bbox2
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
return (bbox1 === null) ? [bbox2[0]-padding.lng, bbox2[1]-padding.lat,
|
|
87
|
+
bbox2[2]+padding.lng, bbox2[3]+padding.lat]
|
|
88
|
+
: [Math.min(bbox1[0], bbox2[0]-padding.lng), Math.min(bbox1[1], bbox2[1]-padding.lat),
|
|
89
|
+
Math.max(bbox1[2], bbox2[2]+padding.lng), Math.max(bbox1[3], bbox2[3]+padding.lat)
|
|
89
90
|
];
|
|
90
91
|
}
|
|
91
92
|
|
|
@@ -615,7 +616,7 @@ export class UserInteractions
|
|
|
615
616
|
{
|
|
616
617
|
options = utils.setDefaults(options, {
|
|
617
618
|
noZoomIn: false,
|
|
618
|
-
padding: 10
|
|
619
|
+
padding: 10 // pixels
|
|
619
620
|
});
|
|
620
621
|
if (featureIds.length) {
|
|
621
622
|
this.unselectFeatures();
|
|
@@ -624,16 +625,20 @@ export class UserInteractions
|
|
|
624
625
|
const bounds = this._map.getBounds().toArray();
|
|
625
626
|
bbox = [...bounds[0], ...bounds[1]];
|
|
626
627
|
}
|
|
628
|
+
// Convert pixel padding to LngLat and apply it to a feature's bounds
|
|
629
|
+
const padding = this._map.unproject({x: options.padding, y: options.padding});
|
|
630
|
+
padding.lng -= bbox[0];
|
|
631
|
+
padding.lat = bbox[3] - padding.lat;
|
|
627
632
|
for (const featureId of featureIds) {
|
|
628
633
|
const annotation = this._flatmap.annotation(featureId);
|
|
629
634
|
if (annotation) {
|
|
630
635
|
if (this.selectFeature(featureId)) {
|
|
631
|
-
bbox = expandBounds(bbox, annotation.bounds);
|
|
636
|
+
bbox = expandBounds(bbox, annotation.bounds, padding);
|
|
632
637
|
if ('type' in annotation && annotation.type.startsWith('line')) {
|
|
633
638
|
for (const pathFeatureId of this.__pathManager.lineFeatureIds([featureId])) {
|
|
634
639
|
if (this.selectFeature(pathFeatureId)) {
|
|
635
640
|
const pathAnnotation = this._flatmap.annotation(pathFeatureId)
|
|
636
|
-
bbox = expandBounds(bbox, pathAnnotation.bounds);
|
|
641
|
+
bbox = expandBounds(bbox, pathAnnotation.bounds, padding);
|
|
637
642
|
}
|
|
638
643
|
}
|
|
639
644
|
}
|
|
@@ -642,7 +647,7 @@ export class UserInteractions
|
|
|
642
647
|
}
|
|
643
648
|
if (bbox !== null) {
|
|
644
649
|
this._map.fitBounds(bbox, {
|
|
645
|
-
padding:
|
|
650
|
+
padding: 0,
|
|
646
651
|
animate: false
|
|
647
652
|
});
|
|
648
653
|
}
|
|
@@ -694,7 +699,7 @@ export class UserInteractions
|
|
|
694
699
|
this._map.panTo(location);
|
|
695
700
|
}
|
|
696
701
|
this.setModal_();
|
|
697
|
-
this._currentPopup = new
|
|
702
|
+
this._currentPopup = new maplibregl.Popup(options).addTo(this._map);
|
|
698
703
|
this._currentPopup.on('close', this.__onCloseCurrentPopup.bind(this));
|
|
699
704
|
this._currentPopup.setLngLat(location);
|
|
700
705
|
if (typeof content === 'object') {
|
|
@@ -955,7 +960,7 @@ export class UserInteractions
|
|
|
955
960
|
html = `<span>${header}</span><br/>${html}`;
|
|
956
961
|
}
|
|
957
962
|
if (html !== '') {
|
|
958
|
-
this._tooltip = new
|
|
963
|
+
this._tooltip = new maplibregl.Popup({
|
|
959
964
|
closeButton: false,
|
|
960
965
|
closeOnClick: false,
|
|
961
966
|
maxWidth: 'none',
|
|
@@ -1127,6 +1132,16 @@ export class UserInteractions
|
|
|
1127
1132
|
this._layerManager.enableSckanPaths(sckanState, enable);
|
|
1128
1133
|
}
|
|
1129
1134
|
|
|
1135
|
+
enableConnectivityByTaxonIds(taxonIds, enable=true)
|
|
1136
|
+
//=================================================
|
|
1137
|
+
{
|
|
1138
|
+
if (enable) {
|
|
1139
|
+
this._layerManager.setFilter({taxons: taxonIds});
|
|
1140
|
+
} else {
|
|
1141
|
+
this._layerManager.setFilter({taxons: []});
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1130
1145
|
excludeAnnotated(exclude=false)
|
|
1131
1146
|
//=============================
|
|
1132
1147
|
{
|
|
@@ -1190,8 +1205,8 @@ export class UserInteractions
|
|
|
1190
1205
|
// order to apply a scale transform we need to create marker icons
|
|
1191
1206
|
// inside the marker container <div>.
|
|
1192
1207
|
const colour = options.colour || '#005974';
|
|
1193
|
-
const markerHTML = options.element ? new
|
|
1194
|
-
: new
|
|
1208
|
+
const markerHTML = options.element ? new maplibregl.Marker({element: options.element})
|
|
1209
|
+
: new maplibregl.Marker({color: colour});
|
|
1195
1210
|
|
|
1196
1211
|
const markerElement = document.createElement('div');
|
|
1197
1212
|
const markerIcon = document.createElement('div');
|
|
@@ -1201,9 +1216,9 @@ export class UserInteractions
|
|
|
1201
1216
|
markerElement.appendChild(markerIcon);
|
|
1202
1217
|
|
|
1203
1218
|
const markerPosition = this.__markerPosition(featureId, annotation);
|
|
1204
|
-
const marker = new
|
|
1205
|
-
|
|
1206
|
-
|
|
1219
|
+
const marker = new maplibregl.Marker(markerElement)
|
|
1220
|
+
.setLngLat(markerPosition)
|
|
1221
|
+
.addTo(this._map);
|
|
1207
1222
|
markerElement.addEventListener('mouseenter',
|
|
1208
1223
|
this.markerMouseEvent_.bind(this, marker, anatomicalId));
|
|
1209
1224
|
markerElement.addEventListener('mousemove',
|
|
@@ -1345,7 +1360,7 @@ export class UserInteractions
|
|
|
1345
1360
|
|
|
1346
1361
|
element.addEventListener('click', e => this.__clearActiveMarker());
|
|
1347
1362
|
|
|
1348
|
-
this._tooltip = new
|
|
1363
|
+
this._tooltip = new maplibregl.Popup({
|
|
1349
1364
|
closeButton: false,
|
|
1350
1365
|
closeOnClick: false,
|
|
1351
1366
|
maxWidth: 'none',
|
package/src/styling.js
CHANGED
|
@@ -374,24 +374,24 @@ function sckanFilter(options)
|
|
|
374
374
|
: options.sckan.toLowerCase();
|
|
375
375
|
const sckanFilter =
|
|
376
376
|
sckanState == 'none' ? [
|
|
377
|
-
['!has', 'sckan']
|
|
377
|
+
['!', ['has', 'sckan']]
|
|
378
378
|
] :
|
|
379
379
|
sckanState == 'valid' ? [[
|
|
380
380
|
'any',
|
|
381
|
-
['!has', 'sckan'],
|
|
381
|
+
['!', ['has', 'sckan']],
|
|
382
382
|
[
|
|
383
383
|
'all',
|
|
384
384
|
['has', 'sckan'],
|
|
385
|
-
['==', 'sckan', true]
|
|
385
|
+
['==', ['get', 'sckan'], true]
|
|
386
386
|
]
|
|
387
387
|
]] :
|
|
388
388
|
sckanState == 'invalid' ? [[
|
|
389
389
|
'any',
|
|
390
|
-
['!has', 'sckan'],
|
|
390
|
+
['!', ['has', 'sckan']],
|
|
391
391
|
[
|
|
392
392
|
'all',
|
|
393
393
|
['has', 'sckan'],
|
|
394
|
-
['!=', 'sckan', true]
|
|
394
|
+
['!=', ['get', 'sckan'], true]
|
|
395
395
|
]
|
|
396
396
|
]] :
|
|
397
397
|
[ ];
|
|
@@ -411,7 +411,6 @@ export class AnnotatedPathLayer extends VectorStyleLayer
|
|
|
411
411
|
{
|
|
412
412
|
return [
|
|
413
413
|
'all',
|
|
414
|
-
['==', '$type', 'LineString'],
|
|
415
414
|
...sckanFilter(options)
|
|
416
415
|
];
|
|
417
416
|
}
|
|
@@ -481,22 +480,33 @@ export class PathLineLayer extends VectorStyleLayer
|
|
|
481
480
|
makeFilter(options={})
|
|
482
481
|
{
|
|
483
482
|
const sckan_filter = sckanFilter(options);
|
|
483
|
+
let taxonFilter = [];
|
|
484
|
+
if ('taxons' in options) {
|
|
485
|
+
taxonFilter.push('all');
|
|
486
|
+
taxonFilter.push(['has', 'taxons']);
|
|
487
|
+
const filterList = ['any'];
|
|
488
|
+
for (const taxon of options.taxons) {
|
|
489
|
+
filterList.push(['in', taxon, ['get', 'taxons']]);
|
|
490
|
+
}
|
|
491
|
+
taxonFilter.push(filterList);
|
|
492
|
+
taxonFilter = [taxonFilter];
|
|
493
|
+
}
|
|
484
494
|
|
|
485
495
|
return this.__dashed ? [
|
|
486
496
|
'all',
|
|
487
|
-
['==', '
|
|
488
|
-
|
|
489
|
-
...
|
|
497
|
+
['==', ['get', 'type'], 'line-dash'],
|
|
498
|
+
...sckan_filter,
|
|
499
|
+
...taxonFilter
|
|
490
500
|
] : [
|
|
491
501
|
'all',
|
|
492
|
-
['==', '$type', 'LineString'],
|
|
493
502
|
[
|
|
494
503
|
'any',
|
|
495
|
-
['==', 'type', 'bezier'],
|
|
504
|
+
['==', ['get', 'type'], 'bezier'],
|
|
496
505
|
[
|
|
497
506
|
'all',
|
|
498
|
-
['==', 'type',
|
|
499
|
-
...sckan_filter
|
|
507
|
+
['==', ['get', 'type'], 'line'],
|
|
508
|
+
...sckan_filter,
|
|
509
|
+
...taxonFilter
|
|
500
510
|
]
|
|
501
511
|
]
|
|
502
512
|
];
|
package/src/utils.js
CHANGED
|
@@ -22,6 +22,10 @@ limitations under the License.
|
|
|
22
22
|
|
|
23
23
|
//==============================================================================
|
|
24
24
|
|
|
25
|
+
const NO_NORMALISATION = ['http', 'https', 'urn', 'NCBITaxon'];
|
|
26
|
+
|
|
27
|
+
//==============================================================================
|
|
28
|
+
|
|
25
29
|
export class List extends Array {
|
|
26
30
|
constructor(iterable=null) {
|
|
27
31
|
super();
|
|
@@ -101,7 +105,7 @@ export function normaliseId(id)
|
|
|
101
105
|
}
|
|
102
106
|
const parts = id.split(':')
|
|
103
107
|
const lastPart = parts[parts.length - 1]
|
|
104
|
-
if (
|
|
108
|
+
if (NO_NORMALISATION.includes(parts[0]) || !'0123456789'.includes(lastPart[0])) {
|
|
105
109
|
return id;
|
|
106
110
|
}
|
|
107
111
|
parts[parts.length - 1] = lastPart.padStart(8, '0');
|