@abi-software/flatmap-viewer 2.5.1 → 2.5.3

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 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.5.1``
41
+ * ``npm install @abi-software/flatmap-viewer@2.5.3``
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.5.1",
3
+ "version": "2.5.3",
4
4
  "description": "Flatmap viewer using Maplibre GL",
5
5
  "repository": "https://github.com/AnatomicMaps/flatmap-viewer.git",
6
6
  "main": "src/main.js",
@@ -17,7 +17,6 @@
17
17
  "author": "David Brooks",
18
18
  "license": "MIT",
19
19
  "dependencies": {
20
- "@abi-software/mapbox-gl-draw-freehand-mode": "^2.2.0",
21
20
  "@babel/runtime": "^7.10.4",
22
21
  "@deck.gl/core": "^8.9.33",
23
22
  "@deck.gl/layers": "^8.9.33",
@@ -44,161 +44,10 @@ limitations under the License.
44
44
  import MapboxDraw from "@mapbox/mapbox-gl-draw"
45
45
  import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css'
46
46
 
47
- // NB: https://github.com/bemky/mapbox-gl-draw-freehand-mode/issues/25
48
- import FreehandMode from 'mapbox-gl-draw-freehand-mode'
49
47
 
50
48
  //==============================================================================
51
49
 
52
- const drawStyles = [
53
- {
54
- 'id': 'highlight-active-points',
55
- 'type': 'circle',
56
- 'filter': ['all',
57
- ['==', '$type', 'Point'],
58
- ['==', 'meta', 'feature'],
59
- ['==', 'active', 'true']],
60
- 'paint': {
61
- 'circle-radius': 7,
62
- 'circle-color': '#080'
63
- }
64
- },
65
- {
66
- 'id': 'points-are-red',
67
- 'type': 'circle',
68
- 'filter': ['all',
69
- ['==', '$type', 'Point'],
70
- ['==', 'meta', 'feature'],
71
- ['==', 'active', 'false']],
72
- 'paint': {
73
- 'circle-radius': 5,
74
- 'circle-color': '#800'
75
- }
76
- },
77
- // ACTIVE (being drawn)
78
- // line stroke
79
- {
80
- "id": "gl-draw-line",
81
- "type": "line",
82
- "filter": ["all", ["==", "$type", "LineString"], ["!=", "mode", "static"]],
83
- "layout": {
84
- "line-cap": "round",
85
- "line-join": "round"
86
- },
87
- "paint": {
88
- "line-color": "#D20C0C",
89
- "line-dasharray": [0.2, 2],
90
- "line-width": 2
91
- }
92
- },
93
- // polygon fill
94
- {
95
- "id": "gl-draw-polygon-fill",
96
- "type": "fill",
97
- "filter": ["all", ["==", "$type", "Polygon"], ["!=", "mode", "static"]],
98
- "paint": {
99
- 'fill-color': [
100
- 'case',
101
- ['boolean', ['feature-state', 'active'], false], '#D88',
102
- '#020C0C'
103
- ],
104
- "fill-outline-color": "#D20C0C",
105
- "fill-opacity": 0.1
106
- }
107
- },
108
- // polygon mid points
109
- {
110
- 'id': 'gl-draw-polygon-midpoint',
111
- 'type': 'circle',
112
- 'filter': ['all',
113
- ['==', '$type', 'Point'],
114
- ['==', 'meta', 'midpoint']],
115
- 'paint': {
116
- 'circle-radius': 3,
117
- 'circle-color': '#fbb03b'
118
- }
119
- },
120
- // polygon outline stroke
121
- // This doesn't style the first edge of the polygon, which uses the line stroke styling instead
122
- {
123
- "id": "gl-draw-polygon-stroke-active",
124
- "type": "line",
125
- "filter": ["all", ["==", "$type", "Polygon"], ["!=", "mode", "static"]],
126
- "layout": {
127
- "line-cap": "round",
128
- "line-join": "round"
129
- },
130
- "paint": {
131
- "line-color": "#D20C0C",
132
- "line-dasharray": [0.2, 2],
133
- "line-width": 2
134
- }
135
- },
136
- // vertex point halos
137
- {
138
- "id": "gl-draw-polygon-and-line-vertex-halo-active",
139
- "type": "circle",
140
- "filter": ["all", ["==", "meta", "vertex"], ["==", "$type", "Point"], ["!=", "mode", "static"]],
141
- "paint": {
142
- "circle-radius": 5,
143
- "circle-color": "#FFF"
144
- }
145
- },
146
- // vertex points
147
- {
148
- "id": "gl-draw-polygon-and-line-vertex-active",
149
- "type": "circle",
150
- "filter": ["all", ["==", "meta", "vertex"], ["==", "$type", "Point"], ["!=", "mode", "static"]],
151
- "paint": {
152
- "circle-radius": 3,
153
- "circle-color": "#D20C0C",
154
- }
155
- },
156
-
157
- // INACTIVE (static, already drawn)
158
- // line stroke
159
- {
160
- "id": "gl-draw-line-static",
161
- "type": "line",
162
- "filter": ["all", ["==", "$type", "LineString"], ["==", "mode", "static"]],
163
- "layout": {
164
- "line-cap": "round",
165
- "line-join": "round"
166
- },
167
- "paint": {
168
- "line-color": "#000",
169
- "line-width": 3
170
- }
171
- },
172
- // polygon fill
173
- {
174
- "id": "gl-draw-polygon-fill-static",
175
- "type": "fill",
176
- "filter": ["all", ["==", "$type", "Polygon"], ["==", "mode", "static"]],
177
- "paint": {
178
- "fill-color": "#000",
179
- "fill-outline-color": "#000",
180
- "fill-opacity": 0.1
181
- }
182
- },
183
- // polygon outline
184
- {
185
- "id": "gl-draw-polygon-stroke-static",
186
- "type": "line",
187
- "filter": ["all", ["==", "$type", "Polygon"], ["==", "mode", "static"]],
188
- "layout": {
189
- "line-cap": "round",
190
- "line-join": "round"
191
- },
192
- "paint": {
193
- "line-color": "#000",
194
- "line-width": 3
195
- }
196
- }
197
- ]
198
-
199
- //==============================================================================
200
-
201
- const drawStyleIds = drawStyles.map(s => s.id)
50
+ const drawStyleIds = MapboxDraw.lib.theme.map(s => s.id)
202
51
 
203
52
  export const DRAW_ANNOTATION_LAYERS = [...drawStyleIds.map(id => `${id}.cold`),
204
53
  ...drawStyleIds.map(id => `${id}.hot`)]
@@ -207,8 +56,6 @@ export const DRAW_ANNOTATION_LAYERS = [...drawStyleIds.map(id => `${id}.cold`),
207
56
 
208
57
  export class AnnotationDrawControl
209
58
  {
210
- #visible
211
-
212
59
  constructor(flatmap, visible=false)
213
60
  {
214
61
  MapboxDraw.constants.classes.CONTROL_BASE = 'maplibregl-ctrl'
@@ -216,7 +63,9 @@ export class AnnotationDrawControl
216
63
  MapboxDraw.constants.classes.CONTROL_GROUP = 'maplibregl-ctrl-group'
217
64
 
218
65
  this.__flatmap = flatmap
219
- this.#visible = visible
66
+ this.__committedFeatures = new Map()
67
+ this.__uncommittedFeatureIds = new Set()
68
+ this.__visible = visible
220
69
  this.__draw = new MapboxDraw({
221
70
  displayControlsDefault: false,
222
71
  controls: {
@@ -226,12 +75,7 @@ export class AnnotationDrawControl
226
75
  trash: true
227
76
  },
228
77
  userProperties: true,
229
- keybindings: true,
230
- modes: {
231
- ...MapboxDraw.modes,
232
- draw_polygon: FreehandMode
233
- },
234
- styles: drawStyles
78
+ keybindings: true
235
79
  })
236
80
  this.__map = null
237
81
  }
@@ -255,7 +99,7 @@ export class AnnotationDrawControl
255
99
  map.on('draw.create', this.createdFeature.bind(this))
256
100
  map.on('draw.delete', this.deletedFeature.bind(this))
257
101
  map.on('draw.update', this.updatedFeature.bind(this))
258
- this.show(this.#visible)
102
+ this.show(this.__visible)
259
103
  return this.__container
260
104
  }
261
105
 
@@ -272,17 +116,17 @@ export class AnnotationDrawControl
272
116
  {
273
117
  if (this.__container) {
274
118
  this.__container.style.display = visible ? 'block' : 'none'
275
- if (visible && !this.#visible) {
119
+ if (visible && !this.__visible) {
276
120
  for (const layerId of DRAW_ANNOTATION_LAYERS) {
277
121
  this.__map.setLayoutProperty(layerId, 'visibility', 'visible')
278
122
  }
279
- } else if (!visible && this.#visible) {
123
+ } else if (!visible && this.__visible) {
280
124
  for (const layerId of DRAW_ANNOTATION_LAYERS) {
281
125
  this.__map.setLayoutProperty(layerId, 'visibility', 'none')
282
126
  }
283
127
  }
284
128
  }
285
- this.#visible = visible
129
+ this.__visible = visible
286
130
  }
287
131
 
288
132
  #cleanFeature(event)
@@ -292,13 +136,20 @@ export class AnnotationDrawControl
292
136
  .map(f => {
293
137
  return {
294
138
  id: f.id,
139
+ type: 'Feature',
295
140
  geometry: f.geometry
296
- // properties
297
141
  }
298
142
  })
299
143
  return features.length ? features[0] : null
300
144
  }
301
145
 
146
+ #sendEvent(type, feature)
147
+ //=======================
148
+ {
149
+ this.__uncommittedFeatureIds.add(feature.id)
150
+ this.__flatmap.annotationEvent(type, feature)
151
+ }
152
+
302
153
  createdFeature(event)
303
154
  //===================
304
155
  {
@@ -307,13 +158,12 @@ export class AnnotationDrawControl
307
158
  // Set properties to indicate that this is a drawn annotation
308
159
  this.__draw.setFeatureProperty(feature.id, 'drawn', true)
309
160
  this.__draw.setFeatureProperty(feature.id, 'label', 'Drawn annotation')
310
- // They also need to be on the feature passed to the annotator
311
- // for storage
161
+ // They need to be on the feature passed to the annotator for storage
312
162
  feature.properties = {
313
163
  user_drawn: true,
314
164
  user_label: 'Drawn annotation'
315
165
  }
316
- this.__flatmap.annotationDrawEvent('created', feature)
166
+ this.#sendEvent('created', feature)
317
167
  }
318
168
  }
319
169
 
@@ -322,7 +172,11 @@ export class AnnotationDrawControl
322
172
  {
323
173
  const feature = this.#cleanFeature(event)
324
174
  if (feature) {
325
- this.__flatmap.annotationDrawEvent('deleted', feature.id)
175
+ if (this.__uncommittedFeatureIds.has(feature.id)) {
176
+ // Ignore delete on an uncommitted create or update
177
+ } else {
178
+ this.#sendEvent('deleted', feature)
179
+ }
326
180
  }
327
181
  }
328
182
 
@@ -331,20 +185,61 @@ export class AnnotationDrawControl
331
185
  {
332
186
  const feature = this.#cleanFeature(event)
333
187
  if (feature) {
334
- this.__flatmap.annotationDrawEvent('updated', feature)
188
+ if (this.__uncommittedFeatureIds.has(feature.id)) {
189
+ // Ignore updates on an uncommitted create or update
190
+ } else {
191
+ this.#sendEvent('updated', feature)
192
+ }
193
+ }
194
+ }
195
+
196
+ commitEvent(event)
197
+ //================
198
+ {
199
+ const feature = event.feature
200
+ if (event.type === 'deleted') {
201
+ this.__committedFeatures.delete(feature.id)
202
+ } else {
203
+ this.__committedFeatures.set(feature.id, feature)
204
+ }
205
+ this.__uncommittedFeatureIds.delete(feature.id)
206
+ }
207
+
208
+ rollbackEvent(event)
209
+ //==================
210
+ {
211
+ const feature = event.feature
212
+ if (event.type === 'created') {
213
+ this.__draw.delete(feature.id)
214
+ this.__committedFeatures.delete(feature.id)
215
+ this.__uncommittedFeatureIds.delete(feature.id)
216
+ } else if (event.type === 'deleted') {
217
+ this.__draw.add(feature)
218
+ this.__committedFeatures.set(feature.id, feature)
219
+ this.__uncommittedFeatureIds.delete(feature.id)
220
+ } else if (event.type === 'updated') {
221
+ const savedFeature = this.__committedFeatures.get(feature.id)
222
+ if (savedFeature) {
223
+ this.__draw.delete(feature.id)
224
+ this.__draw.add(savedFeature)
225
+ this.__uncommittedFeatureIds.delete(feature.id)
226
+ }
335
227
  }
336
228
  }
337
229
 
338
230
  addFeature(feature)
339
231
  //=================
340
232
  {
341
- this.__draw.add(feature)
233
+ feature = Object.assign({}, feature, {type: 'Feature'})
234
+ const ids = this.__draw.add(feature)
235
+ this.__committedFeatures.set(ids[0], feature)
236
+ this.__uncommittedFeatureIds.delete(ids[0])
342
237
  }
343
238
 
344
- removeFeature(feature)
345
- //====================
239
+ refreshGeometry(feature)
240
+ //======================
346
241
  {
347
- this.__draw.delete(feature.id)
242
+ return this.__draw.get(feature.id) || null
348
243
  }
349
244
  }
350
245
 
@@ -589,19 +589,32 @@ class FlatMap
589
589
  }
