@flowmap.gl/data 8.0.0-alpha.2 → 8.0.0-alpha.6

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 (63) hide show
  1. package/dist/{FlowMapAggregateAccessors.d.ts → FlowmapAggregateAccessors.d.ts} +6 -6
  2. package/dist/{FlowMapAggregateAccessors.d.ts.map → FlowmapAggregateAccessors.d.ts.map} +1 -1
  3. package/dist/{FlowMapAggregateAccessors.js → FlowmapAggregateAccessors.js} +3 -3
  4. package/dist/{FlowMapSelectors.d.ts → FlowmapSelectors.d.ts} +47 -45
  5. package/dist/FlowmapSelectors.d.ts.map +1 -0
  6. package/dist/FlowmapSelectors.js +869 -0
  7. package/dist/{FlowMapState.d.ts → FlowmapState.d.ts} +5 -2
  8. package/dist/FlowmapState.d.ts.map +1 -0
  9. package/dist/FlowmapState.js +2 -0
  10. package/dist/colors.d.ts +6 -6
  11. package/dist/colors.d.ts.map +1 -1
  12. package/dist/colors.js +42 -17
  13. package/dist/getViewStateForLocations.d.ts +12 -10
  14. package/dist/getViewStateForLocations.d.ts.map +1 -1
  15. package/dist/getViewStateForLocations.js +4 -1
  16. package/dist/index.d.ts +9 -6
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +9 -6
  19. package/dist/provider/FlowmapDataProvider.d.ts +16 -0
  20. package/dist/provider/FlowmapDataProvider.d.ts.map +1 -0
  21. package/dist/provider/FlowmapDataProvider.js +17 -0
  22. package/dist/provider/LocalFlowmapDataProvider.d.ts +20 -0
  23. package/dist/provider/LocalFlowmapDataProvider.d.ts.map +1 -0
  24. package/dist/provider/LocalFlowmapDataProvider.js +95 -0
  25. package/dist/provider/WorkerFlowmapDataProvider.d.ts +42 -0
  26. package/dist/provider/WorkerFlowmapDataProvider.d.ts.map +1 -0
  27. package/dist/provider/WorkerFlowmapDataProvider.js +82 -0
  28. package/dist/provider/WorkerFlowmapDataProviderWorker.d.ts +2 -0
  29. package/dist/provider/WorkerFlowmapDataProviderWorker.d.ts.map +1 -0
  30. package/dist/provider/WorkerFlowmapDataProviderWorker.js +4 -0
  31. package/dist/provider/createWorkerDataProvider.d.ts +3 -0
  32. package/dist/provider/createWorkerDataProvider.d.ts.map +1 -0
  33. package/dist/provider/createWorkerDataProvider.js +21 -0
  34. package/dist/types.d.ts +2 -2
  35. package/dist/types.js +1 -1
  36. package/dist/util.d.ts +0 -1
  37. package/dist/util.d.ts.map +1 -1
  38. package/dist/util.js +1 -4
  39. package/package.json +7 -2
  40. package/src/{FlowMapAggregateAccessors.ts → FlowmapAggregateAccessors.ts} +6 -6
  41. package/src/{FlowMapSelectors.ts → FlowmapSelectors.ts} +154 -113
  42. package/src/{FlowMapState.ts → FlowmapState.ts} +4 -1
  43. package/src/colors.ts +50 -16
  44. package/src/getViewStateForLocations.ts +20 -16
  45. package/src/index.ts +9 -6
  46. package/src/provider/{FlowMapDataProvider.ts → FlowmapDataProvider.ts} +14 -12
  47. package/src/provider/LocalFlowmapDataProvider.ts +119 -0
  48. package/src/provider/WorkerFlowmapDataProvider.ts +121 -0
  49. package/src/provider/WorkerFlowmapDataProviderWorker.ts +4 -0
  50. package/src/provider/createWorkerDataProvider.ts +18 -0
  51. package/src/types.ts +2 -2
  52. package/src/util.ts +0 -4
  53. package/dist/FlowMapSelectors.d.ts.map +0 -1
  54. package/dist/FlowMapSelectors.js +0 -834
  55. package/dist/FlowMapState.d.ts.map +0 -1
  56. package/dist/FlowMapState.js +0 -2
  57. package/dist/provider/FlowMapDataProvider.d.ts +0 -16
  58. package/dist/provider/FlowMapDataProvider.d.ts.map +0 -1
  59. package/dist/provider/FlowMapDataProvider.js +0 -17
  60. package/dist/provider/LocalFlowMapDataProvider.d.ts +0 -20
  61. package/dist/provider/LocalFlowMapDataProvider.d.ts.map +0 -1
  62. package/dist/provider/LocalFlowMapDataProvider.js +0 -87
  63. package/src/provider/LocalFlowMapDataProvider.ts +0 -105
