@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.
Files changed (97) hide show
  1. package/dist/FlowmapAggregateAccessors.d.ts +16 -0
  2. package/dist/FlowmapAggregateAccessors.d.ts.map +1 -0
  3. package/dist/FlowmapAggregateAccessors.js +46 -0
  4. package/dist/FlowmapSelectors.d.ts +188 -0
  5. package/dist/FlowmapSelectors.d.ts.map +1 -0
  6. package/dist/FlowmapSelectors.js +863 -0
  7. package/dist/FlowmapState.d.ts +27 -0
  8. package/dist/FlowmapState.d.ts.map +1 -0
  9. package/dist/FlowmapState.js +2 -0
  10. package/dist/cluster/cluster.d.ts.map +1 -1
  11. package/dist/cluster/cluster.js +8 -5
  12. package/dist/colors.d.ts +7 -7
  13. package/dist/colors.d.ts.map +1 -1
  14. package/dist/colors.js +55 -20
  15. package/dist/getViewStateForLocations.d.ts +18 -11
  16. package/dist/getViewStateForLocations.d.ts.map +1 -1
  17. package/dist/getViewStateForLocations.js +23 -20
  18. package/dist/index.d.ts +6 -6
  19. package/dist/index.js +6 -6
  20. package/dist/provider/FlowmapDataProvider.d.ts +16 -0
  21. package/dist/provider/FlowmapDataProvider.d.ts.map +1 -0
  22. package/dist/provider/FlowmapDataProvider.js +17 -0
  23. package/dist/provider/LocalFlowmapDataProvider.d.ts +20 -0
  24. package/dist/provider/LocalFlowmapDataProvider.d.ts.map +1 -0
  25. package/dist/provider/LocalFlowmapDataProvider.js +98 -0
  26. package/dist/types.d.ts +6 -4
  27. package/dist/types.d.ts.map +1 -1
  28. package/dist/types.js +1 -1
  29. package/dist/util.d.ts +0 -1
  30. package/dist/util.d.ts.map +1 -1
  31. package/dist/util.js +1 -4
  32. package/dist-es5/FlowmapAggregateAccessors.d.ts +16 -0
  33. package/dist-es5/FlowmapAggregateAccessors.d.ts.map +1 -0
  34. package/dist-es5/FlowmapAggregateAccessors.js +57 -0
  35. package/{dist/FlowMapSelectors.d.ts → dist-es5/FlowmapSelectors.d.ts} +55 -49
  36. package/dist-es5/FlowmapSelectors.d.ts.map +1 -0
  37. package/dist-es5/FlowmapSelectors.js +1507 -0
  38. package/{dist/FlowMapState.d.ts → dist-es5/FlowmapState.d.ts} +6 -3
  39. package/dist-es5/FlowmapState.d.ts.map +1 -0
  40. package/dist-es5/FlowmapState.js +3 -0
  41. package/dist-es5/cluster/ClusterIndex.d.ts +42 -0
  42. package/dist-es5/cluster/ClusterIndex.d.ts.map +1 -0
  43. package/dist-es5/cluster/ClusterIndex.js +297 -0
  44. package/dist-es5/cluster/cluster.d.ts +31 -0
  45. package/dist-es5/cluster/cluster.d.ts.map +1 -0
  46. package/dist-es5/cluster/cluster.js +266 -0
  47. package/dist-es5/colors.d.ts +103 -0
  48. package/dist-es5/colors.d.ts.map +1 -0
  49. package/dist-es5/colors.js +510 -0
  50. package/dist-es5/getViewStateForLocations.d.ts +23 -0
  51. package/dist-es5/getViewStateForLocations.d.ts.map +1 -0
  52. package/dist-es5/getViewStateForLocations.js +64 -0
  53. package/dist-es5/index.d.ts +11 -0
  54. package/dist-es5/index.d.ts.map +1 -0
  55. package/dist-es5/index.js +28 -0
  56. package/dist-es5/provider/FlowmapDataProvider.d.ts +16 -0
  57. package/dist-es5/provider/FlowmapDataProvider.d.ts.map +1 -0
  58. package/dist-es5/provider/FlowmapDataProvider.js +22 -0
  59. package/dist-es5/provider/LocalFlowmapDataProvider.d.ts +20 -0
  60. package/dist-es5/provider/LocalFlowmapDataProvider.d.ts.map +1 -0
  61. package/dist-es5/provider/LocalFlowmapDataProvider.js +154 -0
  62. package/dist-es5/time.d.ts +24 -0
  63. package/dist-es5/time.d.ts.map +1 -0
  64. package/dist-es5/time.js +168 -0
  65. package/dist-es5/types.d.ts +118 -0
  66. package/dist-es5/types.d.ts.map +1 -0
  67. package/dist-es5/types.js +29 -0
  68. package/dist-es5/util.d.ts +5 -0
  69. package/dist-es5/util.d.ts.map +1 -0
  70. package/dist-es5/util.js +14 -0
  71. package/package.json +7 -5
  72. package/src/{FlowMapAggregateAccessors.ts → FlowmapAggregateAccessors.ts} +14 -9
  73. package/src/{FlowMapSelectors.ts → FlowmapSelectors.ts} +213 -178
  74. package/src/{FlowMapState.ts → FlowmapState.ts} +5 -2
  75. package/src/cluster/cluster.ts +7 -4
  76. package/src/colors.ts +65 -21
  77. package/src/getViewStateForLocations.ts +41 -35
  78. package/src/index.ts +6 -6
  79. package/src/provider/{FlowMapDataProvider.ts → FlowmapDataProvider.ts} +14 -12
  80. package/src/provider/LocalFlowmapDataProvider.ts +122 -0
  81. package/src/types.ts +6 -4
  82. package/src/util.ts +0 -4
  83. package/tsconfig.es5.json +11 -0
  84. package/dist/FlowMapAggregateAccessors.d.ts +0 -15
  85. package/dist/FlowMapAggregateAccessors.d.ts.map +0 -1
  86. package/dist/FlowMapAggregateAccessors.js +0 -43
  87. package/dist/FlowMapSelectors.d.ts.map +0 -1
  88. package/dist/FlowMapSelectors.js +0 -834
  89. package/dist/FlowMapState.d.ts.map +0 -1
  90. package/dist/FlowMapState.js +0 -2
  91. package/dist/provider/FlowMapDataProvider.d.ts +0 -16
  92. package/dist/provider/FlowMapDataProvider.d.ts.map +0 -1
  93. package/dist/provider/FlowMapDataProvider.js +0 -17
  94. package/dist/provider/LocalFlowMapDataProvider.d.ts +0 -20
  95. package/dist/provider/LocalFlowMapDataProvider.d.ts.map +0 -1
  96. package/dist/provider/LocalFlowMapDataProvider.js +0 -87
  97. package/src/provider/LocalFlowMapDataProvider.ts +0 -105