590
590
 
591
591
  /**
592
- * Get feature ids of all nodes of a path model.
592
+ * Get GeoJSON feature ids of all nodes of a path model.
593
593
  *
594
594
  * @param {string} pathId The path model identifier
595
- * @return {set<number>} Local (GeoJSON) identifiers of features on the path
595
+ * @return {Array<string>} GeoJSON identifiers of features on the path
596
596
  */
597
597
  pathModelNodes(modelId)
598
598
  //=====================
599
599
  {
600
600
  if (this._userInteractions !== null) {
601
- return this._userInteractions.pathModelNodes(modelId);
601
+ return new [...this._userInteractions.pathModelNodes(modelId)]
602
602
  }
603
603
  }
604
604
 
605
+ /**
606
+ * Get GeoJSON feature ids of all features identified with a taxon.
607
+ *
608
+ * @param {string} taxonId The taxon identifier
609
+ * @return {Array<string>} GeoJSON identifiers of features on the path
610
+ */
611
+ taxonFeatureIds(taxonId)
612
+ //======================
613
+ {
614
+ const featureIds = this.__taxonToFeatureIds.get(utils.normaliseId(taxonId))
615
+ return [...new Set(featureIds ? featureIds : [])]
616
+ }
617
+
605
618
  get layers()
606
619
  //==========
