@flowmap.gl/data 8.0.0-alpha.1 → 8.0.0-alpha.13
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 +16 -0
- package/dist/FlowmapAggregateAccessors.d.ts.map +1 -0
- package/dist/FlowmapAggregateAccessors.js +46 -0
- package/dist/FlowmapSelectors.d.ts +188 -0
- package/dist/FlowmapSelectors.d.ts.map +1 -0
- package/dist/FlowmapSelectors.js +863 -0
- package/dist/FlowmapState.d.ts +27 -0
- package/dist/FlowmapState.d.ts.map +1 -0
- package/dist/FlowmapState.js +2 -0
- package/dist/cluster/cluster.d.ts.map +1 -1
- package/dist/cluster/cluster.js +8 -5
- package/dist/colors.d.ts +7 -7
- package/dist/colors.d.ts.map +1 -1
- package/dist/colors.js +55 -20
- package/dist/getViewStateForLocations.d.ts +18 -11
- package/dist/getViewStateForLocations.d.ts.map +1 -1
- package/dist/getViewStateForLocations.js +23 -20
- package/dist/index.d.ts +6 -6
- package/dist/index.js +6 -6
- package/dist/provider/FlowmapDataProvider.d.ts +16 -0
- package/dist/provider/FlowmapDataProvider.d.ts.map +1 -0
- package/dist/provider/FlowmapDataProvider.js +17 -0
- package/dist/provider/LocalFlowmapDataProvider.d.ts +20 -0
- package/dist/provider/LocalFlowmapDataProvider.d.ts.map +1 -0
- package/dist/provider/LocalFlowmapDataProvider.js +98 -0
- package/dist/types.d.ts +6 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/util.d.ts +0 -1
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +1 -4
- package/dist-es5/FlowmapAggregateAccessors.d.ts +16 -0
- package/dist-es5/FlowmapAggregateAccessors.d.ts.map +1 -0
- package/dist-es5/FlowmapAggregateAccessors.js +57 -0
- package/{dist/FlowMapSelectors.d.ts → dist-es5/FlowmapSelectors.d.ts} +55 -49
- package/dist-es5/FlowmapSelectors.d.ts.map +1 -0
- package/dist-es5/FlowmapSelectors.js +1507 -0
- package/{dist/FlowMapState.d.ts → dist-es5/FlowmapState.d.ts} +6 -3
- package/dist-es5/FlowmapState.d.ts.map +1 -0
- package/dist-es5/FlowmapState.js +3 -0
- package/dist-es5/cluster/ClusterIndex.d.ts +42 -0
- package/dist-es5/cluster/ClusterIndex.d.ts.map +1 -0
- package/dist-es5/cluster/ClusterIndex.js +297 -0
- package/dist-es5/cluster/cluster.d.ts +31 -0
- package/dist-es5/cluster/cluster.d.ts.map +1 -0
- package/dist-es5/cluster/cluster.js +266 -0
- package/dist-es5/colors.d.ts +103 -0
- package/dist-es5/colors.d.ts.map +1 -0
- package/dist-es5/colors.js +510 -0
- package/dist-es5/getViewStateForLocations.d.ts +23 -0
- package/dist-es5/getViewStateForLocations.d.ts.map +1 -0
- package/dist-es5/getViewStateForLocations.js +64 -0
- package/dist-es5/index.d.ts +11 -0
- package/dist-es5/index.d.ts.map +1 -0
- package/dist-es5/index.js +28 -0
- package/dist-es5/provider/FlowmapDataProvider.d.ts +16 -0
- package/dist-es5/provider/FlowmapDataProvider.d.ts.map +1 -0
- package/dist-es5/provider/FlowmapDataProvider.js +22 -0
- package/dist-es5/provider/LocalFlowmapDataProvider.d.ts +20 -0
- package/dist-es5/provider/LocalFlowmapDataProvider.d.ts.map +1 -0
- package/dist-es5/provider/LocalFlowmapDataProvider.js +154 -0
- package/dist-es5/time.d.ts +24 -0
- package/dist-es5/time.d.ts.map +1 -0
- package/dist-es5/time.js +168 -0
- package/dist-es5/types.d.ts +118 -0
- package/dist-es5/types.d.ts.map +1 -0
- package/dist-es5/types.js +29 -0
- package/dist-es5/util.d.ts +5 -0
- package/dist-es5/util.d.ts.map +1 -0
- package/dist-es5/util.js +14 -0
- package/package.json +7 -5
- package/src/{FlowMapAggregateAccessors.ts → FlowmapAggregateAccessors.ts} +14 -9
- package/src/{FlowMapSelectors.ts → FlowmapSelectors.ts} +213 -178
- package/src/{FlowMapState.ts → FlowmapState.ts} +5 -2
- package/src/cluster/cluster.ts +7 -4
- package/src/colors.ts +65 -21
- package/src/getViewStateForLocations.ts +41 -35
- package/src/index.ts +6 -6
- package/src/provider/{FlowMapDataProvider.ts → FlowmapDataProvider.ts} +14 -12
- package/src/provider/LocalFlowmapDataProvider.ts +122 -0
- package/src/types.ts +6 -4
- package/src/util.ts +0 -4
- package/tsconfig.es5.json +11 -0
- package/dist/FlowMapAggregateAccessors.d.ts +0 -15
- package/dist/FlowMapAggregateAccessors.d.ts.map +0 -1
- package/dist/FlowMapAggregateAccessors.js +0 -43
- package/dist/FlowMapSelectors.d.ts.map +0 -1
- package/dist/FlowMapSelectors.js +0 -834
- package/dist/FlowMapState.d.ts.map +0 -1
- package/dist/FlowMapState.js +0 -2
- package/dist/provider/FlowMapDataProvider.d.ts +0 -16
- package/dist/provider/FlowMapDataProvider.d.ts.map +0 -1
- package/dist/provider/FlowMapDataProvider.js +0 -17
- package/dist/provider/LocalFlowMapDataProvider.d.ts +0 -20
- package/dist/provider/LocalFlowMapDataProvider.d.ts.map +0 -1
- package/dist/provider/LocalFlowMapDataProvider.js +0 -87
- package/src/provider/LocalFlowMapDataProvider.ts +0 -105
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import {
|
|
19
|
+
import {WebMercatorViewport} from '@math.gl/web-mercator';
|
|
20
20
|
import {ascending, descending, extent, min} from 'd3-array';
|
|
21
21
|
import {nest} from 'd3-collection';
|
|
22
22
|
import {ScaleLinear, scaleLinear, scaleSqrt} from 'd3-scale';
|
|
@@ -44,8 +44,8 @@ import getColors, {
|
|
|
44
44
|
isDiffColors,
|
|
45
45
|
isDiffColorsRGBA,
|
|
46
46
|
} from './colors';
|
|
47
|
-
import
|
|
48
|
-
import {
|
|
47
|
+
import FlowmapAggregateAccessors from './FlowmapAggregateAccessors';
|
|
48
|
+
import {FlowmapState} from './FlowmapState';
|
|
49
49
|
import {
|
|
50
50
|
getTimeGranularityByKey,
|
|
51
51
|
getTimeGranularityByOrder,
|
|
@@ -60,80 +60,85 @@ import {
|
|
|
60
60
|
FlowAccessors,
|
|
61
61
|
FlowCirclesLayerAttributes,
|
|
62
62
|
FlowLinesLayerAttributes,
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
FlowmapData,
|
|
64
|
+
FlowmapDataAccessors,
|
|
65
65
|
isCluster,
|
|
66
66
|
isLocationClusterNode,
|
|
67
67
|
LayersData,
|
|
68
68
|
LocationFilterMode,
|
|
69
69
|
LocationTotals,
|
|
70
70
|
} from './types';
|
|
71
|
-
import {flatMap} from './util';
|
|
72
71
|
|
|
73
72
|
const MAX_CLUSTER_ZOOM_LEVEL = 20;
|
|
74
|
-
const NUMBER_OF_FLOWS_TO_DISPLAY = 5000;
|
|
75
73
|
type KDBushTree = any;
|
|
76
74
|
|
|
77
75
|
export type Selector<L, F, T> = ParametricSelector<
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
FlowmapState,
|
|
77
|
+
FlowmapData<L, F>,
|
|
80
78
|
T
|
|
81
79
|
>;
|
|
82
80
|
|
|
83
|
-
export default class
|
|
84
|
-
accessors:
|
|
81
|
+
export default class FlowmapSelectors<L, F> {
|
|
82
|
+
accessors: FlowmapAggregateAccessors<L, F>;
|
|
85
83
|
|
|
86
|
-
constructor(accessors:
|
|
87
|
-
this.accessors = new
|
|
84
|
+
constructor(accessors: FlowmapDataAccessors<L, F>) {
|
|
85
|
+
this.accessors = new FlowmapAggregateAccessors(accessors);
|
|
88
86
|
this.setAccessors(accessors);
|
|
89
87
|
}
|
|
90
88
|
|
|
91
|
-
setAccessors(accessors:
|
|
92
|
-
this.accessors = new
|
|
89
|
+
setAccessors(accessors: FlowmapDataAccessors<L, F>) {
|
|
90
|
+
this.accessors = new FlowmapAggregateAccessors(accessors);
|
|
93
91
|
}
|
|
94
92
|
|
|
95
|
-
getFetchedFlows = (state:
|
|
93
|
+
getFetchedFlows = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
96
94
|
props.flows;
|
|
97
|
-
getFetchedLocations = (state:
|
|
95
|
+
getFetchedLocations = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
98
96
|
props.locations;
|
|
99
|
-
|
|
97
|
+
getMaxTopFlowsDisplayNum = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
98
|
+
state.settingsState.maxTopFlowsDisplayNum;
|
|
99
|
+
getSelectedLocations = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
100
100
|
state.filterState.selectedLocations;
|
|
101
|
-
getLocationFilterMode = (state:
|
|
101
|
+
getLocationFilterMode = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
102
102
|
state.filterState.locationFilterMode;
|
|
103
|
-
getClusteringEnabled = (state:
|
|
103
|
+
getClusteringEnabled = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
104
104
|
state.settingsState.clusteringEnabled;
|
|
105
|
-
getLocationTotalsEnabled = (state:
|
|
105
|
+
getLocationTotalsEnabled = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
106
106
|
state.settingsState.locationTotalsEnabled;
|
|
107
|
-
getZoom = (state:
|
|
107
|
+
getZoom = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
108
108
|
state.viewport.zoom;
|
|
109
|
-
getViewport = (state:
|
|
109
|
+
getViewport = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
110
110
|
state.viewport;
|
|
111
|
-
getSelectedTimeRange = (state:
|
|
111
|
+
getSelectedTimeRange = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
112
112
|
state.filterState.selectedTimeRange;
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
state:
|
|
116
|
-
props:
|
|
114
|
+
getColorScheme: Selector<L, F, string | string[] | undefined> = (
|
|
115
|
+
state: FlowmapState,
|
|
116
|
+
props: FlowmapData<L, F>,
|
|
117
117
|
) => state.settingsState.colorScheme;
|
|
118
118
|
|
|
119
119
|
getDarkMode: Selector<L, F, boolean> = (
|
|
120
|
-
state:
|
|
121
|
-
props:
|
|
120
|
+
state: FlowmapState,
|
|
121
|
+
props: FlowmapData<L, F>,
|
|
122
122
|
) => state.settingsState.darkMode;
|
|
123
123
|
|
|
124
124
|
getFadeEnabled: Selector<L, F, boolean> = (
|
|
125
|
-
state:
|
|
126
|
-
props:
|
|
125
|
+
state: FlowmapState,
|
|
126
|
+
props: FlowmapData<L, F>,
|
|
127
127
|
) => state.settingsState.fadeEnabled;
|
|
128
128
|
|
|
129
|
+
getFadeOpacityEnabled: Selector<L, F, boolean> = (
|
|
130
|
+
state: FlowmapState,
|
|
131
|
+
props: FlowmapData<L, F>,
|
|
132
|
+
) => state.settingsState.fadeOpacityEnabled;
|
|
133
|
+
|
|
129
134
|
getFadeAmount: Selector<L, F, number> = (
|
|
130
|
-
state:
|
|
131
|
-
props:
|
|
135
|
+
state: FlowmapState,
|
|
136
|
+
props: FlowmapData<L, F>,
|
|
132
137
|
) => state.settingsState.fadeAmount;
|
|
133
138
|
|
|
134
139
|
getAnimate: Selector<L, F, boolean> = (
|
|
135
|
-
state:
|
|
136
|
-
props:
|
|
140
|
+
state: FlowmapState,
|
|
141
|
+
props: FlowmapData<L, F>,
|
|
137
142
|
) => state.settingsState.animationEnabled;
|
|
138
143
|
|
|
139
144
|
getInvalidLocationIds: Selector<L, F, string[] | undefined> = createSelector(
|
|
@@ -143,10 +148,8 @@ export default class FlowMapSelectors<L, F> {
|
|
|
143
148
|
const invalid = [];
|
|
144
149
|
for (const location of locations) {
|
|
145
150
|
const id = this.accessors.getLocationId(location);
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
NaN,
|
|
149
|
-
];
|
|
151
|
+
const lon = this.accessors.getLocationLon(location);
|
|
152
|
+
const lat = this.accessors.getLocationLat(location);
|
|
150
153
|
if (!(-90 <= lat && lat <= 90) || !(-180 <= lon && lon <= 180)) {
|
|
151
154
|
invalid.push(id);
|
|
152
155
|
}
|
|
@@ -304,11 +307,11 @@ export default class FlowMapSelectors<L, F> {
|
|
|
304
307
|
|
|
305
308
|
const getLocationWeight = makeLocationWeightGetter(
|
|
306
309
|
flows,
|
|
307
|
-
this.accessors.
|
|
310
|
+
this.accessors.getFlowmapDataAccessors(),
|
|
308
311
|
);
|
|
309
312
|
const clusterLevels = clusterLocations(
|
|
310
313
|
locations,
|
|
311
|
-
this.accessors.
|
|
314
|
+
this.accessors.getFlowmapDataAccessors(),
|
|
312
315
|
getLocationWeight,
|
|
313
316
|
{
|
|
314
317
|
maxZoom: MAX_CLUSTER_ZOOM_LEVEL,
|
|
@@ -316,7 +319,7 @@ export default class FlowMapSelectors<L, F> {
|
|
|
316
319
|
);
|
|
317
320
|
const clusterIndex = buildIndex<F>(clusterLevels);
|
|
318
321
|
const {getLocationName, getLocationClusterName} =
|
|
319
|
-
this.accessors.
|
|
322
|
+
this.accessors.getFlowmapDataAccessors();
|
|
320
323
|
|
|
321
324
|
// Adding meaningful names
|
|
322
325
|
const getName = (id: string) => {
|
|
@@ -411,7 +414,7 @@ export default class FlowMapSelectors<L, F> {
|
|
|
411
414
|
},
|
|
412
415
|
);
|
|
413
416
|
|
|
414
|
-
getClusterZoom = (state:
|
|
417
|
+
getClusterZoom = (state: FlowmapState, props: FlowmapData<L, F>) => {
|
|
415
418
|
const {settingsState} = state;
|
|
416
419
|
if (!settingsState.clusteringEnabled) return undefined;
|
|
417
420
|
if (settingsState.clusteringAuto || settingsState.clusteringLevel == null) {
|
|
@@ -482,22 +485,23 @@ export default class FlowMapSelectors<L, F> {
|
|
|
482
485
|
},
|
|
483
486
|
);
|
|
484
487
|
|
|
485
|
-
|
|
488
|
+
_getFlowmapColors = createSelector(
|
|
486
489
|
this.getDiffMode,
|
|
487
|
-
this.
|
|
490
|
+
this.getColorScheme,
|
|
488
491
|
this.getDarkMode,
|
|
489
492
|
this.getFadeEnabled,
|
|
493
|
+
this.getFadeOpacityEnabled,
|
|
490
494
|
this.getFadeAmount,
|
|
491
495
|
this.getAnimate,
|
|
492
496
|
getColors,
|
|
493
497
|
);
|
|
494
498
|
|
|
495
|
-
|
|
496
|
-
this.
|
|
497
|
-
(
|
|
498
|
-
return isDiffColors(
|
|
499
|
-
? getDiffColorsRGBA(
|
|
500
|
-
: getColorsRGBA(
|
|
499
|
+
getFlowmapColorsRGBA = createSelector(
|
|
500
|
+
this._getFlowmapColors,
|
|
501
|
+
(flowmapColors) => {
|
|
502
|
+
return isDiffColors(flowmapColors)
|
|
503
|
+
? getDiffColorsRGBA(flowmapColors)
|
|
504
|
+
: getColorsRGBA(flowmapColors);
|
|
501
505
|
},
|
|
502
506
|
);
|
|
503
507
|
|
|
@@ -544,12 +548,12 @@ export default class FlowMapSelectors<L, F> {
|
|
|
544
548
|
// : flows,
|
|
545
549
|
flows,
|
|
546
550
|
clusterZoom,
|
|
547
|
-
this.accessors.
|
|
551
|
+
this.accessors.getFlowmapDataAccessors(),
|
|
548
552
|
);
|
|
549
553
|
} else {
|
|
550
554
|
aggregated = aggregateFlows(
|
|
551
555
|
flows,
|
|
552
|
-
this.accessors.
|
|
556
|
+
this.accessors.getFlowmapDataAccessors(),
|
|
553
557
|
);
|
|
554
558
|
}
|
|
555
559
|
aggregated.sort((a, b) =>
|
|
@@ -562,33 +566,6 @@ export default class FlowMapSelectors<L, F> {
|
|
|
562
566
|
},
|
|
563
567
|
);
|
|
564
568
|
|
|
565
|
-
getFlowMagnitudeExtent: Selector<L, F, [number, number] | undefined> =
|
|
566
|
-
createSelector(
|
|
567
|
-
this.getSortedAggregatedFilteredFlows,
|
|
568
|
-
this.getSelectedLocationsSet,
|
|
569
|
-
this.getLocationFilterMode,
|
|
570
|
-
(flows, selectedLocationsSet, locationFilterMode) => {
|
|
571
|
-
if (!flows) return undefined;
|
|
572
|
-
let rv: [number, number] | undefined = undefined;
|
|
573
|
-
for (const f of flows) {
|
|
574
|
-
if (
|
|
575
|
-
this.accessors.getFlowOriginId(f) !==
|
|
576
|
-
this.accessors.getFlowDestId(f) &&
|
|
577
|
-
this.isFlowInSelection(f, selectedLocationsSet, locationFilterMode)
|
|
578
|
-
) {
|
|
579
|
-
const count = this.accessors.getFlowMagnitude(f);
|
|
580
|
-
if (rv == null) {
|
|
581
|
-
rv = [count, count];
|
|
582
|
-
} else {
|
|
583
|
-
if (count < rv[0]) rv[0] = count;
|
|
584
|
-
if (count > rv[1]) rv[1] = count;
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
return rv;
|
|
589
|
-
},
|
|
590
|
-
);
|
|
591
|
-
|
|
592
569
|
getExpandedSelectedLocationsSet: Selector<L, F, Set<string> | undefined> =
|
|
593
570
|
createSelector(
|
|
594
571
|
this.getClusteringEnabled,
|
|
@@ -670,12 +647,12 @@ export default class FlowMapSelectors<L, F> {
|
|
|
670
647
|
this.getMaxLocationCircleSize,
|
|
671
648
|
(viewport, maxLocationCircleSize) => {
|
|
672
649
|
const pad = maxLocationCircleSize;
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
viewport.
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
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]];
|
|
679
656
|
},
|
|
680
657
|
);
|
|
681
658
|
|
|
@@ -746,17 +723,9 @@ export default class FlowMapSelectors<L, F> {
|
|
|
746
723
|
// @ts-ignore
|
|
747
724
|
locations,
|
|
748
725
|
(location: L | ClusterNode) =>
|
|
749
|
-
lngX(
|
|
750
|
-
isLocationClusterNode(location)
|
|
751
|
-
? location.centroid[0]
|
|
752
|
-
: this.accessors.getLocationCentroid(location)[0],
|
|
753
|
-
),
|
|
726
|
+
lngX(this.accessors.getLocationLon(location)),
|
|
754
727
|
(location: L | ClusterNode) =>
|
|
755
|
-
latY(
|
|
756
|
-
isLocationClusterNode(location)
|
|
757
|
-
? location.centroid[1]
|
|
758
|
-
: this.accessors.getLocationCentroid(location)[1],
|
|
759
|
-
),
|
|
728
|
+
latY(this.accessors.getLocationLat(location)),
|
|
760
729
|
);
|
|
761
730
|
},
|
|
762
731
|
);
|
|
@@ -845,8 +814,8 @@ export default class FlowMapSelectors<L, F> {
|
|
|
845
814
|
);
|
|
846
815
|
|
|
847
816
|
getLocationTotalsExtent = (
|
|
848
|
-
state:
|
|
849
|
-
props:
|
|
817
|
+
state: FlowmapState,
|
|
818
|
+
props: FlowmapData<L, F>,
|
|
850
819
|
): [number, number] | undefined => {
|
|
851
820
|
if (state.settingsState.adaptiveScalesEnabled) {
|
|
852
821
|
return this._getLocationTotalsForViewportExtent(state, props);
|
|
@@ -855,17 +824,19 @@ export default class FlowMapSelectors<L, F> {
|
|
|
855
824
|
}
|
|
856
825
|
};
|
|
857
826
|
|
|
858
|
-
|
|
827
|
+
getFlowsForFlowmapLayer: Selector<L, F, (F | AggregateFlow)[] | undefined> =
|
|
859
828
|
createSelector(
|
|
860
829
|
this.getSortedAggregatedFilteredFlows,
|
|
861
830
|
this.getLocationIdsInViewport,
|
|
862
831
|
this.getSelectedLocationsSet,
|
|
863
832
|
this.getLocationFilterMode,
|
|
833
|
+
this.getMaxTopFlowsDisplayNum,
|
|
864
834
|
(
|
|
865
835
|
flows,
|
|
866
836
|
locationIdsInViewport,
|
|
867
837
|
selectedLocationsSet,
|
|
868
838
|
locationFilterMode,
|
|
839
|
+
maxTopFlowsDisplayNum,
|
|
869
840
|
) => {
|
|
870
841
|
if (!flows || !locationIdsInViewport) return undefined;
|
|
871
842
|
const picked: (F | AggregateFlow)[] = [];
|
|
@@ -892,7 +863,7 @@ export default class FlowMapSelectors<L, F> {
|
|
|
892
863
|
}
|
|
893
864
|
}
|
|
894
865
|
// Only keep top
|
|
895
|
-
if (pickedCount >
|
|
866
|
+
if (pickedCount > maxTopFlowsDisplayNum) break;
|
|
896
867
|
}
|
|
897
868
|
// assuming they are sorted in descending order,
|
|
898
869
|
// we need ascending for rendering
|
|
@@ -900,20 +871,51 @@ export default class FlowMapSelectors<L, F> {
|
|
|
900
871
|
},
|
|
901
872
|
);
|
|
902
873
|
|
|
903
|
-
_getFlowMagnitudeExtent =
|
|
904
|
-
|
|
905
|
-
|
|
874
|
+
_getFlowMagnitudeExtent: Selector<L, F, [number, number] | undefined> =
|
|
875
|
+
createSelector(
|
|
876
|
+
this.getSortedAggregatedFilteredFlows,
|
|
877
|
+
this.getSelectedLocationsSet,
|
|
878
|
+
this.getLocationFilterMode,
|
|
879
|
+
(flows, selectedLocationsSet, locationFilterMode) => {
|
|
880
|
+
if (!flows) return undefined;
|
|
881
|
+
let rv: [number, number] | undefined = undefined;
|
|
882
|
+
for (const f of flows) {
|
|
883
|
+
if (
|
|
884
|
+
this.accessors.getFlowOriginId(f) !==
|
|
885
|
+
this.accessors.getFlowDestId(f) &&
|
|
886
|
+
this.isFlowInSelection(f, selectedLocationsSet, locationFilterMode)
|
|
887
|
+
) {
|
|
888
|
+
const count = this.accessors.getFlowMagnitude(f);
|
|
889
|
+
if (rv == null) {
|
|
890
|
+
rv = [count, count];
|
|
891
|
+
} else {
|
|
892
|
+
if (count < rv[0]) rv[0] = count;
|
|
893
|
+
if (count > rv[1]) rv[1] = count;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
return rv;
|
|
898
|
+
},
|
|
899
|
+
);
|
|
900
|
+
|
|
901
|
+
_getAdaptiveFlowMagnitudeExtent: Selector<
|
|
902
|
+
L,
|
|
903
|
+
F,
|
|
904
|
+
[number, number] | undefined
|
|
905
|
+
> = createSelector(this.getFlowsForFlowmapLayer, (flows) => {
|
|
906
|
+
if (!flows) return undefined;
|
|
907
|
+
const rv = extent(flows, this.accessors.getFlowMagnitude);
|
|
908
|
+
return rv[0] !== undefined && rv[1] !== undefined ? rv : undefined;
|
|
909
|
+
});
|
|
910
|
+
|
|
911
|
+
getFlowMagnitudeExtent = (
|
|
912
|
+
state: FlowmapState,
|
|
913
|
+
props: FlowmapData<L, F>,
|
|
906
914
|
): [number, number] | undefined => {
|
|
907
915
|
if (state.settingsState.adaptiveScalesEnabled) {
|
|
908
|
-
|
|
909
|
-
if (flows) {
|
|
910
|
-
const rv = extent(flows, this.accessors.getFlowMagnitude);
|
|
911
|
-
return rv[0] !== undefined && rv[1] !== undefined ? rv : undefined;
|
|
912
|
-
} else {
|
|
913
|
-
return undefined;
|
|
914
|
-
}
|
|
916
|
+
return this._getAdaptiveFlowMagnitudeExtent(state, props);
|
|
915
917
|
} else {
|
|
916
|
-
return this.
|
|
918
|
+
return this._getFlowMagnitudeExtent(state, props);
|
|
917
919
|
}
|
|
918
920
|
};
|
|
919
921
|
|
|
@@ -1027,7 +1029,7 @@ export default class FlowMapSelectors<L, F> {
|
|
|
1027
1029
|
},
|
|
1028
1030
|
);
|
|
1029
1031
|
|
|
1030
|
-
|
|
1032
|
+
getLocationsForFlowmapLayer: Selector<
|
|
1031
1033
|
L,
|
|
1032
1034
|
F,
|
|
1033
1035
|
Array<L | ClusterNode> | undefined
|
|
@@ -1057,11 +1059,11 @@ export default class FlowMapSelectors<L, F> {
|
|
|
1057
1059
|
},
|
|
1058
1060
|
);
|
|
1059
1061
|
|
|
1060
|
-
|
|
1062
|
+
getLocationsForFlowmapLayerById: Selector<
|
|
1061
1063
|
L,
|
|
1062
1064
|
F,
|
|
1063
1065
|
Map<string, L | ClusterNode> | undefined
|
|
1064
|
-
> = createSelector(this.
|
|
1066
|
+
> = createSelector(this.getLocationsForFlowmapLayer, (locations) => {
|
|
1065
1067
|
if (!locations) return undefined;
|
|
1066
1068
|
return locations.reduce(
|
|
1067
1069
|
(m, d) => (m.set(this.accessors.getLocationId(d), d), m),
|
|
@@ -1070,10 +1072,10 @@ export default class FlowMapSelectors<L, F> {
|
|
|
1070
1072
|
});
|
|
1071
1073
|
|
|
1072
1074
|
getLayersData: Selector<L, F, LayersData> = createSelector(
|
|
1073
|
-
this.
|
|
1074
|
-
this.
|
|
1075
|
-
this.
|
|
1076
|
-
this.
|
|
1075
|
+
this.getLocationsForFlowmapLayer,
|
|
1076
|
+
this.getFlowsForFlowmapLayer,
|
|
1077
|
+
this.getFlowmapColorsRGBA,
|
|
1078
|
+
this.getLocationsForFlowmapLayerById,
|
|
1077
1079
|
this.getLocationIdsInViewport,
|
|
1078
1080
|
this.getInCircleSizeGetter,
|
|
1079
1081
|
this.getOutCircleSizeGetter,
|
|
@@ -1082,7 +1084,7 @@ export default class FlowMapSelectors<L, F> {
|
|
|
1082
1084
|
(
|
|
1083
1085
|
locations,
|
|
1084
1086
|
flows,
|
|
1085
|
-
|
|
1087
|
+
flowmapColors,
|
|
1086
1088
|
locationsById,
|
|
1087
1089
|
locationIdsInViewport,
|
|
1088
1090
|
getInCircleSize,
|
|
@@ -1093,7 +1095,7 @@ export default class FlowMapSelectors<L, F> {
|
|
|
1093
1095
|
return this._prepareLayersData(
|
|
1094
1096
|
locations,
|
|
1095
1097
|
flows,
|
|
1096
|
-
|
|
1098
|
+
flowmapColors,
|
|
1097
1099
|
locationsById,
|
|
1098
1100
|
locationIdsInViewport,
|
|
1099
1101
|
getInCircleSize,
|
|
@@ -1104,11 +1106,11 @@ export default class FlowMapSelectors<L, F> {
|
|
|
1104
1106
|
},
|
|
1105
1107
|
);
|
|
1106
1108
|
|
|
1107
|
-
prepareLayersData(state:
|
|
1108
|
-
const locations = this.
|
|
1109
|
-
const flows = this.
|
|
1110
|
-
const
|
|
1111
|
-
const locationsById = this.
|
|
1109
|
+
prepareLayersData(state: FlowmapState, props: FlowmapData<L, F>): LayersData {
|
|
1110
|
+
const locations = this.getLocationsForFlowmapLayer(state, props) || [];
|
|
1111
|
+
const flows = this.getFlowsForFlowmapLayer(state, props) || [];
|
|
1112
|
+
const flowmapColors = this.getFlowmapColorsRGBA(state, props);
|
|
1113
|
+
const locationsById = this.getLocationsForFlowmapLayerById(state, props);
|
|
1112
1114
|
const locationIdsInViewport = this.getLocationIdsInViewport(state, props);
|
|
1113
1115
|
const getInCircleSize = this.getInCircleSizeGetter(state, props);
|
|
1114
1116
|
const getOutCircleSize = this.getOutCircleSizeGetter(state, props);
|
|
@@ -1116,7 +1118,7 @@ export default class FlowMapSelectors<L, F> {
|
|
|
1116
1118
|
return this._prepareLayersData(
|
|
1117
1119
|
locations,
|
|
1118
1120
|
flows,
|
|
1119
|
-
|
|
1121
|
+
flowmapColors,
|
|
1120
1122
|
locationsById,
|
|
1121
1123
|
locationIdsInViewport,
|
|
1122
1124
|
getInCircleSize,
|
|
@@ -1129,7 +1131,7 @@ export default class FlowMapSelectors<L, F> {
|
|
|
1129
1131
|
_prepareLayersData(
|
|
1130
1132
|
locations: (L | ClusterNode)[] | undefined,
|
|
1131
1133
|
flows: (F | AggregateFlow)[] | undefined,
|
|
1132
|
-
|
|
1134
|
+
flowmapColors: DiffColorsRGBA | ColorsRGBA,
|
|
1133
1135
|
locationsById: Map<string, L | ClusterNode> | undefined,
|
|
1134
1136
|
locationIdsInViewport: Set<string> | undefined,
|
|
1135
1137
|
getInCircleSize: (locationId: string) => number,
|
|
@@ -1144,80 +1146,113 @@ export default class FlowMapSelectors<L, F> {
|
|
|
1144
1146
|
getFlowDestId,
|
|
1145
1147
|
getFlowMagnitude,
|
|
1146
1148
|
getLocationId,
|
|
1147
|
-
|
|
1149
|
+
getLocationLon,
|
|
1150
|
+
getLocationLat,
|
|
1148
1151
|
} = this.accessors;
|
|
1149
1152
|
|
|
1150
|
-
const getCentroid = (id: string) => {
|
|
1151
|
-
const loc = locationsById?.get(id);
|
|
1152
|
-
return loc ? getLocationCentroid(loc) : [0, 0];
|
|
1153
|
-
};
|
|
1154
|
-
|
|
1155
1153
|
const flowMagnitudeExtent = extent(flows, (f) => getFlowMagnitude(f)) as [
|
|
1156
1154
|
number,
|
|
1157
1155
|
number,
|
|
1158
1156
|
];
|
|
1159
1157
|
const flowColorScale = getFlowColorScale(
|
|
1160
|
-
|
|
1158
|
+
flowmapColors,
|
|
1161
1159
|
flowMagnitudeExtent,
|
|
1162
1160
|
false,
|
|
1163
1161
|
);
|
|
1164
1162
|
|
|
1165
|
-
|
|
1166
|
-
|
|
1163
|
+
// Using a generator here helps to avoid creating intermediary arrays
|
|
1164
|
+
const circlePositions = Float32Array.from(
|
|
1165
|
+
(function* () {
|
|
1166
|
+
for (const location of locations) {
|
|
1167
|
+
yield getLocationLon(location);
|
|
1168
|
+
yield getLocationLat(location);
|
|
1169
|
+
}
|
|
1170
|
+
})(),
|
|
1167
1171
|
);
|
|
1168
1172
|
|
|
1169
1173
|
// TODO: diff mode
|
|
1170
|
-
const circleColor = isDiffColorsRGBA(
|
|
1171
|
-
?
|
|
1172
|
-
:
|
|
1173
|
-
|
|
1174
|
-
const circleColors =
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
}),
|
|
1174
|
+
const circleColor = isDiffColorsRGBA(flowmapColors)
|
|
1175
|
+
? flowmapColors.positive.locationCircles.inner
|
|
1176
|
+
: flowmapColors.locationCircles.inner;
|
|
1177
|
+
|
|
1178
|
+
const circleColors = Uint8Array.from(
|
|
1179
|
+
(function* () {
|
|
1180
|
+
for (const location of locations) {
|
|
1181
|
+
yield* circleColor;
|
|
1182
|
+
}
|
|
1183
|
+
})(),
|
|
1180
1184
|
);
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1185
|
+
|
|
1186
|
+
const inCircleRadii = Float32Array.from(
|
|
1187
|
+
(function* () {
|
|
1188
|
+
for (const location of locations) {
|
|
1189
|
+
const id = getLocationId(location);
|
|
1190
|
+
yield locationIdsInViewport?.has(id) ? getInCircleSize(id) : 1.0;
|
|
1191
|
+
}
|
|
1192
|
+
})(),
|
|
1193
|
+
);
|
|
1194
|
+
const outCircleRadii = Float32Array.from(
|
|
1195
|
+
(function* () {
|
|
1196
|
+
for (const location of locations) {
|
|
1197
|
+
const id = getLocationId(location);
|
|
1198
|
+
yield locationIdsInViewport?.has(id) ? getOutCircleSize(id) : 1.0;
|
|
1199
|
+
}
|
|
1200
|
+
})(),
|
|
1186
1201
|
);
|
|
1187
1202
|
|
|
1188
|
-
const sourcePositions =
|
|
1189
|
-
|
|
1203
|
+
const sourcePositions = Float32Array.from(
|
|
1204
|
+
(function* () {
|
|
1205
|
+
for (const flow of flows) {
|
|
1206
|
+
const loc = locationsById?.get(getFlowOriginId(flow));
|
|
1207
|
+
yield loc ? getLocationLon(loc) : 0;
|
|
1208
|
+
yield loc ? getLocationLat(loc) : 0;
|
|
1209
|
+
}
|
|
1210
|
+
})(),
|
|
1190
1211
|
);
|
|
1191
|
-
const targetPositions =
|
|
1192
|
-
|
|
1212
|
+
const targetPositions = Float32Array.from(
|
|
1213
|
+
(function* () {
|
|
1214
|
+
for (const flow of flows) {
|
|
1215
|
+
const loc = locationsById?.get(getFlowDestId(flow));
|
|
1216
|
+
yield loc ? getLocationLon(loc) : 0;
|
|
1217
|
+
yield loc ? getLocationLat(loc) : 0;
|
|
1218
|
+
}
|
|
1219
|
+
})(),
|
|
1193
1220
|
);
|
|
1194
|
-
const thicknesses =
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1221
|
+
const thicknesses = Float32Array.from(
|
|
1222
|
+
(function* () {
|
|
1223
|
+
for (const flow of flows) {
|
|
1224
|
+
yield flowThicknessScale
|
|
1225
|
+
? flowThicknessScale(getFlowMagnitude(flow)) || 0
|
|
1226
|
+
: 0;
|
|
1227
|
+
}
|
|
1228
|
+
})(),
|
|
1198
1229
|
);
|
|
1199
|
-
const endpointOffsets =
|
|
1200
|
-
|
|
1201
|
-
const
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
Math.max(getInCircleSize(originId), getOutCircleSize(originId))
|
|
1205
|
-
Math.max(getInCircleSize(destId), getOutCircleSize(destId))
|
|
1206
|
-
|
|
1207
|
-
}),
|
|
1230
|
+
const endpointOffsets = Float32Array.from(
|
|
1231
|
+
(function* () {
|
|
1232
|
+
for (const flow of flows) {
|
|
1233
|
+
const originId = getFlowOriginId(flow);
|
|
1234
|
+
const destId = getFlowDestId(flow);
|
|
1235
|
+
yield Math.max(getInCircleSize(originId), getOutCircleSize(originId));
|
|
1236
|
+
yield Math.max(getInCircleSize(destId), getOutCircleSize(destId));
|
|
1237
|
+
}
|
|
1238
|
+
})(),
|
|
1208
1239
|
);
|
|
1209
|
-
const flowLineColors =
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1240
|
+
const flowLineColors = Uint8Array.from(
|
|
1241
|
+
(function* () {
|
|
1242
|
+
for (const flow of flows) {
|
|
1243
|
+
yield* flowColorScale(getFlowMagnitude(flow));
|
|
1244
|
+
}
|
|
1245
|
+
})(),
|
|
1213
1246
|
);
|
|
1214
1247
|
|
|
1215
1248
|
const staggeringValues = animationEnabled
|
|
1216
|
-
?
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1249
|
+
? Float32Array.from(
|
|
1250
|
+
(function* () {
|
|
1251
|
+
for (const f of flows) {
|
|
1252
|
+
// @ts-ignore
|
|
1253
|
+
yield new alea(`${getFlowOriginId(f)}-${getFlowDestId(f)}`)();
|
|
1254
|
+
}
|
|
1255
|
+
})(),
|
|
1221
1256
|
)
|
|
1222
1257
|
: undefined;
|
|
1223
1258
|
|
|
@@ -1414,7 +1449,7 @@ export function getOuterCircleRadiusByIndex(
|
|
|
1414
1449
|
return Math.max(getInRadius.value[index], getOutRadius.value[index]);
|
|
1415
1450
|
}
|
|
1416
1451
|
|
|
1417
|
-
export function
|
|
1452
|
+
export function getLocationCoordsByIndex(
|
|
1418
1453
|
circleAttributes: FlowCirclesLayerAttributes,
|
|
1419
1454
|
index: number,
|
|
1420
1455
|
): [number, number] {
|
|
@@ -9,6 +9,7 @@ export interface FilterState {
|
|
|
9
9
|
export interface SettingsState {
|
|
10
10
|
animationEnabled: boolean;
|
|
11
11
|
fadeEnabled: boolean;
|
|
12
|
+
fadeOpacityEnabled: boolean;
|
|
12
13
|
locationTotalsEnabled: boolean;
|
|
13
14
|
adaptiveScalesEnabled: boolean;
|
|
14
15
|
clusteringEnabled: boolean;
|
|
@@ -16,10 +17,12 @@ export interface SettingsState {
|
|
|
16
17
|
clusteringLevel?: number;
|
|
17
18
|
darkMode: boolean;
|
|
18
19
|
fadeAmount: number;
|
|
19
|
-
colorScheme: string | undefined;
|
|
20
|
+
colorScheme: string | string[] | undefined;
|
|
21
|
+
highlightColor: string;
|
|
22
|
+
maxTopFlowsDisplayNum: number;
|
|
20
23
|
}
|
|
21
24
|
|
|
22
|
-
export interface
|
|
25
|
+
export interface FlowmapState {
|
|
23
26
|
filterState: FilterState;
|
|
24
27
|
settingsState: SettingsState;
|
|
25
28
|
viewport: ViewportProps;
|