@@ -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
114
  getColorSchemeKey: Selector<L, F, string | undefined> = (
115
- state: FlowMapState,
116
- props: FlowMapData<L, F>,
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(
@@ -304,11 +309,11 @@ export default class FlowMapSelectors<L, F> {
304
309
 
305
310
  const getLocationWeight = makeLocationWeightGetter(
306
311
  flows,
307
- this.accessors.getFlowMapDataAccessors(),
312
+ this.accessors.getFlowmapDataAccessors(),
308
313
  );
309
314
  const clusterLevels = clusterLocations(
310
315
  locations,
311
- this.accessors.getFlowMapDataAccessors(),
316
+ this.accessors.getFlowmapDataAccessors(),
312
317
  getLocationWeight,
313
318
  {
314
319
  maxZoom: MAX_CLUSTER_ZOOM_LEVEL,
@@ -316,7 +321,7 @@ export default class FlowMapSelectors<L, F> {
316
321
  );
317
322
  const clusterIndex = buildIndex<F>(clusterLevels);
318
323
  const {getLocationName, getLocationClusterName} =
319
- this.accessors.getFlowMapDataAccessors();
324
+ this.accessors.getFlowmapDataAccessors();
320
325
 
321
326
  // Adding meaningful names
322
327
  const getName = (id: string) => {
@@ -411,7 +416,7 @@ export default class FlowMapSelectors<L, F> {
411
416
  },
412
417
  );
413
418
 
414
- getClusterZoom = (state: FlowMapState, props: FlowMapData<L, F>) => {
419
+ getClusterZoom = (state: FlowmapState, props: FlowmapData<L, F>) => {
415
420
  const {settingsState} = state;
416
421
  if (!settingsState.clusteringEnabled) return undefined;
417
422
  if (settingsState.clusteringAuto || settingsState.clusteringLevel == null) {
@@ -482,22 +487,23 @@ export default class FlowMapSelectors<L, F> {
482
487
  },
483
488
  );
484
489
 
485
- _getFlowMapColors = createSelector(
490
+ _getFlowmapColors = createSelector(
486
491
  this.getDiffMode,
487
492
  this.getColorSchemeKey,
488
493
  this.getDarkMode,
489
494
  this.getFadeEnabled,
495
+ this.getFadeOpacityEnabled,
490
496
  this.getFadeAmount,
491
497
  this.getAnimate,
492
498
  getColors,
493
499
  );
494
500
 
495
- getFlowMapColorsRGBA = createSelector(
496
- this._getFlowMapColors,
497
- (flowMapColors) => {
498
- return isDiffColors(flowMapColors)
499
- ? getDiffColorsRGBA(flowMapColors)
500
- : getColorsRGBA(flowMapColors);
501
+ getFlowmapColorsRGBA = createSelector(
502
+ this._getFlowmapColors,
503
+ (flowmapColors) => {
504
+ return isDiffColors(flowmapColors)
505
+ ? getDiffColorsRGBA(flowmapColors)
506
+ : getColorsRGBA(flowmapColors);
501
507
  },
502
508
  );
503
509
 
@@ -544,12 +550,12 @@ export default class FlowMapSelectors<L, F> {
544
550
  // : flows,
545
551
  flows,
546
552
  clusterZoom,
547
- this.accessors.getFlowMapDataAccessors(),
553
+ this.accessors.getFlowmapDataAccessors(),
548
554
  );
549
555
  } else {
550
556
  aggregated = aggregateFlows(
551
557
  flows,
552
- this.accessors.getFlowMapDataAccessors(),
558
+ this.accessors.getFlowmapDataAccessors(),
553
559
  );
554
560
  }
555
561
  aggregated.sort((a, b) =>
@@ -845,8 +851,8 @@ export default class FlowMapSelectors<L, F> {
845
851
  );
846
852
 
847
853
  getLocationTotalsExtent = (
848
- state: FlowMapState,
849
- props: FlowMapData<L, F>,
854
+ state: FlowmapState,
855
+ props: FlowmapData<L, F>,
850
856
  ): [number, number] | undefined => {
851
857
  if (state.settingsState.adaptiveScalesEnabled) {
852
858
  return this._getLocationTotalsForViewportExtent(state, props);
@@ -855,17 +861,19 @@ export default class FlowMapSelectors<L, F> {
855
861
  }
856
862
  };
857
863
 
858
- getFlowsForFlowMapLayer: Selector<L, F, (F | AggregateFlow)[] | undefined> =
864
+ getFlowsForFlowmapLayer: Selector<L, F, (F | AggregateFlow)[] | undefined> =
859
865
  createSelector(
860
866
  this.getSortedAggregatedFilteredFlows,
861
867
  this.getLocationIdsInViewport,
862
868
  this.getSelectedLocationsSet,
863
869
  this.getLocationFilterMode,
870
+ this.getMaxTopFlowsDisplayNum,
864
871
  (
865
872
  flows,
866
873
  locationIdsInViewport,
867
874
  selectedLocationsSet,
868
875
  locationFilterMode,
876
+ maxTopFlowsDisplayNum,
869
877
  ) => {
870
878
  if (!flows || !locationIdsInViewport) return undefined;
871
879
  const picked: (F | AggregateFlow)[] = [];
@@ -892,7 +900,7 @@ export default class FlowMapSelectors<L, F> {
892
900
  }
893
901
  }
894
902
  // Only keep top
895
- if (pickedCount > NUMBER_OF_FLOWS_TO_DISPLAY) break;
903
+ if (pickedCount > maxTopFlowsDisplayNum) break;
896
904
  }
897
905
  // assuming they are sorted in descending order,
898
906
  // we need ascending for rendering
@@ -901,11 +909,11 @@ export default class FlowMapSelectors<L, F> {
901
909
  );
902
910
 
903
911
  _getFlowMagnitudeExtent = (
904
- state: FlowMapState,
905
- props: FlowMapData<L, F>,
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);
916
+ const flows = this.getFlowsForFlowmapLayer(state, props);
909
917
  if (flows) {
910
918
  const rv = extent(flows, this.accessors.getFlowMagnitude);
911
919
  return rv[0] !== undefined && rv[1] !== undefined ? rv : undefined;
@@ -1027,7 +1035,7 @@ export default class FlowMapSelectors<L, F> {
1027
1035
  },
1028
1036
  );
1029
1037
 
1030
- getLocationsForFlowMapLayer: Selector<
1038
+ getLocationsForFlowmapLayer: Selector<
1031
1039
  L,
1032
1040
  F,
1033
1041
  Array<L | ClusterNode> | undefined
@@ -1057,11 +1065,11 @@ export default class FlowMapSelectors<L, F> {
1057
1065
  },
1058
1066
  );
1059
1067
 
1060
- getLocationsForFlowMapLayerById: Selector<
1068
+ getLocationsForFlowmapLayerById: Selector<
1061
1069
  L,
1062
1070
  F,
1063
1071
  Map<string, L | ClusterNode> | undefined
1064
- > = createSelector(this.getLocationsForFlowMapLayer, (locations) => {
1072
+ > = createSelector(this.getLocationsForFlowmapLayer, (locations) => {
1065
1073
  if (!locations) return undefined;
1066
1074
  return locations.reduce(
1067
1075
  (m, d) => (m.set(this.accessors.getLocationId(d), d), m),
@@ -1070,10 +1078,10 @@ export default class FlowMapSelectors<L, F> {
1070
1078
  });
1071
1079
 
1072
1080
  getLayersData: Selector<L, F, LayersData> = createSelector(
1073
- this.getLocationsForFlowMapLayer,
1074
- this.getFlowsForFlowMapLayer,
1075
- this.getFlowMapColorsRGBA,
1076
- this.getLocationsForFlowMapLayerById,
1081
+ this.getLocationsForFlowmapLayer,
1082
+ this.getFlowsForFlowmapLayer,
1083
+ this.getFlowmapColorsRGBA,
1084
+ this.getLocationsForFlowmapLayerById,
1077
1085
  this.getLocationIdsInViewport,
1078
1086
  this.getInCircleSizeGetter,
1079
1087
  this.getOutCircleSizeGetter,
@@ -1082,7 +1090,7 @@ export default class FlowMapSelectors<L, F> {
1082
1090
  (
1083
1091
  locations,
1084
1092
  flows,
1085
- flowMapColors,
1093
+ flowmapColors,
1086
1094
  locationsById,
1087
1095
  locationIdsInViewport,
1088
1096
  getInCircleSize,
@@ -1093,7 +1101,7 @@ export default class FlowMapSelectors<L, F> {
1093
1101
  return this._prepareLayersData(
1094
1102
  locations,
1095
1103
  flows,
1096
- flowMapColors,
1104
+ flowmapColors,
1097
1105
  locationsById,
1098
1106
  locationIdsInViewport,
1099
1107
  getInCircleSize,
@@ -1104,11 +1112,11 @@ export default class FlowMapSelectors<L, F> {
1104
1112
  },
1105
1113
  );
1106
1114
 
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);
1115
+ prepareLayersData(state: FlowmapState, props: FlowmapData<L, F>): LayersData {
1116
+ const locations = this.getLocationsForFlowmapLayer(state, props) || [];
1117
+ const flows = this.getFlowsForFlowmapLayer(state, props) || [];
1118
+ const flowmapColors = this.getFlowmapColorsRGBA(state, props);
1119
+ const locationsById = this.getLocationsForFlowmapLayerById(state, props);
1112
1120
  const locationIdsInViewport = this.getLocationIdsInViewport(state, props);
1113
1121
  const getInCircleSize = this.getInCircleSizeGetter(state, props);
1114
1122
  const getOutCircleSize = this.getOutCircleSizeGetter(state, props);
@@ -1116,7 +1124,7 @@ export default class FlowMapSelectors<L, F> {
1116
1124
  return this._prepareLayersData(
1117
1125
  locations,
1118
1126
  flows,
1119
- flowMapColors,
1127
+ flowmapColors,
1120
1128
  locationsById,
1121
1129
  locationIdsInViewport,
1122
1130
  getInCircleSize,
@@ -1129,7 +1137,7 @@ export default class FlowMapSelectors<L, F> {
1129
1137
  _prepareLayersData(
1130
1138
  locations: (L | ClusterNode)[] | undefined,
1131
1139
  flows: (F | AggregateFlow)[] | undefined,
1132
- flowMapColors: DiffColorsRGBA | ColorsRGBA,
1140
+ flowmapColors: DiffColorsRGBA | ColorsRGBA,
1133
1141
  locationsById: Map<string, L | ClusterNode> | undefined,
1134
1142
  locationIdsInViewport: Set<string> | undefined,
1135
1143
  getInCircleSize: (locationId: string) => number,
@@ -1157,67 +1165,100 @@ export default class FlowMapSelectors<L, F> {
1157
1165
  number,
1158
1166
  ];
1159
1167
  const flowColorScale = getFlowColorScale(
1160
- flowMapColors,
1168
+ flowmapColors,
1161
1169
  flowMagnitudeExtent,
1162
1170
  false,
1163
1171
  );
1164
1172
 
1165
- const circlePositions = new Float32Array(
1166
- flatMap(locations, getLocationCentroid),
1173
+ // Using a generator here helps to avoid creating intermediary arrays
1174
+ const circlePositions = Float32Array.from(
1175
+ (function* () {
1176
+ for (const location of locations) {
1177
+ // yield* effectively works as flatMap here
1178
+ yield* getLocationCentroid(location);
1179
+ }
1180
+ })(),
1167
1181
  );
1168
1182
 
1169
1183
  // 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
- }),
1184
+ const circleColor = isDiffColorsRGBA(flowmapColors)
1185
+ ? flowmapColors.positive.locationCircles.inner
1186
+ : flowmapColors.locationCircles.inner;
1187
+
1188
+ const circleColors = Uint8Array.from(
1189
+ (function* () {
1190
+ for (const location of locations) {
1191
+ yield* circleColor;
1192
+ }
1193
+ })(),
1194
+ );
1195
+
1196
+ const inCircleRadii = Float32Array.from(
1197
+ (function* () {
1198
+ for (const location of locations) {
1199
+ const id = getLocationId(location);
1200
+ yield locationIdsInViewport?.has(id) ? getInCircleSize(id) : 1.0;
1201
+ }
1202
+ })(),
1180
1203
  );
1181
- const outCircleRadii = new Float32Array(
1182
- locations.map((loc) => {
1183
- const id = getLocationId(loc);
1184
- return locationIdsInViewport?.has(id) ? getOutCircleSize(id) : 1.0;
1185
- }),
1204
+ const outCircleRadii = Float32Array.from(
1205
+ (function* () {
1206
+ for (const location of locations) {
1207
+ const id = getLocationId(location);
1208
+ yield locationIdsInViewport?.has(id) ? getOutCircleSize(id) : 1.0;
1209
+ }
1210
+ })(),
1186
1211
  );
1187
1212
 
1188
- const sourcePositions = new Float32Array(
1189
- flatMap(flows, (d: F | AggregateFlow) => getCentroid(getFlowOriginId(d))),
1213
+ const sourcePositions = Float32Array.from(
1214
+ (function* () {
1215
+ for (const flow of flows) {
1216
+ yield* getCentroid(getFlowOriginId(flow));
1217
+ }
1218
+ })(),
1190
1219
  );
1191
- const targetPositions = new Float32Array(
1192
- flatMap(flows, (d: F | AggregateFlow) => getCentroid(getFlowDestId(d))),
1220
+ const targetPositions = Float32Array.from(
1221
+ (function* () {
1222
+ for (const flow of flows) {
1223
+ yield* getCentroid(getFlowDestId(flow));
1224
+ }
1225
+ })(),
1193
1226
  );
1194
- const thicknesses = new Float32Array(
1195
- flows.map((d: F | AggregateFlow) =>
1196
- flowThicknessScale ? flowThicknessScale(getFlowMagnitude(d)) || 0 : 0,
1197
- ),
1227
+ const thicknesses = Float32Array.from(
1228
+ (function* () {
1229
+ for (const flow of flows) {
1230
+ yield flowThicknessScale
1231
+ ? flowThicknessScale(getFlowMagnitude(flow)) || 0
1232
+ : 0;
1233
+ }
1234
+ })(),
1198
1235
  );
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
- }),
1236
+ const endpointOffsets = Float32Array.from(
1237
+ (function* () {
1238
+ for (const flow of flows) {
1239
+ const originId = getFlowOriginId(flow);
1240
+ const destId = getFlowDestId(flow);
1241
+ yield Math.max(getInCircleSize(originId), getOutCircleSize(originId));
1242
+ yield Math.max(getInCircleSize(destId), getOutCircleSize(destId));
1243
+ }
1244
+ })(),
1208
1245
  );
1209
- const flowLineColors = new Uint8Array(
1210
- flatMap(flows, (f: F | AggregateFlow) =>
1211
- flowColorScale(getFlowMagnitude(f)),
1212
- ),
1246
+ const flowLineColors = Uint8Array.from(
1247
+ (function* () {
1248
+ for (const flow of flows) {
1249
+ yield* flowColorScale(getFlowMagnitude(flow));
1250
+ }
1251
+ })(),
1213
1252
  );
1214
1253
 
1215
1254
  const staggeringValues = animationEnabled
1216
- ? new Float32Array(
1217
- flows.map((f: F | AggregateFlow) =>
1218
- // @ts-ignore
1219
- new alea(`${getFlowOriginId(f)}-${getFlowDestId(f)}`)(),
1220
- ),
1255
+ ? Float32Array.from(
1256
+ (function* () {
1257
+ for (const f of flows) {
1258
+ // @ts-ignore
1259
+ yield new alea(`${getFlowOriginId(f)}-${getFlowDestId(f)}`)();
1260
+ }
1261
+ })(),
1221
1262
  )
1222
1263
  : undefined;
1223
1264
 
@@ -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;
@@ -17,9 +18,11 @@ export interface SettingsState {
17
18
  darkMode: boolean;
18
19
  fadeAmount: number;
19
20
  colorScheme: 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;
package/src/colors.ts CHANGED
@@ -26,9 +26,9 @@ import {
26
26
  } from 'd3-scale-chromatic';
27
27
  import {range} from 'd3-array';
28
28
  import {scalePow, scaleSequential, scaleSequentialPow} from 'd3-scale';
29
- import {interpolateRgbBasis} from 'd3-interpolate';
30
- import {color as d3color, hcl} from 'd3-color';
31
- import {SettingsState} from './FlowMapState';
29
+ import {interpolateBasis, interpolateRgbBasis} from 'd3-interpolate';
30
+ import {color as d3color, hcl, rgb as colorRgb} from 'd3-color';
31
+ import {SettingsState} from './FlowmapState';
32
32
 
33
33
  const DEFAULT_OUTLINE_COLOR = '#fff';
34
34
  const DEFAULT_DIMMED_OPACITY = 0.4;
@@ -100,7 +100,7 @@ const getColorSteps = (interpolate: (x: number) => string) =>
100
100
  .reverse();
101
101
 
102
102
  const FLOW_MIN_COLOR = 'rgba(240,240,240,0.5)';
103
- export const BLUES_PALE = [FLOW_MIN_COLOR, ColorScheme.primary];
103
+ export const GRAYISH = [FLOW_MIN_COLOR, ColorScheme.primary];
104
104
  const schemeBluYl = [
105
105
  '#f7feae',
106
106
  '#b7e6a5',
@@ -134,7 +134,6 @@ export const schemeTeal = [
134
134
  export const DEFAULT_COLOR_SCHEME = schemeTeal;
135
135
  export const COLOR_SCHEMES: {[key: string]: string[]} = {
136
136
  Blues: asScheme(schemeBlues),
137
- BluesPale: BLUES_PALE,
138
137
  BluGrn: [
139
138
  '#c4e6c3',
140
139
  '#96d2a4',
@@ -186,6 +185,7 @@ export const COLOR_SCHEMES: {[key: string]: string[]} = {
186
185
  ],
187
186
  Emrld: schemeEmrld,
188
187
  GnBu: asScheme(schemeGnBu),
188
+ Grayish: GRAYISH,
189
189
  Greens: asScheme(schemeGreens),
190
190
  Greys: asScheme(schemeGreys),
191
191
  Inferno: getColorSteps(interpolateInferno),
@@ -330,7 +330,7 @@ const diffColors: DiffColors = {
330
330
  outlineColor: 'rgb(230,233,237)',
331
331
  };
332
332
 
333
- export function getFlowMapColors(
333
+ export function getFlowmapColors(
334
334
  settingsState: SettingsState,
335
335
  ): Colors | DiffColors {
336
336
  return getColors(
@@ -338,6 +338,7 @@ export function getFlowMapColors(
338
338
  settingsState.colorScheme,
339
339
  settingsState.darkMode,
340
340
  settingsState.fadeEnabled,
341
+ settingsState.fadeOpacityEnabled,
341
342
  settingsState.fadeAmount,
342
343
  settingsState.animationEnabled,
343
344
  );
@@ -348,6 +349,7 @@ export function getColors(
348
349
  schemeKey: string | undefined,
349
350
  darkMode: boolean,
350
351
  fadeEnabled: boolean,
352
+ fadeOpacityEnabled: boolean,
351
353
  fadeAmount: number,
352
354
  animate: boolean,
353
355
  ): Colors | DiffColors {
@@ -390,13 +392,14 @@ export function getColors(
390
392
  scheme = indices.map(
391
393
  (c, i) => {
392
394
  const color = colorScale(i);
393
- const alpha = amount(i);
394
- if (color == null || alpha == null) return '#000';
395
+ const a = amount(i);
396
+ if (color == null || a == null) return '#000';
395
397
  const col = hcl(color);
396
- col.l = darkMode
397
- ? col.l - col.l * alpha
398
- : col.l + (100 - col.l) * alpha;
399
- col.c = col.c - col.c * (alpha / 4);
398
+ col.l = darkMode ? col.l - col.l * a : col.l + (100 - col.l) * a;
399
+ col.c = col.c - col.c * (a / 4);
400
+ if (fadeOpacityEnabled) {
401
+ col.opacity = col.opacity * (1.0 - a);
402
+ }
400
403
  return col.toString();
401
404
  },
402
405
  // interpolateRgbBasis([colorScale(i), darkMode ? '#000' : '#fff'])(amount(i))
@@ -417,15 +420,46 @@ export function getColors(
417
420
  };
418
421
  }
419
422
 
423
+ function interpolateRgbaBasis(colors: string[]) {
424
+ const spline = interpolateBasis;
425
+ const n = colors.length;
426
+ let r: any = new Array(n),
427
+ g: any = new Array(n),
428
+ b: any = new Array(n),
429
+ opacity: any = new Array(n),
430
+ i,
431
+ color: any;
432
+ for (i = 0; i < n; ++i) {
433
+ color = colorRgb(colors[i]);
434
+ r[i] = color.r || 0;
435
+ g[i] = color.g || 0;
436
+ b[i] = color.b || 0;
437
+ opacity[i] = color.opacity || 0;
438
+ }
439
+ r = spline(r);
440
+ g = spline(g);
441
+ b = spline(b);
442
+ opacity = spline(opacity);
443
+ // color.opacity = 1;
444
+ return function (t: number) {
445
+ color.r = r(t);
446
+ color.g = g(t);
447
+ color.b = b(t);
448
+ color.opacity = opacity(t);
449
+ return color + '';
450
+ };
451
+ }
452
+
420
453
  export function createFlowColorScale(
421
454
  domain: [number, number],
422
455
  scheme: string[],
423
456
  animate: boolean | undefined,
424
457
  ): ColorScale {
425
- const scale = scaleSequentialPow(interpolateRgbBasis(scheme))
458
+ const scale = scaleSequentialPow(interpolateRgbaBasis(scheme))
426
459
  // @ts-ignore
427
460
  .exponent(animate ? 1 / 2 : 1 / 3)
428
461
  .domain(domain);
462
+
429
463
  return (value: number) => colorAsRgba(scale(value));
430
464
  }
431
465
 
@@ -516,7 +550,7 @@ export interface LocationCircleColors {
516
550
  incoming?: string;
517
551
  highlighted?: string;
518
552
  empty?: string;
519
- emptyOutline?: string;
553
+ outlineEmptyMix?: number;
520
554
  }
521
555
 
522
556
  export interface LocationAreaColors {
@@ -563,7 +597,7 @@ export interface LocationCircleColorsRGBA {
563
597
  incoming: RGBA;
564
598
  highlighted: RGBA;
565
599
  empty: RGBA;
566
- emptyOutline: RGBA;
600
+ outlineEmptyMix: number;
567
601
  }
568
602
 
569
603
  export interface LocationAreaColorsRGBA {
@@ -648,7 +682,7 @@ function getFlowAndCircleColors(
648
682
  flowColorHighlighted,
649
683
  ),
650
684
  empty: emptyColor,
651
- emptyOutline: mixColorsRGBA(innerColor, emptyColor, 0.4),
685
+ outlineEmptyMix: inputColors?.locationCircles?.outlineEmptyMix ?? 0.4,
652
686
  },
653
687
  };
654
688
  }