607
620
  {
@@ -1051,35 +1064,83 @@ class FlatMap
1051
1064
  }
1052
1065
 
1053
1066
  /**
1054
- * Generate an ``'annotation-draw`` callback when a drawn annotation has changed.
1067
+ * Generate an ``annotation`` callback event when a drawn annotation has been created
1068
+ * a modified.
1055
1069
  *
1056
- * @param {string} operation Either ``created``, ``updated`` or ``deleted``
1057
- * @param {string|Object} feature An object with ``id`` and ``geometry`` fields
1058
- * for a feature that has been created or updated
1059
- * or the ``id`` of a feature that has been deleted.
1070
+ * @param eventType {string} Either ``created``, ``updated`` or ``deleted``
1071
+ * @param feature {Object} A feature object with ``id``, ``type``, and ``geometry``
1072
+ * fields of a feature that has been created, updated or
1073
+ * deleted.
1060
1074
  */
1061
- annotationDrawEvent(drawEvent, feature)
1062
- //=====================================
1075
+ annotationEvent(eventType, feature)
1076
+ //=================================
1063
1077
  {
1064
- this.callback('annotation-draw', {
1065
- type: drawEvent,
1078
+ this.callback('annotation', {
1079
+ type: eventType,
1066
1080
  feature: feature
1067
1081
  });
1068
1082
  }
1069
1083
 
1070
1084
  /**
1071
- * Add or remove a drawn annotation.
1085
+ * Mark a drawn/changed annotation as having been accepted by the user.
1072
1086
  *
1073
- * @param {string} operation Either ``add`` or ``remove``
1074
- * @param {Object} feature The feature to add or remove
1075
- * @param {string} feature.id The feature's id
1076
- * @param {Object} feature.geometry The feature's geometry as GeoJSON
1087
+ * @param event {Object} The object as received in an annotation callback
1088
+ * @param event.type {string} Either ``created``, ``updated`` or ``deleted``
1089
+ * @param event.feature {Object} A feature object.
1077
1090
  */
1078
- modifyDrawnAnnotatorFeature(operation, feature)
1079
- //=============================================
1091
+ commitAnnotationEvent(event)
1092
+ //==========================
1093
+ {
1094
+ if (this._userInteractions) {
1095
+ this._userInteractions.commitAnnotationEvent(event)
1096
+ }
1097
+ }
1098
+
1099
+ /**
1100
+ * Mark a drawn/changed annotation as having been rejected by the user.
1101
+ *
1102
+ * @param event {Object} The object as received in an annotation callback
1103
+ * @param event.type {string} Either ``created``, ``updated`` or ``deleted``
1104
+ * @param event.feature {Object} A feature object.
1105
+ */
1106
+ rollbackAnnotationEvent(event)
1107
+ //============================
1108
+ {
1109
+ if (this._userInteractions) {
1110
+ this._userInteractions.rollbackAnnotationEvent(event)
1111
+ }
1112
+ }
1113
+
1114
+ /**
1115
+ * Add a drawn feature to the annotation drawing tool.
1116
+ *
1117
+ * @param feature {Object} The feature to add
1118
+ * @param feature.id {string} The feature's id
1119
+ * @param feature.geometry {Object} The feature's geometry as GeoJSON
1120
+ */
1121
+ addAnnotationFeature(feature)
1122
+ //===========================
1123
+ {
1124
+ if (this._userInteractions) {
1125
+ this._userInteractions.addAnnotationFeature(feature)
1126
+ }
1127
+ }
1128
+
1129
+ /**
1130
+ * Return the feature as it is currently drawn. This is so
1131
+ * the correct geometry can be saved with a feature should
1132
+ * a user make changes before submitting dialog provided
1133
+ * by an external annotator.
1134
+ *
1135
+ * @param feature {Object} The drawn feature to refresh.
1136
+ * @returns {Object|null} The feature with currently geometry or ``null``
1137
+ * if the feature has been deleted.
1138
+ */
1139
+ refreshAnnotationFeatureGeometry(feature)
1140
+ //=======================================
1080
1141
  {
1081
1142
  if (this._userInteractions) {
1082
- this._userInteractions.modifyDrawnAnnotatorFeature(operation, feature)
1143
+ this._userInteractions.refreshAnnotationFeatureGeometry(feature)
1083
1144
  }
1084
1145
  }
1085
1146
 
@@ -1283,6 +1344,42 @@ class FlatMap
1283
1344
  this._userInteractions.zoomToFeatures(featureIds, options);
1284
1345
  }
1285
1346
  }
