@flowmap.gl/data 8.0.0-alpha.18 → 8.0.0-alpha.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/FlowmapAggregateAccessors.d.ts +3 -3
- package/dist/FlowmapAggregateAccessors.d.ts.map +1 -1
- package/dist/FlowmapAggregateAccessors.js +2 -2
- package/dist/FlowmapSelectors.d.ts +44 -33
- package/dist/FlowmapSelectors.d.ts.map +1 -1
- package/dist/FlowmapSelectors.js +50 -49
- package/dist/FlowmapState.d.ts +5 -5
- package/dist/FlowmapState.d.ts.map +1 -1
- package/dist/FlowmapState.js +1 -1
- package/dist/cluster/ClusterIndex.d.ts +3 -3
- package/dist/cluster/ClusterIndex.d.ts.map +1 -1
- package/dist/cluster/ClusterIndex.js +1 -1
- package/dist/cluster/cluster.d.ts.map +1 -1
- package/dist/cluster/cluster.js +64 -13
- package/dist/colors.d.ts +1 -1
- package/dist/colors.d.ts.map +1 -1
- package/dist/colors.js +3 -3
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/provider/FlowmapDataProvider.d.ts +7 -2
- package/dist/provider/FlowmapDataProvider.d.ts.map +1 -1
- package/dist/provider/FlowmapDataProvider.js +1 -1
- package/dist/provider/LocalFlowmapDataProvider.d.ts +3 -2
- package/dist/provider/LocalFlowmapDataProvider.d.ts.map +1 -1
- package/dist/provider/LocalFlowmapDataProvider.js +6 -1
- package/dist/selector-functions.d.ts +4 -0
- package/dist/selector-functions.d.ts.map +1 -0
- package/dist/selector-functions.js +20 -0
- package/dist/types.d.ts +12 -11
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/package.json +2 -3
- package/src/FlowmapAggregateAccessors.ts +2 -2
- package/src/FlowmapSelectors.ts +171 -160
- package/src/FlowmapState.ts +5 -5
- package/src/cluster/ClusterIndex.ts +19 -12
- package/src/cluster/cluster.ts +71 -16
- package/src/colors.ts +7 -9
- package/src/index.ts +3 -0
- package/src/provider/FlowmapDataProvider.ts +13 -2
- package/src/provider/LocalFlowmapDataProvider.ts +10 -2
- package/src/selector-functions.ts +34 -0
- package/src/types.ts +12 -11
|
@@ -27,14 +27,14 @@ import {
|
|
|
27
27
|
} from './../types';
|
|
28
28
|
import {ascending, bisectLeft, extent} from 'd3-array';
|
|
29
29
|
|
|
30
|
-
export type LocationWeightGetter = (id: string) => number;
|
|
30
|
+
export type LocationWeightGetter = (id: string | number) => number;
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* A data structure representing the cluster levels for efficient flow aggregation.
|
|
34
34
|
*/
|
|
35
35
|
export interface ClusterIndex<F> {
|
|
36
36
|
availableZoomLevels: number[];
|
|
37
|
-
getClusterById: (clusterId: string) => Cluster | undefined;
|
|
37
|
+
getClusterById: (clusterId: string | number) => Cluster | undefined;
|
|
38
38
|
/**
|
|
39
39
|
* List the nodes on the given zoom level.
|
|
40
40
|
*/
|
|
@@ -50,7 +50,10 @@ export interface ClusterIndex<F> {
|
|
|
50
50
|
/**
|
|
51
51
|
* Find the cluster the given location is residing in on the specified zoom level.
|
|
52
52
|
*/
|
|
53
|
-
findClusterFor: (
|
|
53
|
+
findClusterFor: (
|
|
54
|
+
locationId: string | number,
|
|
55
|
+
zoom: number,
|
|
56
|
+
) => string | number | undefined;
|
|
54
57
|
/**
|
|
55
58
|
* Aggregate flows for the specified zoom level.
|
|
56
59
|
*/
|
|
@@ -69,8 +72,8 @@ export interface ClusterIndex<F> {
|
|
|
69
72
|
*/
|
|
70
73
|
export function buildIndex<F>(clusterLevels: ClusterLevels): ClusterIndex<F> {
|
|
71
74
|
const nodesByZoom = new Map<number, ClusterNode[]>();
|
|
72
|
-
const clustersById = new Map<string, Cluster>();
|
|
73
|
-
const minZoomByLocationId = new Map<string, number>();
|
|
75
|
+
const clustersById = new Map<string | number, Cluster>();
|
|
76
|
+
const minZoomByLocationId = new Map<string | number, number>();
|
|
74
77
|
for (const {zoom, nodes} of clusterLevels) {
|
|
75
78
|
nodesByZoom.set(zoom, nodes);
|
|
76
79
|
for (const node of nodes) {
|
|
@@ -91,7 +94,10 @@ export function buildIndex<F>(clusterLevels: ClusterLevels): ClusterIndex<F> {
|
|
|
91
94
|
throw new Error('Could not determine minZoom or maxZoom');
|
|
92
95
|
}
|
|
93
96
|
|
|
94
|
-
const leavesToClustersByZoom = new Map<
|
|
97
|
+
const leavesToClustersByZoom = new Map<
|
|
98
|
+
number,
|
|
99
|
+
Map<string | number, Cluster>
|
|
100
|
+
>();
|
|
95
101
|
|
|
96
102
|
for (const cluster of clustersById.values()) {
|
|
97
103
|
const {zoom} = cluster;
|
|
@@ -118,7 +124,7 @@ export function buildIndex<F>(clusterLevels: ClusterLevels): ClusterIndex<F> {
|
|
|
118
124
|
|
|
119
125
|
const expandCluster = (cluster: Cluster, targetZoom: number = maxZoom) => {
|
|
120
126
|
const ids: string[] = [];
|
|
121
|
-
const visit = (c: Cluster, expandedIds: string[]) => {
|
|
127
|
+
const visit = (c: Cluster, expandedIds: (string | number)[]) => {
|
|
122
128
|
if (targetZoom > c.zoom) {
|
|
123
129
|
for (const childId of c.children) {
|
|
124
130
|
const child = clustersById.get(childId);
|
|
@@ -136,7 +142,7 @@ export function buildIndex<F>(clusterLevels: ClusterLevels): ClusterIndex<F> {
|
|
|
136
142
|
return ids;
|
|
137
143
|
};
|
|
138
144
|
|
|
139
|
-
function findClusterFor(locationId: string, zoom: number) {
|
|
145
|
+
function findClusterFor(locationId: string | number, zoom: number) {
|
|
140
146
|
const leavesToClusters = leavesToClustersByZoom.get(zoom);
|
|
141
147
|
if (!leavesToClusters) {
|
|
142
148
|
return undefined;
|
|
@@ -179,7 +185,8 @@ export function buildIndex<F>(clusterLevels: ClusterLevels): ClusterIndex<F> {
|
|
|
179
185
|
}
|
|
180
186
|
const result: (F | AggregateFlow)[] = [];
|
|
181
187
|
const aggFlowsByKey = new Map<string, AggregateFlow>();
|
|
182
|
-
const makeKey = (origin: string, dest: string) =>
|
|
188
|
+
const makeKey = (origin: string | number, dest: string | number) =>
|
|
189
|
+
`${origin}:${dest}`;
|
|
183
190
|
const {
|
|
184
191
|
flowCountsMapReduce = {
|
|
185
192
|
map: getFlowMagnitude,
|
|
@@ -223,8 +230,8 @@ export function makeLocationWeightGetter<F>(
|
|
|
223
230
|
{getFlowOriginId, getFlowDestId, getFlowMagnitude}: FlowAccessors<F>,
|
|
224
231
|
): LocationWeightGetter {
|
|
225
232
|
const locationTotals = {
|
|
226
|
-
incoming: new Map<string, number>(),
|
|
227
|
-
outgoing: new Map<string, number>(),
|
|
233
|
+
incoming: new Map<string | number, number>(),
|
|
234
|
+
outgoing: new Map<string | number, number>(),
|
|
228
235
|
};
|
|
229
236
|
for (const flow of flows) {
|
|
230
237
|
const origin = getFlowOriginId(flow);
|
|
@@ -239,7 +246,7 @@ export function makeLocationWeightGetter<F>(
|
|
|
239
246
|
(locationTotals.outgoing.get(origin) || 0) + count,
|
|
240
247
|
);
|
|
241
248
|
}
|
|
242
|
-
return (id: string) =>
|
|
249
|
+
return (id: string | number) =>
|
|
243
250
|
Math.max(
|
|
244
251
|
Math.abs(locationTotals.incoming.get(id) || 0),
|
|
245
252
|
Math.abs(locationTotals.outgoing.get(id) || 0),
|
package/src/cluster/cluster.ts
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
37
37
|
// THIS SOFTWARE.
|
|
38
38
|
|
|
39
|
-
import {rollup} from 'd3-array';
|
|
39
|
+
import {min, rollup} from 'd3-array';
|
|
40
40
|
import KDBush from 'kdbush';
|
|
41
41
|
import {LocationWeightGetter} from './ClusterIndex';
|
|
42
42
|
import {Cluster, ClusterLevel, ClusterNode, LocationAccessors} from '../types';
|
|
@@ -110,7 +110,7 @@ export function clusterLocations<L>(
|
|
|
110
110
|
|
|
111
111
|
// generate a cluster object for each point and index input points into a KD-tree
|
|
112
112
|
let clusters = new Array<Point<L>>();
|
|
113
|
-
let
|
|
113
|
+
let locationsCount = 0;
|
|
114
114
|
for (const location of locations) {
|
|
115
115
|
const x = getLocationLon(location);
|
|
116
116
|
const y = getLocationLat(location);
|
|
@@ -119,41 +119,65 @@ export function clusterLocations<L>(
|
|
|
119
119
|
y: latY(y),
|
|
120
120
|
weight: getLocationWeight(getLocationId(location)),
|
|
121
121
|
zoom: Infinity, // the last zoom the point was processed at
|
|
122
|
-
index:
|
|
122
|
+
index: locationsCount, // index of the source feature in the original input array,
|
|
123
123
|
parentId: -1, // parent cluster id
|
|
124
124
|
location,
|
|
125
125
|
});
|
|
126
|
-
|
|
126
|
+
locationsCount++;
|
|
127
127
|
}
|
|
128
|
-
trees[maxZoom + 1] = new KDBush(clusters, getX, getY, nodeSize, Float32Array);
|
|
129
128
|
|
|
130
129
|
// cluster points on max zoom, then cluster the results on previous zoom, etc.;
|
|
131
130
|
// results in a cluster hierarchy across zoom levels
|
|
131
|
+
trees[maxZoom + 1] = new KDBush(clusters, getX, getY, nodeSize, Float32Array);
|
|
132
|
+
let prevZoom = maxZoom + 1;
|
|
133
|
+
|
|
132
134
|
for (let z = maxZoom; z >= minZoom; z--) {
|
|
133
135
|
// create a new set of clusters for the zoom and index them with a KD-tree
|
|
134
|
-
|
|
135
|
-
|
|
136
|
+
const _clusters = cluster(clusters, z, trees[prevZoom], opts);
|
|
137
|
+
if (_clusters.length === clusters.length) {
|
|
138
|
+
// same number of clusters => move the higher level clusters up
|
|
139
|
+
// no need to keep the same data on multiple levels
|
|
140
|
+
trees[z] = trees[prevZoom];
|
|
141
|
+
trees[prevZoom] = undefined;
|
|
142
|
+
prevZoom = z;
|
|
143
|
+
clusters = _clusters;
|
|
144
|
+
} else {
|
|
145
|
+
prevZoom = z;
|
|
146
|
+
clusters = _clusters;
|
|
147
|
+
trees[z] = new KDBush(clusters, getX, getY, nodeSize, Float32Array);
|
|
148
|
+
}
|
|
136
149
|
}
|
|
137
150
|
|
|
138
151
|
if (trees.length === 0) {
|
|
139
152
|
return [];
|
|
140
153
|
}
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
);
|
|
154
|
+
|
|
155
|
+
const numbersOfClusters = trees.map((d) => d?.points.length);
|
|
156
|
+
const minClusters = min(numbersOfClusters.filter((d) => d > 0));
|
|
157
|
+
const maxClusters = getMaxNumberOfClusters(locations, locationAccessors);
|
|
158
|
+
|
|
159
|
+
let maxAvailZoom = numbersOfClusters.indexOf(maxClusters);
|
|
160
|
+
if (maxClusters < locationsCount) {
|
|
161
|
+
maxAvailZoom++;
|
|
162
|
+
if (maxAvailZoom < maxZoom + 1) {
|
|
163
|
+
trees[maxAvailZoom] = trees[maxZoom + 1];
|
|
164
|
+
trees[maxZoom + 1] = undefined;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
145
167
|
const minAvailZoom = Math.min(
|
|
146
168
|
maxAvailZoom,
|
|
147
|
-
numbersOfClusters.lastIndexOf(
|
|
169
|
+
numbersOfClusters.lastIndexOf(minClusters),
|
|
148
170
|
);
|
|
149
171
|
|
|
150
172
|
const clusterLevels = new Array<ClusterLevel>();
|
|
151
|
-
|
|
152
|
-
|
|
173
|
+
prevZoom = NaN;
|
|
174
|
+
for (let zoom = maxAvailZoom; zoom >= minAvailZoom; zoom--) {
|
|
175
|
+
let childrenByParent: Map<number, (string | number)[]> | undefined;
|
|
153
176
|
const tree = trees[zoom];
|
|
177
|
+
if (!tree) continue;
|
|
154
178
|
if (zoom < maxAvailZoom) {
|
|
155
|
-
childrenByParent = rollup<Point<L>, string[], number>(
|
|
156
|
-
trees[
|
|
179
|
+
childrenByParent = rollup<Point<L>, (string | number)[], number>(
|
|
180
|
+
trees[prevZoom].points,
|
|
157
181
|
(points: any[]) =>
|
|
158
182
|
points.map((p: any) =>
|
|
159
183
|
p.id ? makeClusterId(p.id) : getLocationId(p.location),
|
|
@@ -192,6 +216,7 @@ export function clusterLocations<L>(
|
|
|
192
216
|
zoom,
|
|
193
217
|
nodes,
|
|
194
218
|
});
|
|
219
|
+
prevZoom = zoom;
|
|
195
220
|
}
|
|
196
221
|
return clusterLevels;
|
|
197
222
|
}
|
|
@@ -303,3 +328,33 @@ function getX<L>(p: Point<L>) {
|
|
|
303
328
|
function getY<L>(p: Point<L>) {
|
|
304
329
|
return p.y;
|
|
305
330
|
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Finds groups of locations which share the same positions.
|
|
334
|
+
* They will always be clustered together at any zoom level
|
|
335
|
+
* which can lead to having too many zooms.
|
|
336
|
+
*/
|
|
337
|
+
function getMaxNumberOfClusters<L>(
|
|
338
|
+
locations: Iterable<L>,
|
|
339
|
+
locationAccessors: LocationAccessors<L>,
|
|
340
|
+
) {
|
|
341
|
+
const {getLocationLon, getLocationLat} = locationAccessors;
|
|
342
|
+
const countByLatLon = new Map<string, number>();
|
|
343
|
+
let numLocations = 0;
|
|
344
|
+
for (const loc of locations) {
|
|
345
|
+
const lon = getLocationLon(loc);
|
|
346
|
+
const lat = getLocationLat(loc);
|
|
347
|
+
const key = `${lon},${lat}`;
|
|
348
|
+
const prev = countByLatLon.get(key);
|
|
349
|
+
countByLatLon.set(key, prev ? prev + 1 : 1);
|
|
350
|
+
numLocations++;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
let numSame = 0;
|
|
354
|
+
for (const [key, count] of countByLatLon) {
|
|
355
|
+
if (count > 1) {
|
|
356
|
+
numSame++;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return numLocations - numSame;
|
|
360
|
+
}
|
package/src/colors.ts
CHANGED
|
@@ -333,17 +333,15 @@ const diffColors: DiffColors = {
|
|
|
333
333
|
outlineColor: 'rgb(230,233,237)',
|
|
334
334
|
};
|
|
335
335
|
|
|
336
|
-
export function getFlowmapColors(
|
|
337
|
-
settingsState: SettingsState,
|
|
338
|
-
): Colors | DiffColors {
|
|
336
|
+
export function getFlowmapColors(settings: SettingsState): Colors | DiffColors {
|
|
339
337
|
return getColors(
|
|
340
338
|
false, // TODO: diffMode
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
339
|
+
settings.colorScheme,
|
|
340
|
+
settings.darkMode,
|
|
341
|
+
settings.fadeEnabled,
|
|
342
|
+
settings.fadeOpacityEnabled,
|
|
343
|
+
settings.fadeAmount,
|
|
344
|
+
settings.animationEnabled,
|
|
347
345
|
);
|
|
348
346
|
}
|
|
349
347
|
|
package/src/index.ts
CHANGED
|
@@ -2,9 +2,12 @@ export * from './types';
|
|
|
2
2
|
export * from './colors';
|
|
3
3
|
export * from './FlowmapState';
|
|
4
4
|
export * from './FlowmapSelectors';
|
|
5
|
+
export * from './selector-functions';
|
|
5
6
|
export * from './time';
|
|
6
7
|
export * from './getViewStateForLocations';
|
|
7
8
|
export * from './provider/FlowmapDataProvider';
|
|
9
|
+
export * from './cluster/cluster';
|
|
10
|
+
export * from './cluster/ClusterIndex';
|
|
8
11
|
export {default as FlowmapAggregateAccessors} from './FlowmapAggregateAccessors';
|
|
9
12
|
export type {default as FlowmapDataProvider} from './provider/FlowmapDataProvider';
|
|
10
13
|
export {default as LocalFlowmapDataProvider} from './provider/LocalFlowmapDataProvider';
|
|
@@ -23,11 +23,13 @@ export default interface FlowmapDataProvider<L, F> {
|
|
|
23
23
|
|
|
24
24
|
getFlowByIndex(index: number): Promise<F | AggregateFlow | undefined>;
|
|
25
25
|
|
|
26
|
-
getLocationById(id: string): Promise<L | Cluster | undefined>;
|
|
26
|
+
getLocationById(id: string | number): Promise<L | Cluster | undefined>;
|
|
27
27
|
|
|
28
28
|
getLocationByIndex(idx: number): Promise<L | ClusterNode | undefined>;
|
|
29
29
|
|
|
30
|
-
getTotalsForLocation(
|
|
30
|
+
getTotalsForLocation(
|
|
31
|
+
id: string | number,
|
|
32
|
+
): Promise<LocationTotals | undefined>;
|
|
31
33
|
|
|
32
34
|
// getLocationsInBbox(
|
|
33
35
|
// bbox: [number, number, number, number],
|
|
@@ -36,6 +38,15 @@ export default interface FlowmapDataProvider<L, F> {
|
|
|
36
38
|
// getLocationsForSearchBox(): Promise<(FlowLocation | ClusterNode)[] | undefined>;
|
|
37
39
|
|
|
38
40
|
getLayersData(): Promise<LayersData | undefined>;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* This is to give the data provider control over when/how often layersData
|
|
44
|
+
* is updated which leads to the flowmap being redrawn.
|
|
45
|
+
*/
|
|
46
|
+
updateLayersData(
|
|
47
|
+
setLayersData: (layersData: LayersData | undefined) => void,
|
|
48
|
+
changeFlags: Record<string, boolean>,
|
|
49
|
+
): Promise<void>;
|
|
39
50
|
}
|
|
40
51
|
|
|
41
52
|
export function isFlowmapData<L, F>(
|
|
@@ -72,7 +72,7 @@ export default class LocalFlowmapDataProvider<L, F>
|
|
|
72
72
|
return this.selectors.getLayersData(this.flowmapState, this.flowmapData);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
async getLocationById(id: string): Promise<L | Cluster | undefined> {
|
|
75
|
+
async getLocationById(id: string | number): Promise<L | Cluster | undefined> {
|
|
76
76
|
if (!this.flowmapState || !this.flowmapData) {
|
|
77
77
|
return undefined;
|
|
78
78
|
}
|
|
@@ -93,7 +93,9 @@ export default class LocalFlowmapDataProvider<L, F>
|
|
|
93
93
|
return locationsById?.get(id);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
async getTotalsForLocation(
|
|
96
|
+
async getTotalsForLocation(
|
|
97
|
+
id: string | number,
|
|
98
|
+
): Promise<LocationTotals | undefined> {
|
|
97
99
|
if (!this.flowmapState || !this.flowmapData) {
|
|
98
100
|
return undefined;
|
|
99
101
|
}
|
|
@@ -120,4 +122,10 @@ export default class LocalFlowmapDataProvider<L, F>
|
|
|
120
122
|
opts,
|
|
121
123
|
);
|
|
122
124
|
}
|
|
125
|
+
|
|
126
|
+
async updateLayersData(
|
|
127
|
+
setLayersData: (layersData: LayersData | undefined) => void,
|
|
128
|
+
) {
|
|
129
|
+
setLayersData(await this.getLayersData());
|
|
130
|
+
}
|
|
123
131
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {WebMercatorViewport} from '@math.gl/web-mercator';
|
|
2
|
+
import {ViewportProps} from './types';
|
|
3
|
+
import {scaleLinear} from 'd3-scale';
|
|
4
|
+
|
|
5
|
+
// TODO: use re-reselect
|
|
6
|
+
|
|
7
|
+
export const getViewportBoundingBox = (
|
|
8
|
+
viewport: ViewportProps,
|
|
9
|
+
maxLocationCircleSize = 0,
|
|
10
|
+
): [number, number, number, number] => {
|
|
11
|
+
const pad = maxLocationCircleSize;
|
|
12
|
+
const bounds = new WebMercatorViewport({
|
|
13
|
+
...viewport,
|
|
14
|
+
width: viewport.width + pad * 2,
|
|
15
|
+
height: viewport.height + pad * 2,
|
|
16
|
+
}).getBounds();
|
|
17
|
+
return [bounds[0][0], bounds[0][1], bounds[1][0], bounds[1][1]];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const getFlowThicknessScale = (
|
|
21
|
+
magnitudeExtent: [number, number] | undefined,
|
|
22
|
+
) => {
|
|
23
|
+
if (!magnitudeExtent) return undefined;
|
|
24
|
+
return scaleLinear()
|
|
25
|
+
.range([0.025, 0.5])
|
|
26
|
+
.domain([
|
|
27
|
+
0,
|
|
28
|
+
// should support diff mode too
|
|
29
|
+
Math.max.apply(
|
|
30
|
+
null,
|
|
31
|
+
magnitudeExtent.map((x: number | undefined) => Math.abs(x || 0)),
|
|
32
|
+
),
|
|
33
|
+
]);
|
|
34
|
+
};
|
package/src/types.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export type FlowmapData<L, F> = {
|
|
2
2
|
locations: Iterable<L> | undefined;
|
|
3
3
|
flows: Iterable<F> | undefined;
|
|
4
|
+
clusterLevels?: ClusterLevels;
|
|
4
5
|
};
|
|
5
6
|
|
|
6
7
|
export interface ViewState {
|
|
@@ -16,19 +17,19 @@ export type FlowAccessor<F, T> = (flow: F) => T; // objectInfo?: AccessorObjectI
|
|
|
16
17
|
export type LocationAccessor<L, T> = (location: L) => T;
|
|
17
18
|
|
|
18
19
|
export interface FlowAccessors<F> {
|
|
19
|
-
getFlowOriginId: FlowAccessor<F, string>;
|
|
20
|
-
getFlowDestId: FlowAccessor<F, string>;
|
|
20
|
+
getFlowOriginId: FlowAccessor<F, string | number>;
|
|
21
|
+
getFlowDestId: FlowAccessor<F, string | number>;
|
|
21
22
|
getFlowMagnitude: FlowAccessor<F, number>;
|
|
22
23
|
getFlowTime?: FlowAccessor<F, Date>; // TODO: use number instead of Date
|
|
23
24
|
// getFlowColor?: FlowAccessor<string | undefined>;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export interface LocationAccessors<L> {
|
|
27
|
-
getLocationId: LocationAccessor<L, string>;
|
|
28
|
-
getLocationName?: LocationAccessor<L, string>;
|
|
28
|
+
getLocationId: LocationAccessor<L, string | number>;
|
|
29
|
+
getLocationName?: LocationAccessor<L, string | number>;
|
|
29
30
|
getLocationLat: LocationAccessor<L, number>;
|
|
30
31
|
getLocationLon: LocationAccessor<L, number>;
|
|
31
|
-
getLocationClusterName?: (locationIds: string[]) => string;
|
|
32
|
+
getLocationClusterName?: (locationIds: (string | number)[]) => string;
|
|
32
33
|
// getLocationTotalIn?: LocationAccessor<number>;
|
|
33
34
|
// getLocationTotalOut?: LocationAccessor<number>;
|
|
34
35
|
// getLocationTotalInternal?: LocationAccessor<number>;
|
|
@@ -59,9 +60,9 @@ export interface ViewportProps {
|
|
|
59
60
|
height: number;
|
|
60
61
|
latitude: number;
|
|
61
62
|
longitude: number;
|
|
62
|
-
zoom
|
|
63
|
-
bearing
|
|
64
|
-
pitch
|
|
63
|
+
zoom?: number;
|
|
64
|
+
bearing?: number;
|
|
65
|
+
pitch?: number;
|
|
65
66
|
altitude?: number;
|
|
66
67
|
maxZoom?: number;
|
|
67
68
|
minZoom?: number;
|
|
@@ -74,7 +75,7 @@ export interface ViewportProps {
|
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
export interface ClusterNode {
|
|
77
|
-
id: string;
|
|
78
|
+
id: string | number;
|
|
78
79
|
zoom: number;
|
|
79
80
|
lat: number;
|
|
80
81
|
lon: number;
|
|
@@ -104,8 +105,8 @@ export function isLocationClusterNode<L>(l: L | ClusterNode): l is ClusterNode {
|
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
export interface AggregateFlow {
|
|
107
|
-
origin: string;
|
|
108
|
-
dest: string;
|
|
108
|
+
origin: string | number;
|
|
109
|
+
dest: string | number;
|
|
109
110
|
count: number;
|
|
110
111
|
aggregate: true;
|
|
111
112
|
}
|