@abi-software/flatmap-viewer 2.5.1 → 2.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.rst +1 -1
- package/package.json +1 -2
- package/src/controls/annotation.js +70 -175
- package/src/flatmap-viewer.js +65 -17
- package/src/interactions.js +29 -9
- package/src/layers/paths3d.js +0 -1
- package/src/main.js +54 -1
- package/static/css/flatmap-viewer.css +3 -133
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.
|
|
41
|
+
* ``npm install @abi-software/flatmap-viewer@2.5.2``
|
|
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.
|
|
3
|
+
"version": "2.5.2",
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
345
|
-
|
|
239
|
+
refreshGeometry(feature)
|
|
240
|
+
//======================
|
|
346
241
|
{
|
|
347
|
-
this.__draw.
|
|
242
|
+
return this.__draw.get(feature.id) || null
|
|
348
243
|
}
|
|
349
244
|
}
|
|
350
245
|
|
package/src/flatmap-viewer.js
CHANGED
|
@@ -1051,35 +1051,83 @@ class FlatMap
|
|
|
1051
1051
|
}
|
|
1052
1052
|
|
|
1053
1053
|
/**
|
|
1054
|
-
* Generate an ``
|
|
1054
|
+
* Generate an ``annotation`` callback event when a drawn annotation has been created
|
|
1055
|
+
* a modified.
|
|
1055
1056
|
*
|
|
1056
|
-
* @param {string}
|
|
1057
|
-
* @param {
|
|
1058
|
-
*
|
|
1059
|
-
*
|
|
1057
|
+
* @param eventType {string} Either ``created``, ``updated`` or ``deleted``
|
|
1058
|
+
* @param feature {Object} A feature object with ``id``, ``type``, and ``geometry``
|
|
1059
|
+
* fields of a feature that has been created, updated or
|
|
1060
|
+
* deleted.
|
|
1060
1061
|
*/
|
|
1061
|
-
|
|
1062
|
-
|
|
1062
|
+
annotationEvent(eventType, feature)
|
|
1063
|
+
//=================================
|
|
1063
1064
|
{
|
|
1064
|
-
this.callback('annotation
|
|
1065
|
-
type:
|
|
1065
|
+
this.callback('annotation', {
|
|
1066
|
+
type: eventType,
|
|
1066
1067
|
feature: feature
|
|
1067
1068
|
});
|
|
1068
1069
|
}
|
|
1069
1070
|
|
|
1070
1071
|
/**
|
|
1071
|
-
*
|
|
1072
|
+
* Mark a drawn/changed annotation as having been accepted by the user.
|
|
1073
|
+
*
|
|
1074
|
+
* @param event {Object} The object as received in an annotation callback
|
|
1075
|
+
* @param event.type {string} Either ``created``, ``updated`` or ``deleted``
|
|
1076
|
+
* @param event.feature {Object} A feature object.
|
|
1077
|
+
*/
|
|
1078
|
+
commitAnnotationEvent(event)
|
|
1079
|
+
//==========================
|
|
1080
|
+
{
|
|
1081
|
+
if (this._userInteractions) {
|
|
1082
|
+
this._userInteractions.commitAnnotationEvent(event)
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
/**
|
|
1087
|
+
* Mark a drawn/changed annotation as having been rejected by the user.
|
|
1088
|
+
*
|
|
1089
|
+
* @param event {Object} The object as received in an annotation callback
|
|
1090
|
+
* @param event.type {string} Either ``created``, ``updated`` or ``deleted``
|
|
1091
|
+
* @param event.feature {Object} A feature object.
|
|
1092
|
+
*/
|
|
1093
|
+
rollbackAnnotationEvent(event)
|
|
1094
|
+
//============================
|
|
1095
|
+
{
|
|
1096
|
+
if (this._userInteractions) {
|
|
1097
|
+
this._userInteractions.rollbackAnnotationEvent(event)
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
/**
|
|
1102
|
+
* Add a drawn feature to the annotation drawing tool.
|
|
1072
1103
|
*
|
|
1073
|
-
* @param {
|
|
1074
|
-
* @param {
|
|
1075
|
-
* @param {
|
|
1076
|
-
* @param {Object} feature.geometry The feature's geometry as GeoJSON
|
|
1104
|
+
* @param feature {Object} The feature to add
|
|
1105
|
+
* @param feature.id {string} The feature's id
|
|
1106
|
+
* @param feature.geometry {Object} The feature's geometry as GeoJSON
|
|
1077
1107
|
*/
|
|
1078
|
-
|
|
1079
|
-
|
|
1108
|
+
addAnnotationFeature(feature)
|
|
1109
|
+
//===========================
|
|
1110
|
+
{
|
|
1111
|
+
if (this._userInteractions) {
|
|
1112
|
+
this._userInteractions.addAnnotationFeature(feature)
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
/**
|
|
1117
|
+
* Return the feature as it is currently drawn. This is so
|
|
1118
|
+
* the correct geometry can be saved with a feature should
|
|
1119
|
+
* a user make changes before submitting dialog provided
|
|
1120
|
+
* by an external annotator.
|
|
1121
|
+
*
|
|
1122
|
+
* @param feature {Object} The drawn feature to refresh.
|
|
1123
|
+
* @returns {Object|null} The feature with currently geometry or ``null``
|
|
1124
|
+
* if the feature has been deleted.
|
|
1125
|
+
*/
|
|
1126
|
+
refreshAnnotationFeatureGeometry(feature)
|
|
1127
|
+
//=======================================
|
|
1080
1128
|
{
|
|
1081
1129
|
if (this._userInteractions) {
|
|
1082
|
-
this._userInteractions.
|
|
1130
|
+
this._userInteractions.refreshAnnotationFeatureGeometry(feature)
|
|
1083
1131
|
}
|
|
1084
1132
|
}
|
|
1085
1133
|
|
package/src/interactions.js
CHANGED
|
@@ -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
|
-
|
|
330
|
-
|
|
329
|
+
commitAnnotationEvent(event)
|
|
330
|
+
//==========================
|
|
331
331
|
{
|
|
332
332
|
if (this.#annotationDrawControl) {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
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
|
|
package/src/layers/paths3d.js
CHANGED
package/src/main.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Flatmap viewer and annotation tool
|
|
4
4
|
|
|
5
|
-
Copyright (c) 2019
|
|
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
|
-
/*
|
|
234
|
-
.
|
|
235
|
-
|
|
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 */
|