@abi-software/flatmap-viewer 2.7.2 → 2.7.3-a.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/dist/flatmapviewer.es.js +80577 -0
- package/dist/flatmapviewer.umd.js +1687 -0
- package/dist/lib/index.d.ts +4 -0
- package/dist/style.css +1 -0
- package/package.json +10 -8
- package/lib/index.ts +0 -10
- package/src/contextmenu.js +0 -97
- package/src/controls/annotation.js +0 -302
- package/src/controls/controls.js +0 -645
- package/src/controls/flightpaths.js +0 -95
- package/src/controls/info.js +0 -291
- package/src/controls/minimap.js +0 -442
- package/src/controls/paths.js +0 -143
- package/src/controls/search.js +0 -113
- package/src/controls/systems.js +0 -75
- package/src/controls/taxons.js +0 -73
- package/src/flatmap-viewer.js +0 -1789
- package/src/images.js +0 -66
- package/src/interactions.js +0 -1569
- package/src/layers/cluster.js +0 -177
- package/src/layers/filter.js +0 -310
- package/src/layers/flightpaths.js +0 -383
- package/src/layers/index.js +0 -478
- package/src/layers/styling.js +0 -1077
- package/src/main.js +0 -272
- package/src/mapserver.js +0 -64
- package/src/mathjax.js +0 -100
- package/src/pathways.js +0 -427
- package/src/search.js +0 -137
- package/src/systems.js +0 -146
- package/src/utils.js +0 -152
- package/static/css/flatmap-viewer.css +0 -238
- package/static/icons/favicon.ico +0 -0
- package/static/images/active.png +0 -0
- package/static/images/inactive.png +0 -0
- package/static/images/reset-map-active.png +0 -0
- package/static/images/reset-map-button.png +0 -0
- package/static/images/rounded-background.png +0 -0
- package/static/images/zoom-in-active.png +0 -0
- package/static/images/zoom-in-button.png +0 -0
- package/static/images/zoom-out-active.png +0 -0
- package/static/images/zoom-out-button.png +0 -0
- package/thirdParty/maplibre-gl-svg/CHANGELOG.md +0 -13
- package/thirdParty/maplibre-gl-svg/LICENSE +0 -21
- package/thirdParty/maplibre-gl-svg/LICENSE.md +0 -21
- package/thirdParty/maplibre-gl-svg/README.md +0 -24
- package/thirdParty/maplibre-gl-svg/assets/Add custom SVG template to template manager.jpg +0 -0
- package/thirdParty/maplibre-gl-svg/assets/All built-in SVG templates as HTML markers.jpg +0 -0
- package/thirdParty/maplibre-gl-svg/assets/All built-in SVG templates as symbols.jpg +0 -0
- package/thirdParty/maplibre-gl-svg/assets/Fill polygon with built-in SVG template.jpg +0 -0
- package/thirdParty/maplibre-gl-svg/assets/HTML Marker with Custom SVG Template.jpg +0 -0
- package/thirdParty/maplibre-gl-svg/assets/HTML Marker with built-in SVG template.jpg +0 -0
- package/thirdParty/maplibre-gl-svg/assets/Line layer with built-in SVG template.jpg +0 -0
- package/thirdParty/maplibre-gl-svg/assets/Load SVG from URL.jpg +0 -0
- package/thirdParty/maplibre-gl-svg/assets/SVG template options.jpg +0 -0
- package/thirdParty/maplibre-gl-svg/assets/Smiley_face_changed.svg +0 -37
- package/thirdParty/maplibre-gl-svg/assets/Symbol layer with built-in SVG template.jpg +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/arrow-up-thin.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/arrow-up.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/car.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/checker-rotated.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/checker.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/circles-spaced.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/circles.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/diagonal-lines-down.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/diagonal-lines-up.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/diagonal-stripes-down.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/diagonal-stripes-up.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/dots.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/flag-triangle.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/flag.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/grid-lines.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/hexagon-rounded-thick.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/hexagon-rounded.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/hexagon-thick.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/hexagon.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/marker-arrow.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/marker-ball-pin.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/marker-circle.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/marker-flat.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/marker-square-cluster.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/marker-square-rounded-cluster.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/marker-square-rounded.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/marker-square.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/marker-thick.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/marker.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/pin-round.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/pin.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/rotated-grid-lines.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/rotated-grid-stripes.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/rounded-square-thick.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/rounded-square.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/triangle-arrow-left.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/triangle-arrow-up.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/triangle-thick.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/triangle.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/x-fill.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/zig-zag-vertical.png +0 -0
- package/thirdParty/maplibre-gl-svg/assets/image-templates/zig-zag.png +0 -0
- package/thirdParty/maplibre-gl-svg/build/build.js +0 -210
- package/thirdParty/maplibre-gl-svg/dist/maplibre-gl-svg.js +0 -339
- package/thirdParty/maplibre-gl-svg/dist/maplibre-gl-svg.min.js +0 -4
- package/thirdParty/maplibre-gl-svg/docs/docs.md +0 -375
- package/thirdParty/maplibre-gl-svg/examples/Add custom SVG template to template manager.html +0 -101
- package/thirdParty/maplibre-gl-svg/examples/All built-in SVG templates as HTML markers.html +0 -82
- package/thirdParty/maplibre-gl-svg/examples/All built-in SVG templates as symbols.html +0 -124
- package/thirdParty/maplibre-gl-svg/examples/Fill polygon with built-in SVG template.html +0 -94
- package/thirdParty/maplibre-gl-svg/examples/HTML Marker with Custom SVG Template.html +0 -86
- package/thirdParty/maplibre-gl-svg/examples/HTML Marker with built-in SVG template.html +0 -83
- package/thirdParty/maplibre-gl-svg/examples/Line layer with built-in SVG template.html +0 -129
- package/thirdParty/maplibre-gl-svg/examples/Load SVG from URL.html +0 -96
- package/thirdParty/maplibre-gl-svg/examples/SVG template options.html +0 -264
- package/thirdParty/maplibre-gl-svg/examples/Symbol layer with built-in SVG template.html +0 -93
- package/thirdParty/maplibre-gl-svg/index.html +0 -151
- package/thirdParty/maplibre-gl-svg/package-lock.json +0 -5882
- package/thirdParty/maplibre-gl-svg/package.json +0 -49
- package/thirdParty/maplibre-gl-svg/src/SvgManager.ts +0 -186
- package/thirdParty/maplibre-gl-svg/src/SvgTemplateManager.ts +0 -144
- package/thirdParty/maplibre-gl-svg/src/index.ts +0 -4
- package/thirdParty/maplibre-gl-svg/tsconfig.json +0 -31
- package/thirdParty/maplibre-gl-svg/typings/index.d.ts +0 -111
package/src/flatmap-viewer.js
DELETED
|
@@ -1,1789 +0,0 @@
|
|
|
1
|
-
/******************************************************************************
|
|
2
|
-
|
|
3
|
-
Flatmap viewer and annotation tool
|
|
4
|
-
|
|
5
|
-
Copyright (c) 2019 David Brooks
|
|
6
|
-
|
|
7
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
-
you may not use this file except in compliance with the License.
|
|
9
|
-
You may obtain a copy of the License at
|
|
10
|
-
|
|
11
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
-
|
|
13
|
-
Unless required by applicable law or agreed to in writing, software
|
|
14
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
-
See the License for the specific language governing permissions and
|
|
17
|
-
limitations under the License.
|
|
18
|
-
|
|
19
|
-
******************************************************************************/
|
|
20
|
-
|
|
21
|
-
'use strict';
|
|
22
|
-
|
|
23
|
-
//==============================================================================
|
|
24
|
-
|
|
25
|
-
import maplibregl from 'maplibre-gl';
|
|
26
|
-
import 'maplibre-gl/dist/maplibre-gl.css';
|
|
27
|
-
|
|
28
|
-
//==============================================================================
|
|
29
|
-
|
|
30
|
-
// Load our stylesheet last so we can overide styling rules
|
|
31
|
-
|
|
32
|
-
import '../static/css/flatmap-viewer.css';
|
|
33
|
-
|
|
34
|
-
//==============================================================================
|
|
35
|
-
|
|
36
|
-
import {MapServer} from './mapserver.js';
|
|
37
|
-
import {SearchIndex} from './search.js';
|
|
38
|
-
import {UserInteractions} from './interactions.js';
|
|
39
|
-
|
|
40
|
-
import {APINATOMY_PATH_PREFIX} from './pathways';
|
|
41
|
-
|
|
42
|
-
import {loadClusterIcons} from './layers/cluster'
|
|
43
|
-
|
|
44
|
-
import * as images from './images.js';
|
|
45
|
-
import * as utils from './utils.js';
|
|
46
|
-
|
|
47
|
-
//==============================================================================
|
|
48
|
-
|
|
49
|
-
const MAP_MAKER_SEPARATE_LAYERS_VERSION = 1.4;
|
|
50
|
-
|
|
51
|
-
//==============================================================================
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* The taxon identifier used when none has been given.
|
|
55
|
-
*
|
|
56
|
-
* @type {string}
|
|
57
|
-
*/
|
|
58
|
-
export const UNCLASSIFIED_TAXON_ID = 'NCBITaxon:2787823'; // unclassified entries
|
|
59
|
-
|
|
60
|
-
//==============================================================================
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Maps are not created directly but instead are created and loaded by
|
|
64
|
-
* :meth:`LoadMap` of :class:`MapManager`.
|
|
65
|
-
*/
|
|
66
|
-
export class FlatMap
|
|
67
|
-
{
|
|
68
|
-
constructor(container, mapBaseUrl, mapDescription, resolve)
|
|
69
|
-
{
|
|
70
|
-
this._baseUrl = mapBaseUrl;
|
|
71
|
-
this.__id = mapDescription.id;
|
|
72
|
-
this.__uuid = mapDescription.uuid;
|
|
73
|
-
this.__details = mapDescription.details;
|
|
74
|
-
this.__provenance = mapDescription.provenance;
|
|
75
|
-
this.__created = mapDescription.created;
|
|
76
|
-
this.__taxon = mapDescription.taxon;
|
|
77
|
-
this.__biologicalSex = mapDescription.biologicalSex;
|
|
78
|
-
this._mapNumber = mapDescription.number;
|
|
79
|
-
this._callback = mapDescription.callback;
|
|
80
|
-
this._layers = mapDescription.layers;
|
|
81
|
-
this._markers = mapDescription.markers;
|
|
82
|
-
this._options = mapDescription.options;
|
|
83
|
-
this._pathways = mapDescription.pathways;
|
|
84
|
-
this._resolve = resolve;
|
|
85
|
-
this._map = null;
|
|
86
|
-
this.__searchIndex = new SearchIndex(this);
|
|
87
|
-
this.__idToAnnotation = new Map();
|
|
88
|
-
this.__datasetToFeatureIds = new Map();
|
|
89
|
-
this.__modelToFeatureIds = new Map();
|
|
90
|
-
this.__mapSourceToFeatureIds = new Map();
|
|
91
|
-
this.__annIdToFeatureId = new Map();
|
|
92
|
-
this.__taxonToFeatureIds = new Map();
|
|
93
|
-
|
|
94
|
-
for (const [featureId, annotation] of Object.entries(mapDescription.annotations)) {
|
|
95
|
-
this.__addAnnotation(featureId, annotation);
|
|
96
|
-
this.__searchIndex.indexMetadata(featureId, annotation);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Set base of source URLs in map's style
|
|
100
|
-
|
|
101
|
-
for (const [id, source] of Object.entries(mapDescription.style.sources)) {
|
|
102
|
-
if (source.url) {
|
|
103
|
-
source.url = this.makeServerUrl(source.url);
|
|
104
|
-
}
|
|
105
|
-
if (source.tiles) {
|
|
106
|
-
const tiles = [];
|
|
107
|
-
for (const tileUrl of source.tiles) {
|
|
108
|
-
tiles.push(this.makeServerUrl(tileUrl));
|
|
109
|
-
}
|
|
110
|
-
source.tiles = tiles;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Ensure rounded background images (for feature labels) are loaded
|
|
115
|
-
|
|
116
|
-
if (!('images' in mapDescription.options)) {
|
|
117
|
-
mapDescription.options.images = [];
|
|
118
|
-
}
|
|
119
|
-
for (const image of images.LABEL_BACKGROUNDS) {
|
|
120
|
-
let found = false;
|
|
121
|
-
for (const im of mapDescription.options.images) {
|
|
122
|
-
if (image.id === im.id) {
|
|
123
|
-
found = true;
|
|
124
|
-
break;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
if (!found) {
|
|
128
|
-
mapDescription.options.images.push(image);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Set options for the map
|
|
133
|
-
|
|
134
|
-
const mapOptions = {
|
|
135
|
-
style: mapDescription.style,
|
|
136
|
-
container: container,
|
|
137
|
-
attributionControl: false
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
if ('maxZoom' in mapDescription.options) {
|
|
141
|
-
mapOptions.maxZoom = mapDescription.options.maxZoom;
|
|
142
|
-
}
|
|
143
|
-
if ('minZoom' in mapDescription.options) {
|
|
144
|
-
mapOptions.minZoom = mapDescription.options.minZoom;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Only show location in address bar when debugging
|
|
148
|
-
|
|
149
|
-
mapOptions.hash = (mapDescription.options.debug === true);
|
|
150
|
-
|
|
151
|
-
// Create the map
|
|
152
|
-
|
|
153
|
-
this._map = new maplibregl.Map(mapOptions);
|
|
154
|
-
|
|
155
|
-
// Show tile boundaries if debugging
|
|
156
|
-
|
|
157
|
-
if (mapDescription.options.debug === true) {
|
|
158
|
-
this._map.showTileBoundaries = true;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Don't wrap around at +/-180 degrees
|
|
162
|
-
|
|
163
|
-
this._map.setRenderWorldCopies(false);
|
|
164
|
-
|
|
165
|
-
// Disable map rotation
|
|
166
|
-
|
|
167
|
-
//this._map.dragRotate.disable();
|
|
168
|
-
//this._map.touchZoomRotate.disableRotation();
|
|
169
|
-
|
|
170
|
-
// Finish initialisation when all sources have loaded
|
|
171
|
-
// and map has rendered
|
|
172
|
-
|
|
173
|
-
this._userInteractions = null;
|
|
174
|
-
this._initialState = null;
|
|
175
|
-
|
|
176
|
-
this._map.on('idle', () => {
|
|
177
|
-
if (this._userInteractions === null) {
|
|
178
|
-
this.setupUserInteractions_();
|
|
179
|
-
} else if (this._initialState === null) {
|
|
180
|
-
this._map.setMinZoom(3.0);
|
|
181
|
-
this._map.setMaxBounds(null);
|
|
182
|
-
this._map.setRenderWorldCopies(true);
|
|
183
|
-
this._bounds = this._map.getBounds();
|
|
184
|
-
const bounds = this._bounds.toArray();
|
|
185
|
-
const sw = maplibregl.MercatorCoordinate.fromLngLat(bounds[0]);
|
|
186
|
-
const ne = maplibregl.MercatorCoordinate.fromLngLat(bounds[1]);
|
|
187
|
-
this.__normalised_origin = [sw.x, ne.y];
|
|
188
|
-
this.__normalised_size = [ne.x - sw.x, sw.y - ne.y];
|
|
189
|
-
if ('state' in this._options) {
|
|
190
|
-
this._userInteractions.setState(this._options.state);
|
|
191
|
-
}
|
|
192
|
-
this._initialState = this.getState();
|
|
193
|
-
if (this._userInteractions.minimap) {
|
|
194
|
-
this._userInteractions.minimap.initialise()
|
|
195
|
-
}
|
|
196
|
-
this._resolve(this);
|
|
197
|
-
}
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
async setupUserInteractions_()
|
|
202
|
-
//============================
|
|
203
|
-
{
|
|
204
|
-
// Load any images required by the map
|
|
205
|
-
for (const image of this._options.images) {
|
|
206
|
-
await this.addImage(image.id, image.url, '', image.options);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Load icons used for clustered markers
|
|
210
|
-
await loadClusterIcons(this._map)
|
|
211
|
-
|
|
212
|
-
// Layers have now loaded so finish setting up
|
|
213
|
-
this._userInteractions = new UserInteractions(this);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* The flatmap's bounds.
|
|
218
|
-
*/
|
|
219
|
-
get bounds()
|
|
220
|
-
//==========
|
|
221
|
-
{
|
|
222
|
-
return this._bounds;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// Map control methods
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Reset a map to its initial state.
|
|
229
|
-
*/
|
|
230
|
-
resetMap()
|
|
231
|
-
//========
|
|
232
|
-
{
|
|
233
|
-
if (this._initialState !== null) {
|
|
234
|
-
this.setState(this._initialState);
|
|
235
|
-
}
|
|
236
|
-
if (this._userInteractions !== null) {
|
|
237
|
-
this._userInteractions.reset();
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* Zoom the map in.
|
|
243
|
-
*/
|
|
244
|
-
zoomIn()
|
|
245
|
-
//======
|
|
246
|
-
{
|
|
247
|
-
this._map.zoomIn();
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Zoom the map out.
|
|
252
|
-
*/
|
|
253
|
-
zoomOut()
|
|
254
|
-
//=======
|
|
255
|
-
{
|
|
256
|
-
this._map.zoomOut();
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* @returns {Array.<{type: string, label: string, colour: string}>} an array of objects giving the path types
|
|
261
|
-
* present in the map along with their
|
|
262
|
-
* descriptions and colours
|
|
263
|
-
*/
|
|
264
|
-
pathTypes()
|
|
265
|
-
//=========
|
|
266
|
-
{
|
|
267
|
-
if (this._userInteractions !== null) {
|
|
268
|
-
return this._userInteractions.pathManager.pathTypes();
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* Hide or show paths of a given type.
|
|
274
|
-
*
|
|
275
|
-
* @param {string} pathType The path type
|
|
276
|
-
* @param {boolean} enable Show or hide paths of that type. Defaults to
|
|
277
|
-
* ``true`` (show)
|
|
278
|
-
*/
|
|
279
|
-
enablePath(pathType, enable=true)
|
|
280
|
-
//===============================
|
|
281
|
-
{
|
|
282
|
-
if (this._userInteractions !== null) {
|
|
283
|
-
this._userInteractions.enablePathsByType(pathType, enable);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* Hide or show all paths valid in SCKAN.
|
|
289
|
-
*
|
|
290
|
-
* @param {string} sckanState Either ``valid`` or ``invalid``
|
|
291
|
-
* @param {boolean} enable Show or hide paths with that SCKAN state.
|
|
292
|
-
* Defaults to ``true`` (show)
|
|
293
|
-
*/
|
|
294
|
-
enableSckanPath(sckanState, enable=true)
|
|
295
|
-
//======================================
|
|
296
|
-
{
|
|
297
|
-
if (this._userInteractions !== null) {
|
|
298
|
-
this._userInteractions.enableSckanPaths(sckanState, enable);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Show or hide connectivity features observed in particular species.
|
|
304
|
-
*
|
|
305
|
-
* @param {string | Array.<string>} taxonId(s) A single taxon identifier
|
|
306
|
-
* or an array of identifiers.
|
|
307
|
-
* @param {boolean} enable Show or hide connectivity paths and features.
|
|
308
|
-
* Defaults to ``true`` (show)
|
|
309
|
-
*/
|
|
310
|
-
enableConnectivityByTaxonIds(taxonIds, enable=true)
|
|
311
|
-
//=================================================
|
|
312
|
-
{
|
|
313
|
-
if (this._userInteractions !== null) {
|
|
314
|
-
if (Array.isArray(taxonIds)) {
|
|
315
|
-
this._userInteractions.enableConnectivityByTaxonIds(taxonIds, enable);
|
|
316
|
-
} else {
|
|
317
|
-
this._userInteractions.enableConnectivityByTaxonIds([taxonIds], enable);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* Hide or show centrelines and nodes.
|
|
324
|
-
*
|
|
325
|
-
* @param {boolean} enable Show or centrelines and associated nodes.
|
|
326
|
-
* Defaults to ``true`` (show)
|
|
327
|
-
*/
|
|
328
|
-
enableCentrelines(enable=true)
|
|
329
|
-
//============================
|
|
330
|
-
{
|
|
331
|
-
if (this._userInteractions !== null) {
|
|
332
|
-
this._userInteractions.enableCentrelines(enable);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Load images and patterns/textures referenced in style rules.
|
|
338
|
-
*
|
|
339
|
-
* @private
|
|
340
|
-
*/
|
|
341
|
-
loadImage_(url)
|
|
342
|
-
//=============
|
|
343
|
-
{
|
|
344
|
-
return new Promise((resolve, reject) => {
|
|
345
|
-
this._map.loadImage(url, (error, image) => {
|
|
346
|
-
if (error) reject(error);
|
|
347
|
-
else resolve(image);
|
|
348
|
-
});
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
loadEncodedImage_(encodedImageUrl)
|
|
353
|
-
//================================
|
|
354
|
-
{
|
|
355
|
-
return new Promise((resolve, reject) => {
|
|
356
|
-
const image = new Image();
|
|
357
|
-
image.src = encodedImageUrl;
|
|
358
|
-
image.onload = (e) => resolve(e.target);
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
async addImage(id, path, baseUrl, options={})
|
|
363
|
-
//===========================================
|
|
364
|
-
{
|
|
365
|
-
if (!this._map.hasImage(id)) {
|
|
366
|
-
const image = await (path.startsWith('data:image') ? this.loadEncodedImage_(path)
|
|
367
|
-
: this.loadImage_(path.startsWith('/') ? this.makeServerUrl(path)
|
|
368
|
-
: new URL(path, baseUrl)));
|
|
369
|
-
this._map.addImage(id, image, options);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
makeServerUrl(url, resource='flatmap/')
|
|
374
|
-
//=====================================
|
|
375
|
-
{
|
|
376
|
-
if (url.startsWith('http://') || url.startsWith('https://')) {
|
|
377
|
-
return url;
|
|
378
|
-
} else if (url.startsWith('/')) {
|
|
379
|
-
// We don't want embedded `{` and `}` characters escaped
|
|
380
|
-
return `${this._baseUrl}${resource}${this.__uuid}${url}`;
|
|
381
|
-
} else {
|
|
382
|
-
return `${this._baseUrl}${resource}${this.__uuid}/${url}`;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* The taxon identifier of the species described by the map.
|
|
388
|
-
*
|
|
389
|
-
* @type string
|
|
390
|
-
*/
|
|
391
|
-
get taxon()
|
|
392
|
-
//=========
|
|
393
|
-
{
|
|
394
|
-
return this.__taxon;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* The biological sex identifier of the species described by the map.
|
|
399
|
-
*
|
|
400
|
-
* @type string
|
|
401
|
-
*/
|
|
402
|
-
get biologicalSex()
|
|
403
|
-
//=================
|
|
404
|
-
{
|
|
405
|
-
return this.__biologicalSex;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
/**
|
|
409
|
-
* The map's creation time.
|
|
410
|
-
*
|
|
411
|
-
* @type string
|
|
412
|
-
*/
|
|
413
|
-
get created()
|
|
414
|
-
//===========
|
|
415
|
-
{
|
|
416
|
-
return this.__created;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/**
|
|
420
|
-
* The map's id as specified at generation time.
|
|
421
|
-
*
|
|
422
|
-
* @type string
|
|
423
|
-
*/
|
|
424
|
-
get id()
|
|
425
|
-
//======
|
|
426
|
-
{
|
|
427
|
-
return this.__id;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/**
|
|
431
|
-
* The map's unique universal identifier.
|
|
432
|
-
*
|
|
433
|
-
* For published maps this is different to the map's ``id``;
|
|
434
|
-
* it might be the same as ``id`` for unpublished maps.
|
|
435
|
-
*
|
|
436
|
-
* @type string
|
|
437
|
-
*/
|
|
438
|
-
get uuid()
|
|
439
|
-
//========
|
|
440
|
-
{
|
|
441
|
-
return this.__uuid;
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
/**
|
|
445
|
-
* The map's URL on the map server.
|
|
446
|
-
*
|
|
447
|
-
* @type string
|
|
448
|
-
*/
|
|
449
|
-
get url()
|
|
450
|
-
//========
|
|
451
|
-
{
|
|
452
|
-
let url = this.makeServerUrl('')
|
|
453
|
-
if (url.endsWith('/')) {
|
|
454
|
-
return url.substring(0, url.length - 1)
|
|
455
|
-
}
|
|
456
|
-
return url
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
/**
|
|
460
|
-
* The map's ``index.json`` as returned from the map server.
|
|
461
|
-
*
|
|
462
|
-
* @type Object
|
|
463
|
-
*/
|
|
464
|
-
get details()
|
|
465
|
-
//===========
|
|
466
|
-
{
|
|
467
|
-
return this.__details;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
/**
|
|
471
|
-
* The map's provenance as returned from the map server.
|
|
472
|
-
*
|
|
473
|
-
* @type Object
|
|
474
|
-
*/
|
|
475
|
-
get provenance()
|
|
476
|
-
//==============
|
|
477
|
-
{
|
|
478
|
-
return this.__provenance;
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
/**
|
|
482
|
-
* A unique identifier for the map within the viewer.
|
|
483
|
-
*
|
|
484
|
-
* @type string
|
|
485
|
-
*/
|
|
486
|
-
get uniqueId()
|
|
487
|
-
//============
|
|
488
|
-
{
|
|
489
|
-
return `${this.__uuid}-${this._mapNumber}`;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
get annotations()
|
|
493
|
-
//===============
|
|
494
|
-
{
|
|
495
|
-
return this.__idToAnnotation;
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
annotation(featureId)
|
|
499
|
-
//===================
|
|
500
|
-
{
|
|
501
|
-
return this.__idToAnnotation.get(featureId.toString());
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
/**
|
|
505
|
-
* Flag the feature as having external annotation.
|
|
506
|
-
*
|
|
507
|
-
* @param {string} featureId The feature's external identifier
|
|
508
|
-
*/
|
|
509
|
-
setFeatureAnnotated(featureId)
|
|
510
|
-
//============================
|
|
511
|
-
{
|
|
512
|
-
if (this._userInteractions !== null) {
|
|
513
|
-
this._userInteractions.setFeatureAnnotated(featureId);
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
__updateFeatureIdMapEntry(propertyId, featureIdMap, featureId)
|
|
518
|
-
//============================================================
|
|
519
|
-
{
|
|
520
|
-
const id = utils.normaliseId(propertyId)
|
|
521
|
-
const featureIds = featureIdMap.get(id);
|
|
522
|
-
if (featureIds) {
|
|
523
|
-
featureIds.push(featureId);
|
|
524
|
-
} else {
|
|
525
|
-
featureIdMap.set(id, [featureId]);
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
__updateFeatureIdMap(property, featureIdMap, annotation, missingId=null)
|
|
530
|
-
//======================================================================
|
|
531
|
-
{
|
|
532
|
-
if (property in annotation && annotation[property].length) {
|
|
533
|
-
const propertyId = annotation[property];
|
|
534
|
-
if (Array.isArray(propertyId)) {
|
|
535
|
-
for (const id of propertyId) {
|
|
536
|
-
this.__updateFeatureIdMapEntry(id, featureIdMap, annotation.featureId);
|
|
537
|
-
}
|
|
538
|
-
} else {
|
|
539
|
-
this.__updateFeatureIdMapEntry(propertyId, featureIdMap, annotation.featureId);
|
|
540
|
-
}
|
|
541
|
-
} else if (missingId !== null
|
|
542
|
-
&& 'models' in annotation
|
|
543
|
-
&& annotation.models.startsWith(APINATOMY_PATH_PREFIX)) {
|
|
544
|
-
this.__updateFeatureIdMapEntry(missingId, featureIdMap, annotation.featureId);
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
__addAnnotation(featureId, ann)
|
|
549
|
-
//=============================
|
|
550
|
-
{
|
|
551
|
-
ann.featureId = featureId;
|
|
552
|
-
this.__idToAnnotation.set(featureId, ann);
|
|
553
|
-
this.__updateFeatureIdMap('dataset', this.__datasetToFeatureIds, ann);
|
|
554
|
-
this.__updateFeatureIdMap('models', this.__modelToFeatureIds, ann);
|
|
555
|
-
this.__updateFeatureIdMap('source', this.__mapSourceToFeatureIds, ann);
|
|
556
|
-
this.__updateFeatureIdMap('taxons', this.__taxonToFeatureIds, ann, UNCLASSIFIED_TAXON_ID);
|
|
557
|
-
this.__annIdToFeatureId.set(ann.id, featureId);
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
modelFeatureIds(anatomicalId)
|
|
561
|
-
//===========================
|
|
562
|
-
{
|
|
563
|
-
const featureIds = this.__modelToFeatureIds.get(utils.normaliseId(anatomicalId));
|
|
564
|
-
return featureIds ? featureIds : [];
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
modelFeatureIdList(anatomicalIds)
|
|
568
|
-
//===============================
|
|
569
|
-
{
|
|
570
|
-
const featureIds = new utils.List();
|
|
571
|
-
if (Array.isArray(anatomicalIds)) {
|
|
572
|
-
for (const id of anatomicalIds) {
|
|
573
|
-
featureIds.extend(this.modelFeatureIds(id));
|
|
574
|
-
}
|
|
575
|
-
} else {
|
|
576
|
-
featureIds.extend(this.modelFeatureIds(anatomicalIds));
|
|
577
|
-
}
|
|
578
|
-
if (featureIds.length == 0) {
|
|
579
|
-
// We couldn't find a feature by anatomical id, so check dataset and source
|
|
580
|
-
featureIds.extend(this.__datasetToFeatureIds.get(anatomicalIds));
|
|
581
|
-
featureIds.extend(this.__mapSourceToFeatureIds.get(anatomicalIds));
|
|
582
|
-
}
|
|
583
|
-
if (featureIds.length == 0 && this._userInteractions !== null) {
|
|
584
|
-
// We still haven't found a feature, so check connectivity
|
|
585
|
-
featureIds.extend(this._userInteractions.pathFeatureIds(anatomicalIds));
|
|
586
|
-
}
|
|
587
|
-
return featureIds;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
modelForFeature(featureId)
|
|
591
|
-
//========================
|
|
592
|
-
{
|
|
593
|
-
const ann = this.__idToAnnotation.get(featureId);
|
|
594
|
-
return (ann && 'models' in ann) ? utils.normaliseId(ann.models) : null;
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
/**
|
|
598
|
-
* Get model terms of all paths connected to a node.
|
|
599
|
-
*
|
|
600
|
-
* @param {number} pathId The local (GeoJSON) identifier of a node
|
|
601
|
-
* @return {set<string>} Model terms of all paths connected to the node
|
|
602
|
-
*/
|
|
603
|
-
nodePathModels(nodeId)
|
|
604
|
-
//====================
|
|
605
|
-
{
|
|
606
|
-
if (this._userInteractions !== null) {
|
|
607
|
-
return this._userInteractions.nodePathModels(nodeId);
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
/**
|
|
612
|
-
* Get GeoJSON feature ids of all nodes of a path model.
|
|
613
|
-
*
|
|
614
|
-
* @param {string} pathId The path model identifier
|
|
615
|
-
* @return {Array<string>} GeoJSON identifiers of features on the path
|
|
616
|
-
*/
|
|
617
|
-
pathModelNodes(modelId)
|
|
618
|
-
//=====================
|
|
619
|
-
{
|
|
620
|
-
if (this._userInteractions !== null) {
|
|
621
|
-
return [...this._userInteractions.pathModelNodes(modelId)]
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
/**
|
|
626
|
-
* Get GeoJSON feature ids of all features identified with a taxon.
|
|
627
|
-
*
|
|
628
|
-
* @param {string} taxonId The taxon identifier
|
|
629
|
-
* @return {Array<string>} GeoJSON identifiers of features on the path
|
|
630
|
-
*/
|
|
631
|
-
taxonFeatureIds(taxonId)
|
|
632
|
-
//======================
|
|
633
|
-
{
|
|
634
|
-
const featureIds = this.__taxonToFeatureIds.get(utils.normaliseId(taxonId))
|
|
635
|
-
return [...new Set(featureIds ? featureIds : [])]
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
get layers()
|
|
639
|
-
//==========
|
|
640
|
-
{
|
|
641
|
-
return this._layers;
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
get map()
|
|
645
|
-
//=======
|
|
646
|
-
{
|
|
647
|
-
return this._map;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
get markers()
|
|
651
|
-
//===========
|
|
652
|
-
{
|
|
653
|
-
return this._markers;
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
/**
|
|
657
|
-
* The anatomical identifiers of features in the map.
|
|
658
|
-
*
|
|
659
|
-
* @type {string|Array.<string>}
|
|
660
|
-
*/
|
|
661
|
-
get anatomicalIdentifiers()
|
|
662
|
-
//=========================
|
|
663
|
-
{
|
|
664
|
-
return [...this.__modelToFeatureIds.keys()]
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
/**
|
|
668
|
-
* The taxon identifiers of species which the map's connectivity has been observed in.
|
|
669
|
-
*
|
|
670
|
-
* @type {string|Array.<string>}
|
|
671
|
-
*/
|
|
672
|
-
get taxonIdentifiers()
|
|
673
|
-
//====================
|
|
674
|
-
{
|
|
675
|
-
return [...this.__taxonToFeatureIds.keys()]
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
/**
|
|
679
|
-
* Datasets associated with the map.
|
|
680
|
-
*
|
|
681
|
-
* @type {string|Array.<string>}
|
|
682
|
-
*/
|
|
683
|
-
get datasets()
|
|
684
|
-
//============
|
|
685
|
-
{
|
|
686
|
-
return [...this.__datasetToFeatureIds.keys()]
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
get options()
|
|
690
|
-
//===========
|
|
691
|
-
{
|
|
692
|
-
return this._options;
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
get pathways()
|
|
696
|
-
//============
|
|
697
|
-
{
|
|
698
|
-
return this._pathways;
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
/**
|
|
702
|
-
* Get the map's zoom settings.
|
|
703
|
-
*
|
|
704
|
-
* @return {Object.<{minZoom: number, zoom: number, maxZoom: number}>} The map's minimum, current, and maximum zoom levels.
|
|
705
|
-
*/
|
|
706
|
-
getZoom()
|
|
707
|
-
//=======
|
|
708
|
-
{
|
|
709
|
-
return {
|
|
710
|
-
mapUUID: this.__uuid,
|
|
711
|
-
minZoom: this._map.getMinZoom(),
|
|
712
|
-
zoom: this._map.getZoom(),
|
|
713
|
-
maxZoom: this._map.getMaxZoom()
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
callback(type, data, ...args)
|
|
718
|
-
//===========================
|
|
719
|
-
{
|
|
720
|
-
if (this._callback) {
|
|
721
|
-
data.mapUUID = this.__uuid;
|
|
722
|
-
return this._callback(type, data, ...args);
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
setInitialPosition()
|
|
727
|
-
//==================
|
|
728
|
-
{
|
|
729
|
-
if ('bounds' in this._options) {
|
|
730
|
-
this._map.fitBounds(this._options['bounds'], {animate: false});
|
|
731
|
-
}
|
|
732
|
-
if ('center' in this._options) {
|
|
733
|
-
this._map.setCenter(this._options['center']);
|
|
734
|
-
}
|
|
735
|
-
if ('zoom' in this._options) {
|
|
736
|
-
this._map.setZoom(this._options['zoom']);
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
close()
|
|
741
|
-
//=====
|
|
742
|
-
{
|
|
743
|
-
if (this._map) {
|
|
744
|
-
this._map.remove();
|
|
745
|
-
this._map = null;
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
resize()
|
|
750
|
-
//======
|
|
751
|
-
{
|
|
752
|
-
// Resize our map
|
|
753
|
-
|
|
754
|
-
this._map.resize();
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
getIdentifier()
|
|
758
|
-
//=============
|
|
759
|
-
{
|
|
760
|
-
// Return identifiers for reloading the map
|
|
761
|
-
|
|
762
|
-
return {
|
|
763
|
-
taxon: this.__taxon,
|
|
764
|
-
biologicalSex: this.__biologicalSex,
|
|
765
|
-
uuid: this.__uuid
|
|
766
|
-
};
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
getState()
|
|
770
|
-
//========
|
|
771
|
-
{
|
|
772
|
-
return (this._userInteractions !== null) ? this._userInteractions.getState() : {};
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
setState(state)
|
|
776
|
-
//=============
|
|
777
|
-
{
|
|
778
|
-
if (this._userInteractions !== null) {
|
|
779
|
-
this._userInteractions.setState(state);
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
showPopup(featureId, content, options)
|
|
784
|
-
//====================================
|
|
785
|
-
{
|
|
786
|
-
if (this._userInteractions !== null) {
|
|
787
|
-
this._userInteractions.showPopup(featureId, content, options);
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
setPaint(options=null)
|
|
792
|
-
//====================
|
|
793
|
-
{
|
|
794
|
-
options = utils.setDefaults(options, {
|
|
795
|
-
colour: true,
|
|
796
|
-
outline: true
|
|
797
|
-
});
|
|
798
|
-
if (this._userInteractions !== null) {
|
|
799
|
-
this._userInteractions.setPaint(options);
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
setColour(options=null)
|
|
804
|
-
//=====================
|
|
805
|
-
{
|
|
806
|
-
console.log('`setColour()` is deprecated; please use `setPaint()` instead.')
|
|
807
|
-
this.setPaint(options);
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
//==========================================================================
|
|
811
|
-
|
|
812
|
-
/**
|
|
813
|
-
* Get the map's current background colour.
|
|
814
|
-
*
|
|
815
|
-
* @return {string} The background colour.
|
|
816
|
-
*/
|
|
817
|
-
getBackgroundColour()
|
|
818
|
-
//===================
|
|
819
|
-
{
|
|
820
|
-
return this._map.getPaintProperty('background', 'background-color');
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
/**
|
|
824
|
-
* Get the map's current background opacity.
|
|
825
|
-
*
|
|
826
|
-
* @return {number} The background opacity.
|
|
827
|
-
*/
|
|
828
|
-
getBackgroundOpacity()
|
|
829
|
-
//====================
|
|
830
|
-
{
|
|
831
|
-
return this._map.getPaintProperty('background', 'background-opacity');
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
/**
|
|
835
|
-
* Sets the map's background colour.
|
|
836
|
-
*
|
|
837
|
-
* @param {string} colour The colour
|
|
838
|
-
*/
|
|
839
|
-
setBackgroundColour(colour)
|
|
840
|
-
//=========================
|
|
841
|
-
{
|
|
842
|
-
localStorage.setItem('flatmap-background-colour', colour);
|
|
843
|
-
|
|
844
|
-
this._map.setPaintProperty('background', 'background-color', colour);
|
|
845
|
-
|
|
846
|
-
if (this._userInteractions.minimap) {
|
|
847
|
-
this._userInteractions.minimap.setBackgroundColour(colour);
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
/**
|
|
852
|
-
* Sets the map's background opacity.
|
|
853
|
-
*
|
|
854
|
-
* @param {number} opacity The opacity
|
|
855
|
-
*/
|
|
856
|
-
setBackgroundOpacity(opacity)
|
|
857
|
-
//===========================
|
|
858
|
-
{
|
|
859
|
-
this._map.setPaintProperty('background', 'background-opacity', opacity);
|
|
860
|
-
|
|
861
|
-
if (this._userInteractions.minimap) {
|
|
862
|
-
this._userInteractions.minimap.setBackgroundOpacity(opacity);
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
/**
|
|
867
|
-
* Show and hide the minimap.
|
|
868
|
-
*
|
|
869
|
-
* @param {boolean} show Set false to hide minimap
|
|
870
|
-
*/
|
|
871
|
-
showMinimap(show)
|
|
872
|
-
//===============
|
|
873
|
-
{
|
|
874
|
-
if (this._userInteractions.minimap) {
|
|
875
|
-
this._userInteractions.minimap.show(show);
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
//==========================================================================
|
|
881
|
-
|
|
882
|
-
/**
|
|
883
|
-
* Get a list of the flatmap's layers.
|
|
884
|
-
*
|
|
885
|
-
* @return {Array.<{id: string, description: string, enabled: boolean}>} An array with layer details
|
|
886
|
-
*/
|
|
887
|
-
getLayers()
|
|
888
|
-
//=========
|
|
889
|
-
{
|
|
890
|
-
if (this._userInteractions !== null) {
|
|
891
|
-
return this._userInteractions.getLayers();
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
/**
|
|
896
|
-
* @param {string} layerId The layer identifier to enable
|
|
897
|
-
* @param {boolean} enable Show or hide the layer. Defaults to ``true`` (show)
|
|
898
|
-
*
|
|
899
|
-
*/
|
|
900
|
-
enableLayer(layerId, enable=true)
|
|
901
|
-
//===============================
|
|
902
|
-
{
|
|
903
|
-
if (this._userInteractions !== null) {
|
|
904
|
-
return this._userInteractions.enableLayer(layerId, enable);
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
/**
|
|
909
|
-
* Show/hide flight path view.
|
|
910
|
-
*
|
|
911
|
-
* @param {boolean} [enable=true]
|
|
912
|
-
*/
|
|
913
|
-
enableFlightPaths(enable=true)
|
|
914
|
-
//============================
|
|
915
|
-
{
|
|
916
|
-
if (this._userInteractions !== null) {
|
|
917
|
-
this._userInteractions.enableFlightPaths(enable)
|
|
918
|
-
}
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
//==========================================================================
|
|
922
|
-
|
|
923
|
-
/**
|
|
924
|
-
* Get a list of a FC flatmap's systems.
|
|
925
|
-
*
|
|
926
|
-
* @return {Array.<{id: string, name: string, colour: string, enabled: boolean}>} An array with system details
|
|
927
|
-
*/
|
|
928
|
-
getSystems()
|
|
929
|
-
//==========
|
|
930
|
-
{
|
|
931
|
-
if (this._userInteractions !== null) {
|
|
932
|
-
return this._userInteractions.getSystems();
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
/**
|
|
937
|
-
* @param {string} systemId The identifier of the system to enable
|
|
938
|
-
* @param {boolean} enable Show or hide the system. Defaults to ``true`` (show)
|
|
939
|
-
*
|
|
940
|
-
*/
|
|
941
|
-
enableSystem(systemId, enable=true)
|
|
942
|
-
//===================================
|
|
943
|
-
{
|
|
944
|
-
if (this._userInteractions !== null) {
|
|
945
|
-
return this._userInteractions.enableSystem(systemId, enable);
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
//==========================================================================
|
|
950
|
-
|
|
951
|
-
/**
|
|
952
|
-
* Add a marker to the map.
|
|
953
|
-
*
|
|
954
|
-
* @param {string} anatomicalId The anatomical identifier of the feature on which
|
|
955
|
-
* to place the marker.
|
|
956
|
-
* @arg {Object} options Configurable options for the marker.
|
|
957
|
-
* @arg {string} options.className Space-separated CSS class names to add to marker element.
|
|
958
|
-
* @arg {string} options.cluster The marker will be clustered together with other geographically
|
|
959
|
-
* close markers. Defaults to ``true``.
|
|
960
|
-
* @arg {string} options.colour Colour of the marker. Defaults to ``'#005974'``
|
|
961
|
-
* (dark cyan).
|
|
962
|
-
* @arg {string} options.element The DOM element to use as a marker. The default is
|
|
963
|
-
* a dark blue droplet-shaped SVG marker.
|
|
964
|
-
* @return {integer} The identifier for the resulting marker. -1 is returned if the
|
|
965
|
-
* map doesn't contain a feature with the given anatomical identifier
|
|
966
|
-
*/
|
|
967
|
-
addMarker(anatomicalId, options={})
|
|
968
|
-
//==================================
|
|
969
|
-
{
|
|
970
|
-
options = Object.assign({cluster: true}, options)
|
|
971
|
-
if (this._userInteractions !== null) {
|
|
972
|
-
return this._userInteractions.addMarker(anatomicalId, options);
|
|
973
|
-
}
|
|
974
|
-
return -1;
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
/**
|
|
978
|
-
* Add a list of markers to the map.
|
|
979
|
-
*
|
|
980
|
-
* @param {Array.<string>} anatomicalId Anatomical identifiers of features on which
|
|
981
|
-
* to place markers.
|
|
982
|
-
* @arg {Object} options Configurable options for the markers.
|
|
983
|
-
* @arg {string} options.className Space-separated CSS class names to add to marker elemens.
|
|
984
|
-
* @arg {string} options.cluster The markers will be clustered together with other geographically
|
|
985
|
-
* close markers. Defaults to ``true``.
|
|
986
|
-
* @arg {string} options.colour Colour of the markers. Defaults to ``'#005974'``
|
|
987
|
-
* (dark cyan).
|
|
988
|
-
* @arg {string} options.element The DOM element to use as a marker. The default is
|
|
989
|
-
* a dark blue droplet-shaped SVG marker.
|
|
990
|
-
* @return {array.<integer>} The identifiers of the resulting markers. -1 is returned if the
|
|
991
|
-
* map doesn't contain a feature with the given anatomical identifier
|
|
992
|
-
*/
|
|
993
|
-
addMarkers(anatomicalIds, options={})
|
|
994
|
-
//====================================
|
|
995
|
-
{
|
|
996
|
-
options = Object.assign({cluster: true}, options)
|
|
997
|
-
const markerIds = []
|
|
998
|
-
for (const anatomicalId of anatomicalIds) {
|
|
999
|
-
if (this._userInteractions !== null) {
|
|
1000
|
-
markerIds.push(this._userInteractions.addMarker(anatomicalId, options))
|
|
1001
|
-
} else {
|
|
1002
|
-
markerIds.push(-1)
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
return markerIds
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
/**
|
|
1009
|
-
* Remove a marker from the map.
|
|
1010
|
-
*
|
|
1011
|
-
* @param {integer} markerId The identifier of the marker, as returned
|
|
1012
|
-
* by ``addMarker()``
|
|
1013
|
-
*/
|
|
1014
|
-
removeMarker(markerId)
|
|
1015
|
-
//====================
|
|
1016
|
-
{
|
|
1017
|
-
if (markerId > -1 && this._userInteractions !== null) {
|
|
1018
|
-
this._userInteractions.removeMarker(markerId);
|
|
1019
|
-
}
|
|
1020
|
-
}
|
|
1021
|
-
|
|
1022
|
-
/**
|
|
1023
|
-
* Remove all markers from the map.
|
|
1024
|
-
*/
|
|
1025
|
-
clearMarkers()
|
|
1026
|
-
//============
|
|
1027
|
-
{
|
|
1028
|
-
if (this._userInteractions !== null) {
|
|
1029
|
-
this._userInteractions.clearMarkers();
|
|
1030
|
-
}
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
/**
|
|
1034
|
-
* Return the set of anatomical identifiers visible in the current map view.
|
|
1035
|
-
*
|
|
1036
|
-
* @return {Array.<string>} A list of identifiers
|
|
1037
|
-
*/
|
|
1038
|
-
visibleMarkerAnatomicalIds()
|
|
1039
|
-
//==========================
|
|
1040
|
-
{
|
|
1041
|
-
if (this._userInteractions !== null) {
|
|
1042
|
-
return this._userInteractions.visibleMarkerAnatomicalIds();
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1045
|
-
|
|
1046
|
-
/**
|
|
1047
|
-
* Shows a popup at a marker.
|
|
1048
|
-
*
|
|
1049
|
-
* This method should only be called in response to a ``mouseenter`` event
|
|
1050
|
-
* passed to the map's ``callback`` function otherwise a popup won't be shown.
|
|
1051
|
-
*
|
|
1052
|
-
* @param {integer} markerId The identifier of the marker
|
|
1053
|
-
* @param {string | DOMElement} content The popup's content
|
|
1054
|
-
* @param {Object} options
|
|
1055
|
-
* @returns {boolean} Return true if the popup is shown
|
|
1056
|
-
*
|
|
1057
|
-
* The resulting popup is given a class name of ``flatmap-tooltip-popup``.
|
|
1058
|
-
*/
|
|
1059
|
-
showMarkerPopup(markerId, content, options={})
|
|
1060
|
-
//============================================
|
|
1061
|
-
{
|
|
1062
|
-
if (this._userInteractions !== null) {
|
|
1063
|
-
return this._userInteractions.showMarkerPopup(markerId, content, options);
|
|
1064
|
-
}
|
|
1065
|
-
return false;
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
|
-
__exportedProperties(properties)
|
|
1069
|
-
//==============================
|
|
1070
|
-
{
|
|
1071
|
-
const data = {};
|
|
1072
|
-
const exportedProperties = [
|
|
1073
|
-
'id',
|
|
1074
|
-
'featureId',
|
|
1075
|
-
'connectivity',
|
|
1076
|
-
'dataset',
|
|
1077
|
-
'kind',
|
|
1078
|
-
'label',
|
|
1079
|
-
'models',
|
|
1080
|
-
'source',
|
|
1081
|
-
'taxons',
|
|
1082
|
-
'hyperlinks',
|
|
1083
|
-
'completeness',
|
|
1084
|
-
'missing-nodes',
|
|
1085
|
-
'alert',
|
|
1086
|
-
'biological-sex'
|
|
1087
|
-
];
|
|
1088
|
-
for (const property of exportedProperties) {
|
|
1089
|
-
if (property in properties) {
|
|
1090
|
-
const value = properties[property];
|
|
1091
|
-
if (value !== undefined) {
|
|
1092
|
-
if ((Array.isArray(value) && value.length)
|
|
1093
|
-
|| (value.constructor === Object && Object.keys(value).length)) {
|
|
1094
|
-
data[property] = value
|
|
1095
|
-
} else if (property === 'featureId') {
|
|
1096
|
-
data[property] = +value; // Ensure numeric
|
|
1097
|
-
} else {
|
|
1098
|
-
data[property] = value;
|
|
1099
|
-
}
|
|
1100
|
-
}
|
|
1101
|
-
}
|
|
1102
|
-
}
|
|
1103
|
-
if (Object.keys(data).length > 0) {
|
|
1104
|
-
data['type'] = 'feature';
|
|
1105
|
-
}
|
|
1106
|
-
return data;
|
|
1107
|
-
}
|
|
1108
|
-
|
|
1109
|
-
/**
|
|
1110
|
-
* Show or hide a tool for drawing regions to annotate on the map.
|
|
1111
|
-
*
|
|
1112
|
-
* @param {boolean} [visible=true]
|
|
1113
|
-
*/
|
|
1114
|
-
showAnnotator(visible=true)
|
|
1115
|
-
//=========================
|
|
1116
|
-
{
|
|
1117
|
-
if (this._userInteractions !== null) {
|
|
1118
|
-
this._userInteractions.showAnnotator(visible)
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
/**
|
|
1123
|
-
* Generate an ``annotation`` callback event when a drawn annotation has been created
|
|
1124
|
-
* a modified.
|
|
1125
|
-
*
|
|
1126
|
-
* @param eventType {string} Either ``created``, ``updated`` or ``deleted``
|
|
1127
|
-
* @param feature {Object} A feature object with ``id``, ``type``, and ``geometry``
|
|
1128
|
-
* fields of a feature that has been created, updated or
|
|
1129
|
-
* deleted.
|
|
1130
|
-
*/
|
|
1131
|
-
annotationEvent(eventType, feature)
|
|
1132
|
-
//=================================
|
|
1133
|
-
{
|
|
1134
|
-
this.callback('annotation', {
|
|
1135
|
-
type: eventType,
|
|
1136
|
-
feature: feature
|
|
1137
|
-
});
|
|
1138
|
-
}
|
|
1139
|
-
|
|
1140
|
-
/**
|
|
1141
|
-
* Mark a drawn/changed annotation as having been accepted by the user.
|
|
1142
|
-
*
|
|
1143
|
-
* @param event {Object} The object as received in an annotation callback
|
|
1144
|
-
* @param event.type {string} Either ``created``, ``updated`` or ``deleted``
|
|
1145
|
-
* @param event.feature {Object} A feature object.
|
|
1146
|
-
*/
|
|
1147
|
-
commitAnnotationEvent(event)
|
|
1148
|
-
//==========================
|
|
1149
|
-
{
|
|
1150
|
-
if (this._userInteractions) {
|
|
1151
|
-
this._userInteractions.commitAnnotationEvent(event)
|
|
1152
|
-
}
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
/**
|
|
1156
|
-
* Mark a drawn/changed annotation as having been rejected by the user.
|
|
1157
|
-
*
|
|
1158
|
-
* @param event {Object} The object as received in an annotation callback
|
|
1159
|
-
* @param event.type {string} Either ``created``, ``updated`` or ``deleted``
|
|
1160
|
-
* @param event.feature {Object} A feature object.
|
|
1161
|
-
*/
|
|
1162
|
-
rollbackAnnotationEvent(event)
|
|
1163
|
-
//============================
|
|
1164
|
-
{
|
|
1165
|
-
if (this._userInteractions) {
|
|
1166
|
-
this._userInteractions.rollbackAnnotationEvent(event)
|
|
1167
|
-
}
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
|
-
/**
|
|
1171
|
-
* Clear all drawn annotations from current annotation layer.
|
|
1172
|
-
*/
|
|
1173
|
-
clearAnnotationFeature()
|
|
1174
|
-
//======================
|
|
1175
|
-
{
|
|
1176
|
-
if (this._userInteractions) {
|
|
1177
|
-
this._userInteractions.clearAnnotationFeatures()
|
|
1178
|
-
}
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
/**
|
|
1182
|
-
* Delete the selected drawn feature
|
|
1183
|
-
*/
|
|
1184
|
-
removeAnnotationFeature()
|
|
1185
|
-
//=======================
|
|
1186
|
-
{
|
|
1187
|
-
if (this._userInteractions) {
|
|
1188
|
-
this._userInteractions.removeAnnotationFeature()
|
|
1189
|
-
}
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
|
-
/**
|
|
1193
|
-
* Add a drawn feature to the annotation drawing tool.
|
|
1194
|
-
*
|
|
1195
|
-
* @param feature {Object} The feature to add
|
|
1196
|
-
* @param feature.id {string} The feature's id
|
|
1197
|
-
* @param feature.geometry {Object} The feature's geometry as GeoJSON
|
|
1198
|
-
*/
|
|
1199
|
-
addAnnotationFeature(feature)
|
|
1200
|
-
//===========================
|
|
1201
|
-
{
|
|
1202
|
-
if (this._userInteractions) {
|
|
1203
|
-
this._userInteractions.addAnnotationFeature(feature)
|
|
1204
|
-
}
|
|
1205
|
-
}
|
|
1206
|
-
|
|
1207
|
-
/**
|
|
1208
|
-
* Return the feature as it is currently drawn. This is so
|
|
1209
|
-
* the correct geometry can be saved with a feature should
|
|
1210
|
-
* a user make changes before submitting dialog provided
|
|
1211
|
-
* by an external annotator.
|
|
1212
|
-
*
|
|
1213
|
-
* @param feature {Object} The drawn feature to refresh.
|
|
1214
|
-
* @returns {Object|null} The feature with currently geometry or ``null``
|
|
1215
|
-
* if the feature has been deleted.
|
|
1216
|
-
*/
|
|
1217
|
-
refreshAnnotationFeatureGeometry(feature)
|
|
1218
|
-
//=======================================
|
|
1219
|
-
{
|
|
1220
|
-
if (this._userInteractions) {
|
|
1221
|
-
return this._userInteractions.refreshAnnotationFeatureGeometry(feature)
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
|
|
1225
|
-
/**
|
|
1226
|
-
* Changes draw to another mode. The mode argument must be one of the following:
|
|
1227
|
-
* `simple_select`, `direct_select`, `draw_line_string`,
|
|
1228
|
-
* `draw_polygon` or `draw_point`. Options is accepted in first three modes.
|
|
1229
|
-
* More details in mapbox-gl-draw github repository.
|
|
1230
|
-
*
|
|
1231
|
-
* @param type {Object} The object
|
|
1232
|
-
* @param type.mode {string} Either ``simple_select``, ``direct_select``, etc
|
|
1233
|
-
* @param type.options {Object} Feature id(s) object.
|
|
1234
|
-
*/
|
|
1235
|
-
changeAnnotationDrawMode(type)
|
|
1236
|
-
//============================
|
|
1237
|
-
{
|
|
1238
|
-
if (this._userInteractions) {
|
|
1239
|
-
this._userInteractions.changeAnnotationDrawMode(type)
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
|
-
/**
|
|
1244
|
-
* Generate a callback as a result of some event with a flatmap feature.
|
|
1245
|
-
*
|
|
1246
|
-
* @param {string} eventType The event type
|
|
1247
|
-
* @param {Object} properties Properties associated with the feature
|
|
1248
|
-
*/
|
|
1249
|
-
featureEvent(eventType, properties)
|
|
1250
|
-
//=================================
|
|
1251
|
-
{
|
|
1252
|
-
const data = this.__exportedProperties(properties);
|
|
1253
|
-
|
|
1254
|
-
if (Object.keys(data).length > 0) {
|
|
1255
|
-
this.callback(eventType, data);
|
|
1256
|
-
return true;
|
|
1257
|
-
}
|
|
1258
|
-
return false;
|
|
1259
|
-
}
|
|
1260
|
-
|
|
1261
|
-
/**
|
|
1262
|
-
* Return properties associated with a feature.
|
|
1263
|
-
*
|
|
1264
|
-
* @param {number} featureId The feature's internal (GeoJSON) id
|
|
1265
|
-
* @returns {Object} Properties associated with the feature
|
|
1266
|
-
*/
|
|
1267
|
-
featureProperties(featureId)
|
|
1268
|
-
//==========================
|
|
1269
|
-
{
|
|
1270
|
-
const properties = this.annotation(featureId);
|
|
1271
|
-
return properties ? this.__exportedProperties(properties) : {};
|
|
1272
|
-
}
|
|
1273
|
-
|
|
1274
|
-
/**
|
|
1275
|
-
* Generate a callback as a result of some event with a marker.
|
|
1276
|
-
*
|
|
1277
|
-
* @param {string} eventType The event type
|
|
1278
|
-
* @param {integer} markerId The marker identifier
|
|
1279
|
-
* @param {string} anatomicalId The anatomical identifier for the marker
|
|
1280
|
-
*/
|
|
1281
|
-
markerEvent(eventType, markerId, anatomicalId)
|
|
1282
|
-
//============================================
|
|
1283
|
-
{
|
|
1284
|
-
this.callback(eventType, {
|
|
1285
|
-
type: 'marker',
|
|
1286
|
-
id: markerId,
|
|
1287
|
-
models: anatomicalId
|
|
1288
|
-
});
|
|
1289
|
-
}
|
|
1290
|
-
|
|
1291
|
-
/**
|
|
1292
|
-
* Generate a callback as a result of some event in a control.
|
|
1293
|
-
*
|
|
1294
|
-
* @param {string} eventType The event type
|
|
1295
|
-
* @param {string} control The name of the control
|
|
1296
|
-
* @param {string} value The value of the control
|
|
1297
|
-
*/
|
|
1298
|
-
controlEvent(eventType, control, value)
|
|
1299
|
-
//=====================================
|
|
1300
|
-
{
|
|
1301
|
-
this.callback(eventType, {
|
|
1302
|
-
type: 'control',
|
|
1303
|
-
control: control,
|
|
1304
|
-
value: value
|
|
1305
|
-
});
|
|
1306
|
-
}
|
|
1307
|
-
|
|
1308
|
-
/**
|
|
1309
|
-
* Generate callbacks as a result of panning/zooming the map.
|
|
1310
|
-
*
|
|
1311
|
-
* @param {boolean} enabled Generate callbacks when ``true``,
|
|
1312
|
-
* otherwise disable them.
|
|
1313
|
-
*/
|
|
1314
|
-
enablePanZoomEvents(enabled=true)
|
|
1315
|
-
//===============================
|
|
1316
|
-
{
|
|
1317
|
-
if (this._userInteractions !== null) {
|
|
1318
|
-
this._userInteractions.enablePanZoomEvents(enabled);
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
|
|
1322
|
-
/**
|
|
1323
|
-
* Generate a callback as a result of panning/zooming the map.
|
|
1324
|
-
*
|
|
1325
|
-
* @param {string} type The event type, ``pan`` or ``zoom``.
|
|
1326
|
-
* @param {Array.<float>} origin The map's normalised top-left corner
|
|
1327
|
-
* @param {Array.<float>} size The map's normalised size
|
|
1328
|
-
*/
|
|
1329
|
-
panZoomEvent(type)
|
|
1330
|
-
//================
|
|
1331
|
-
{
|
|
1332
|
-
const bounds = this._map.getBounds();
|
|
1333
|
-
if (this.__normalised_origin !== undefined) {
|
|
1334
|
-
const sw = maplibregl.MercatorCoordinate.fromLngLat(bounds.toArray()[0]);
|
|
1335
|
-
const ne = maplibregl.MercatorCoordinate.fromLngLat(bounds.toArray()[1]);
|
|
1336
|
-
const top_left = [(sw.x - this.__normalised_origin[0])/this.__normalised_size[0],
|
|
1337
|
-
(ne.y - this.__normalised_origin[1])/this.__normalised_size[1]];
|
|
1338
|
-
const size = [(ne.x - sw.x)/this.__normalised_size[0],
|
|
1339
|
-
(sw.y - ne.y)/this.__normalised_size[1]];
|
|
1340
|
-
this.callback('pan-zoom', {
|
|
1341
|
-
type: type,
|
|
1342
|
-
origin: top_left,
|
|
1343
|
-
size: size
|
|
1344
|
-
});
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
|
|
1348
|
-
/**
|
|
1349
|
-
* Pan/zoom the map to a new view
|
|
1350
|
-
*
|
|
1351
|
-
* @param {Array.<float>} origin The map's normalised top-left corner
|
|
1352
|
-
* @param {Array.<float>} size The map's normalised size
|
|
1353
|
-
*/
|
|
1354
|
-
panZoomTo(origin, size)
|
|
1355
|
-
//=====================
|
|
1356
|
-
{
|
|
1357
|
-
if (this.__normalised_origin !== undefined) {
|
|
1358
|
-
const sw_x = origin[0]*this.__normalised_size[0] + this.__normalised_origin[0];
|
|
1359
|
-
const ne_y = origin[1]*this.__normalised_size[1] + this.__normalised_origin[1];
|
|
1360
|
-
const ne_x = sw_x + size[0]*this.__normalised_size[0];
|
|
1361
|
-
const sw_y = ne_y + size[1]*this.__normalised_size[1];
|
|
1362
|
-
const sw = (new maplibregl.MercatorCoordinate(sw_x, sw_y, 0)).toLngLat();
|
|
1363
|
-
const ne = (new maplibregl.MercatorCoordinate(ne_x, ne_y, 0)).toLngLat();
|
|
1364
|
-
this._map.fitBounds([sw, ne], {animate: false});
|
|
1365
|
-
}
|
|
1366
|
-
}
|
|
1367
|
-
|
|
1368
|
-
//==========================================================================
|
|
1369
|
-
|
|
1370
|
-
/**
|
|
1371
|
-
* Find features with labels or terms matching ``text``.
|
|
1372
|
-
*
|
|
1373
|
-
* @param {string} text The text to search
|
|
1374
|
-
* @param {boolean} [auto=false] If ``true`` return suggestions of text to search for.
|
|
1375
|
-
* @return Either a ``Searchresults`` object with fields of ``featureIds`` and ``results``,
|
|
1376
|
-
* where ``results`` has ``featureId``, ``score``, ``terms`` and ``text`` fields,
|
|
1377
|
-
* or a ``Suggestion`` object containing suggested matches
|
|
1378
|
-
* (see https://lucaong.github.io/minisearch/modules/_minisearch_.html#suggestion).
|
|
1379
|
-
*/
|
|
1380
|
-
search(text, auto=false)
|
|
1381
|
-
//======================
|
|
1382
|
-
{
|
|
1383
|
-
if (auto) {
|
|
1384
|
-
return this.__searchIndex.auto_suggest(text);
|
|
1385
|
-
} else {
|
|
1386
|
-
return this.__searchIndex.search(text);
|
|
1387
|
-
}
|
|
1388
|
-
}
|
|
1389
|
-
|
|
1390
|
-
clearSearchResults()
|
|
1391
|
-
//==================
|
|
1392
|
-
{
|
|
1393
|
-
if (this._userInteractions !== null) {
|
|
1394
|
-
this._userInteractions.clearSearchResults();
|
|
1395
|
-
}
|
|
1396
|
-
}
|
|
1397
|
-
|
|
1398
|
-
showSearchResults(searchResults)
|
|
1399
|
-
//==============================
|
|
1400
|
-
{
|
|
1401
|
-
if (this._userInteractions !== null) {
|
|
1402
|
-
this._userInteractions.showSearchResults(searchResults.featureIds);
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
|
-
//==========================================================================
|
|
1407
|
-
|
|
1408
|
-
/**
|
|
1409
|
-
* Select features on the map.
|
|
1410
|
-
*
|
|
1411
|
-
* @param {Array.<string>} externalIds An array of anaotomical terms identifing features to select
|
|
1412
|
-
*/
|
|
1413
|
-
selectFeatures(externalIds)
|
|
1414
|
-
//=========================
|
|
1415
|
-
{
|
|
1416
|
-
if (this._userInteractions !== null) {
|
|
1417
|
-
const featureIds = this.modelFeatureIdList(externalIds);
|
|
1418
|
-
this._userInteractions.selectFeatures(featureIds);
|
|
1419
|
-
}
|
|
1420
|
-
}
|
|
1421
|
-
|
|
1422
|
-
/**
|
|
1423
|
-
* Select features and zoom the map to them.
|
|
1424
|
-
*
|
|
1425
|
-
* @param {Array.<string>} featureIds An array of feature identifiers
|
|
1426
|
-
* @param {Object} [options]
|
|
1427
|
-
* @param {boolean} [options.noZoomIn=false] Don't zoom in (although zoom out as necessary)
|
|
1428
|
-
* @param {number} [options.padding=10] Padding in pixels around the composite bounding box
|
|
1429
|
-
*/
|
|
1430
|
-
zoomToFeatures(externalIds, options=null)
|
|
1431
|
-
//=======================================
|
|
1432
|
-
{
|
|
1433
|
-
options = utils.setDefaults(options, {
|
|
1434
|
-
select: true,
|
|
1435
|
-
highlight: false,
|
|
1436
|
-
padding:100
|
|
1437
|
-
});
|
|
1438
|
-
if (this._userInteractions !== null) {
|
|
1439
|
-
const featureIds = this.modelFeatureIdList(externalIds);
|
|
1440
|
-
this._userInteractions.zoomToFeatures(featureIds, options);
|
|
1441
|
-
}
|
|
1442
|
-
}
|
|
1443
|
-
|
|
1444
|
-
/**
|
|
1445
|
-
* Select features on the map.
|
|
1446
|
-
*
|
|
1447
|
-
* @param {string | Array.<string>} geojsonIds A single GeoJSON feature identifiers
|
|
1448
|
-
* or an array of identifiers.
|
|
1449
|
-
*/
|
|
1450
|
-
selectGeoJSONFeatures(geojsonIds)
|
|
1451
|
-
//===============================
|
|
1452
|
-
{
|
|
1453
|
-
if (this._userInteractions !== null) {
|
|
1454
|
-
this._userInteractions.selectFeatures(geojsonIds)
|
|
1455
|
-
}
|
|
1456
|
-
}
|
|
1457
|
-
|
|
1458
|
-
/**
|
|
1459
|
-
* Select features and zoom the map to them.
|
|
1460
|
-
*
|
|
1461
|
-
* @param {string | Array.<string>} geojsonIds A single GeoJSON feature identifiers
|
|
1462
|
-
* or an array of identifiers.
|
|
1463
|
-
* @param {Object} [options]
|
|
1464
|
-
* @param {boolean} [options.noZoomIn=false] Don't zoom in (although zoom out as necessary)
|
|
1465
|
-
* @param {number} [options.padding=10] Padding in pixels around the composite bounding box
|
|
1466
|
-
*/
|
|
1467
|
-
zoomToGeoJSONFeatures(geojsonIds, options=null)
|
|
1468
|
-
//=============================================
|
|
1469
|
-
{
|
|
1470
|
-
options = utils.setDefaults(options, {
|
|
1471
|
-
select: true,
|
|
1472
|
-
highlight: false,
|
|
1473
|
-
padding:100
|
|
1474
|
-
})
|
|
1475
|
-
if (this._userInteractions !== null) {
|
|
1476
|
-
this._userInteractions.zoomToFeatures(geojsonIds, options)
|
|
1477
|
-
}
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
|
-
|
|
1481
|
-
//==============================================================================
|
|
1482
|
-
|
|
1483
|
-
/**
|
|
1484
|
-
* A manager for FlatMaps.
|
|
1485
|
-
* @example
|
|
1486
|
-
* const mapManager = new MapManger('https://mapcore-demo.org/flatmaps/');
|
|
1487
|
-
*/
|
|
1488
|
-
export class MapManager
|
|
1489
|
-
{
|
|
1490
|
-
/* Create a MapManager */
|
|
1491
|
-
constructor(mapServerUrl, options={})
|
|
1492
|
-
{
|
|
1493
|
-
this._mapServer = new MapServer(mapServerUrl);
|
|
1494
|
-
this._options = options;
|
|
1495
|
-
|
|
1496
|
-
this._mapList = [];
|
|
1497
|
-
this._mapNumber = 0;
|
|
1498
|
-
|
|
1499
|
-
this._initialisingMutex = new utils.Mutex();
|
|
1500
|
-
this._initialised = false;
|
|
1501
|
-
}
|
|
1502
|
-
|
|
1503
|
-
async ensureInitialised_()
|
|
1504
|
-
//========================
|
|
1505
|
-
{
|
|
1506
|
-
return await this._initialisingMutex.dispatch(async () => {
|
|
1507
|
-
if (!this._initialised) {
|
|
1508
|
-
this._mapList = [];
|
|
1509
|
-
const maps = await this._mapServer.loadJSON('');
|
|
1510
|
-
// Check map schema version (set by mapmaker) and
|
|
1511
|
-
// remove maps we can't view (giving a console warning...)
|
|
1512
|
-
for (const map of maps) {
|
|
1513
|
-
// Are features in separate vector tile source layers?
|
|
1514
|
-
map.separateLayers = ('version' in map && map.version >= MAP_MAKER_SEPARATE_LAYERS_VERSION);
|
|
1515
|
-
this._mapList.push(map);
|
|
1516
|
-
}
|
|
1517
|
-
this._initialised = true;
|
|
1518
|
-
}
|
|
1519
|
-
});
|
|
1520
|
-
}
|
|
1521
|
-
|
|
1522
|
-
allMaps()
|
|
1523
|
-
//=======
|
|
1524
|
-
{
|
|
1525
|
-
return new Promise(async(resolve, reject) => {
|
|
1526
|
-
await this.ensureInitialised_();
|
|
1527
|
-
const allMaps = {};
|
|
1528
|
-
for (const map of this._mapList) {
|
|
1529
|
-
const id = ('uuid' in map) ? map.uuid : map.id;
|
|
1530
|
-
allMaps[id] = map;
|
|
1531
|
-
}
|
|
1532
|
-
resolve(allMaps);
|
|
1533
|
-
});
|
|
1534
|
-
}
|
|
1535
|
-
|
|
1536
|
-
findMap_(identifier)
|
|
1537
|
-
//==================
|
|
1538
|
-
{
|
|
1539
|
-
return new Promise(async(resolve, reject) => {
|
|
1540
|
-
await this.ensureInitialised_();
|
|
1541
|
-
resolve(this.lookupMap_(identifier));
|
|
1542
|
-
});
|
|
1543
|
-
}
|
|
1544
|
-
|
|
1545
|
-
latestMap_(identifier)
|
|
1546
|
-
//====================
|
|
1547
|
-
{
|
|
1548
|
-
const mapDescribes = (identifier.constructor.name === "String") ? identifier
|
|
1549
|
-
: ('uuid' in identifier) ? identifier.uuid
|
|
1550
|
-
: ('taxon' in identifier) ? identifier.taxon
|
|
1551
|
-
: null;
|
|
1552
|
-
if (mapDescribes === null) {
|
|
1553
|
-
return null;
|
|
1554
|
-
}
|
|
1555
|
-
let latestMap = null;
|
|
1556
|
-
let lastCreatedTime = '';
|
|
1557
|
-
for (const map of this._mapList) {
|
|
1558
|
-
if (('uuid' in map && mapDescribes === map.uuid
|
|
1559
|
-
|| mapDescribes === map.id
|
|
1560
|
-
|| 'taxon' in map && mapDescribes === map.taxon
|
|
1561
|
-
|| mapDescribes === map.source)
|
|
1562
|
-
&& (!('biologicalSex' in identifier)
|
|
1563
|
-
|| ('biologicalSex' in map
|
|
1564
|
-
&& identifier.biologicalSex === map.biologicalSex))) {
|
|
1565
|
-
if ('created' in map) {
|
|
1566
|
-
if (lastCreatedTime < map.created) {
|
|
1567
|
-
lastCreatedTime = map.created;
|
|
1568
|
-
latestMap = map;
|
|
1569
|
-
}
|
|
1570
|
-
} else {
|
|
1571
|
-
latestMap = map;
|
|
1572
|
-
break;
|
|
1573
|
-
}
|
|
1574
|
-
}
|
|
1575
|
-
}
|
|
1576
|
-
return latestMap;
|
|
1577
|
-
}
|
|
1578
|
-
|
|
1579
|
-
lookupMap_(identifier)
|
|
1580
|
-
//====================
|
|
1581
|
-
{
|
|
1582
|
-
if (typeof identifier === 'object') {
|
|
1583
|
-
return this.latestMap_(identifier);
|
|
1584
|
-
}
|
|
1585
|
-
return this.latestMap_({uuid: identifier});
|
|
1586
|
-
}
|
|
1587
|
-
|
|
1588
|
-
/**
|
|
1589
|
-
* Load and display a FlatMap.
|
|
1590
|
-
*
|
|
1591
|
-
* @arg identifier {string|Object} A string or object identifying the map to load. If a string its
|
|
1592
|
-
* value can be either the map's ``uuid``, assigned at generation time,
|
|
1593
|
-
* or taxon and biological sex identifiers of the species that the map
|
|
1594
|
-
* represents. The latest version of a map is loaded unless it has been
|
|
1595
|
-
* identified using a ``uuid`` (see below).
|
|
1596
|
-
* @arg identifier.taxon {string} The taxon identifier of the species represented by the map. This is
|
|
1597
|
-
* specified as metadata in the map's source file.)
|
|
1598
|
-
* @arg identifier.biologicalSex {string} The biological sex of the species represented by the map.
|
|
1599
|
-
* This is specified as metadata in the map's source file.)
|
|
1600
|
-
* @arg identifier.uuid {string} The unique uuid the flatmap. If given then this exact map will
|
|
1601
|
-
* be loaded, overriding ``taxon`` and ``biologicalSex``.
|
|
1602
|
-
* @arg container {string} The id of the HTML container in which to display the map.
|
|
1603
|
-
* @arg callback {function(string, Object)} A callback function, invoked when events occur with the map. The
|
|
1604
|
-
* first parameter gives the type of event, the second provides
|
|
1605
|
-
* details about the event.
|
|
1606
|
-
* @arg options {Object} Configurable options for the map.
|
|
1607
|
-
* @arg options.background {string} Background colour of flatmap. Defaults to ``white``.
|
|
1608
|
-
* @arg options.debug {boolean} Enable debugging mode.
|
|
1609
|
-
* @arg options.flightPaths {boolean} Enable flight path (3D) view of neuron paths
|
|
1610
|
-
* @arg options.fullscreenControl {boolean} Add a ``Show full screen`` button to the map.
|
|
1611
|
-
* @arg options.layerOptions {Object} Options to control colour and outlines of features
|
|
1612
|
-
* @arg options.layerOptions.colour {boolean} Use colour fill (if available) for features. Defaults to ``true``.
|
|
1613
|
-
* @arg options.layerOptions.outline {boolean} Show the border of features. Defaults to ``true``.
|
|
1614
|
-
* @arg options.layerOptions.sckan {string} Show neuron paths known to SCKAN: values are ``valid`` (default),
|
|
1615
|
-
* ``invalid``, ``all`` or ``none``.
|
|
1616
|
-
* @arg options.minimap {boolean|Object} Display a MiniMap of the flatmap. Defaults to ``false``.
|
|
1617
|
-
* @arg options.minimap.position {string} The minimap's position: ``bottom-left`` (default), ``bottom-right``,
|
|
1618
|
-
* ``top-left`` or ``top-right``.
|
|
1619
|
-
* @arg options.minimap.width {number|string} The width of the minimap. Defaults to ``320px``. Can also
|
|
1620
|
-
* be given as a percentage of the flatmap's width, e.g. ``10%``.
|
|
1621
|
-
* The minimap's ``height`` is determined from its width using
|
|
1622
|
-
* the flatmap's aspect ratio.
|
|
1623
|
-
* @arg options.maxZoom {number} The maximum zoom level of the map.
|
|
1624
|
-
* @arg options.minZoom {number} The minimum zoom level of the map.
|
|
1625
|
-
* @arg options.navigationControl {boolean} Add navigation controls (zoom buttons) to the map.
|
|
1626
|
-
* @arg options.showPosition {boolean} Show ``position`` of tooltip.
|
|
1627
|
-
* @arg options.standalone {boolean} Viewer is running ``standalone``, as opposed to integrated into
|
|
1628
|
-
* another application so show a number of controls. Defaults to ``false``.
|
|
1629
|
-
* @example
|
|
1630
|
-
* const humanMap1 = mapManager.loadMap('humanV1', 'div-1');
|
|
1631
|
-
*
|
|
1632
|
-
* const humanMap2 = mapManager.loadMap('NCBITaxon:9606', 'div-2');
|
|
1633
|
-
*
|
|
1634
|
-
* const humanMap3 = mapManager.loadMap({taxon: 'NCBITaxon:9606'}, 'div-3');
|
|
1635
|
-
*
|
|
1636
|
-
* const humanMap4 = mapManager.loadMap(
|
|
1637
|
-
* {uuid: 'a563be90-9225-51c1-a84d-00ed2d03b7dc'},
|
|
1638
|
-
* 'div-4');
|
|
1639
|
-
*/
|
|
1640
|
-
loadMap(identifier, container, callback, options={})
|
|
1641
|
-
//==================================================
|
|
1642
|
-
{
|
|
1643
|
-
return new Promise(async(resolve, reject) => {
|
|
1644
|
-
try {
|
|
1645
|
-
const map = await this.findMap_(identifier);
|
|
1646
|
-
if (map === null) {
|
|
1647
|
-
reject(`Unknown map: ${JSON.stringify(identifier)}`);
|
|
1648
|
-
};
|
|
1649
|
-
|
|
1650
|
-
// Load the maps index file
|
|
1651
|
-
|
|
1652
|
-
const mapId = ('uuid' in map) ? map.uuid : map.id;
|
|
1653
|
-
const mapIndex = await this._mapServer.loadJSON(`flatmap/${mapId}/`);
|
|
1654
|
-
const mapIndexId = ('uuid' in mapIndex) ? mapIndex.uuid : mapIndex.id;
|
|
1655
|
-
if (mapId !== mapIndexId) {
|
|
1656
|
-
throw new Error(`Map '${mapId}' has wrong ID in index`);
|
|
1657
|
-
}
|
|
1658
|
-
const mapOptions = Object.assign({}, this._options, options);
|
|
1659
|
-
|
|
1660
|
-
// If bounds are not specified in options then set them
|
|
1661
|
-
|
|
1662
|
-
if (!('bounds' in options) && ('bounds' in mapIndex)) {
|
|
1663
|
-
mapOptions['bounds'] = mapIndex['bounds'];
|
|
1664
|
-
}
|
|
1665
|
-
|
|
1666
|
-
// Note the kind of map
|
|
1667
|
-
|
|
1668
|
-
if ('style' in mapIndex) {
|
|
1669
|
-
mapOptions.style = mapIndex.style; // Currently ``anatomical`` or ``functional``
|
|
1670
|
-
} else {
|
|
1671
|
-
mapOptions.style = 'flatmap'; // Default is a generic ``flatmap``
|
|
1672
|
-
}
|
|
1673
|
-
|
|
1674
|
-
// Mapmaker has changed the name of the field to indicate that indicates if
|
|
1675
|
-
// there are raster layers
|
|
1676
|
-
if (!('image-layers' in mapIndex) && ('image_layer' in mapIndex)) {
|
|
1677
|
-
mapIndex['image-layers'] = mapIndex['image_layer'];
|
|
1678
|
-
}
|
|
1679
|
-
|
|
1680
|
-
// Get details about the map's layers
|
|
1681
|
-
|
|
1682
|
-
let mapLayers = [];
|
|
1683
|
-
if (!('version' in mapIndex) || mapIndex.version <= 1.0) {
|
|
1684
|
-
for (const layer of mapIndex.layers) {
|
|
1685
|
-
// Set layer data if the layer just has an id specified
|
|
1686
|
-
if (typeof layer === 'string') {
|
|
1687
|
-
mapLayers.push({
|
|
1688
|
-
id: layer,
|
|
1689
|
-
description: layer.charAt(0).toUpperCase() + layer.slice(1),
|
|
1690
|
-
selectable: true
|
|
1691
|
-
});
|
|
1692
|
-
} else {
|
|
1693
|
-
mapLayers.push(layer);
|
|
1694
|
-
}
|
|
1695
|
-
}
|
|
1696
|
-
} else {
|
|
1697
|
-
mapLayers = await this._mapServer.loadJSON(`flatmap/${mapId}/layers`);
|
|
1698
|
-
}
|
|
1699
|
-
|
|
1700
|
-
// Get the map's style file
|
|
1701
|
-
|
|
1702
|
-
const mapStyle = await this._mapServer.loadJSON(`flatmap/${mapId}/style`);
|
|
1703
|
-
|
|
1704
|
-
// Make sure the style has glyphs defined
|
|
1705
|
-
|
|
1706
|
-
if (!('glyphs' in mapStyle)) {
|
|
1707
|
-
mapStyle.glyphs = 'https://fonts.openmaptiles.org/{fontstack}/{range}.pbf';
|
|
1708
|
-
}
|
|
1709
|
-
|
|
1710
|
-
// Get the map's pathways
|
|
1711
|
-
|
|
1712
|
-
const pathways = await this._mapServer.loadJSON(`flatmap/${mapId}/pathways`);
|
|
1713
|
-
|
|
1714
|
-
// Get the map's annotations
|
|
1715
|
-
|
|
1716
|
-
const annotations = await this._mapServer.loadJSON(`flatmap/${mapId}/annotations`);
|
|
1717
|
-
|
|
1718
|
-
// Get the map's provenance
|
|
1719
|
-
|
|
1720
|
-
const provenance = await this._mapServer.loadJSON(`flatmap/${mapId}/metadata`);
|
|
1721
|
-
|
|
1722
|
-
// Get additional marker details for the map
|
|
1723
|
-
|
|
1724
|
-
const mapMarkers = await this._mapServer.loadJSON(`flatmap/${mapId}/markers`);
|
|
1725
|
-
|
|
1726
|
-
// Set zoom range if not specified as an option
|
|
1727
|
-
|
|
1728
|
-
if ('vector-tiles' in mapStyle.sources) {
|
|
1729
|
-
if (!('minZoom' in mapOptions)) {
|
|
1730
|
-
mapOptions['minZoom'] = mapStyle.sources['vector-tiles'].minzoom;
|
|
1731
|
-
}
|
|
1732
|
-
if (!('maxZoom' in mapOptions)) {
|
|
1733
|
-
mapOptions['maxZoom'] = mapStyle.sources['vector-tiles'].maxzoom;
|
|
1734
|
-
}
|
|
1735
|
-
}
|
|
1736
|
-
|
|
1737
|
-
// Make sure ``layerOptions`` are set
|
|
1738
|
-
|
|
1739
|
-
if ('layerOptions' in mapOptions) {
|
|
1740
|
-
if (!('colour' in mapOptions.layerOptions)) {
|
|
1741
|
-
mapOptions.layerOptions.colour = true;
|
|
1742
|
-
}
|
|
1743
|
-
if (!('outline' in mapOptions.layerOptions)) {
|
|
1744
|
-
mapOptions.layerOptions.outline = true;
|
|
1745
|
-
}
|
|
1746
|
-
} else {
|
|
1747
|
-
mapOptions.layerOptions = {
|
|
1748
|
-
colour: true,
|
|
1749
|
-
outline: true
|
|
1750
|
-
};
|
|
1751
|
-
}
|
|
1752
|
-
mapOptions.layerOptions.authoring = ('authoring' in mapIndex) ? mapIndex.authoring : false;
|
|
1753
|
-
|
|
1754
|
-
// Are features in separate vector tile source layers?
|
|
1755
|
-
|
|
1756
|
-
mapOptions.separateLayers = map.separateLayers;
|
|
1757
|
-
|
|
1758
|
-
// Display the map
|
|
1759
|
-
|
|
1760
|
-
this._mapNumber += 1;
|
|
1761
|
-
const flatmap = new FlatMap(container, this._mapServer.url(),
|
|
1762
|
-
{
|
|
1763
|
-
id: map,
|
|
1764
|
-
uuid: mapId,
|
|
1765
|
-
details: mapIndex,
|
|
1766
|
-
taxon: map.taxon,
|
|
1767
|
-
biologicalSex: map.biologicalSex,
|
|
1768
|
-
style: mapStyle,
|
|
1769
|
-
options: mapOptions,
|
|
1770
|
-
layers: mapLayers,
|
|
1771
|
-
markers: mapMarkers,
|
|
1772
|
-
annotations: annotations,
|
|
1773
|
-
number: this._mapNumber,
|
|
1774
|
-
pathways: pathways,
|
|
1775
|
-
provenance, provenance,
|
|
1776
|
-
callback: callback
|
|
1777
|
-
},
|
|
1778
|
-
resolve);
|
|
1779
|
-
|
|
1780
|
-
return flatmap;
|
|
1781
|
-
|
|
1782
|
-
} catch (err) {
|
|
1783
|
-
reject(err);
|
|
1784
|
-
}
|
|
1785
|
-
});
|
|
1786
|
-
}
|
|
1787
|
-
}
|
|
1788
|
-
|
|
1789
|
-
//==============================================================================
|