@flowmap.gl/layers 8.0.0-alpha.0

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.
Files changed (64) hide show
  1. package/LICENSE +199 -0
  2. package/dist/AnimatedFlowLinesLayer/AnimatedFlowLinesLayer.d.ts +76 -0
  3. package/dist/AnimatedFlowLinesLayer/AnimatedFlowLinesLayer.d.ts.map +1 -0
  4. package/dist/AnimatedFlowLinesLayer/AnimatedFlowLinesLayer.js +139 -0
  5. package/dist/AnimatedFlowLinesLayer/AnimatedFlowLinesLayerFragment.glsl.d.ts +3 -0
  6. package/dist/AnimatedFlowLinesLayer/AnimatedFlowLinesLayerFragment.glsl.d.ts.map +1 -0
  7. package/dist/AnimatedFlowLinesLayer/AnimatedFlowLinesLayerFragment.glsl.js +37 -0
  8. package/dist/AnimatedFlowLinesLayer/AnimatedFlowLinesLayerVertex.glsl.d.ts +3 -0
  9. package/dist/AnimatedFlowLinesLayer/AnimatedFlowLinesLayerVertex.glsl.d.ts.map +1 -0
  10. package/dist/AnimatedFlowLinesLayer/AnimatedFlowLinesLayerVertex.glsl.js +91 -0
  11. package/dist/AnimatedFlowLinesLayer/index.d.ts +3 -0
  12. package/dist/AnimatedFlowLinesLayer/index.d.ts.map +1 -0
  13. package/dist/AnimatedFlowLinesLayer/index.js +3 -0
  14. package/dist/FlowCirclesLayer/FlowCirclesLayer.d.ts +59 -0
  15. package/dist/FlowCirclesLayer/FlowCirclesLayer.d.ts.map +1 -0
  16. package/dist/FlowCirclesLayer/FlowCirclesLayer.js +115 -0
  17. package/dist/FlowCirclesLayer/FlowCirclesLayerFragment.glsl.d.ts +3 -0
  18. package/dist/FlowCirclesLayer/FlowCirclesLayerFragment.glsl.d.ts.map +1 -0
  19. package/dist/FlowCirclesLayer/FlowCirclesLayerFragment.glsl.js +73 -0
  20. package/dist/FlowCirclesLayer/FlowCirclesLayerVertex.glsl.d.ts +3 -0
  21. package/dist/FlowCirclesLayer/FlowCirclesLayerVertex.glsl.d.ts.map +1 -0
  22. package/dist/FlowCirclesLayer/FlowCirclesLayerVertex.glsl.js +63 -0
  23. package/dist/FlowCirclesLayer/index.d.ts +3 -0
  24. package/dist/FlowCirclesLayer/index.d.ts.map +1 -0
  25. package/dist/FlowCirclesLayer/index.js +3 -0
  26. package/dist/FlowLinesLayer/FlowLinesLayer.d.ts +64 -0
  27. package/dist/FlowLinesLayer/FlowLinesLayer.d.ts.map +1 -0
  28. package/dist/FlowLinesLayer/FlowLinesLayer.js +182 -0
  29. package/dist/FlowLinesLayer/FlowLinesLayerFragment.glsl.d.ts +3 -0
  30. package/dist/FlowLinesLayer/FlowLinesLayerFragment.glsl.d.ts.map +1 -0
  31. package/dist/FlowLinesLayer/FlowLinesLayerFragment.glsl.js +36 -0
  32. package/dist/FlowLinesLayer/FlowLinesLayerVertex.glsl.d.ts +3 -0
  33. package/dist/FlowLinesLayer/FlowLinesLayerVertex.glsl.d.ts.map +1 -0
  34. package/dist/FlowLinesLayer/FlowLinesLayerVertex.glsl.js +102 -0
  35. package/dist/FlowLinesLayer/index.d.ts +3 -0
  36. package/dist/FlowLinesLayer/index.d.ts.map +1 -0
  37. package/dist/FlowLinesLayer/index.js +3 -0
  38. package/dist/FlowMapLayer.d.ts +70 -0
  39. package/dist/FlowMapLayer.d.ts.map +1 -0
  40. package/dist/FlowMapLayer.js +304 -0
  41. package/dist/index.d.ts +7 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +6 -0
  44. package/dist/types.d.ts +31 -0
  45. package/dist/types.d.ts.map +1 -0
  46. package/dist/types.js +20 -0
  47. package/package.json +24 -0
  48. package/src/AnimatedFlowLinesLayer/AnimatedFlowLinesLayer.ts +189 -0
  49. package/src/AnimatedFlowLinesLayer/AnimatedFlowLinesLayerFragment.glsl.ts +37 -0
  50. package/src/AnimatedFlowLinesLayer/AnimatedFlowLinesLayerVertex.glsl.ts +90 -0
  51. package/src/AnimatedFlowLinesLayer/index.ts +3 -0
  52. package/src/FlowCirclesLayer/FlowCirclesLayer.ts +150 -0
  53. package/src/FlowCirclesLayer/FlowCirclesLayerFragment.glsl.ts +72 -0
  54. package/src/FlowCirclesLayer/FlowCirclesLayerVertex.glsl.ts +62 -0
  55. package/src/FlowCirclesLayer/index.ts +3 -0
  56. package/src/FlowLinesLayer/FlowLinesLayer.ts +238 -0
  57. package/src/FlowLinesLayer/FlowLinesLayerFragment.glsl.ts +35 -0
  58. package/src/FlowLinesLayer/FlowLinesLayerVertex.glsl.ts +101 -0
  59. package/src/FlowLinesLayer/index.ts +3 -0
  60. package/src/FlowMapLayer.ts +448 -0
  61. package/src/index.ts +7 -0
  62. package/src/types.ts +67 -0
  63. package/tsconfig.json +11 -0
  64. package/typings.d.ts +4 -0
