@abi-software/flatmap-viewer 2.5.0-a.2 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.rst +1 -1
- package/package.json +3 -3
- package/src/controls/annotation.js +351 -0
- package/src/controls/controls.js +68 -0
- package/src/controls/minimap.js +3 -8
- package/src/controls/paths3d.js +14 -0
- package/src/flatmap-viewer.js +55 -35
- package/src/interactions.js +167 -49
- package/src/layers/paths3d.js +253 -88
- package/src/main.js +1 -0
- package/src/pathways.js +29 -9
package/src/layers/paths3d.js
CHANGED
|
@@ -18,66 +18,134 @@ limitations under the License.
|
|
|
18
18
|
|
|
19
19
|
******************************************************************************/
|
|
20
20
|
|
|
21
|
-
import {colord} from 'colord'
|
|
22
21
|
import {ArcLayer} from '@deck.gl/layers'
|
|
23
22
|
import {MapboxOverlay as DeckOverlay} from '@deck.gl/mapbox'
|
|
24
|
-
import {
|
|
23
|
+
import {Model, Geometry} from '@luma.gl/core'
|
|
24
|
+
import GL from '@luma.gl/constants'
|
|
25
25
|
|
|
26
26
|
//==============================================================================
|
|
27
27
|
|
|
28
|
-
import {
|
|
28
|
+
import {pathColourArray} from '../pathways'
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
|
|
31
|
+
//==============================================================================
|
|
32
|
+
|
|
33
|
+
const transparencyCheck = '|| length(vColor) == 0.0'
|
|
34
|
+
|
|
35
|
+
class ArcMapLayer extends ArcLayer
|
|
33
36
|
{
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
static layerName = 'ArcMapLayer'
|
|
38
|
+
|
|
39
|
+
#dirty = false
|
|
40
|
+
#pathData
|
|
41
|
+
|
|
42
|
+
constructor(...args)
|
|
43
|
+
{
|
|
44
|
+
super(...args)
|
|
45
|
+
this.#pathData = new Map([...this.props.data].map(ann => [+ann.featureId, ann]))
|
|
46
|
+
this.#pathData.forEach(ann => delete ann['hidden'])
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get featureIds()
|
|
50
|
+
//==============
|
|
51
|
+
{
|
|
52
|
+
return [...this.#pathData.keys()]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
getShaders()
|
|
56
|
+
//==========
|
|
57
|
+
{
|
|
58
|
+
const shaders = super.getShaders()
|
|
59
|
+
shaders.fs = `#version 300 es\n${shaders.fs}`
|
|
60
|
+
.replace('isValid == 0.0', `isValid == 0.0 ${transparencyCheck}`)
|
|
61
|
+
shaders.vs = `#version 300 es\n${shaders.vs}`
|
|
62
|
+
return shaders
|
|
63
|
+
}
|
|
64
|
+
setDataProperty(featureId, key, enabled)
|
|
65
|
+
//======================================
|
|
66
|
+
{
|
|
67
|
+
const properties = this.#pathData.get(+featureId)
|
|
68
|
+
if (properties) {
|
|
69
|
+
if (!(key in properties) || properties[key] !== enabled) {
|
|
70
|
+
properties[key] = enabled
|
|
71
|
+
this.#dirty = true
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
redraw(force=false)
|
|
77
|
+
//=================
|
|
78
|
+
{
|
|
79
|
+
if (force || this.#dirty) {
|
|
80
|
+
this.internalState.changeFlags.dataChanged = true
|
|
81
|
+
this.setNeedsUpdate()
|
|
82
|
+
this.#dirty = false
|
|
83
|
+
}
|
|
84
|
+
}
|
|
36
85
|
}
|
|
37
86
|
|
|
38
87
|
//==============================================================================
|
|
39
88
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
* Dashed paths
|
|
44
|
-
* Control by SCKAN status
|
|
45
|
-
* Control by taxon visibility
|
|
46
|
-
* Control by visible layer
|
|
89
|
+
const makeDashedTriangles = ` float alpha = floor(fract(float(gl_VertexID)/12.0)+0.5);
|
|
90
|
+
if (vColor.a != 0.0) vColor.a *= alpha;
|
|
91
|
+
`
|
|
47
92
|
|
|
93
|
+
class ArcDashedLayer extends ArcMapLayer
|
|
94
|
+
{
|
|
95
|
+
static layerName = 'ArcDashedLayer'
|
|
48
96
|
|
|
49
|
-
|
|
97
|
+
constructor(...args)
|
|
98
|
+
{
|
|
99
|
+
super(...args)
|
|
100
|
+
}
|
|
50
101
|
|
|
102
|
+
getShaders()
|
|
103
|
+
//==========
|
|
104
|
+
{
|
|
105
|
+
const shaders = super.getShaders()
|
|
106
|
+
shaders.vs = shaders.vs.replace('DECKGL_FILTER_COLOR(', `${makeDashedTriangles}\n DECKGL_FILTER_COLOR(`)
|
|
107
|
+
return shaders
|
|
108
|
+
}
|
|
51
109
|
|
|
110
|
+
_getModel(gl)
|
|
111
|
+
//===========
|
|
52
112
|
{
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
113
|
+
const {numSegments} = this.props
|
|
114
|
+
let positions = []
|
|
115
|
+
for (let i = 0; i < numSegments; i++) {
|
|
116
|
+
positions = positions.concat([i, 1, 0, i, -1, 0, i+1, 1, 0,
|
|
117
|
+
i, -1, 0, i+1, 1, 0, i+1, -1, 0])
|
|
118
|
+
}
|
|
119
|
+
const model = new Model(gl, {
|
|
120
|
+
...this.getShaders(),
|
|
121
|
+
id: this.props.id,
|
|
122
|
+
geometry: new Geometry({
|
|
123
|
+
drawMode: GL.TRIANGLES,
|
|
124
|
+
attributes: {
|
|
125
|
+
positions: new Float32Array(positions)
|
|
126
|
+
}
|
|
127
|
+
}),
|
|
128
|
+
isInstanced: true,
|
|
129
|
+
})
|
|
130
|
+
model.setUniforms({numSegments: numSegments})
|
|
131
|
+
return model
|
|
69
132
|
}
|
|
70
|
-
|
|
133
|
+
}
|
|
71
134
|
|
|
72
135
|
//==============================================================================
|
|
73
136
|
|
|
74
137
|
export class Paths3DLayer
|
|
75
138
|
{
|
|
139
|
+
#arcLayers = new Map()
|
|
76
140
|
#deckOverlay = null
|
|
141
|
+
#dimmed = false
|
|
77
142
|
#enabled = false
|
|
143
|
+
#featureToLayer = new Map()
|
|
144
|
+
#knownTypes = []
|
|
78
145
|
#map
|
|
79
146
|
#pathData
|
|
80
147
|
#pathManager
|
|
148
|
+
#pathStyles
|
|
81
149
|
#ui
|
|
82
150
|
|
|
83
151
|
constructor(flatmap, ui)
|
|
@@ -86,85 +154,182 @@ export class Paths3DLayer
|
|
|
86
154
|
this.#map = flatmap.map
|
|
87
155
|
this.#pathManager = ui.pathManager
|
|
88
156
|
this.#pathManager.addWatcher(this.#pathStateChanged.bind(this))
|
|
89
|
-
this.#pathData = [...flatmap.annotations.values()]
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
157
|
+
this.#pathData = new Map([...flatmap.annotations.values()]
|
|
158
|
+
.filter(ann => ann['tile-layer'] === 'pathways'
|
|
159
|
+
&& ann['geometry'] === 'LineString'
|
|
160
|
+
&& 'type' in ann && ann['type'].startsWith('line')
|
|
161
|
+
&& 'kind' in ann
|
|
162
|
+
&& 'pathStartPosition' in ann
|
|
163
|
+
&& 'pathEndPosition' in ann)
|
|
164
|
+
.map(ann => [ann.featureId, ann]))
|
|
165
|
+
this.#pathStyles = new Map(this.#pathManager.pathStyles().map(s => [s.type, s]))
|
|
166
|
+
this.#knownTypes = [...this.#pathStyles.keys()].filter(t => t !== 'other')
|
|
96
167
|
}
|
|
97
168
|
|
|
98
169
|
enable(enable=true)
|
|
99
170
|
//=================
|
|
100
171
|
{
|
|
101
172
|
if (enable && !this.#enabled) {
|
|
102
|
-
this.#
|
|
173
|
+
this.#setupDeckOverlay()
|
|
103
174
|
this.#map.addControl(this.#deckOverlay)
|
|
104
175
|
} else if (!enable && this.#enabled) {
|
|
105
176
|
if (this.#deckOverlay) {
|
|
106
177
|
this.#map.removeControl(this.#deckOverlay)
|
|
178
|
+
this.#deckOverlay.finalize()
|
|
107
179
|
this.#deckOverlay = null
|
|
108
180
|
}
|
|
181
|
+
this.#featureToLayer = new Map()
|
|
109
182
|
}
|
|
110
183
|
this.#enabled = enable
|
|
111
184
|
}
|
|
112
185
|
|
|
113
|
-
|
|
114
|
-
|
|
186
|
+
queryFeaturesAtPoint(point)
|
|
187
|
+
//=========================
|
|
115
188
|
{
|
|
116
189
|
if (this.#deckOverlay) {
|
|
117
|
-
this.#
|
|
118
|
-
|
|
119
|
-
|
|
190
|
+
return this.#deckOverlay
|
|
191
|
+
.pickMultipleObjects(point)
|
|
192
|
+
.map(o => this.#makeMapFeature(o.object))
|
|
193
|
+
}
|
|
194
|
+
return []
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
redraw(force=false)
|
|
198
|
+
//=================
|
|
199
|
+
{
|
|
200
|
+
for (const layer of this.#arcLayers.values()) {
|
|
201
|
+
layer.redraw(force)
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
removeFeatureState(featureId, key)
|
|
206
|
+
//================================
|
|
207
|
+
{
|
|
208
|
+
const layer = this.#featureToLayer.get(+featureId)
|
|
209
|
+
if (layer) {
|
|
210
|
+
layer.setDataProperty(featureId, key, false)
|
|
211
|
+
layer.redraw()
|
|
120
212
|
}
|
|
121
213
|
}
|
|
122
214
|
|
|
123
|
-
|
|
215
|
+
setFeatureState(featureId, state)
|
|
216
|
+
//===============================
|
|
217
|
+
{
|
|
218
|
+
const layer = this.#featureToLayer.get(+featureId)
|
|
219
|
+
if (layer) {
|
|
220
|
+
for (const [key, value] of Object.entries(state)) {
|
|
221
|
+
layer.setDataProperty(featureId, key, value)
|
|
222
|
+
}
|
|
223
|
+
layer.redraw()
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
setPaint(options)
|
|
124
228
|
//===============
|
|
125
229
|
{
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
230
|
+
const dimmed = options.dimmed || false
|
|
231
|
+
if (this.#dimmed !== dimmed) {
|
|
232
|
+
this.#dimmed = dimmed
|
|
233
|
+
this.redraw(true)
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
#addArcLayer(pathType)
|
|
238
|
+
//====================
|
|
239
|
+
{
|
|
240
|
+
const layer = this.#pathStyles.get(pathType).dashed
|
|
241
|
+
? new ArcDashedLayer(this.#layerOptions(pathType))
|
|
242
|
+
: new ArcMapLayer(this.#layerOptions(pathType))
|
|
243
|
+
layer.featureIds.forEach(id => this.#featureToLayer.set(+id, layer))
|
|
244
|
+
this.#arcLayers.set(pathType, layer)
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
#removeArcLayer(pathType)
|
|
248
|
+
//=======================
|
|
249
|
+
{
|
|
250
|
+
const layer = this.#arcLayers.get(pathType)
|
|
251
|
+
if (layer) {
|
|
252
|
+
layer.featureIds.forEach(id => this.#featureToLayer.delete(+id))
|
|
253
|
+
this.#arcLayers.delete(pathType)
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
#pathColour(properties)
|
|
258
|
+
//=====================
|
|
259
|
+
{
|
|
260
|
+
if (properties.hidden) {
|
|
261
|
+
return [0, 0, 0, 0]
|
|
262
|
+
}
|
|
263
|
+
return pathColourArray(properties.kind,
|
|
264
|
+
properties.active || properties.selected ? 255
|
|
265
|
+
: this.#dimmed ? 20 : 160)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
#pathStateChanged(changes={})
|
|
269
|
+
//===========================
|
|
270
|
+
{
|
|
271
|
+
if (this.#deckOverlay) {
|
|
272
|
+
if ('pathType' in changes) {
|
|
273
|
+
const pathType = changes.pathType
|
|
274
|
+
const enabled = this.#pathManager.pathTypeEnabled(pathType)
|
|
275
|
+
if (enabled && !this.#arcLayers.has(pathType)) {
|
|
276
|
+
this.#addArcLayer(pathType)
|
|
277
|
+
} else if (!enabled && this.#arcLayers.has(pathType)) {
|
|
278
|
+
this.#removeArcLayer(pathType)
|
|
279
|
+
}
|
|
280
|
+
this.#deckOverlay.setProps({
|
|
281
|
+
layers: [...this.#arcLayers.values()]
|
|
165
282
|
})
|
|
166
|
-
|
|
167
|
-
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
#layerOptions(pathType)
|
|
289
|
+
//=====================
|
|
290
|
+
{
|
|
291
|
+
const pathData = [...this.#pathData.values()]
|
|
292
|
+
.filter(ann => (this.#knownTypes.includes(ann.kind) && (ann.kind === pathType)
|
|
293
|
+
|| !this.#knownTypes.includes(ann.kind) && (pathType === 'other')))
|
|
294
|
+
return {
|
|
295
|
+
id: `arc-${pathType}`,
|
|
296
|
+
data: pathData,
|
|
297
|
+
pickable: true,
|
|
298
|
+
autoHighlight: true,
|
|
299
|
+
numSegments: 400,
|
|
300
|
+
// Styles
|
|
301
|
+
getSourcePosition: f => f.pathStartPosition,
|
|
302
|
+
getTargetPosition: f => f.pathEndPosition,
|
|
303
|
+
getSourceColor: this.#pathColour.bind(this),
|
|
304
|
+
getTargetColor: this.#pathColour.bind(this),
|
|
305
|
+
highlightColor: o => this.#pathColour(o.object),
|
|
306
|
+
opacity: 1.0,
|
|
307
|
+
getWidth: 3,
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
#makeMapFeature(pickedObject)
|
|
312
|
+
//===========================
|
|
313
|
+
{
|
|
314
|
+
// Mock up a map vector feature
|
|
315
|
+
return {
|
|
316
|
+
id: pickedObject.featureId,
|
|
317
|
+
source: 'vector-tiles',
|
|
318
|
+
sourceLayer: `${pickedObject.layer}_${pickedObject['tile-layer']}`,
|
|
319
|
+
properties: pickedObject,
|
|
320
|
+
arc3dLayer: true
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
#setupDeckOverlay()
|
|
325
|
+
//=================
|
|
326
|
+
{
|
|
327
|
+
[...this.#pathStyles.values()].filter(style => this.#pathManager.pathTypeEnabled(style.type))
|
|
328
|
+
.forEach(style => this.#addArcLayer(style.type))
|
|
329
|
+
this.#deckOverlay = new DeckOverlay({
|
|
330
|
+
layers: [...this.#arcLayers.values()],
|
|
168
331
|
})
|
|
169
332
|
}
|
|
170
333
|
}
|
|
334
|
+
|
|
335
|
+
//==============================================================================
|
package/src/main.js
CHANGED
package/src/pathways.js
CHANGED
|
@@ -20,6 +20,8 @@ limitations under the License.
|
|
|
20
20
|
|
|
21
21
|
'use strict';
|
|
22
22
|
|
|
23
|
+
import {colord} from 'colord'
|
|
24
|
+
|
|
23
25
|
//==============================================================================
|
|
24
26
|
|
|
25
27
|
import { reverseMap } from './utils';
|
|
@@ -49,15 +51,18 @@ const PATH_TYPES = [
|
|
|
49
51
|
{ type: "error", label: "Paths with errors or warnings", colour: "#FF0", enabled: false}
|
|
50
52
|
];
|
|
51
53
|
|
|
54
|
+
const PathTypeMap = new Map(PATH_TYPES.map(t => [t.type, t]))
|
|
55
|
+
|
|
52
56
|
export const PATH_STYLE_RULES =
|
|
53
57
|
PATH_TYPES.flatMap(pathType => [['==', ['get', 'kind'], pathType.type], pathType.colour]);
|
|
54
58
|
|
|
55
|
-
export
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
export function pathColour(pathType)
|
|
59
|
+
export function pathColourArray(pathType, alpha=255)
|
|
60
|
+
//==================================================
|
|
59
61
|
{
|
|
60
|
-
|
|
62
|
+
const rgb = colord(PathTypeMap.has(pathType)
|
|
63
|
+
? PathTypeMap.get(pathType).colour
|
|
64
|
+
: '#FF0').toRgb()
|
|
65
|
+
return [rgb.r, rgb.g, rgb.b, alpha]
|
|
61
66
|
}
|
|
62
67
|
|
|
63
68
|
//==============================================================================
|
|
@@ -162,6 +167,21 @@ export class PathManager
|
|
|
162
167
|
}
|
|
163
168
|
}
|
|
164
169
|
|
|
170
|
+
pathStyles()
|
|
171
|
+
//==========
|
|
172
|
+
{
|
|
173
|
+
const styles = []
|
|
174
|
+
for (const mapType of this.pathTypes()) {
|
|
175
|
+
const defn = PathTypeMap.get(mapType.type)
|
|
176
|
+
styles.push({
|
|
177
|
+
type: defn.type,
|
|
178
|
+
colour: defn.colour,
|
|
179
|
+
dashed: defn.dashed || false
|
|
180
|
+
})
|
|
181
|
+
}
|
|
182
|
+
return styles
|
|
183
|
+
}
|
|
184
|
+
|
|
165
185
|
pathTypes()
|
|
166
186
|
//=========
|
|
167
187
|
{
|
|
@@ -335,7 +355,7 @@ export class PathManager
|
|
|
335
355
|
this.__ui.enableFeature(featureId, enable, force);
|
|
336
356
|
}
|
|
337
357
|
this.__pathtypeEnabled[pathType] = enable;
|
|
338
|
-
this.#notifyWatchers()
|
|
358
|
+
this.#notifyWatchers({pathType})
|
|
339
359
|
}
|
|
340
360
|
}
|
|
341
361
|
|
|
@@ -390,11 +410,11 @@ export class PathManager
|
|
|
390
410
|
this.#watcherCallbacks.delete(watcherId)
|
|
391
411
|
}
|
|
392
412
|
|
|
393
|
-
#notifyWatchers()
|
|
394
|
-
|
|
413
|
+
#notifyWatchers(changes={})
|
|
414
|
+
//=========================
|
|
395
415
|
{
|
|
396
416
|
for (const callback of this.#watcherCallbacks.values()) {
|
|
397
|
-
callback()
|
|
417
|
+
callback(changes)
|
|
398
418
|
}
|
|
399
419
|
}
|
|
400
420
|
}
|