1347
+
1348
+ /**
1349
+ * Select features on the map.
1350
+ *
1351
+ * @param {string | Array.<string>} geojsonIds A single GeoJSON feature identifiers
1352
+ * or an array of identifiers.
1353
+ */
1354
+ selectGeoJSONFeatures(geojsonIds)
1355
+ //===============================
1356
+ {
1357
+ if (this._userInteractions !== null) {
1358
+ this._userInteractions.selectFeatures(geojsonIds)
1359
+ }
1360
+ }
1361
+
1362
+ /**
1363
+ * Select features and zoom the map to them.
1364
+ *
1365
+ * @param {string | Array.<string>} geojsonIds A single GeoJSON feature identifiers
1366
+ * or an array of identifiers.
1367
+ * @param {Object} [options]
1368
+ * @param {boolean} [options.noZoomIn=false] Don't zoom in (although zoom out as necessary)
1369
+ * @param {number} [options.padding=10] Padding in pixels around the composite bounding box
1370
+ */
1371
+ zoomToGeoJSONFeatures(geojsonIds, options=null)
1372
+ //=============================================
1373
+ {
1374
+ options = utils.setDefaults(options, {
1375
+ select: true,
1376
+ highlight: false,
1377
+ padding:100
1378
+ })
1379
+ if (this._userInteractions !== null) {
1380
+ this._userInteractions.zoomToFeatures(geojsonIds, options)
1381
+ }
1382
+ }
1286
1383
  }
