@flowmap.gl/data 8.0.0-alpha.21 → 8.0.0-alpha.24
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.map +1 -1
- package/dist/FlowmapAggregateAccessors.js +11 -9
- package/dist/FlowmapSelectors.d.ts +20 -5
- package/dist/FlowmapSelectors.d.ts.map +1 -1
- package/dist/FlowmapSelectors.js +22 -46
- package/dist/FlowmapState.d.ts +2 -1
- package/dist/FlowmapState.d.ts.map +1 -1
- package/dist/FlowmapState.js +1 -1
- package/dist/cluster/ClusterIndex.d.ts +1 -1
- package/dist/cluster/ClusterIndex.d.ts.map +1 -1
- package/dist/cluster/ClusterIndex.js +1 -1
- package/dist/provider/LocalFlowmapDataProvider.d.ts +11 -1
- package/dist/provider/LocalFlowmapDataProvider.d.ts.map +1 -1
- package/dist/provider/LocalFlowmapDataProvider.js +36 -4
- package/dist/selector-functions.d.ts +7 -1
- package/dist/selector-functions.d.ts.map +1 -1
- package/dist/selector-functions.js +37 -1
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/package.json +2 -2
- package/src/FlowmapAggregateAccessors.ts +10 -8
- package/src/FlowmapSelectors.ts +60 -63
- package/src/FlowmapState.ts +2 -1
- package/src/cluster/ClusterIndex.ts +1 -1
- package/src/provider/LocalFlowmapDataProvider.ts +47 -1
- package/src/selector-functions.ts +54 -1
- package/src/types.ts +2 -1
package/src/FlowmapSelectors.ts
CHANGED
|
@@ -46,6 +46,7 @@ import getColors, {
|
|
|
46
46
|
import FlowmapAggregateAccessors from './FlowmapAggregateAccessors';
|
|
47
47
|
import {FlowmapState} from './FlowmapState';
|
|
48
48
|
import {
|
|
49
|
+
addClusterNames,
|
|
49
50
|
getFlowThicknessScale,
|
|
50
51
|
getViewportBoundingBox,
|
|
51
52
|
} from './selector-functions';
|
|
@@ -94,6 +95,10 @@ export default class FlowmapSelectors<L, F> {
|
|
|
94
95
|
this.accessors = new FlowmapAggregateAccessors(accessors);
|
|
95
96
|
}
|
|
96
97
|
|
|
98
|
+
getAggregateAccessors(): FlowmapAggregateAccessors<L, F> {
|
|
99
|
+
return this.accessors;
|
|
100
|
+
}
|
|
101
|
+
|
|
97
102
|
getFlowsFromProps = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
98
103
|
props.flows;
|
|
99
104
|
getLocationsFromProps = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
@@ -114,6 +119,8 @@ export default class FlowmapSelectors<L, F> {
|
|
|
114
119
|
state.settings.clusteringEnabled;
|
|
115
120
|
getLocationTotalsEnabled = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
116
121
|
state.settings.locationTotalsEnabled;
|
|
122
|
+
getLocationLabelsEnabled = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
123
|
+
state.settings.locationLabelsEnabled;
|
|
117
124
|
getZoom = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
118
125
|
state.viewport.zoom;
|
|
119
126
|
getViewport = (state: FlowmapState, props: FlowmapData<L, F>) =>
|
|
@@ -194,7 +201,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
194
201
|
return ids;
|
|
195
202
|
});
|
|
196
203
|
|
|
197
|
-
getSelectedLocationsSet: Selector<L, F, Set<string> | undefined> =
|
|
204
|
+
getSelectedLocationsSet: Selector<L, F, Set<string | number> | undefined> =
|
|
198
205
|
createSelector(this.getSelectedLocations, (ids) =>
|
|
199
206
|
ids && ids.length > 0 ? new Set(ids) : undefined,
|
|
200
207
|
);
|
|
@@ -361,46 +368,14 @@ export default class FlowmapSelectors<L, F> {
|
|
|
361
368
|
return undefined;
|
|
362
369
|
|
|
363
370
|
const clusterIndex = buildIndex<F>(clusterLevels);
|
|
364
|
-
const {getLocationName, getLocationClusterName} =
|
|
365
|
-
this.accessors.getFlowmapDataAccessors();
|
|
366
|
-
|
|
367
371
|
// Adding meaningful names
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
return `"${id}"`;
|
|
376
|
-
};
|
|
377
|
-
for (const level of clusterLevels) {
|
|
378
|
-
for (const node of level.nodes) {
|
|
379
|
-
// Here mutating the nodes (adding names)
|
|
380
|
-
if (isCluster(node)) {
|
|
381
|
-
const leaves = clusterIndex.expandCluster(node);
|
|
382
|
-
|
|
383
|
-
leaves.sort((a, b) =>
|
|
384
|
-
descending(getLocationWeight(a), getLocationWeight(b)),
|
|
385
|
-
);
|
|
386
|
-
|
|
387
|
-
if (getLocationClusterName) {
|
|
388
|
-
node.name = getLocationClusterName(leaves);
|
|
389
|
-
} else {
|
|
390
|
-
const topId = leaves[0];
|
|
391
|
-
const otherId = leaves.length === 2 ? leaves[1] : undefined;
|
|
392
|
-
node.name = `"${getName(topId)}" and ${
|
|
393
|
-
otherId
|
|
394
|
-
? `"${getName(otherId)}"`
|
|
395
|
-
: `${leaves.length - 1} others`
|
|
396
|
-
}`;
|
|
397
|
-
}
|
|
398
|
-
} else {
|
|
399
|
-
(node as any).name = getName(node.id);
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
|
|
372
|
+
addClusterNames(
|
|
373
|
+
clusterIndex,
|
|
374
|
+
clusterLevels,
|
|
375
|
+
locationsById,
|
|
376
|
+
this.accessors.getFlowmapDataAccessors(),
|
|
377
|
+
getLocationWeight,
|
|
378
|
+
);
|
|
404
379
|
return clusterIndex;
|
|
405
380
|
},
|
|
406
381
|
);
|
|
@@ -416,7 +391,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
416
391
|
let maxZoom = Number.POSITIVE_INFINITY;
|
|
417
392
|
let minZoom = Number.NEGATIVE_INFINITY;
|
|
418
393
|
|
|
419
|
-
const adjust = (zoneId: string) => {
|
|
394
|
+
const adjust = (zoneId: string | number) => {
|
|
420
395
|
const cluster = clusterIndex.getClusterById(zoneId);
|
|
421
396
|
if (cluster) {
|
|
422
397
|
minZoom = Math.max(minZoom, cluster.zoom);
|
|
@@ -611,31 +586,34 @@ export default class FlowmapSelectors<L, F> {
|
|
|
611
586
|
},
|
|
612
587
|
);
|
|
613
588
|
|
|
614
|
-
getExpandedSelectedLocationsSet: Selector<
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
589
|
+
getExpandedSelectedLocationsSet: Selector<
|
|
590
|
+
L,
|
|
591
|
+
F,
|
|
592
|
+
Set<string | number> | undefined
|
|
593
|
+
> = createSelector(
|
|
594
|
+
this.getClusteringEnabled,
|
|
595
|
+
this.getSelectedLocationsSet,
|
|
596
|
+
this.getClusterIndex,
|
|
597
|
+
(clusteringEnabled, selectedLocations, clusterIndex) => {
|
|
598
|
+
if (!selectedLocations || !clusterIndex) {
|
|
599
|
+
return selectedLocations;
|
|
600
|
+
}
|
|
623
601
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
}
|
|
632
|
-
} else {
|
|
633
|
-
result.add(locationId);
|
|
602
|
+
const result = new Set<string | number>();
|
|
603
|
+
for (const locationId of selectedLocations) {
|
|
604
|
+
const cluster = clusterIndex.getClusterById(locationId);
|
|
605
|
+
if (cluster) {
|
|
606
|
+
const expanded = clusterIndex.expandCluster(cluster);
|
|
607
|
+
for (const id of expanded) {
|
|
608
|
+
result.add(id);
|
|
634
609
|
}
|
|
610
|
+
} else {
|
|
611
|
+
result.add(locationId);
|
|
635
612
|
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
613
|
+
}
|
|
614
|
+
return result;
|
|
615
|
+
},
|
|
616
|
+
);
|
|
639
617
|
|
|
640
618
|
getTotalCountsByTime: Selector<L, F, CountByTime[] | undefined> =
|
|
641
619
|
createSelector(
|
|
@@ -1099,6 +1077,15 @@ export default class FlowmapSelectors<L, F> {
|
|
|
1099
1077
|
);
|
|
1100
1078
|
});
|
|
1101
1079
|
|
|
1080
|
+
getLocationOrClusterByIdGetter = createSelector(
|
|
1081
|
+
this.getClusterIndex,
|
|
1082
|
+
this.getLocationsById,
|
|
1083
|
+
(clusterIndex, locationsById) => {
|
|
1084
|
+
return (id: string | number) =>
|
|
1085
|
+
clusterIndex?.getClusterById(id) ?? locationsById?.get(id);
|
|
1086
|
+
},
|
|
1087
|
+
);
|
|
1088
|
+
|
|
1102
1089
|
getLayersData: Selector<L, F, LayersData> = createSelector(
|
|
1103
1090
|
this.getLocationsForFlowmapLayer,
|
|
1104
1091
|
this.getFlowsForFlowmapLayer,
|
|
@@ -1109,6 +1096,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
1109
1096
|
this.getOutCircleSizeGetter,
|
|
1110
1097
|
this.getFlowThicknessScale,
|
|
1111
1098
|
this.getAnimate,
|
|
1099
|
+
this.getLocationLabelsEnabled,
|
|
1112
1100
|
(
|
|
1113
1101
|
locations,
|
|
1114
1102
|
flows,
|
|
@@ -1119,6 +1107,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
1119
1107
|
getOutCircleSize,
|
|
1120
1108
|
flowThicknessScale,
|
|
1121
1109
|
animationEnabled,
|
|
1110
|
+
locationLabelsEnabled,
|
|
1122
1111
|
) => {
|
|
1123
1112
|
return this._prepareLayersData(
|
|
1124
1113
|
locations,
|
|
@@ -1130,6 +1119,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
1130
1119
|
getOutCircleSize,
|
|
1131
1120
|
flowThicknessScale,
|
|
1132
1121
|
animationEnabled,
|
|
1122
|
+
locationLabelsEnabled,
|
|
1133
1123
|
);
|
|
1134
1124
|
},
|
|
1135
1125
|
);
|
|
@@ -1143,6 +1133,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
1143
1133
|
const getInCircleSize = this.getInCircleSizeGetter(state, props);
|
|
1144
1134
|
const getOutCircleSize = this.getOutCircleSizeGetter(state, props);
|
|
1145
1135
|
const flowThicknessScale = this.getFlowThicknessScale(state, props);
|
|
1136
|
+
const locationLabelsEnabled = this.getLocationLabelsEnabled(state, props);
|
|
1146
1137
|
return this._prepareLayersData(
|
|
1147
1138
|
locations,
|
|
1148
1139
|
flows,
|
|
@@ -1153,6 +1144,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
1153
1144
|
getOutCircleSize,
|
|
1154
1145
|
flowThicknessScale,
|
|
1155
1146
|
state.settings.animationEnabled,
|
|
1147
|
+
locationLabelsEnabled,
|
|
1156
1148
|
);
|
|
1157
1149
|
}
|
|
1158
1150
|
|
|
@@ -1166,6 +1158,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
1166
1158
|
getOutCircleSize: (locationId: string | number) => number,
|
|
1167
1159
|
flowThicknessScale: ScaleLinear<number, number, never> | undefined,
|
|
1168
1160
|
animationEnabled: boolean,
|
|
1161
|
+
locationLabelsEnabled: boolean,
|
|
1169
1162
|
): LayersData {
|
|
1170
1163
|
if (!locations) locations = [];
|
|
1171
1164
|
if (!flows) flows = [];
|
|
@@ -1176,6 +1169,7 @@ export default class FlowmapSelectors<L, F> {
|
|
|
1176
1169
|
getLocationId,
|
|
1177
1170
|
getLocationLon,
|
|
1178
1171
|
getLocationLat,
|
|
1172
|
+
getLocationName,
|
|
1179
1173
|
} = this.accessors;
|
|
1180
1174
|
|
|
1181
1175
|
const flowMagnitudeExtent = extent(flows, (f) => getFlowMagnitude(f)) as [
|
|
@@ -1307,6 +1301,9 @@ export default class FlowmapSelectors<L, F> {
|
|
|
1307
1301
|
: {}),
|
|
1308
1302
|
},
|
|
1309
1303
|
},
|
|
1304
|
+
...(locationLabelsEnabled
|
|
1305
|
+
? {locationLabels: locations.map(getLocationName)}
|
|
1306
|
+
: undefined),
|
|
1310
1307
|
};
|
|
1311
1308
|
}
|
|
1312
1309
|
|
package/src/FlowmapState.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {LocationFilterMode, ViewportProps} from './types';
|
|
2
2
|
|
|
3
3
|
export interface FilterState {
|
|
4
|
-
selectedLocations?: string[];
|
|
4
|
+
selectedLocations?: (string | number)[];
|
|
5
5
|
locationFilterMode?: LocationFilterMode;
|
|
6
6
|
selectedTimeRange?: [Date, Date];
|
|
7
7
|
}
|
|
@@ -11,6 +11,7 @@ export interface SettingsState {
|
|
|
11
11
|
fadeEnabled: boolean;
|
|
12
12
|
fadeOpacityEnabled: boolean;
|
|
13
13
|
locationTotalsEnabled: boolean;
|
|
14
|
+
locationLabelsEnabled: boolean;
|
|
14
15
|
adaptiveScalesEnabled: boolean;
|
|
15
16
|
clusteringEnabled: boolean;
|
|
16
17
|
clusteringAuto: boolean;
|
|
@@ -42,7 +42,7 @@ export interface ClusterIndex<F> {
|
|
|
42
42
|
/**
|
|
43
43
|
* Get the min zoom level on which the location is not clustered.
|
|
44
44
|
*/
|
|
45
|
-
getMinZoomForLocation: (locationId: string) => number;
|
|
45
|
+
getMinZoomForLocation: (locationId: string | number) => number;
|
|
46
46
|
/**
|
|
47
47
|
* List the IDs of all locations in the cluster (leaves of the subtree starting in the cluster).
|
|
48
48
|
*/
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
GetViewStateOptions,
|
|
16
16
|
getViewStateForLocations,
|
|
17
17
|
} from '../getViewStateForLocations';
|
|
18
|
+
import {ClusterIndex} from '../cluster/ClusterIndex';
|
|
18
19
|
|
|
19
20
|
export default class LocalFlowmapDataProvider<L, F>
|
|
20
21
|
implements FlowmapDataProvider<L, F>
|
|
@@ -34,14 +35,26 @@ export default class LocalFlowmapDataProvider<L, F>
|
|
|
34
35
|
this.selectors.setAccessors(accessors);
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
setFlowmapData(flowmapData: FlowmapData<L, F>): void {
|
|
38
39
|
this.flowmapData = flowmapData;
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
getSelectors(): FlowmapSelectors<L, F> {
|
|
43
|
+
return this.selectors;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
getFlowmapData(): FlowmapData<L, F> | undefined {
|
|
47
|
+
return this.flowmapData;
|
|
48
|
+
}
|
|
49
|
+
|
|
41
50
|
async setFlowmapState(flowmapState: FlowmapState): Promise<void> {
|
|
42
51
|
this.flowmapState = flowmapState;
|
|
43
52
|
}
|
|
44
53
|
|
|
54
|
+
getFlowmapState(): FlowmapState | undefined {
|
|
55
|
+
return this.flowmapState;
|
|
56
|
+
}
|
|
57
|
+
|
|
45
58
|
async getFlowByIndex(idx: number): Promise<F | AggregateFlow | undefined> {
|
|
46
59
|
if (!this.flowmapState || !this.flowmapData) {
|
|
47
60
|
return undefined;
|
|
@@ -128,4 +141,37 @@ export default class LocalFlowmapDataProvider<L, F>
|
|
|
128
141
|
) {
|
|
129
142
|
setLayersData(await this.getLayersData());
|
|
130
143
|
}
|
|
144
|
+
|
|
145
|
+
getClusterZoom(): number | undefined {
|
|
146
|
+
return this.flowmapState && this.flowmapData
|
|
147
|
+
? this.selectors.getClusterZoom(this.flowmapState, this.flowmapData)
|
|
148
|
+
: undefined;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
getClusterIndex(): ClusterIndex<F> | undefined {
|
|
152
|
+
return this.flowmapState && this.flowmapData
|
|
153
|
+
? this.selectors.getClusterIndex(this.flowmapState, this.flowmapData)
|
|
154
|
+
: undefined;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
getLocationsById(): Map<string | number, L> | undefined {
|
|
158
|
+
return this.flowmapState && this.flowmapData
|
|
159
|
+
? this.selectors.getLocationsById(this.flowmapState, this.flowmapData)
|
|
160
|
+
: undefined;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
getLocationTotals(): Map<string | number, LocationTotals> | undefined {
|
|
164
|
+
return this.flowmapState && this.flowmapData
|
|
165
|
+
? this.selectors.getLocationTotals(this.flowmapState, this.flowmapData)
|
|
166
|
+
: undefined;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
getFlowsForFlowmapLayer(): Array<F | AggregateFlow> | undefined {
|
|
170
|
+
return this.flowmapState && this.flowmapData
|
|
171
|
+
? this.selectors.getFlowsForFlowmapLayer(
|
|
172
|
+
this.flowmapState,
|
|
173
|
+
this.flowmapData,
|
|
174
|
+
)
|
|
175
|
+
: undefined;
|
|
176
|
+
}
|
|
131
177
|
}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import {WebMercatorViewport} from '@math.gl/web-mercator';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
ClusterLevel,
|
|
4
|
+
isCluster,
|
|
5
|
+
LocationAccessors,
|
|
6
|
+
ViewportProps,
|
|
7
|
+
} from './types';
|
|
3
8
|
import {scaleLinear} from 'd3-scale';
|
|
9
|
+
import {ClusterIndex, LocationWeightGetter} from './cluster/ClusterIndex';
|
|
10
|
+
import {descending} from 'd3-array';
|
|
4
11
|
|
|
5
12
|
// TODO: use re-reselect
|
|
6
13
|
|
|
@@ -32,3 +39,49 @@ export const getFlowThicknessScale = (
|
|
|
32
39
|
),
|
|
33
40
|
]);
|
|
34
41
|
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Adding meaningful cluster names.
|
|
45
|
+
* NOTE: this will mutate the nodes in clusterIndex
|
|
46
|
+
*/
|
|
47
|
+
export function addClusterNames<L, F>(
|
|
48
|
+
clusterIndex: ClusterIndex<F>,
|
|
49
|
+
clusterLevels: ClusterLevel[],
|
|
50
|
+
locationsById: Map<string | number, L>,
|
|
51
|
+
locationAccessors: LocationAccessors<L>,
|
|
52
|
+
getLocationWeight: LocationWeightGetter,
|
|
53
|
+
): void {
|
|
54
|
+
const {getLocationId, getLocationName, getLocationClusterName} =
|
|
55
|
+
locationAccessors;
|
|
56
|
+
const getName = (id: string | number) => {
|
|
57
|
+
const loc = locationsById.get(id);
|
|
58
|
+
if (loc) {
|
|
59
|
+
return getLocationName ? getLocationName(loc) : getLocationId(loc) || id;
|
|
60
|
+
}
|
|
61
|
+
return `"${id}"`;
|
|
62
|
+
};
|
|
63
|
+
for (const level of clusterLevels) {
|
|
64
|
+
for (const node of level.nodes) {
|
|
65
|
+
// Here mutating the nodes (adding names)
|
|
66
|
+
if (isCluster(node)) {
|
|
67
|
+
const leaves = clusterIndex.expandCluster(node);
|
|
68
|
+
|
|
69
|
+
leaves.sort((a, b) =>
|
|
70
|
+
descending(getLocationWeight(a), getLocationWeight(b)),
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
if (getLocationClusterName) {
|
|
74
|
+
node.name = getLocationClusterName(leaves);
|
|
75
|
+
} else {
|
|
76
|
+
const topId = leaves[0];
|
|
77
|
+
const otherId = leaves.length === 2 ? leaves[1] : undefined;
|
|
78
|
+
node.name = `"${getName(topId)}" and ${
|
|
79
|
+
otherId ? `"${getName(otherId)}"` : `${leaves.length - 1} others`
|
|
80
|
+
}`;
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
(node as any).name = getName(node.id);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -26,7 +26,7 @@ export interface FlowAccessors<F> {
|
|
|
26
26
|
|
|
27
27
|
export interface LocationAccessors<L> {
|
|
28
28
|
getLocationId: LocationAccessor<L, string | number>;
|
|
29
|
-
getLocationName?: LocationAccessor<L, string
|
|
29
|
+
getLocationName?: LocationAccessor<L, string>;
|
|
30
30
|
getLocationLat: LocationAccessor<L, number>;
|
|
31
31
|
getLocationLon: LocationAccessor<L, number>;
|
|
32
32
|
getLocationClusterName?: (locationIds: (string | number)[]) => string;
|
|
@@ -160,6 +160,7 @@ export interface FlowLinesLayerAttributes {
|
|
|
160
160
|
export interface LayersData {
|
|
161
161
|
circleAttributes: FlowCirclesLayerAttributes;
|
|
162
162
|
lineAttributes: FlowLinesLayerAttributes;
|
|
163
|
+
locationLabels?: string[];
|
|
163
164
|
}
|
|
164
165
|
|
|
165
166
|
export type LayersDataAttrValues<T> = {value: T; size: number};
|