@@ -0,0 +1,101 @@
1
+ /*
2
+ * Copyright 2022 FlowmapBlue
3
+ * Copyright 2018-2020 Teralytics, modified by FlowmapBlue
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ *
17
+ */
18
+ export default `\
19
+ #define SHADER_NAME flow-line-layer-vertex-shader
20
+
21
+ attribute vec3 positions;
22
+ attribute vec3 normals;
23
+ attribute vec4 instanceColors;
24
+ attribute float instanceThickness; // 0..0.5
25
+ attribute vec3 instanceSourcePositions;
26
+ attribute vec3 instanceTargetPositions;
27
+ attribute vec3 instanceSourcePositions64Low;
28
+ attribute vec3 instanceTargetPositions64Low;
29
+ attribute vec3 instancePickingColors;
30
+ attribute vec2 instanceEndpointOffsets;
31
+ attribute float instancePickable;
32
+
33
+ uniform vec4 outlineColor;
34
+ uniform float thicknessUnit;
35
+ uniform float gap;
36
+ uniform float opacity;
37
+
38
+ varying vec4 vColor;
39
+ varying vec2 uv;
40
+
41
+ void main(void) {
42
+ geometry.worldPosition = instanceSourcePositions;
43
+ geometry.worldPositionAlt = instanceTargetPositions;
44
+
45
+ // Position
46
+ vec4 source_commonspace;
47
+ vec4 target_commonspace;
48
+ vec4 source = project_position_to_clipspace(instanceSourcePositions, instanceSourcePositions64Low, vec3(0.), source_commonspace);
49
+ vec4 target = project_position_to_clipspace(instanceTargetPositions, instanceTargetPositions64Low, vec3(0.), target_commonspace);
50
+
51
+ // linear interpolation of source & target to pick right coord
52
+ float sourceOrTarget = positions.x;
53
+ geometry.position = mix(source_commonspace, target_commonspace, sourceOrTarget);
54
+ uv = positions.xy;
55
+ geometry.uv = uv;
56
+ if (instancePickable > 0.5) {
57
+ geometry.pickingColor = instancePickingColors;
58
+ }
59
+
60
+ // set the clamp limits in pixel size
61
+ float lengthCommon = length(target_commonspace - source_commonspace);
62
+ vec2 offsetDistances = project_pixel_size(positions.yz) * thicknessUnit;
63
+
64
+ vec2 limitedOffsetDistances = clamp(
65
+ project_pixel_size(positions.yz) * thicknessUnit,
66
+ -lengthCommon*.8, lengthCommon*.8
67
+ );
68
+ float startOffsetCommon = project_pixel_size(instanceEndpointOffsets[0]);
69
+ float endOffsetCommon = project_pixel_size(instanceEndpointOffsets[1]);
70
+ float endpointOffset = mix(
71
+ clamp(startOffsetCommon, 0.0, lengthCommon*.2),
72
+ -clamp(endOffsetCommon, 0.0, lengthCommon*.2),
73
+ positions.x
74
+ );
75
+
76
+ vec2 flowlineDir = normalize(target_commonspace.xy - source_commonspace.xy);
77
+ vec2 perpendicularDir = vec2(-flowlineDir.y, flowlineDir.x);
78
+ vec2 normalsCommon = project_pixel_size(normals.xy);
79
+ float gapCommon = project_pixel_size(gap);
80
+ vec3 offsetCommon = vec3(
81
+ flowlineDir * (instanceThickness * limitedOffsetDistances[1] + normalsCommon.y + endpointOffset * 1.05) -
82
+ perpendicularDir * (instanceThickness * limitedOffsetDistances[0] + gapCommon + normalsCommon.x),
83
+ 0.0
84
+ );
85
+
86
+ DECKGL_FILTER_SIZE(offsetCommon, geometry);
87
+ vec4 position_commonspace = mix(source_commonspace, target_commonspace, sourceOrTarget);
88
+ vec4 offset_commonspace = vec4(offsetCommon, 0.0);
89
+ gl_Position = project_common_position_to_clipspace(position_commonspace + offset_commonspace);
90
+
91
+ DECKGL_FILTER_GL_POSITION(gl_Position, geometry);
92
+
93
+ vec4 fillColor = vec4(instanceColors.rgb, instanceColors.a * opacity) / 255.;
94
+ if (instancePickable <= 0.5) {
95
+ vColor = mix(fillColor, vec4(outlineColor.xyz, instanceThickness), normals.z);
96
+ } else {
97
+ vColor = mix(fillColor, vec4(outlineColor.xyz, outlineColor.w * fillColor.w), normals.z);
98
+ }
99
+ DECKGL_FILTER_COLOR(vColor, geometry);
100
+ }
101
+ `;
@@ -0,0 +1,3 @@
1
+ import FlowLinesLayer from './FlowLinesLayer';
2
+
3
+ export default FlowLinesLayer;
@@ -0,0 +1,448 @@
1
+ /*
2
+ * Copyright 2022 FlowmapBlue
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+ import {CompositeLayer} from '@deck.gl/core';
18
+ import {ScatterplotLayer} from '@deck.gl/layers';
19
+ import {
20
+ colorAsRgba,
21
+ FlowLinesLayerAttributes,
22
+ FlowMapData,
23
+ FlowMapDataAccessors,
24
+ FlowMapDataProvider,
25
+ getFlowLineAttributesByIndex,
26
+ getFlowMapColors,
27
+ getOuterCircleRadiusByIndex,
28
+ getLocationCentroidByIndex,
29
+ isFlowMapData,
30
+ isFlowMapDataProvider,
31
+ LayersData,
32
+ LocalFlowMapDataProvider,
33
+ LocationFilterMode,
34
+ ViewportProps,
35
+ FlowMapAggregateAccessors,
36
+ ClusterNode,
37
+ AggregateFlow,
38
+ } from '@flowmap.gl/data';
39
+ import AnimatedFlowLinesLayer from './AnimatedFlowLinesLayer';
40
+ import FlowCirclesLayer from './FlowCirclesLayer';
41
+ import FlowLinesLayer from './FlowLinesLayer';
42
+ import {
43
+ FlowLayerPickingInfo,
44
+ LayerProps,
45
+ PickingInfo,
46
+ PickingType,
47
+ } from './types';
48
+
49
+ export type FlowMapLayerProps<L, F> = {
50
+ data: FlowMapData<L, F> | FlowMapDataProvider<L, F>;
51
+ locationTotalsEnabled?: boolean;
52
+ adaptiveScalesEnabled?: boolean;
53
+ animationEnabled?: boolean;
54
+ clusteringEnabled?: boolean;
55
+ clusteringLevel?: number;
56
+ fadeEnabled?: boolean;
57
+ clusteringAuto?: boolean;
58
+ darkMode?: boolean;
59
+ fadeAmount?: number;
60
+ colorScheme?: string;
61
+ onHover?: (
62
+ info: FlowLayerPickingInfo<L, F> | undefined,
63
+ event: SourceEvent,
64
+ ) => void;
65
+ onClick?: (info: FlowLayerPickingInfo<L, F>, event: SourceEvent) => void;
66
+ } & Partial<FlowMapDataAccessors<L, F>> &
67
+ LayerProps;
68
+
69
+ enum HighlightType {
70
+ LOCATION = 'location',
71
+ FLOW = 'flow',
72
+ }
73
+
74
+ type HighlightedLocationObject = {
75
+ type: HighlightType.LOCATION;
76
+ centroid: [number, number];
77
+ radius: number;
78
+ };
79
+
80
+ type HighlightedFlowObject = {
81
+ type: HighlightType.FLOW;
82
+ lineAttributes: FlowLinesLayerAttributes;
83
+ };
84
+
85
+ type HighlightedObject = HighlightedLocationObject | HighlightedFlowObject;
86
+
87
+ type State<L, F> = {
88
+ accessors: FlowMapAggregateAccessors<L, F>;
89
+ dataProvider: FlowMapDataProvider<L, F>;
90
+ layersData: LayersData | undefined;
91
+ highlightedObject: HighlightedObject | undefined;
92
+ };
93
+
94
+ export type SourceEvent = {srcEvent: MouseEvent};
95
+
96
+ export default class FlowMapLayer<L, F> extends CompositeLayer {
97
+ static defaultProps = {
98
+ darkMode: true,
99
+ fadeAmount: 50,
100
+ locationTotalsEnabled: true,
101
+ animationEnabled: false,
102
+ clusteringEnabled: true,
103
+ fadeEnabled: true,
104
+ clusteringAuto: true,
105
+ clusteringLevel: undefined,
106
+ adaptiveScalesEnabled: true,
107
+ colorScheme: 'Teal',
108
+ };
109
+ state: State<L, F> | undefined;
110
+
111
+ public constructor(props: FlowMapLayerProps<L, F>) {
112
+ super({
113
+ ...props,
114
+ onHover: (info: PickingInfo<any>, event: SourceEvent) => {
115
+ // TODO: if (lastHoverEventStartTimeRef > startTime) {
116
+ // // Skipping, because this is not the latest hover event
117
+ // return;
118
+ // }
119
+ this.setState({highlightedObject: this._getHighlightedObject(info)});
120
+ const {onHover} = props;
121
+ if (onHover) {
122
+ this._getFlowLayerPickingInfo(info).then((info) =>
123
+ onHover(info, event),
124
+ );
125
+ }
126
+ },
127
+ onClick: (info: PickingInfo<any>, event: SourceEvent) => {
128
+ const {onClick} = props;
129
+ if (onClick) {
130
+ this._getFlowLayerPickingInfo(info).then((info) => {
131
+ if (info) {
132
+ onClick(info, event);
133
+ }
134
+ });
135
+ }
136
+ },
137
+ });
138
+ }
139
+
140
+ initializeState() {
141
+ this.state = {
142
+ accessors: new FlowMapAggregateAccessors<L, F>(this.props),
143
+ dataProvider: this._makeDataProvider(),
144
+ layersData: undefined,
145
+ highlightedObject: undefined,
146
+ };
147
+ }
148
+
149
+ private _updateAccessors() {
150
+ this.state?.dataProvider?.setAccessors(this.props);
151
+ this.setState({accessors: new FlowMapAggregateAccessors(this.props)});
152
+ }
153
+
154
+ private _makeDataProvider() {
155
+ const {data} = this.props;
156
+ if (isFlowMapDataProvider<L, F>(data)) {
157
+ return data;
158
+ } else if (isFlowMapData<L, F>(data)) {
159
+ const dataProvider = new LocalFlowMapDataProvider<L, F>(this.props);
160
+ dataProvider.setFlowMapData(data);
161
+ return dataProvider;
162
+ }
163
+ throw new Error(
164
+ 'FlowMapLayer: data must be a FlowMapDataProvider or FlowMapData',
165
+ );
166
+ }
167
+
168
+ private _updateDataProvider() {
169
+ this.setState({dataProvider: this._makeDataProvider()});
170
+ }
171
+
172
+ shouldUpdateState(params: Record<string, any>): boolean {
173
+ const {changeFlags} = params;
174
+ // if (this._viewportChanged()) {
175
+ // return true;
176
+ // }
177
+ if (changeFlags.viewportChanged) {
178
+ return true;
179
+ }
180
+ return super.shouldUpdateState(params);
181
+ // TODO: be smarter on when to update
182
+ // (e.g. ignore viewport changes when adaptiveScalesEnabled and clustering are false)
183
+ }
184
+
185
+ updateState({oldProps, props, changeFlags}: Record<string, any>): void {
186
+ const {dataProvider, highlightedObject} = this.state || {};
187
+ if (!dataProvider) {
188
+ return;
189
+ }
190
+
191
+ if (changeFlags.propsChanged) {
192
+ this._updateAccessors();
193
+ }
194
+ if (changeFlags.dataChanged) {
195
+ this._updateDataProvider();
196
+ }
197
+
198
+ if (changeFlags.viewportChanged || changeFlags.propsOrDataChanged) {
199
+ dataProvider.setFlowMapState(this._getFlowMapState());
200
+
201
+ (async () => {
202
+ const layersData = await dataProvider.getLayersData();
203
+ this.setState({layersData});
204
+ })();
205
+ }
206
+ }
207
+
208
+ private _getSettingsState() {
209
+ const {
210
+ locationTotalsEnabled,
211
+ adaptiveScalesEnabled,
212
+ animationEnabled,
213
+ clusteringEnabled,
214
+ clusteringLevel,
215
+ fadeEnabled,
216
+ clusteringAuto,
217
+ darkMode,
218
+ fadeAmount,
219
+ colorScheme,
220
+ } = this.props;
221
+ return {
222
+ locationTotalsEnabled,
223
+ adaptiveScalesEnabled,
224
+ animationEnabled,
225
+ clusteringEnabled,
226
+ clusteringLevel,
227
+ fadeEnabled,
228
+ clusteringAuto,
229
+ darkMode,
230
+ fadeAmount,
231
+ colorScheme,
232
+ };
233
+ }
234
+
235
+ private _getFlowMapState() {
236
+ return {
237
+ viewport: asViewState(this.context.viewport),
238
+ filterState: {
239
+ selectedLocations: undefined,
240
+ locationFilterMode: LocationFilterMode.ALL,
241
+ selectedTimeRange: undefined,
242
+ },
243
+ settingsState: this._getSettingsState(),
244
+ };
245
+ }
246
+
247
+ private async _getFlowLayerPickingInfo(
248
+ info: Record<string, any>,
249
+ ): Promise<FlowLayerPickingInfo<L, F> | undefined> {
250
+ const {index, sourceLayer} = info;
251
+ const {dataProvider, accessors} = this.state || {};
252
+ if (!dataProvider || !accessors) {
253
+ return undefined;
254
+ }
255
+ const commonInfo = {
256
+ // ...info,
257
+ layer: info.layer,
258
+ index: info.index,
259
+ x: info.x,
260
+ y: info.y,
261
+ coordinate: info.coordinate,
262
+ };
263
+ if (
264
+ sourceLayer instanceof FlowLinesLayer ||
265
+ sourceLayer instanceof AnimatedFlowLinesLayer
266
+ ) {
267
+ const flow =
268
+ index === -1 ? undefined : await dataProvider.getFlowByIndex(index);
269
+ if (flow) {
270
+ const origin = await dataProvider.getLocationById(
271
+ accessors.getFlowOriginId(flow),
272
+ );
273
+ const dest = await dataProvider.getLocationById(
274
+ accessors.getFlowDestId(flow),
275
+ );
276
+ if (origin && dest) {
277
+ return {
278
+ ...commonInfo,
279
+ type: PickingType.FLOW,
280
+ object: flow,
281
+ origin: origin,
282
+ dest: dest,
283
+ count: accessors.getFlowMagnitude(flow),
284
+ };
285
+ }
286
+ }
287
+ } else if (sourceLayer instanceof FlowCirclesLayer) {
288
+ const location =
289
+ index === -1 ? undefined : await dataProvider.getLocationByIndex(index);
290
+
291
+ if (location) {
292
+ const id = accessors.getLocationId(location);
293
+ const name = accessors.getLocationName(location);
294
+ const totals = await dataProvider.getTotalsForLocation(id);
295
+ const {circleAttributes} = this.state?.layersData || {};
296
+ if (totals && circleAttributes) {
297
+ const circleRadius = getOuterCircleRadiusByIndex(
298
+ circleAttributes,
299
+ info.index,
300
+ );
301
+ return {
302
+ ...commonInfo,
303
+ type: PickingType.LOCATION,
304
+ object: location,
305
+ id,
306
+ name,
307
+ totals,
308
+ circleRadius: circleRadius,
309
+ event: undefined,
310
+ };
311
+ }
312
+ }
313
+ }
314
+
315
+ return undefined;
316
+ }
317
+
318
+ private _getHighlightedObject(
319
+ info: Record<string, any>,
320
+ ): HighlightedObject | undefined {
321
+ const {index, sourceLayer} = info;
322
+ if (index < 0) return undefined;
323
+ if (
324
+ sourceLayer instanceof FlowLinesLayer ||
325
+ sourceLayer instanceof AnimatedFlowLinesLayer
326
+ ) {
327
+ const {lineAttributes} = this.state?.layersData || {};
328
+ if (lineAttributes) {
329
+ return {
330
+ type: HighlightType.FLOW,
331
+ lineAttributes: getFlowLineAttributesByIndex(lineAttributes, index),
332
+ };
333
+ }
334
+ } else if (sourceLayer instanceof FlowCirclesLayer) {
335
+ const {circleAttributes} = this.state?.layersData || {};
336
+ if (circleAttributes) {
337
+ return {
338
+ type: HighlightType.LOCATION,
339
+ centroid: getLocationCentroidByIndex(circleAttributes, index),
340
+ radius: getOuterCircleRadiusByIndex(circleAttributes, index),
341
+ };
342
+ }
343
+ }
344
+ return undefined;
345
+ }
346
+
347
+ renderLayers(): Array<any> {
348
+ const layers = [];
349
+ if (this.state?.layersData) {
350
+ const {layersData, highlightedObject} = this.state;
351
+ const {circleAttributes, lineAttributes} = layersData || {};
352
+ if (circleAttributes && lineAttributes) {
353
+ const flowMapColors = getFlowMapColors(this._getSettingsState());
354
+ const outlineColor = colorAsRgba(
355
+ flowMapColors.outlineColor || (this.props.darkMode ? '#000' : '#fff'),
356
+ );
357
+ const commonLineLayerProps = {
358
+ data: lineAttributes,
359
+ parameters: {
360
+ // prevent z-fighting at non-zero bearing/pitch
361
+ depthTest: false,
362
+ },
363
+ };
364
+ if (this.props.animationEnabled) {
365
+ layers.push(
366
+ // @ts-ignore
367
+ new AnimatedFlowLinesLayer({
368
+ ...this.getSubLayerProps({
369
+ ...commonLineLayerProps,
370
+ id: 'animated-flow-lines',
371
+ drawOutline: false,
372
+ thicknessUnit: 20,
373
+ }),
374
+ }),
375
+ );
376
+ } else {
377
+ layers.push(
378
+ new FlowLinesLayer({
379
+ ...this.getSubLayerProps({
380
+ ...commonLineLayerProps,
381
+ id: 'flow-lines',
382
+ drawOutline: true,
383
+ outlineColor: outlineColor,
384
+ }),
385
+ }),
386
+ );
387
+ }
388
+ layers.push(
389
+ new FlowCirclesLayer(
390
+ this.getSubLayerProps({
391
+ id: 'circles',
392
+ data: circleAttributes,
393
+ emptyColor: [0, 0, 0, 255],
394
+ emptyOutlineColor: [0, 0, 0, 255],
395
+ }),
396
+ ),
397
+ );
398
+ if (highlightedObject) {
399
+ switch (highlightedObject.type) {
400
+ case HighlightType.LOCATION:
401
+ layers.push(
402
+ new ScatterplotLayer({
403
+ id: 'location-highlight',
404
+ data: [highlightedObject],
405
+ stroked: true,
406
+ filled: false,
407
+ lineWidthUnits: 'pixels',
408
+ getLineWidth: 2,
409
+ radiusUnits: 'pixels',
410
+ getRadius: (d: HighlightedLocationObject) => d.radius,
411
+ getLineColor: (d: HighlightedLocationObject) =>
412
+ colorAsRgba('orange'),
413
+ getPosition: (d: HighlightedLocationObject) => d.centroid,
414
+ }),
415
+ );
416
+ break;
417
+ case HighlightType.FLOW:
418
+ layers.push(
419
+ new FlowLinesLayer({
420
+ id: 'flow-highlight',
421
+ data: highlightedObject.lineAttributes,
422
+ drawOutline: true,
423
+ outlineColor: colorAsRgba('orange'),
424
+ outlineThickness: 1,
425
+ }),
426
+ );
427
+ break;
428
+ }
429
+ }
430
+ }
431
+ }
432
+
433
+ return layers;
434
+ }
435
+ }
436
+
437
+ function asViewState(viewport: Record<string, any>): ViewportProps {
438
+ const {width, height, longitude, latitude, zoom, pitch, bearing} = viewport;
439
+ return {
440
+ width,
441
+ height,
442
+ longitude,
443
+ latitude,
444
+ zoom,
445
+ pitch,
446
+ bearing,
447
+ };
448
+ }
package/src/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ export {default as AnimatedFlowLinesLayer} from './AnimatedFlowLinesLayer';
2
+ export {default as FlowLinesLayer} from './FlowLinesLayer';
3
+ export {default as FlowCirclesLayer} from './FlowCirclesLayer';
4
+ export {default as FlowMapLayer} from './FlowMapLayer';
5
+ export type {FlowMapLayerProps} from './FlowMapLayer';
6
+
7
+ export * from './types';
package/src/types.ts ADDED
@@ -0,0 +1,67 @@
1
+ import {
2
+ AggregateFlow,
3
+ Cluster,
4
+ ClusterNode,
5
+ LocationTotals,
6
+ } from '@flowmap.gl/data';
7
+
8
+ export type LayerProps = Record<string, unknown>;
9
+
10
+ export enum PickingType {
11
+ LOCATION = 'location',
12
+ FLOW = 'flow',
13
+ // LOCATION_AREA = 'location-area',
14
+ }
15
+
16
+ export type DeckGLLayer = Record<string, any>;
17
+
18
+ export interface PickingInfo<T> {
19
+ layer: DeckGLLayer;
20
+ index: number;
21
+ object: T | undefined;
22
+ x: number;
23
+ y: number;
24
+ coordinate: [number, number];
25
+ }
26
+
27
+ export interface LocationPickingInfo<L> extends PickingInfo<L | ClusterNode> {
28
+ type: PickingType.LOCATION;
29
+ id: string;
30
+ name: string;
31
+ totals: LocationTotals;
32
+ circleRadius: number;
33
+ event: MouseEvent | undefined;
34
+ }
35
+
36
+ export interface FlowPickingInfo<L, F> extends PickingInfo<F | AggregateFlow> {
37
+ type: PickingType.FLOW;
38
+ origin: L | ClusterNode;
39
+ dest: L | ClusterNode;
40
+ count: number;
41
+ }
42
+
43
+ // export interface LocationAreaPickingInfo extends PickingInfo<PickingInfoData> {
44
+ // type: PickingType.LOCATION_AREA;
45
+ // object: FlowLocation;
46
+ // }
47
+
48
+ export type FlowLayerPickingInfo<L, F> =
49
+ | LocationPickingInfo<L>
50
+ // | LocationAreaPickingInfo
51
+ | FlowPickingInfo<L, F>;
52
+
53
+ // import {FeatureCollection, GeometryObject} from 'geojson';
54
+ // export type LocationProperties = Record<string, unknown>;
55
+
56
+ // export type Locations =
57
+ // | FeatureCollection<GeometryObject, LocationProperties>
58
+ // | FlowLocation[];
59
+
60
+ // export function isFeatureCollection(
61
+ // locations: Locations,
62
+ // ): locations is FeatureCollection<GeometryObject, LocationProperties> {
63
+ // return (
64
+ // (locations as FeatureCollection<GeometryObject, LocationProperties>)
65
+ // .type === 'FeatureCollection'
66
+ // );
67
+ // }
package/tsconfig.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "../../tsconfig.common.json",
3
+ "compilerOptions": {
4
+ "noEmit": false,
5
+ "outDir": "dist"
6
+ },
7
+ "include": [
8
+ "src/**/*.ts",
9
+ "**/typings.d.ts"
10
+ ]
11
+ }
package/typings.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ declare module '@deck.gl/core';
2
+ declare module '@deck.gl/layers';
3
+ declare module '@luma.gl/constants';
4
+ declare module '@luma.gl/core';