1287
1384
 
1288
1385
  //==============================================================================
@@ -248,11 +248,11 @@ export class UserInteractions
248
248
  this._map.addControl(new TaxonsControl(flatmap));
249
249
  }
250
250
 
251
+ this._map.addControl(new Path3DControl(this));
252
+
251
253
  if (flatmap.options.annotator) {
252
254
  this._map.addControl(new AnnotatorControl(flatmap));
253
255
  }
254
-
255
- this._map.addControl(new Path3DControl(this));
256
256
  }
257
257
 
258
258
  // Add an initially hidden tool for drawing on the map.
@@ -326,15 +326,35 @@ export class UserInteractions
326
326
  }
327
327
  }
328
328
 
329
- modifyDrawnAnnotatorFeature(operation, feature)
330
- //=============================================
329
+ commitAnnotationEvent(event)
330
+ //==========================
331
331
  {
332
332
  if (this.#annotationDrawControl) {
333
- if (operation === 'add') {
334
- this.#annotationDrawControl.addFeature(feature)
335
- } else if (operation === 'remove') {
336
- this.#annotationDrawControl.removeFeature(feature)
337
- }
333
+ this.#annotationDrawControl.commitEvent(event)
334
+ }
335
+ }
336
+
337
+ rollbackAnnotationEvent(event)
338
+ //==========================
339
+ {
340
+ if (this.#annotationDrawControl) {
341
+ this.#annotationDrawControl.rollbackEvent(event)
342
+ }
343
+ }
344
+
345
+ addAnnotationFeature(feature)
346
+ //===========================
347
+ {
348
+ if (this.#annotationDrawControl) {
349
+ this.#annotationDrawControl.addFeature(feature)
350
+ }
351
+ }
352
+
353
+ refreshAnnotationFeatureGeometry(feature)
354
+ //=======================================
355
+ {
356
+ if (this.#annotationDrawControl) {
357
+ this.#annotationDrawControl.refreshGeometry(feature)
338
358
  }
339
359
  }
