@flowmap.gl/data 8.0.0-alpha.9 → 8.0.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/.turbo/turbo-build.log +3 -0
- package/.turbo/turbo-dev.log +6 -0
- package/LICENSE +2 -2
- package/dist/FlowmapAggregateAccessors.d.ts +4 -4
- package/dist/FlowmapAggregateAccessors.d.ts.map +1 -1
- package/dist/FlowmapAggregateAccessors.js +16 -9
- package/dist/FlowmapSelectors.d.ts +41 -87
- package/dist/FlowmapSelectors.d.ts.map +1 -1
- package/dist/FlowmapSelectors.js +174 -161
- package/dist/FlowmapState.d.ts +7 -5
- package/dist/FlowmapState.d.ts.map +1 -1
- package/dist/FlowmapState.js +6 -1
- package/dist/cluster/ClusterIndex.d.ts +4 -4
- package/dist/cluster/ClusterIndex.d.ts.map +1 -1
- package/dist/cluster/ClusterIndex.js +5 -17
- package/dist/cluster/cluster.d.ts +25 -5
- package/dist/cluster/cluster.d.ts.map +1 -1
- package/dist/cluster/cluster.js +115 -57
- package/dist/colors.d.ts +3 -3
- package/dist/colors.d.ts.map +1 -1
- package/dist/colors.js +19 -8
- package/dist/getViewStateForLocations.d.ts +3 -3
- package/dist/getViewStateForLocations.d.ts.map +1 -1
- package/dist/getViewStateForLocations.js +33 -12
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -4
- package/dist/provider/FlowmapDataProvider.d.ts +7 -2
- package/dist/provider/FlowmapDataProvider.d.ts.map +1 -1
- package/dist/provider/FlowmapDataProvider.js +11 -6
- package/dist/provider/LocalFlowmapDataProvider.d.ts +15 -4
- package/dist/provider/LocalFlowmapDataProvider.d.ts.map +1 -1
- package/dist/provider/LocalFlowmapDataProvider.js +98 -81
- package/dist/selector-functions.d.ts +10 -0
- package/dist/selector-functions.d.ts.map +1 -0
- package/dist/selector-functions.js +65 -0
- package/dist/time.d.ts.map +1 -1
- package/dist/time.js +6 -1
- package/dist/types.d.ts +20 -18
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +9 -4
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +6 -1
- package/package.json +22 -27
- package/src/FlowmapAggregateAccessors.ts +21 -10
- package/src/FlowmapSelectors.ts +304 -280
- package/src/FlowmapState.ts +13 -5
- package/src/cluster/ClusterIndex.ts +23 -28
- package/src/cluster/cluster.ts +165 -73
- package/src/colors.ts +13 -9
- package/src/getViewStateForLocations.ts +23 -7
- package/src/index.ts +9 -3
- package/src/provider/FlowmapDataProvider.ts +23 -7
- package/src/provider/LocalFlowmapDataProvider.ts +68 -5
- package/src/selector-functions.ts +93 -0
- package/src/time.ts +6 -0
- package/src/types.ts +23 -15
- package/src/util.ts +6 -0
- package/dist/provider/WorkerFlowmapDataProvider.d.ts +0 -42
- package/dist/provider/WorkerFlowmapDataProvider.d.ts.map +0 -1
- package/dist/provider/WorkerFlowmapDataProvider.js +0 -80
- package/dist/provider/WorkerFlowmapDataProviderWorker.d.ts +0 -2
- package/dist/provider/WorkerFlowmapDataProviderWorker.d.ts.map +0 -1
- package/dist/provider/WorkerFlowmapDataProviderWorker.js +0 -4
- package/dist/provider/createWorkerDataProvider.d.ts +0 -3
- package/dist/provider/createWorkerDataProvider.d.ts.map +0 -1
- package/dist/provider/createWorkerDataProvider.js +0 -21
- package/src/provider/WorkerFlowmapDataProvider.ts +0 -121
- package/src/provider/WorkerFlowmapDataProviderWorker.ts +0 -4
- package/src/provider/createWorkerDataProvider.ts +0 -18
package/src/FlowmapSelectors.ts
CHANGED
|
@@ -1,25 +1,11 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
3
|
-
* Copyright 2018-2020 Teralytics
|
|
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
|
-
*
|
|
2
|
+
* Copyright (c) Flowmap.gl contributors
|
|
3
|
+
* Copyright (c) 2018-2020 Teralytics
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
17
5
|
*/
|
|
18
6
|
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {nest} from 'd3-collection';
|
|
22
|
-
import {ScaleLinear, scaleLinear, scaleSqrt} from 'd3-scale';
|
|
7
|
+
import {ascending, descending, extent, min, rollup} from 'd3-array';
|
|
8
|
+
import {ScaleLinear, scaleSqrt} from 'd3-scale';
|
|
23
9
|
import KDBush from 'kdbush';
|
|
24
10
|
import {
|
|
25
11
|
createSelector,
|
|
@@ -33,6 +19,7 @@ import {
|
|
|
33
19
|
buildIndex,
|
|
34
20
|
ClusterIndex,
|
|
35
21
|
findAppropriateZoomLevel,
|
|
22
|
+
LocationWeightGetter,
|
|
36
23
|
makeLocationWeightGetter,
|
|
37
24
|
} from './cluster/ClusterIndex';
|
|
38
25
|
import getColors, {
|
|
@@ -46,6 +33,11 @@ import getColors, {
|
|
|
46
33
|
} from './colors';
|
|
47
34
|
import FlowmapAggregateAccessors from './FlowmapAggregateAccessors';
|
|
48
35
|
import {FlowmapState} from './FlowmapState';
|
|
36
|
+
import {
|
|
37
|
+
addClusterNames,
|
|
38
|
+
getFlowThicknessScale,
|
|
39
|
+
getViewportBoundingBox,
|
|
40
|
+
} from './selector-functions';
|
|
49
41
|
import {
|
|
50
42
|
getTimeGranularityByKey,
|
|
51
43
|
getTimeGranularityByOrder,
|
|
@@ -55,6 +47,7 @@ import {
|
|
|
55
47
|
import {
|
|
56
48
|
AggregateFlow,
|
|
57
49
|
Cluster,
|
|
50
|
+
ClusterLevels,
|
|
58
51
|
ClusterNode,
|
|
59
52
|
CountByTime,
|
|
60
53
|
FlowAccessors,
|
|
@@ -78,7 +71,10 @@ export type Selector<L, F, T> = ParametricSelector<
|
|
|
78
71
|
T
|
|
79
72
|
>;
|
|
80
73
|
|
|
81
|
-
export default class FlowmapSelectors<
|
|
74
|
+
export default class FlowmapSelectors<
|
|
75
|
+
L extends Record<string, any>,
|
|
76
|
+
F extends Record<string, any>,
|
|
77
|
+
> {
|
|
82
78
|
accessors: FlowmapAggregateAccessors<L, F>;
|
|
83
79
|
|
|
84
80
|
constructor(accessors: FlowmapDataAccessors<L, F>) {
|
|
@@ -90,60 +86,71 @@ export default class FlowmapSelectors<L, F> {
|
|
|
90
86
|
this.accessors = new FlowmapAggregateAccessors(accessors);
|
|
91
87
|
}
|
|
92
88
|
|
|
93
|
-
|
|
89
|
+
getAggregateAccessors(): FlowmapAggregateAccessors<L, F> {
|
|
90
|
+
return this.accessors;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
getFlowsFromProps = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
94
94
|
props.flows;
|
|
95
|
-
|
|
95
|
+
getLocationsFromProps = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
96
96
|
props.locations;
|
|
97
|
+
getClusterLevelsFromProps = (
|
|
98
|
+
state: FlowmapState,
|
|
99
|
+
props: FlowmapData<L, F>,
|
|
100
|
+
) => {
|
|
101
|
+
return props.clusterLevels;
|
|
102
|
+
};
|
|
97
103
|
getMaxTopFlowsDisplayNum = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
98
|
-
state.
|
|
104
|
+
state.settings.maxTopFlowsDisplayNum;
|
|
99
105
|
getSelectedLocations = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
100
|
-
state.
|
|
106
|
+
state.filter?.selectedLocations;
|
|
101
107
|
getLocationFilterMode = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
102
|
-
state.
|
|
108
|
+
state.filter?.locationFilterMode;
|
|
103
109
|
getClusteringEnabled = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
104
|
-
state.
|
|
110
|
+
state.settings.clusteringEnabled;
|
|
105
111
|
getLocationTotalsEnabled = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
106
|
-
state.
|
|
112
|
+
state.settings.locationTotalsEnabled;
|
|
113
|
+
getLocationLabelsEnabled = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
114
|
+
state.settings.locationLabelsEnabled;
|
|
107
115
|
getZoom = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
108
116
|
state.viewport.zoom;
|
|
109
117
|
getViewport = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
110
118
|
state.viewport;
|
|
111
119
|
getSelectedTimeRange = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
112
|
-
state.
|
|
120
|
+
state.filter?.selectedTimeRange;
|
|
113
121
|
|
|
114
122
|
getColorScheme: Selector<L, F, string | string[] | undefined> = (
|
|
115
123
|
state: FlowmapState,
|
|
116
124
|
props: FlowmapData<L, F>,
|
|
117
|
-
) => state.
|
|
125
|
+
) => state.settings.colorScheme;
|
|
118
126
|
|
|
119
127
|
getDarkMode: Selector<L, F, boolean> = (
|
|
120
128
|
state: FlowmapState,
|
|
121
129
|
props: FlowmapData<L, F>,
|
|
122
|
-
) => state.
|
|
130
|
+
) => state.settings.darkMode;
|
|
123
131
|
|
|
124
132
|
getFadeEnabled: Selector<L, F, boolean> = (
|
|
125
133
|
state: FlowmapState,
|
|
126
134
|
props: FlowmapData<L, F>,
|
|
127
|
-
) => state.
|
|
135
|
+
) => state.settings.fadeEnabled;
|
|
128
136
|
|
|
129
137
|
getFadeOpacityEnabled: Selector<L, F, boolean> = (
|
|
130
138
|
state: FlowmapState,
|
|
131
139
|
props: FlowmapData<L, F>,
|
|
132
|
-
) => state.
|
|
140
|
+
) => state.settings.fadeOpacityEnabled;
|
|
133
141
|
|
|
134
142
|
getFadeAmount: Selector<L, F, number> = (
|
|
135
143
|
state: FlowmapState,
|
|
136
144
|
props: FlowmapData<L, F>,
|
|
137
|
-
) => state.
|
|
145
|
+
) => state.settings.fadeAmount;
|
|
138
146
|
|
|
139
147
|
getAnimate: Selector<L, F, boolean> = (
|
|
140
148
|
state: FlowmapState,
|
|
141
149
|
props: FlowmapData<L, F>,
|
|
142
|
-
) => state.
|
|
150
|
+
) => state.settings.animationEnabled;
|
|
143
151
|
|
|
144
|
-
getInvalidLocationIds: Selector<L, F, string[] | undefined> =
|
|
145
|
-
this.
|
|
146
|
-
(locations) => {
|
|
152
|
+
getInvalidLocationIds: Selector<L, F, (string | number)[] | undefined> =
|
|
153
|
+
createSelector(this.getLocationsFromProps, (locations) => {
|
|
147
154
|
if (!locations) return undefined;
|
|
148
155
|
const invalid = [];
|
|
149
156
|
for (const location of locations) {
|
|
@@ -155,51 +162,63 @@ export default class FlowmapSelectors<L, F> {
|
|
|
155
162
|
}
|
|
156
163
|
}
|
|
157
164
|
return invalid.length > 0 ? invalid : undefined;
|
|
158
|
-
}
|
|
159
|
-
);
|
|
165
|
+
});
|
|
160
166
|
|
|
161
|
-
getLocations: Selector<L, F, L
|
|
162
|
-
this.
|
|
167
|
+
getLocations: Selector<L, F, Iterable<L> | undefined> = createSelector(
|
|
168
|
+
this.getLocationsFromProps,
|
|
163
169
|
this.getInvalidLocationIds,
|
|
164
170
|
(locations, invalidIds) => {
|
|
165
171
|
if (!locations) return undefined;
|
|
166
172
|
if (!invalidIds || invalidIds.length === 0) return locations;
|
|
167
173
|
const invalid = new Set(invalidIds);
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
174
|
+
const filtered: L[] = [];
|
|
175
|
+
for (const location of locations) {
|
|
176
|
+
const id = this.accessors.getLocationId(location);
|
|
177
|
+
if (!invalid.has(id)) {
|
|
178
|
+
filtered.push(location);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return filtered;
|
|
171
182
|
},
|
|
172
183
|
);
|
|
173
184
|
|
|
174
|
-
getLocationIds: Selector<L, F, Set<string> | undefined> =
|
|
175
|
-
this.getLocations,
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
185
|
+
getLocationIds: Selector<L, F, Set<string | number> | undefined> =
|
|
186
|
+
createSelector(this.getLocations, (locations) => {
|
|
187
|
+
if (!locations) return undefined;
|
|
188
|
+
const ids = new Set<string | number>();
|
|
189
|
+
for (const id of locations) {
|
|
190
|
+
ids.add(this.accessors.getLocationId(id));
|
|
191
|
+
}
|
|
192
|
+
return ids;
|
|
193
|
+
});
|
|
181
194
|
|
|
182
|
-
getSelectedLocationsSet: Selector<L, F, Set<string> | undefined> =
|
|
195
|
+
getSelectedLocationsSet: Selector<L, F, Set<string | number> | undefined> =
|
|
183
196
|
createSelector(this.getSelectedLocations, (ids) =>
|
|
184
197
|
ids && ids.length > 0 ? new Set(ids) : undefined,
|
|
185
198
|
);
|
|
186
199
|
|
|
187
200
|
getSortedFlowsForKnownLocations: Selector<L, F, F[] | undefined> =
|
|
188
|
-
createSelector(
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
201
|
+
createSelector(
|
|
202
|
+
this.getFlowsFromProps,
|
|
203
|
+
this.getLocationIds,
|
|
204
|
+
(flows, ids) => {
|
|
205
|
+
if (!ids || !flows) return undefined;
|
|
206
|
+
const filtered = [];
|
|
207
|
+
for (const flow of flows) {
|
|
208
|
+
const srcId = this.accessors.getFlowOriginId(flow);
|
|
209
|
+
const dstId = this.accessors.getFlowDestId(flow);
|
|
210
|
+
if (ids.has(srcId) && ids.has(dstId)) {
|
|
211
|
+
filtered.push(flow);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return filtered.sort((a: F, b: F) =>
|
|
197
215
|
descending(
|
|
198
216
|
Math.abs(this.accessors.getFlowMagnitude(a)),
|
|
199
217
|
Math.abs(this.accessors.getFlowMagnitude(b)),
|
|
200
218
|
),
|
|
201
219
|
);
|
|
202
|
-
|
|
220
|
+
},
|
|
221
|
+
);
|
|
203
222
|
|
|
204
223
|
getActualTimeExtent: Selector<L, F, [Date, Date] | undefined> =
|
|
205
224
|
createSelector(this.getSortedFlowsForKnownLocations, (flows) => {
|
|
@@ -271,44 +290,54 @@ export default class FlowmapSelectors<L, F> {
|
|
|
271
290
|
},
|
|
272
291
|
);
|
|
273
292
|
|
|
274
|
-
getLocationsHavingFlows: Selector<L, F, L
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
293
|
+
getLocationsHavingFlows: Selector<L, F, Iterable<L> | undefined> =
|
|
294
|
+
createSelector(
|
|
295
|
+
this.getSortedFlowsForKnownLocations,
|
|
296
|
+
this.getLocations,
|
|
297
|
+
(flows, locations) => {
|
|
298
|
+
if (!locations || !flows) return locations;
|
|
299
|
+
const withFlows = new Set();
|
|
300
|
+
for (const flow of flows) {
|
|
301
|
+
withFlows.add(this.accessors.getFlowOriginId(flow));
|
|
302
|
+
withFlows.add(this.accessors.getFlowDestId(flow));
|
|
303
|
+
}
|
|
304
|
+
const filtered = [];
|
|
305
|
+
for (const location of locations) {
|
|
306
|
+
if (withFlows.has(this.accessors.getLocationId(location))) {
|
|
307
|
+
filtered.push(location);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return filtered;
|
|
311
|
+
},
|
|
312
|
+
);
|
|
289
313
|
|
|
290
|
-
getLocationsById: Selector<L, F, Map<string, L> | undefined> =
|
|
291
|
-
this.getLocationsHavingFlows,
|
|
292
|
-
(locations) => {
|
|
314
|
+
getLocationsById: Selector<L, F, Map<string | number, L> | undefined> =
|
|
315
|
+
createSelector(this.getLocationsHavingFlows, (locations) => {
|
|
293
316
|
if (!locations) return undefined;
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
.
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
getClusterIndex: Selector<L, F, ClusterIndex<F> | undefined> = createSelector(
|
|
302
|
-
this.getLocationsHavingFlows,
|
|
303
|
-
this.getLocationsById,
|
|
304
|
-
this.getSortedFlowsForKnownLocations,
|
|
305
|
-
(locations, locationsById, flows) => {
|
|
306
|
-
if (!locations || !locationsById || !flows) return undefined;
|
|
317
|
+
const locationsById = new Map<string | number, L>();
|
|
318
|
+
for (const location of locations) {
|
|
319
|
+
locationsById.set(this.accessors.getLocationId(location), location);
|
|
320
|
+
}
|
|
321
|
+
return locationsById;
|
|
322
|
+
});
|
|
307
323
|
|
|
324
|
+
getLocationWeightGetter: Selector<L, F, LocationWeightGetter | undefined> =
|
|
325
|
+
createSelector(this.getSortedFlowsForKnownLocations, (flows) => {
|
|
326
|
+
if (!flows) return undefined;
|
|
308
327
|
const getLocationWeight = makeLocationWeightGetter(
|
|
309
328
|
flows,
|
|
310
329
|
this.accessors.getFlowmapDataAccessors(),
|
|
311
330
|
);
|
|
331
|
+
return getLocationWeight;
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
getClusterLevels: Selector<L, F, ClusterLevels | undefined> = createSelector(
|
|
335
|
+
this.getClusterLevelsFromProps,
|
|
336
|
+
this.getLocationsHavingFlows,
|
|
337
|
+
this.getLocationWeightGetter,
|
|
338
|
+
(clusterLevelsFromProps, locations, getLocationWeight) => {
|
|
339
|
+
if (clusterLevelsFromProps) return clusterLevelsFromProps;
|
|
340
|
+
if (!locations || !getLocationWeight) return undefined;
|
|
312
341
|
const clusterLevels = clusterLocations(
|
|
313
342
|
locations,
|
|
314
343
|
this.accessors.getFlowmapDataAccessors(),
|
|
@@ -317,47 +346,27 @@ export default class FlowmapSelectors<L, F> {
|
|
|
317
346
|
maxZoom: MAX_CLUSTER_ZOOM_LEVEL,
|
|
318
347
|
},
|
|
319
348
|
);
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
// Adding meaningful names
|
|
325
|
-
const getName = (id: string) => {
|
|
326
|
-
const loc = locationsById.get(id);
|
|
327
|
-
if (loc) {
|
|
328
|
-
return getLocationName
|
|
329
|
-
? getLocationName(loc)
|
|
330
|
-
: this.accessors.getLocationId(loc) || id;
|
|
331
|
-
}
|
|
332
|
-
return `"${id}"`;
|
|
333
|
-
};
|
|
334
|
-
for (const level of clusterLevels) {
|
|
335
|
-
for (const node of level.nodes) {
|
|
336
|
-
// Here mutating the nodes (adding names)
|
|
337
|
-
if (isCluster(node)) {
|
|
338
|
-
const leaves = clusterIndex.expandCluster(node);
|
|
339
|
-
|
|
340
|
-
leaves.sort((a, b) =>
|
|
341
|
-
descending(getLocationWeight(a), getLocationWeight(b)),
|
|
342
|
-
);
|
|
349
|
+
return clusterLevels;
|
|
350
|
+
},
|
|
351
|
+
);
|
|
343
352
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
? `"${getName(otherId)}"`
|
|
352
|
-
: `${leaves.length - 1} others`
|
|
353
|
-
}`;
|
|
354
|
-
}
|
|
355
|
-
} else {
|
|
356
|
-
(node as any).name = getName(node.id);
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
}
|
|
353
|
+
getClusterIndex: Selector<L, F, ClusterIndex<F> | undefined> = createSelector(
|
|
354
|
+
this.getLocationsById,
|
|
355
|
+
this.getLocationWeightGetter,
|
|
356
|
+
this.getClusterLevels,
|
|
357
|
+
(locationsById, getLocationWeight, clusterLevels) => {
|
|
358
|
+
if (!locationsById || !getLocationWeight || !clusterLevels)
|
|
359
|
+
return undefined;
|
|
360
360
|
|
|
361
|
+
const clusterIndex = buildIndex<F>(clusterLevels);
|
|
362
|
+
// Adding meaningful names
|
|
363
|
+
addClusterNames(
|
|
364
|
+
clusterIndex,
|
|
365
|
+
clusterLevels,
|
|
366
|
+
locationsById,
|
|
367
|
+
this.accessors.getFlowmapDataAccessors(),
|
|
368
|
+
getLocationWeight,
|
|
369
|
+
);
|
|
361
370
|
return clusterIndex;
|
|
362
371
|
},
|
|
363
372
|
);
|
|
@@ -373,7 +382,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
373
382
|
let maxZoom = Number.POSITIVE_INFINITY;
|
|
374
383
|
let minZoom = Number.NEGATIVE_INFINITY;
|
|
375
384
|
|
|
376
|
-
const adjust = (zoneId: string) => {
|
|
385
|
+
const adjust = (zoneId: string | number) => {
|
|
377
386
|
const cluster = clusterIndex.getClusterById(zoneId);
|
|
378
387
|
if (cluster) {
|
|
379
388
|
minZoom = Math.max(minZoom, cluster.zoom);
|
|
@@ -402,7 +411,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
402
411
|
this.getAvailableClusterZoomLevels,
|
|
403
412
|
(clusterIndex, mapZoom, availableClusterZoomLevels) => {
|
|
404
413
|
if (!clusterIndex) return undefined;
|
|
405
|
-
if (!availableClusterZoomLevels) {
|
|
414
|
+
if (!availableClusterZoomLevels || mapZoom == null) {
|
|
406
415
|
return undefined;
|
|
407
416
|
}
|
|
408
417
|
|
|
@@ -415,12 +424,12 @@ export default class FlowmapSelectors<L, F> {
|
|
|
415
424
|
);
|
|
416
425
|
|
|
417
426
|
getClusterZoom = (state: FlowmapState, props: FlowmapData<L, F>) => {
|
|
418
|
-
const {
|
|
419
|
-
if (!
|
|
420
|
-
if (
|
|
427
|
+
const {settings} = state;
|
|
428
|
+
if (!settings.clusteringEnabled) return undefined;
|
|
429
|
+
if (settings.clusteringAuto || settings.clusteringLevel == null) {
|
|
421
430
|
return this._getClusterZoom(state, props);
|
|
422
431
|
}
|
|
423
|
-
return
|
|
432
|
+
return settings.clusteringLevel;
|
|
424
433
|
};
|
|
425
434
|
|
|
426
435
|
getLocationsForSearchBox: Selector<L, F, (L | Cluster)[] | undefined> =
|
|
@@ -438,7 +447,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
438
447
|
clusterIndex,
|
|
439
448
|
) => {
|
|
440
449
|
if (!locations) return undefined;
|
|
441
|
-
let result: (L | Cluster)[] = locations;
|
|
450
|
+
let result: (L | Cluster)[] = Array.from(locations);
|
|
442
451
|
// if (clusteringEnabled) {
|
|
443
452
|
// if (clusterIndex) {
|
|
444
453
|
// const zoomItems = clusterIndex.getClusterNodesFor(clusterZoom);
|
|
@@ -448,7 +457,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
448
457
|
// }
|
|
449
458
|
// }
|
|
450
459
|
|
|
451
|
-
if (
|
|
460
|
+
if (clusterIndex && selectedLocations) {
|
|
452
461
|
const toAppend = [];
|
|
453
462
|
for (const id of selectedLocations) {
|
|
454
463
|
const cluster = clusterIndex.getClusterById(id);
|
|
@@ -473,13 +482,14 @@ export default class FlowmapSelectors<L, F> {
|
|
|
473
482
|
);
|
|
474
483
|
|
|
475
484
|
getDiffMode: Selector<L, F, boolean> = createSelector(
|
|
476
|
-
this.
|
|
485
|
+
this.getFlowsFromProps,
|
|
477
486
|
(flows) => {
|
|
478
|
-
if (
|
|
479
|
-
flows
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
487
|
+
if (flows) {
|
|
488
|
+
for (const f of flows) {
|
|
489
|
+
if (this.accessors.getFlowMagnitude(f) < 0) {
|
|
490
|
+
return true;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
483
493
|
}
|
|
484
494
|
return false;
|
|
485
495
|
},
|
|
@@ -505,27 +515,28 @@ export default class FlowmapSelectors<L, F> {
|
|
|
505
515
|
},
|
|
506
516
|
);
|
|
507
517
|
|
|
508
|
-
getUnknownLocations: Selector<L, F, Set<string> | undefined> =
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
518
|
+
getUnknownLocations: Selector<L, F, Set<string | number> | undefined> =
|
|
519
|
+
createSelector(
|
|
520
|
+
this.getLocationIds,
|
|
521
|
+
this.getFlowsFromProps,
|
|
522
|
+
this.getSortedFlowsForKnownLocations,
|
|
523
|
+
(ids, flows, flowsForKnownLocations) => {
|
|
524
|
+
if (!ids || !flows) return undefined;
|
|
525
|
+
if (
|
|
526
|
+
flowsForKnownLocations
|
|
527
|
+
// && flows.length === flowsForKnownLocations.length
|
|
528
|
+
)
|
|
529
|
+
return undefined;
|
|
530
|
+
const missing = new Set<string | number>();
|
|
531
|
+
for (const flow of flows) {
|
|
532
|
+
if (!ids.has(this.accessors.getFlowOriginId(flow)))
|
|
533
|
+
missing.add(this.accessors.getFlowOriginId(flow));
|
|
534
|
+
if (!ids.has(this.accessors.getFlowDestId(flow)))
|
|
535
|
+
missing.add(this.accessors.getFlowDestId(flow));
|
|
536
|
+
}
|
|
537
|
+
return missing;
|
|
538
|
+
},
|
|
539
|
+
);
|
|
529
540
|
|
|
530
541
|
getSortedAggregatedFilteredFlows: Selector<
|
|
531
542
|
L,
|
|
@@ -566,31 +577,34 @@ export default class FlowmapSelectors<L, F> {
|
|
|
566
577
|
},
|
|
567
578
|
);
|
|
568
579
|
|
|
569
|
-
getExpandedSelectedLocationsSet: Selector<
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
580
|
+
getExpandedSelectedLocationsSet: Selector<
|
|
581
|
+
L,
|
|
582
|
+
F,
|
|
583
|
+
Set<string | number> | undefined
|
|
584
|
+
> = createSelector(
|
|
585
|
+
this.getClusteringEnabled,
|
|
586
|
+
this.getSelectedLocationsSet,
|
|
587
|
+
this.getClusterIndex,
|
|
588
|
+
(clusteringEnabled, selectedLocations, clusterIndex) => {
|
|
589
|
+
if (!selectedLocations || !clusterIndex) {
|
|
590
|
+
return selectedLocations;
|
|
591
|
+
}
|
|
578
592
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
}
|
|
587
|
-
} else {
|
|
588
|
-
result.add(locationId);
|
|
593
|
+
const result = new Set<string | number>();
|
|
594
|
+
for (const locationId of selectedLocations) {
|
|
595
|
+
const cluster = clusterIndex.getClusterById(locationId);
|
|
596
|
+
if (cluster) {
|
|
597
|
+
const expanded = clusterIndex.expandCluster(cluster);
|
|
598
|
+
for (const id of expanded) {
|
|
599
|
+
result.add(id);
|
|
589
600
|
}
|
|
601
|
+
} else {
|
|
602
|
+
result.add(locationId);
|
|
590
603
|
}
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
604
|
+
}
|
|
605
|
+
return result;
|
|
606
|
+
},
|
|
607
|
+
);
|
|
594
608
|
|
|
595
609
|
getTotalCountsByTime: Selector<L, F, CountByTime[] | undefined> =
|
|
596
610
|
createSelector(
|
|
@@ -645,18 +659,10 @@ export default class FlowmapSelectors<L, F> {
|
|
|
645
659
|
createSelector(
|
|
646
660
|
this.getViewport,
|
|
647
661
|
this.getMaxLocationCircleSize,
|
|
648
|
-
|
|
649
|
-
const pad = maxLocationCircleSize;
|
|
650
|
-
const bounds = new WebMercatorViewport({
|
|
651
|
-
...viewport,
|
|
652
|
-
width: viewport.width + pad * 2,
|
|
653
|
-
height: viewport.height + pad * 2,
|
|
654
|
-
}).getBounds();
|
|
655
|
-
return [bounds[0][0], bounds[0][1], bounds[1][0], bounds[1][1]];
|
|
656
|
-
},
|
|
662
|
+
getViewportBoundingBox,
|
|
657
663
|
);
|
|
658
664
|
|
|
659
|
-
getLocationsForZoom: Selector<L, F, L
|
|
665
|
+
getLocationsForZoom: Selector<L, F, Iterable<L> | ClusterNode[] | undefined> =
|
|
660
666
|
createSelector(
|
|
661
667
|
this.getClusteringEnabled,
|
|
662
668
|
this.getLocationsHavingFlows,
|
|
@@ -671,47 +677,50 @@ export default class FlowmapSelectors<L, F> {
|
|
|
671
677
|
},
|
|
672
678
|
);
|
|
673
679
|
|
|
674
|
-
getLocationTotals: Selector<
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
if (d.internalCount != null) rv.internalCount += d.internalCount;
|
|
695
|
-
return rv;
|
|
680
|
+
getLocationTotals: Selector<
|
|
681
|
+
L,
|
|
682
|
+
F,
|
|
683
|
+
Map<string | number, LocationTotals> | undefined
|
|
684
|
+
> = createSelector(
|
|
685
|
+
this.getLocationsForZoom,
|
|
686
|
+
this.getSortedAggregatedFilteredFlows,
|
|
687
|
+
this.getSelectedLocationsSet,
|
|
688
|
+
this.getLocationFilterMode,
|
|
689
|
+
(locations, flows, selectedLocationsSet, locationFilterMode) => {
|
|
690
|
+
if (!flows) return undefined;
|
|
691
|
+
const totals = new Map<string | number, LocationTotals>();
|
|
692
|
+
const add = (
|
|
693
|
+
id: string | number,
|
|
694
|
+
d: Partial<LocationTotals>,
|
|
695
|
+
): LocationTotals => {
|
|
696
|
+
const rv = totals.get(id) ?? {
|
|
697
|
+
incomingCount: 0,
|
|
698
|
+
outgoingCount: 0,
|
|
699
|
+
internalCount: 0,
|
|
696
700
|
};
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
701
|
+
if (d.incomingCount != null) rv.incomingCount += d.incomingCount;
|
|
702
|
+
if (d.outgoingCount != null) rv.outgoingCount += d.outgoingCount;
|
|
703
|
+
if (d.internalCount != null) rv.internalCount += d.internalCount;
|
|
704
|
+
return rv;
|
|
705
|
+
};
|
|
706
|
+
for (const f of flows) {
|
|
707
|
+
if (
|
|
708
|
+
this.isFlowInSelection(f, selectedLocationsSet, locationFilterMode)
|
|
709
|
+
) {
|
|
710
|
+
const originId = this.accessors.getFlowOriginId(f);
|
|
711
|
+
const destId = this.accessors.getFlowDestId(f);
|
|
712
|
+
const count = this.accessors.getFlowMagnitude(f);
|
|
713
|
+
if (originId === destId) {
|
|
714
|
+
totals.set(originId, add(originId, {internalCount: count}));
|
|
715
|
+
} else {
|
|
716
|
+
totals.set(originId, add(originId, {outgoingCount: count}));
|
|
717
|
+
totals.set(destId, add(destId, {incomingCount: count}));
|
|
710
718
|
}
|
|
711
719
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
720
|
+
}
|
|
721
|
+
return totals;
|
|
722
|
+
},
|
|
723
|
+
);
|
|
715
724
|
|
|
716
725
|
getLocationsTree: Selector<L, F, KDBushTree> = createSelector(
|
|
717
726
|
this.getLocationsForZoom,
|
|
@@ -719,14 +728,20 @@ export default class FlowmapSelectors<L, F> {
|
|
|
719
728
|
if (!locations) {
|
|
720
729
|
return undefined;
|
|
721
730
|
}
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
locations
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
731
|
+
const nodes = Array.isArray(locations)
|
|
732
|
+
? locations
|
|
733
|
+
: Array.from(locations);
|
|
734
|
+
const bush = new KDBush(nodes.length, 64, Float32Array);
|
|
735
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
736
|
+
const node = nodes[i];
|
|
737
|
+
bush.add(
|
|
738
|
+
lngX(this.accessors.getLocationLon(node)),
|
|
739
|
+
latY(this.accessors.getLocationLat(node)),
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
bush.finish();
|
|
743
|
+
bush.points = nodes;
|
|
744
|
+
return bush;
|
|
730
745
|
},
|
|
731
746
|
);
|
|
732
747
|
|
|
@@ -745,7 +760,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
745
760
|
},
|
|
746
761
|
);
|
|
747
762
|
|
|
748
|
-
getLocationIdsInViewport: Selector<L, F, Set<string> | undefined> =
|
|
763
|
+
getLocationIdsInViewport: Selector<L, F, Set<string | number> | undefined> =
|
|
749
764
|
createSelectorCreator(
|
|
750
765
|
defaultMemoize,
|
|
751
766
|
// @ts-ignore
|
|
@@ -817,7 +832,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
817
832
|
state: FlowmapState,
|
|
818
833
|
props: FlowmapData<L, F>,
|
|
819
834
|
): [number, number] | undefined => {
|
|
820
|
-
if (state.
|
|
835
|
+
if (state.settings.adaptiveScalesEnabled) {
|
|
821
836
|
return this._getLocationTotalsForViewportExtent(state, props);
|
|
822
837
|
} else {
|
|
823
838
|
return this._getLocationTotalsExtent(state, props);
|
|
@@ -912,7 +927,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
912
927
|
state: FlowmapState,
|
|
913
928
|
props: FlowmapData<L, F>,
|
|
914
929
|
): [number, number] | undefined => {
|
|
915
|
-
if (state.
|
|
930
|
+
if (state.settings.adaptiveScalesEnabled) {
|
|
916
931
|
return this._getAdaptiveFlowMagnitudeExtent(state, props);
|
|
917
932
|
} else {
|
|
918
933
|
return this._getFlowMagnitudeExtent(state, props);
|
|
@@ -935,19 +950,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
935
950
|
|
|
936
951
|
getFlowThicknessScale = createSelector(
|
|
937
952
|
this.getFlowMagnitudeExtent,
|
|
938
|
-
|
|
939
|
-
if (!magnitudeExtent) return undefined;
|
|
940
|
-
return scaleLinear()
|
|
941
|
-
.range([0.025, 0.5])
|
|
942
|
-
.domain([
|
|
943
|
-
0,
|
|
944
|
-
// should support diff mode too
|
|
945
|
-
Math.max.apply(
|
|
946
|
-
null,
|
|
947
|
-
magnitudeExtent.map((x: number | undefined) => Math.abs(x || 0)),
|
|
948
|
-
),
|
|
949
|
-
]);
|
|
950
|
-
},
|
|
953
|
+
getFlowThicknessScale,
|
|
951
954
|
);
|
|
952
955
|
|
|
953
956
|
getCircleSizeScale = createSelector(
|
|
@@ -978,7 +981,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
978
981
|
this.getCircleSizeScale,
|
|
979
982
|
this.getLocationTotals,
|
|
980
983
|
(circleSizeScale, locationTotals) => {
|
|
981
|
-
return (locationId: string) => {
|
|
984
|
+
return (locationId: string | number) => {
|
|
982
985
|
const total = locationTotals?.get(locationId);
|
|
983
986
|
if (total && circleSizeScale) {
|
|
984
987
|
return (
|
|
@@ -996,7 +999,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
996
999
|
this.getCircleSizeScale,
|
|
997
1000
|
this.getLocationTotals,
|
|
998
1001
|
(circleSizeScale, locationTotals) => {
|
|
999
|
-
return (locationId: string) => {
|
|
1002
|
+
return (locationId: string | number) => {
|
|
1000
1003
|
const total = locationTotals?.get(locationId);
|
|
1001
1004
|
if (total && circleSizeScale) {
|
|
1002
1005
|
return (
|
|
@@ -1071,6 +1074,15 @@ export default class FlowmapSelectors<L, F> {
|
|
|
1071
1074
|
);
|
|
1072
1075
|
});
|
|
1073
1076
|
|
|
1077
|
+
getLocationOrClusterByIdGetter = createSelector(
|
|
1078
|
+
this.getClusterIndex,
|
|
1079
|
+
this.getLocationsById,
|
|
1080
|
+
(clusterIndex, locationsById) => {
|
|
1081
|
+
return (id: string | number) =>
|
|
1082
|
+
clusterIndex?.getClusterById(id) ?? locationsById?.get(id);
|
|
1083
|
+
},
|
|
1084
|
+
);
|
|
1085
|
+
|
|
1074
1086
|
getLayersData: Selector<L, F, LayersData> = createSelector(
|
|
1075
1087
|
this.getLocationsForFlowmapLayer,
|
|
1076
1088
|
this.getFlowsForFlowmapLayer,
|
|
@@ -1081,6 +1093,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
1081
1093
|
this.getOutCircleSizeGetter,
|
|
1082
1094
|
this.getFlowThicknessScale,
|
|
1083
1095
|
this.getAnimate,
|
|
1096
|
+
this.getLocationLabelsEnabled,
|
|
1084
1097
|
(
|
|
1085
1098
|
locations,
|
|
1086
1099
|
flows,
|
|
@@ -1091,6 +1104,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
1091
1104
|
getOutCircleSize,
|
|
1092
1105
|
flowThicknessScale,
|
|
1093
1106
|
animationEnabled,
|
|
1107
|
+
locationLabelsEnabled,
|
|
1094
1108
|
) => {
|
|
1095
1109
|
return this._prepareLayersData(
|
|
1096
1110
|
locations,
|
|
@@ -1102,6 +1116,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
1102
1116
|
getOutCircleSize,
|
|
1103
1117
|
flowThicknessScale,
|
|
1104
1118
|
animationEnabled,
|
|
1119
|
+
locationLabelsEnabled,
|
|
1105
1120
|
);
|
|
1106
1121
|
},
|
|
1107
1122
|
);
|
|
@@ -1115,6 +1130,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
1115
1130
|
const getInCircleSize = this.getInCircleSizeGetter(state, props);
|
|
1116
1131
|
const getOutCircleSize = this.getOutCircleSizeGetter(state, props);
|
|
1117
1132
|
const flowThicknessScale = this.getFlowThicknessScale(state, props);
|
|
1133
|
+
const locationLabelsEnabled = this.getLocationLabelsEnabled(state, props);
|
|
1118
1134
|
return this._prepareLayersData(
|
|
1119
1135
|
locations,
|
|
1120
1136
|
flows,
|
|
@@ -1124,7 +1140,8 @@ export default class FlowmapSelectors<L, F> {
|
|
|
1124
1140
|
getInCircleSize,
|
|
1125
1141
|
getOutCircleSize,
|
|
1126
1142
|
flowThicknessScale,
|
|
1127
|
-
state.
|
|
1143
|
+
state.settings.animationEnabled,
|
|
1144
|
+
locationLabelsEnabled,
|
|
1128
1145
|
);
|
|
1129
1146
|
}
|
|
1130
1147
|
|
|
@@ -1132,12 +1149,13 @@ export default class FlowmapSelectors<L, F> {
|
|
|
1132
1149
|
locations: (L | ClusterNode)[] | undefined,
|
|
1133
1150
|
flows: (F | AggregateFlow)[] | undefined,
|
|
1134
1151
|
flowmapColors: DiffColorsRGBA | ColorsRGBA,
|
|
1135
|
-
locationsById: Map<string, L | ClusterNode> | undefined,
|
|
1136
|
-
locationIdsInViewport: Set<string> | undefined,
|
|
1137
|
-
getInCircleSize: (locationId: string) => number,
|
|
1138
|
-
getOutCircleSize: (locationId: string) => number,
|
|
1152
|
+
locationsById: Map<string | number, L | ClusterNode> | undefined,
|
|
1153
|
+
locationIdsInViewport: Set<string | number> | undefined,
|
|
1154
|
+
getInCircleSize: (locationId: string | number) => number,
|
|
1155
|
+
getOutCircleSize: (locationId: string | number) => number,
|
|
1139
1156
|
flowThicknessScale: ScaleLinear<number, number, never> | undefined,
|
|
1140
1157
|
animationEnabled: boolean,
|
|
1158
|
+
locationLabelsEnabled: boolean,
|
|
1141
1159
|
): LayersData {
|
|
1142
1160
|
if (!locations) locations = [];
|
|
1143
1161
|
if (!flows) flows = [];
|
|
@@ -1148,6 +1166,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
1148
1166
|
getLocationId,
|
|
1149
1167
|
getLocationLon,
|
|
1150
1168
|
getLocationLat,
|
|
1169
|
+
getLocationName,
|
|
1151
1170
|
} = this.accessors;
|
|
1152
1171
|
|
|
1153
1172
|
const flowMagnitudeExtent = extent(flows, (f) => getFlowMagnitude(f)) as [
|
|
@@ -1279,6 +1298,9 @@ export default class FlowmapSelectors<L, F> {
|
|
|
1279
1298
|
: {}),
|
|
1280
1299
|
},
|
|
1281
1300
|
},
|
|
1301
|
+
...(locationLabelsEnabled
|
|
1302
|
+
? {locationLabels: locations.map(getLocationName)}
|
|
1303
|
+
: undefined),
|
|
1282
1304
|
};
|
|
1283
1305
|
}
|
|
1284
1306
|
|
|
@@ -1309,8 +1331,8 @@ export default class FlowmapSelectors<L, F> {
|
|
|
1309
1331
|
|
|
1310
1332
|
isFlowInSelection(
|
|
1311
1333
|
flow: F | AggregateFlow,
|
|
1312
|
-
selectedLocationsSet: Set<string> | undefined,
|
|
1313
|
-
locationFilterMode
|
|
1334
|
+
selectedLocationsSet: Set<string | number> | undefined,
|
|
1335
|
+
locationFilterMode?: LocationFilterMode,
|
|
1314
1336
|
) {
|
|
1315
1337
|
const origin = this.accessors.getFlowOriginId(flow);
|
|
1316
1338
|
const dest = this.accessors.getFlowDestId(flow);
|
|
@@ -1356,8 +1378,8 @@ export default class FlowmapSelectors<L, F> {
|
|
|
1356
1378
|
}
|
|
1357
1379
|
|
|
1358
1380
|
function calcLocationTotalsExtent(
|
|
1359
|
-
locationTotals: Map<string, LocationTotals> | undefined,
|
|
1360
|
-
locationIdsInViewport: Set<string> | undefined,
|
|
1381
|
+
locationTotals: Map<string | number, LocationTotals> | undefined,
|
|
1382
|
+
locationIdsInViewport: Set<string | number> | undefined,
|
|
1361
1383
|
) {
|
|
1362
1384
|
if (!locationTotals) return undefined;
|
|
1363
1385
|
let rv: [number, number] | undefined = undefined;
|
|
@@ -1403,10 +1425,9 @@ function aggregateFlows<F>(
|
|
|
1403
1425
|
flowAccessors: FlowAccessors<F>,
|
|
1404
1426
|
): AggregateFlow[] {
|
|
1405
1427
|
// Sum up flows with same origin, dest
|
|
1406
|
-
const byOriginDest =
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
.rollup((ff: F[]) => {
|
|
1428
|
+
const byOriginDest = rollup(
|
|
1429
|
+
flows,
|
|
1430
|
+
(ff: F[]) => {
|
|
1410
1431
|
const origin = flowAccessors.getFlowOriginId(ff[0]);
|
|
1411
1432
|
const dest = flowAccessors.getFlowDestId(ff[0]);
|
|
1412
1433
|
// const color = ff[0].color;
|
|
@@ -1425,11 +1446,14 @@ function aggregateFlows<F>(
|
|
|
1425
1446
|
};
|
|
1426
1447
|
// if (color) rv.color = color;
|
|
1427
1448
|
return rv;
|
|
1428
|
-
}
|
|
1429
|
-
.
|
|
1449
|
+
},
|
|
1450
|
+
flowAccessors.getFlowOriginId,
|
|
1451
|
+
flowAccessors.getFlowDestId,
|
|
1452
|
+
);
|
|
1453
|
+
|
|
1430
1454
|
const rv: AggregateFlow[] = [];
|
|
1431
|
-
for (const
|
|
1432
|
-
for (const
|
|
1455
|
+
for (const values of byOriginDest.values()) {
|
|
1456
|
+
for (const value of values.values()) {
|
|
1433
1457
|
rv.push(value);
|
|
1434
1458
|
}
|
|
1435
1459
|
}
|