@@ -16,7 +16,7 @@
16
16
  *
17
17
  */
18
18
 
19
- import {bounds} from '@mapbox/geo-viewport';
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 FlowMapAggregateAccessors from './FlowMapAggregateAccessors';
48
- import {FlowMapState} from './FlowMapState';
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
- FlowMapData,
64
- FlowMapDataAccessors,
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
- FlowMapState,
79
- FlowMapData<L, F>,
76
+ FlowmapState,
77
+ FlowmapData<L, F>,
80
78
  T
81
79
  >;
82
80
 
83
- export default class FlowMapSelectors<L, F> {
84
- accessors: FlowMapAggregateAccessors<L, F>;
81
+ export default class FlowmapSelectors<L, F> {
82
+ accessors: FlowmapAggregateAccessors<L, F>;
85
83
 
86
- constructor(accessors: FlowMapDataAccessors<L, F>) {
87
- this.accessors = new FlowMapAggregateAccessors(accessors);
84
+ constructor(accessors: FlowmapDataAccessors<L, F>) {
85
+ this.accessors = new FlowmapAggregateAccessors(accessors);
88
86
  this.setAccessors(accessors);
89
87
  }
90
88
 
91
- setAccessors(accessors: FlowMapDataAccessors<L, F>) {
92
- this.accessors = new FlowMapAggregateAccessors(accessors);
89
+ setAccessors(accessors: FlowmapDataAccessors<L, F>) {
90
+ this.accessors = new FlowmapAggregateAccessors(accessors);
93
91
  }
94
92
 
95
- getFetchedFlows = (state: FlowMapState, props: FlowMapData<L, F>) =>
93
+ getFetchedFlows = (state: FlowmapState, props: FlowmapData<L, F>) =>
96
94
  props.flows;
97
- getFetchedLocations = (state: FlowMapState, props: FlowMapData<L, F>) =>
95
+ getFetchedLocations = (state: FlowmapState, props: FlowmapData<L, F>) =>
98
96
  props.locations;
99
- getSelectedLocations = (state: FlowMapState, props: FlowMapData<L, F>) =>
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: FlowMapState, props: FlowMapData<L, F>) =>
101
+ getLocationFilterMode = (state: FlowmapState, props: FlowmapData<L, F>) =>
102
102
  state.filterState.locationFilterMode;
103
- getClusteringEnabled = (state: FlowMapState, props: FlowMapData<L, F>) =>
103
+ getClusteringEnabled = (state: FlowmapState, props: FlowmapData<L, F>) =>
104
104
  state.settingsState.clusteringEnabled;
105
- getLocationTotalsEnabled = (state: FlowMapState, props: FlowMapData<L, F>) =>
105
+ getLocationTotalsEnabled = (state: FlowmapState, props: FlowmapData<L, F>) =>
106
106
  state.settingsState.locationTotalsEnabled;
107
- getZoom = (state: FlowMapState, props: FlowMapData<L, F>) =>
107
+ getZoom = (state: FlowmapState, props: FlowmapData<L, F>) =>
108
108
  state.viewport.zoom;
109
- getViewport = (state: FlowMapState, props: FlowMapData<L, F>) =>
109
+ getViewport = (state: FlowmapState, props: FlowmapData<L, F>) =>
110
110
  state.viewport;
111
- getSelectedTimeRange = (state: FlowMapState, props: FlowMapData<L, F>) =>
111
+ getSelectedTimeRange = (state: FlowmapState, props: FlowmapData<L, F>) =>
112
112
  state.filterState.selectedTimeRange;
113
113
 
114
- getColorSchemeKey: Selector<L, F, string | undefined> = (
115
- state: FlowMapState,
116
- props: FlowMapData<L, F>,
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: FlowMapState,
121
- props: FlowMapData<L, F>,
120
+ state: FlowmapState,
121
+ props: FlowmapData<L, F>,
122
122
  ) => state.settingsState.darkMode;
123
123
 
124
124
  getFadeEnabled: Selector<L, F, boolean> = (
125
- state: FlowMapState,
126
- props: FlowMapData<L, F>,
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: FlowMapState,
131
- props: FlowMapData<L, F>,
135
+ state: FlowmapState,
136
+ props: FlowmapData<L, F>,
132
137
  ) => state.settingsState.fadeAmount;
133
138
 
134
139
  getAnimate: Selector<L, F, boolean> = (
135
- state: FlowMapState,
136
- props: FlowMapData<L, F>,
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 [lon, lat] = this.accessors.getLocationCentroid(location) || [
147
- NaN,
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.getFlowMapDataAccessors(),
310
+ this.accessors.getFlowmapDataAccessors(),
308
311
  );
309
312
  const clusterLevels = clusterLocations(
310
313
  locations,
311
- this.accessors.getFlowMapDataAccessors(),
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.getFlowMapDataAccessors();
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: FlowMapState, props: FlowMapData<L, F>) => {
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
- _getFlowMapColors = createSelector(
488
+ _getFlowmapColors = createSelector(
486
489
  this.getDiffMode,
487
- this.getColorSchemeKey,
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
- getFlowMapColorsRGBA = createSelector(
496
- this._getFlowMapColors,
497
- (flowMapColors) => {
498
- return isDiffColors(flowMapColors)
499
- ? getDiffColorsRGBA(flowMapColors)
500
- : getColorsRGBA(flowMapColors);
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.getFlowMapDataAccessors(),
551
+ this.accessors.getFlowmapDataAccessors(),
548
552
  );
549
553
  } else {
550
554
  aggregated = aggregateFlows(
551
555
  flows,
552
- this.accessors.getFlowMapDataAccessors(),
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
- return bounds(
674
- [viewport.longitude, viewport.latitude],
675
- viewport.zoom,
676
- [viewport.width + pad * 2, viewport.height + pad * 2],
677
- 512,
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: FlowMapState,
849
- props: FlowMapData<L, F>,
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
- getFlowsForFlowMapLayer: Selector<L, F, (F | AggregateFlow)[] | undefined> =
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 > NUMBER_OF_FLOWS_TO_DISPLAY) break;
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
- state: FlowMapState,
905
- props: FlowMapData<L, F>,
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
- const flows = this.getFlowsForFlowMapLayer(state, props);
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.getFlowMagnitudeExtent(state, props);
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
- getLocationsForFlowMapLayer: Selector<
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
- getLocationsForFlowMapLayerById: Selector<
1062
+ getLocationsForFlowmapLayerById: Selector<
1061
1063
  L,
1062
1064
  F,
1063
1065
  Map<string, L | ClusterNode> | undefined
1064
- > = createSelector(this.getLocationsForFlowMapLayer, (locations) => {
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.getLocationsForFlowMapLayer,
1074
- this.getFlowsForFlowMapLayer,
1075
- this.getFlowMapColorsRGBA,
1076
- this.getLocationsForFlowMapLayerById,
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
- flowMapColors,
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
- flowMapColors,
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: FlowMapState, props: FlowMapData<L, F>): LayersData {
1108
- const locations = this.getLocationsForFlowMapLayer(state, props) || [];
1109
- const flows = this.getFlowsForFlowMapLayer(state, props) || [];
1110
- const flowMapColors = this.getFlowMapColorsRGBA(state, props);
1111
- const locationsById = this.getLocationsForFlowMapLayerById(state, props);
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
- flowMapColors,
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
- flowMapColors: DiffColorsRGBA | ColorsRGBA,
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
- getLocationCentroid,
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
- flowMapColors,
1158
+ flowmapColors,
1161
1159
  flowMagnitudeExtent,
1162
1160
  false,
1163
1161
  );
1164
1162
 
1165
- const circlePositions = new Float32Array(
1166
- flatMap(locations, getLocationCentroid),
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(flowMapColors)
1171
- ? flowMapColors.positive.locationCircles.inner
1172
- : flowMapColors.locationCircles.inner;
1173
-
1174
- const circleColors = new Uint8Array(flatMap(locations, (d) => circleColor));
1175
- const inCircleRadii = new Float32Array(
1176
- locations.map((loc) => {
1177
- const id = getLocationId(loc);
1178
- return locationIdsInViewport?.has(id) ? getInCircleSize(id) : 1.0;
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
- const outCircleRadii = new Float32Array(
1182
- locations.map((loc) => {
1183
- const id = getLocationId(loc);
1184
- return locationIdsInViewport?.has(id) ? getOutCircleSize(id) : 1.0;
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 = new Float32Array(
1189
- flatMap(flows, (d: F | AggregateFlow) => getCentroid(getFlowOriginId(d))),
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 = new Float32Array(
1192
- flatMap(flows, (d: F | AggregateFlow) => getCentroid(getFlowDestId(d))),
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 = new Float32Array(
1195
- flows.map((d: F | AggregateFlow) =>
1196
- flowThicknessScale ? flowThicknessScale(getFlowMagnitude(d)) || 0 : 0,
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 = new Float32Array(
1200
- flatMap(flows, (d: F | AggregateFlow) => {
1201
- const originId = getFlowOriginId(d);
1202
- const destId = getFlowDestId(d);
1203
- return [
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 = new Uint8Array(
1210
- flatMap(flows, (f: F | AggregateFlow) =>
1211
- flowColorScale(getFlowMagnitude(f)),
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
- ? new Float32Array(
1217
- flows.map((f: F | AggregateFlow) =>
1218
- // @ts-ignore
1219
- new alea(`${getFlowOriginId(f)}-${getFlowDestId(f)}`)(),
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 getLocationCentroidByIndex(
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 FlowMapState {
25
+ export interface FlowmapState {
23
26
  filterState: FilterState;
24
27
  settingsState: SettingsState;
25
28
  viewport: ViewportProps;