340
360
 
@@ -27,7 +27,6 @@ import GL from '@luma.gl/constants'
27
27
 
28
28
  import {pathColourArray} from '../pathways'
29
29
 
30
-
31
30
  //==============================================================================
32
31
 
33
32
  const transparencyCheck = '|| length(vColor) == 0.0'
package/src/main.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Flatmap viewer and annotation tool
4
4
 
5
- Copyright (c) 2019 David Brooks
5
+ Copyright (c) 2019 - 2024 David Brooks
6
6
 
7
7
  Licensed under the Apache License, Version 2.0 (the "License");
8
8
  you may not use this file except in compliance with the License.
@@ -27,6 +27,52 @@ export { MapManager };
27
27
 
28
28
  //==============================================================================
29
29
 
30
+ class DrawControl
31
+ {
32
+ constructor(flatmap)
33
+ {
34
+ this._flatmap = flatmap
35
+ this._lastEvent = null
36
+ this._idField = document.getElementById('drawing-id')
37
+
38
+ this._okBtn = document.getElementById('drawing-ok')
39
+ if (this._okBtn) {
40
+ this._okBtn.addEventListener('click', e => {
41
+ if (this._lastEvent) {
42
+ const feature = this._flatmap.refreshAnnotationFeatureGeometry(this._lastEvent.feature)
43
+ this._flatmap.commitAnnotationEvent(this._lastEvent)
44
+ this._idField.innerText = ''
45
+ this._lastEvent = null
46
+ // Send `feature`, along with user comments, to the annotation service
47
+ }
48
+ })
49
+ }
50
+
51
+ this._cancelBtn = document.getElementById('drawing-cancel')
52
+ if (this._cancelBtn) {
53
+ this._cancelBtn.addEventListener('click', e => {
54
+ if (this._lastEvent) {
55
+ this._flatmap.rollbackAnnotationEvent(this._lastEvent)
56
+ this._idField.innerText = ''
57
+ this._lastEvent = null
58
+ }
59
+ })
60
+ }
61
+ }
62
+
63
+ handleEvent(event)
64
+ //================
65
+ {
66
+ console.log(event)
67
+ if (this._idField) {
68
+ this._idField.innerText = `Annotation ${event.type}, Id: ${event.feature.id}`
69
+ this._lastEvent = event
70
+ }
71
+ }
72
+ }
73
+
74
+ //==============================================================================
75
+
30
76
  export async function standaloneViewer(map_endpoint=null, options={})
31
77
  {
32
78
  const requestUrl = new URL(window.location.href);
@@ -52,6 +98,7 @@ export async function standaloneViewer(map_endpoint=null, options={})
52
98
  });
53
99
 
54
100
  let currentMap = null;
101
+ let drawControl = null;
55
102
  let defaultBackground = localStorage.getItem('flatmap-background-colour') || 'black';
56
103
 
57
104
  const mapOptions = Object.assign({
@@ -90,6 +137,8 @@ export async function standaloneViewer(map_endpoint=null, options={})
90
137
  mapManager.loadMap(id, 'map-canvas', (eventType, ...args) => {
91
138
  if (args[0].type === 'control' && args[0].control === 'background') {
92
139
  mapOptions.background = args[0].value;
140
+ } else if (eventType === 'annotation') {
141
+ drawControl.handleEvent(...args)
93
142
  }
94
143
  }, mapOptions)
95
144
  .then(map => {
@@ -99,6 +148,7 @@ export async function standaloneViewer(map_endpoint=null, options={})
99
148
  map.addMarker('UBERON:0001155'); // Colon
100
149
  map.addMarker('UBERON:0001255'); // Bladder
101
150
  currentMap = map;
151
+ drawControl = new DrawControl(map)
102
152
  })
103
153
  .catch(error => {
104
154
  console.log(error);
@@ -180,3 +230,6 @@ export async function standaloneViewer(map_endpoint=null, options={})
180
230
 
181
231
  loadMap(mapId, mapTaxon, mapSex);
182
232
  }
233
+
234
+ //==============================================================================
235
+
@@ -230,139 +230,9 @@ label[for=layer-all-layers] {
230
230
  font-weight: bold;
231
231
  }
232
232
 
233
- /* Annotator */
234
- .flex-auto {
235
- flex: 1 1 auto;
233
+ /* Control buttons for standalone annotation */
234
+ .mapbox-gl-draw_ctrl-draw-btn.active {
235
+ background-color: #FBB !important;
236
236
  }
237
237
 
238
- #flatmap-annotation-panel {
239
- display: flex;
240
- flex-direction: column;
241
- flex-wrap: nowrap;
242
- height: 100%;
243
- }
244
- #flatmap-annotation-form
245
- {
246
- flex: auto;
247
- }
248
-
249
- #flatmap-annotation-feature,
250
- #flatmap-annotation-form,
251
- #flatmap-annotation-existing
252
- {
253
- padding: 4px;
254
- }
255
- #flatmap-annotation-feature,
256
- #flatmap-annotation-existing
257
- {
258
- background-color: #DDD;
259
- border: 2px solid #888;
260
- }
261
-
262
- #flatmap-annotation-existing
263
- {
264
- overflow: scroll;
265
- max-height: 400px;
266
- }
267
-
268
- .flatmap-annotation-prompt
269
- {
270
- font-weight: bold;
271
- display: inline-block;
272
- min-width: 80px;
273
- padding-right: 6px;
274
- vertical-align: top;
275
- }
276
-
277
- .flatmap-annotation-value
278
- {
279
- display: inline-block;
280
- vertical-align: top;
281
- }
282
-
283
- #flatmap-annotation-formdata
284
- {
285
- display: flex;
286
- flex-direction: column;
287
- flex-wrap: nowrap;
288
- padding-right: 4px;
289
- }
290
-
291
- #flatmap-annotation-formdata div
292
- {
293
- padding-top: 4px;
294
- padding-bottom: 4px;
295
- }
296
-
297
- .flatmap-annotation-entry {
298
- display: flex;
299
- flex-wrap: nowrap;
300
- }
301
-
302
- #flatmap-annotation-form input,
303
- #flatmap-annotation-form .multiple,
304
- #flatmap-annotation-form select,
305
- #flatmap-annotation-form textarea
306
- {
307
- flex: auto;
308
- }
309
-
310
- #flatmap-annotation-form label
311
- {
312
- padding-right: 6px;
313
- display: inline-block;
314
- width: 80px;
315
- }
316
- #flatmap-annotation-form .multiple,
317
- #flatmap-annotation-form textarea
318
- {
319
- width: 360px;
320
- }
321
- #flatmap-annotation-form input[type="text"]
322
- {
323
- width: 300px;
324
- }
325
- #flatmap-annotation-form .multiple
326
- {
327
- padding:0;
328
- }
329
- #flatmap-annotation-form select
330
- {
331
- width: 160px;
332
- }
333
- #flatmap-annotation-form input[type="button"]
334
- {
335
- float: right;
336
- background-color: #BBB;
337
- }
338
-
339
- #annotation-feature-selection
340
- {
341
- display: flex;
342
- }
343
-
344
- #annotation-feature-buttons
345
- {
346
- float: right;
347
- padding-top: 10px;
348
- padding-bottom: 10px;
349
- }
350
-
351
- .jsPanel-title {
352
- font-size: 1.4em !important;
353
- font-weight: bold !important;
354
- }
355
-
356
- .jsPanel-content
357
- {
358
- background-color: #EEE !important;
359
- }
360
- .jsPanel-hdr,
361
- .jsPanel-ftr
362
- {
363
- background-color: #BBB !important;
364
- }
365
- .jsPanel-ftr-btn {
366
- cursor: pointer;
367
- }
368
238
  /* End of file */