@deck.gl/carto 9.0.23 → 9.0.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/api/layer-map.d.ts +4 -6
- package/dist/api/layer-map.d.ts.map +1 -1
- package/dist/api/layer-map.js +16 -17
- package/dist/cartoRasterTile-worker.js +1 -1
- package/dist/cartoSpatialTile-worker.js +1 -1
- package/dist/cartoVectorTile-worker.js +1 -1
- package/dist/dist.dev.js +1982 -1606
- package/dist/index.cjs +747 -517
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/layers/cluster-tile-layer.d.ts +41 -0
- package/dist/layers/cluster-tile-layer.d.ts.map +1 -0
- package/dist/layers/cluster-tile-layer.js +116 -0
- package/dist/layers/cluster-utils.d.ts +30 -0
- package/dist/layers/cluster-utils.d.ts.map +1 -0
- package/dist/layers/cluster-utils.js +122 -0
- package/dist/layers/schema/carto-raster-tile-loader.js +1 -1
- package/dist/layers/schema/carto-spatial-tile-loader.js +1 -1
- package/dist/layers/schema/carto-vector-tile-loader.js +1 -1
- package/dist/style/color-bins-style.d.ts +1 -2
- package/dist/style/color-bins-style.d.ts.map +1 -1
- package/dist/style/color-categories-style.d.ts +1 -2
- package/dist/style/color-categories-style.d.ts.map +1 -1
- package/dist/style/color-continuous-style.d.ts +1 -2
- package/dist/style/color-continuous-style.d.ts.map +1 -1
- package/dist/style/palette.d.ts +1 -1
- package/dist/style/palette.d.ts.map +1 -1
- package/dist.min.js +10 -10
- package/package.json +2 -2
- package/src/api/layer-map.ts +30 -29
- package/src/index.ts +3 -0
- package/src/layers/cluster-tile-layer.ts +218 -0
- package/src/layers/cluster-utils.ts +160 -0
- package/src/style/color-bins-style.ts +2 -2
- package/src/style/color-categories-style.ts +2 -2
- package/src/style/color-continuous-style.ts +2 -2
- package/src/style/palette.ts +1 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { default as ClusterTileLayer } from "./layers/cluster-tile-layer.js";
|
|
1
2
|
import { default as H3TileLayer } from "./layers/h3-tile-layer.js";
|
|
2
3
|
import { default as HeatmapTileLayer } from "./layers/heatmap-tile-layer.js";
|
|
3
4
|
import { default as _PointLabelLayer } from "./layers/point-label-layer.js";
|
|
@@ -5,6 +6,7 @@ import { default as QuadbinTileLayer } from "./layers/quadbin-tile-layer.js";
|
|
|
5
6
|
import { default as RasterTileLayer } from "./layers/raster-tile-layer.js";
|
|
6
7
|
import { default as VectorTileLayer } from "./layers/vector-tile-layer.js";
|
|
7
8
|
declare const CARTO_LAYERS: {
|
|
9
|
+
ClusterTileLayer: typeof ClusterTileLayer;
|
|
8
10
|
H3TileLayer: typeof H3TileLayer;
|
|
9
11
|
HeatmapTileLayer: typeof HeatmapTileLayer;
|
|
10
12
|
_PointLabelLayer: typeof _PointLabelLayer;
|
|
@@ -12,7 +14,7 @@ declare const CARTO_LAYERS: {
|
|
|
12
14
|
RasterTileLayer: typeof RasterTileLayer;
|
|
13
15
|
VectorTileLayer: typeof VectorTileLayer;
|
|
14
16
|
};
|
|
15
|
-
export { CARTO_LAYERS, H3TileLayer, HeatmapTileLayer, _PointLabelLayer, QuadbinTileLayer, RasterTileLayer, VectorTileLayer };
|
|
17
|
+
export { CARTO_LAYERS, ClusterTileLayer, H3TileLayer, HeatmapTileLayer, _PointLabelLayer, QuadbinTileLayer, RasterTileLayer, VectorTileLayer };
|
|
16
18
|
export { default as BASEMAP, GOOGLE_BASEMAPS as _GOOGLE_BASEMAPS, getStyleUrl as _getStyleUrl, fetchStyle as _fetchStyle, applyLayerGroupFilters as _applyLayerGroupFilters, STYLE_LAYER_GROUPS as _STYLE_LAYER_GROUPS } from "./basemap.js";
|
|
17
19
|
export { default as colorBins } from "./style/color-bins-style.js";
|
|
18
20
|
export { default as colorCategories } from "./style/color-categories-style.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,IAAI,WAAW,EAAC,kCAA+B;AAC9D,OAAO,EAAC,OAAO,IAAI,gBAAgB,EAAC,uCAAoC;AACxE,OAAO,EAAC,OAAO,IAAI,gBAAgB,EAAC,sCAAmC;AACvE,OAAO,EAAC,OAAO,IAAI,gBAAgB,EAAC,uCAAoC;AACxE,OAAO,EAAC,OAAO,IAAI,eAAe,EAAC,sCAAmC;AACtE,OAAO,EAAC,OAAO,IAAI,eAAe,EAAC,sCAAmC;AACtE,QAAA,MAAM,YAAY
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,IAAI,gBAAgB,EAAC,uCAAoC;AACxE,OAAO,EAAC,OAAO,IAAI,WAAW,EAAC,kCAA+B;AAC9D,OAAO,EAAC,OAAO,IAAI,gBAAgB,EAAC,uCAAoC;AACxE,OAAO,EAAC,OAAO,IAAI,gBAAgB,EAAC,sCAAmC;AACvE,OAAO,EAAC,OAAO,IAAI,gBAAgB,EAAC,uCAAoC;AACxE,OAAO,EAAC,OAAO,IAAI,eAAe,EAAC,sCAAmC;AACtE,OAAO,EAAC,OAAO,IAAI,eAAe,EAAC,sCAAmC;AACtE,QAAA,MAAM,YAAY;;;;;;;;CAQjB,CAAC;AACF,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,eAAe,EAChB,CAAC;AAEF,OAAO,EACL,OAAO,IAAI,OAAO,EAClB,eAAe,IAAI,gBAAgB,EACnC,WAAW,IAAI,YAAY,EAC3B,UAAU,IAAI,WAAW,EACzB,sBAAsB,IAAI,uBAAuB,EACjD,kBAAkB,IAAI,mBAAmB,EAC1C,qBAAkB;AACnB,OAAO,EAAC,OAAO,IAAI,SAAS,EAAC,oCAAiC;AAC9D,OAAO,EAAC,OAAO,IAAI,eAAe,EAAC,0CAAuC;AAC1E,OAAO,EAAC,OAAO,IAAI,eAAe,EAAC,0CAAuC;AAC1E,OAAO,EAAC,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAC,uBAAoB;AAC3D,OAAO,EAAC,iBAAiB,EAAC,yBAAsB;AAChD,YAAY,EACV,eAAe,EACf,eAAe,EACf,cAAc,EACd,MAAM,EACN,OAAO,EACP,WAAW,EACX,eAAe,EACf,YAAY,EACZ,OAAO,IAAI,QAAQ,EACnB,eAAe,IAAI,gBAAgB,EACnC,aAAa,IAAI,cAAc,EAChC,uBAAoB;AAErB,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,aAAa,EACb,aAAa,EACb,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EAChB,2BAAwB;AAEzB,QAAA,MAAM,aAAa;;;;;;;;;;;;;CAalB,CAAC;AAEF,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,aAAa,EACb,aAAa,EACb,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,eAAe,EAChB,CAAC;AAEF,YAAY,EACV,aAAa,EACb,UAAU,EACV,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,0BAA0B,EAC1B,0BAA0B,EAC1B,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,EACnB,yBAAyB,EACzB,yBAAyB,EACzB,2BAA2B,EAC3B,wBAAwB,EACxB,wBAAwB,EACxB,0BAA0B,EAC3B,2BAAwB"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { default as ClusterTileLayer } from "./layers/cluster-tile-layer.js";
|
|
1
2
|
import { default as H3TileLayer } from "./layers/h3-tile-layer.js";
|
|
2
3
|
import { default as HeatmapTileLayer } from "./layers/heatmap-tile-layer.js";
|
|
3
4
|
import { default as _PointLabelLayer } from "./layers/point-label-layer.js";
|
|
@@ -5,6 +6,7 @@ import { default as QuadbinTileLayer } from "./layers/quadbin-tile-layer.js";
|
|
|
5
6
|
import { default as RasterTileLayer } from "./layers/raster-tile-layer.js";
|
|
6
7
|
import { default as VectorTileLayer } from "./layers/vector-tile-layer.js";
|
|
7
8
|
const CARTO_LAYERS = {
|
|
9
|
+
ClusterTileLayer,
|
|
8
10
|
H3TileLayer,
|
|
9
11
|
HeatmapTileLayer,
|
|
10
12
|
_PointLabelLayer,
|
|
@@ -12,7 +14,7 @@ const CARTO_LAYERS = {
|
|
|
12
14
|
RasterTileLayer,
|
|
13
15
|
VectorTileLayer
|
|
14
16
|
};
|
|
15
|
-
export { CARTO_LAYERS, H3TileLayer, HeatmapTileLayer, _PointLabelLayer, QuadbinTileLayer, RasterTileLayer, VectorTileLayer };
|
|
17
|
+
export { CARTO_LAYERS, ClusterTileLayer, H3TileLayer, HeatmapTileLayer, _PointLabelLayer, QuadbinTileLayer, RasterTileLayer, VectorTileLayer };
|
|
16
18
|
export { default as BASEMAP, GOOGLE_BASEMAPS as _GOOGLE_BASEMAPS, getStyleUrl as _getStyleUrl, fetchStyle as _fetchStyle, applyLayerGroupFilters as _applyLayerGroupFilters, STYLE_LAYER_GROUPS as _STYLE_LAYER_GROUPS } from "./basemap.js";
|
|
17
19
|
export { default as colorBins } from "./style/color-bins-style.js";
|
|
18
20
|
export { default as colorCategories } from "./style/color-categories-style.js";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { GeoJsonLayerProps } from '@deck.gl/layers';
|
|
2
|
+
import { TileLayerProps, TileLayerPickingInfo } from '@deck.gl/geo-layers';
|
|
3
|
+
import type { Feature, Geometry } from 'geojson';
|
|
4
|
+
import { Accessor, DefaultProps, CompositeLayer, Layer, LayersList, PickingInfo } from '@deck.gl/core';
|
|
5
|
+
import { ClusteredFeaturePropertiesT, ParsedQuadbinCell, ParsedQuadbinTile } from "./cluster-utils.js";
|
|
6
|
+
import type { TilejsonResult } from "../sources/types.js";
|
|
7
|
+
export type ClusterTileLayerPickingInfo<FeaturePropertiesT = {}> = TileLayerPickingInfo<ParsedQuadbinTile<FeaturePropertiesT>, PickingInfo<Feature<Geometry, FeaturePropertiesT>>>;
|
|
8
|
+
/** All properties supported by ClusterTileLayer. */
|
|
9
|
+
export type ClusterTileLayerProps<FeaturePropertiesT = unknown> = _ClusterTileLayerProps<FeaturePropertiesT> & Omit<TileLayerProps<ParsedQuadbinTile<FeaturePropertiesT>>, 'data'>;
|
|
10
|
+
/** Properties added by ClusterTileLayer. */
|
|
11
|
+
type _ClusterTileLayerProps<FeaturePropertiesT> = Omit<GeoJsonLayerProps<ClusteredFeaturePropertiesT<FeaturePropertiesT>>, 'data'> & {
|
|
12
|
+
data: null | TilejsonResult | Promise<TilejsonResult>;
|
|
13
|
+
/**
|
|
14
|
+
* The number of aggregation levels to cluster cells by. Larger values increase
|
|
15
|
+
* the clustering radius, with an increment of `clusterLevel` doubling the radius.
|
|
16
|
+
*
|
|
17
|
+
* @default 5
|
|
18
|
+
*/
|
|
19
|
+
clusterLevel?: number;
|
|
20
|
+
/**
|
|
21
|
+
* The (average) position of points in a cell used for clustering.
|
|
22
|
+
* If not supplied the center of the quadbin cell is used.
|
|
23
|
+
*
|
|
24
|
+
* @default cell center
|
|
25
|
+
*/
|
|
26
|
+
getPosition?: Accessor<ParsedQuadbinCell<FeaturePropertiesT>, [number, number]>;
|
|
27
|
+
/**
|
|
28
|
+
* The weight of each cell used for clustering.
|
|
29
|
+
*
|
|
30
|
+
* @default 1
|
|
31
|
+
*/
|
|
32
|
+
getWeight?: Accessor<ParsedQuadbinCell<FeaturePropertiesT>, number>;
|
|
33
|
+
};
|
|
34
|
+
export default class ClusterTileLayer<FeaturePropertiesT = any, ExtraProps extends {} = {}> extends CompositeLayer<ExtraProps & Required<_ClusterTileLayerProps<FeaturePropertiesT>>> {
|
|
35
|
+
static layerName: string;
|
|
36
|
+
static defaultProps: DefaultProps<ClusterTileLayerProps<unknown>>;
|
|
37
|
+
getLoadOptions(): any;
|
|
38
|
+
renderLayers(): Layer | null | LayersList;
|
|
39
|
+
}
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=cluster-tile-layer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cluster-tile-layer.d.ts","sourceRoot":"","sources":["../../src/layers/cluster-tile-layer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,iBAAiB,EAAC,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAGL,cAAc,EACd,oBAAoB,EACrB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,KAAK,EAAC,OAAO,EAAE,QAAQ,EAAC,MAAM,SAAS,CAAC;AAE/C,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,cAAc,EAGd,KAAK,EACL,UAAU,EACV,WAAW,EACZ,MAAM,eAAe,CAAC;AAEvB,OAAO,EAEL,2BAA2B,EAI3B,iBAAiB,EACjB,iBAAiB,EAClB,2BAAwB;AAMzB,OAAO,KAAK,EAAC,cAAc,EAAC,4BAAyB;AAgBrD,MAAM,MAAM,2BAA2B,CAAC,kBAAkB,GAAG,EAAE,IAAI,oBAAoB,CACrF,iBAAiB,CAAC,kBAAkB,CAAC,EACrC,WAAW,CAAC,OAAO,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CACnD,CAAC;AAEF,oDAAoD;AACpD,MAAM,MAAM,qBAAqB,CAAC,kBAAkB,GAAG,OAAO,IAC5D,sBAAsB,CAAC,kBAAkB,CAAC,GACxC,IAAI,CAAC,cAAc,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;AAExE,4CAA4C;AAC5C,KAAK,sBAAsB,CAAC,kBAAkB,IAAI,IAAI,CACpD,iBAAiB,CAAC,2BAA2B,CAAC,kBAAkB,CAAC,CAAC,EAClE,MAAM,CACP,GAAG;IACF,IAAI,EAAE,IAAI,GAAG,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAEtD;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,QAAQ,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAEhF;;;;OAIG;IACH,SAAS,CAAC,EAAE,QAAQ,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC,CAAC;CACrE,CAAC;AA6FF,MAAM,CAAC,OAAO,OAAO,gBAAgB,CACnC,kBAAkB,GAAG,GAAG,EACxB,UAAU,SAAS,EAAE,GAAG,EAAE,CAC1B,SAAQ,cAAc,CAAC,UAAU,GAAG,QAAQ,CAAC,sBAAsB,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACzF,MAAM,CAAC,SAAS,SAAsB;IACtC,MAAM,CAAC,YAAY,+CAAgB;IAEnC,cAAc,IAAI,GAAG;IAQrB,YAAY,IAAI,KAAK,GAAG,IAAI,GAAG,UAAU;CAiB1C"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { GeoJsonLayer } from '@deck.gl/layers';
|
|
2
|
+
import { TileLayer } from '@deck.gl/geo-layers';
|
|
3
|
+
import { registerLoaders } from '@loaders.gl/core';
|
|
4
|
+
import { binaryToGeojson } from '@loaders.gl/gis';
|
|
5
|
+
import { CompositeLayer, _deepEqual as deepEqual } from '@deck.gl/core';
|
|
6
|
+
import { aggregateTile, clustersToBinary, computeAggregationStats, extractAggregationProperties } from "./cluster-utils.js";
|
|
7
|
+
import { DEFAULT_TILE_SIZE } from "../constants.js";
|
|
8
|
+
import QuadbinTileset2D from "./quadbin-tileset-2d.js";
|
|
9
|
+
import { getQuadbinPolygon } from "./quadbin-utils.js";
|
|
10
|
+
import CartoSpatialTileLoader from "./schema/carto-spatial-tile-loader.js";
|
|
11
|
+
import { injectAccessToken, TilejsonPropType } from "./utils.js";
|
|
12
|
+
registerLoaders([CartoSpatialTileLoader]);
|
|
13
|
+
const defaultProps = {
|
|
14
|
+
data: TilejsonPropType,
|
|
15
|
+
clusterLevel: { type: 'number', value: 5, min: 1 },
|
|
16
|
+
getPosition: {
|
|
17
|
+
type: 'accessor',
|
|
18
|
+
value: ({ id }) => getQuadbinPolygon(id, 0.5).slice(2, 4)
|
|
19
|
+
},
|
|
20
|
+
getWeight: { type: 'accessor', value: 1 },
|
|
21
|
+
refinementStrategy: 'no-overlap',
|
|
22
|
+
tileSize: DEFAULT_TILE_SIZE
|
|
23
|
+
};
|
|
24
|
+
class ClusterGeoJsonLayer extends TileLayer {
|
|
25
|
+
static { this.layerName = 'ClusterGeoJsonLayer'; }
|
|
26
|
+
static { this.defaultProps = defaultProps; }
|
|
27
|
+
renderLayers() {
|
|
28
|
+
const visibleTiles = this.state.tileset?.tiles.filter((tile) => {
|
|
29
|
+
return tile.isLoaded && tile.content && this.state.tileset.isTileVisible(tile);
|
|
30
|
+
});
|
|
31
|
+
if (!visibleTiles?.length) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
visibleTiles.sort((a, b) => b.zoom - a.zoom);
|
|
35
|
+
const { zoom } = this.context.viewport;
|
|
36
|
+
const { clusterLevel, getPosition, getWeight } = this.props;
|
|
37
|
+
const properties = extractAggregationProperties(visibleTiles[0]);
|
|
38
|
+
const data = [];
|
|
39
|
+
for (const tile of visibleTiles) {
|
|
40
|
+
// Calculate aggregation based on viewport zoom
|
|
41
|
+
const overZoom = Math.round(zoom - tile.zoom);
|
|
42
|
+
const aggregationLevels = Math.round(clusterLevel) - overZoom;
|
|
43
|
+
aggregateTile(tile, aggregationLevels, properties, getPosition, getWeight);
|
|
44
|
+
data.push(...tile.userData[aggregationLevels]);
|
|
45
|
+
}
|
|
46
|
+
data.sort((a, b) => Number(b.count - a.count));
|
|
47
|
+
const clusterIds = data?.map((tile) => tile.id);
|
|
48
|
+
const needsUpdate = !deepEqual(clusterIds, this.state.clusterIds, 1);
|
|
49
|
+
this.setState({ clusterIds });
|
|
50
|
+
if (needsUpdate) {
|
|
51
|
+
const stats = computeAggregationStats(data, properties);
|
|
52
|
+
for (const d of data) {
|
|
53
|
+
d.stats = stats;
|
|
54
|
+
}
|
|
55
|
+
this.setState({ data: clustersToBinary(data) });
|
|
56
|
+
}
|
|
57
|
+
const props = {
|
|
58
|
+
...this.props,
|
|
59
|
+
id: 'clusters',
|
|
60
|
+
data: this.state.data,
|
|
61
|
+
dataComparator: (data, oldData) => {
|
|
62
|
+
const newIds = data?.points?.properties?.map((tile) => tile.id);
|
|
63
|
+
const oldIds = oldData?.points?.properties?.map((tile) => tile.id);
|
|
64
|
+
return deepEqual(newIds, oldIds, 1);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
return new GeoJsonLayer(this.getSubLayerProps(props));
|
|
68
|
+
}
|
|
69
|
+
getPickingInfo(params) {
|
|
70
|
+
const info = params.info;
|
|
71
|
+
if (info.index !== -1) {
|
|
72
|
+
const { data } = params.sourceLayer.props;
|
|
73
|
+
info.object = binaryToGeojson(data, {
|
|
74
|
+
globalFeatureId: info.index
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return info;
|
|
78
|
+
}
|
|
79
|
+
_updateAutoHighlight(info) {
|
|
80
|
+
for (const layer of this.getSubLayers()) {
|
|
81
|
+
layer.updateAutoHighlight(info);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
filterSubLayer() {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Adapter layer around ClusterLayer that converts tileJSON into TileLayer API
|
|
89
|
+
export default class ClusterTileLayer extends CompositeLayer {
|
|
90
|
+
static { this.layerName = 'ClusterTileLayer'; }
|
|
91
|
+
static { this.defaultProps = defaultProps; }
|
|
92
|
+
getLoadOptions() {
|
|
93
|
+
const loadOptions = super.getLoadOptions() || {};
|
|
94
|
+
const tileJSON = this.props.data;
|
|
95
|
+
injectAccessToken(loadOptions, tileJSON.accessToken);
|
|
96
|
+
loadOptions.cartoSpatialTile = { ...loadOptions.cartoSpatialTile, scheme: 'quadbin' };
|
|
97
|
+
return loadOptions;
|
|
98
|
+
}
|
|
99
|
+
renderLayers() {
|
|
100
|
+
const tileJSON = this.props.data;
|
|
101
|
+
if (!tileJSON)
|
|
102
|
+
return null;
|
|
103
|
+
const { tiles: data, maxresolution: maxZoom } = tileJSON;
|
|
104
|
+
return [
|
|
105
|
+
// @ts-ignore
|
|
106
|
+
new ClusterGeoJsonLayer(this.props, {
|
|
107
|
+
id: `cluster-geojson-layer-${this.props.id}`,
|
|
108
|
+
data,
|
|
109
|
+
// TODO: Tileset2D should be generic over TileIndex type
|
|
110
|
+
TilesetClass: QuadbinTileset2D,
|
|
111
|
+
maxZoom,
|
|
112
|
+
loadOptions: this.getLoadOptions()
|
|
113
|
+
})
|
|
114
|
+
];
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { _Tile2DHeader as Tile2DHeader } from '@deck.gl/geo-layers';
|
|
2
|
+
import { Accessor } from '@deck.gl/core';
|
|
3
|
+
import { BinaryFeatureCollection } from '@loaders.gl/schema';
|
|
4
|
+
export type Aggregation = 'any' | 'average' | 'count' | 'min' | 'max' | 'sum';
|
|
5
|
+
export type AggregationProperties<FeaturePropertiesT> = {
|
|
6
|
+
aggregation: Aggregation;
|
|
7
|
+
name: keyof FeaturePropertiesT;
|
|
8
|
+
}[];
|
|
9
|
+
export type ClusteredFeaturePropertiesT<FeaturePropertiesT> = FeaturePropertiesT & {
|
|
10
|
+
id: bigint;
|
|
11
|
+
count: number;
|
|
12
|
+
position: [number, number];
|
|
13
|
+
stats: Record<keyof FeaturePropertiesT, {
|
|
14
|
+
min: number;
|
|
15
|
+
max: number;
|
|
16
|
+
}>;
|
|
17
|
+
};
|
|
18
|
+
export type ParsedQuadbinCell<FeaturePropertiesT> = {
|
|
19
|
+
id: bigint;
|
|
20
|
+
properties: FeaturePropertiesT;
|
|
21
|
+
};
|
|
22
|
+
export type ParsedQuadbinTile<FeaturePropertiesT> = ParsedQuadbinCell<FeaturePropertiesT>[];
|
|
23
|
+
export declare function aggregateTile<FeaturePropertiesT>(tile: Tile2DHeader<ParsedQuadbinTile<FeaturePropertiesT>>, aggregationLevels: number, properties: AggregationProperties<FeaturePropertiesT> | undefined, getPosition: Accessor<ParsedQuadbinCell<FeaturePropertiesT>, [number, number]>, getWeight: Accessor<ParsedQuadbinCell<FeaturePropertiesT>, number>): void;
|
|
24
|
+
export declare function extractAggregationProperties<FeaturePropertiesT extends {}>(tile: Tile2DHeader<ParsedQuadbinTile<FeaturePropertiesT>>): AggregationProperties<FeaturePropertiesT>;
|
|
25
|
+
export declare function computeAggregationStats<FeaturePropertiesT>(data: ClusteredFeaturePropertiesT<FeaturePropertiesT>[], properties: AggregationProperties<FeaturePropertiesT>): Record<keyof FeaturePropertiesT, {
|
|
26
|
+
min: number;
|
|
27
|
+
max: number;
|
|
28
|
+
}>;
|
|
29
|
+
export declare function clustersToBinary<FeaturePropertiesT>(data: ClusteredFeaturePropertiesT<FeaturePropertiesT>[]): BinaryFeatureCollection;
|
|
30
|
+
//# sourceMappingURL=cluster-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cluster-utils.d.ts","sourceRoot":"","sources":["../../src/layers/cluster-utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,aAAa,IAAI,YAAY,EAAC,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAC,QAAQ,EAAC,MAAM,eAAe,CAAC;AACvC,OAAO,EAAC,uBAAuB,EAAC,MAAM,oBAAoB,CAAC;AAE3D,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,OAAO,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAC9E,MAAM,MAAM,qBAAqB,CAAC,kBAAkB,IAAI;IACtD,WAAW,EAAE,WAAW,CAAC;IACzB,IAAI,EAAE,MAAM,kBAAkB,CAAC;CAChC,EAAE,CAAC;AACJ,MAAM,MAAM,2BAA2B,CAAC,kBAAkB,IAAI,kBAAkB,GAAG;IACjF,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,kBAAkB,EAAE;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;CACrE,CAAC;AACF,MAAM,MAAM,iBAAiB,CAAC,kBAAkB,IAAI;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,kBAAkB,CAAA;CAAC,CAAC;AACjG,MAAM,MAAM,iBAAiB,CAAC,kBAAkB,IAAI,iBAAiB,CAAC,kBAAkB,CAAC,EAAE,CAAC;AAE5F,wBAAgB,aAAa,CAAC,kBAAkB,EAC9C,IAAI,EAAE,YAAY,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,CAAC,EACzD,iBAAiB,EAAE,MAAM,EACzB,UAAU,uDAAgD,EAC1D,WAAW,EAAE,QAAQ,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC9E,SAAS,EAAE,QAAQ,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC,GACjE,IAAI,CAyDN;AAED,wBAAgB,4BAA4B,CAAC,kBAAkB,SAAS,EAAE,EACxE,IAAI,EAAE,YAAY,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,CAAC,GACxD,qBAAqB,CAAC,kBAAkB,CAAC,CAY3C;AAED,wBAAgB,uBAAuB,CAAC,kBAAkB,EACxD,IAAI,EAAE,2BAA2B,CAAC,kBAAkB,CAAC,EAAE,EACvD,UAAU,EAAE,qBAAqB,CAAC,kBAAkB,CAAC;SAEM,MAAM;SAAO,MAAM;GAY/E;AAWD,wBAAgB,gBAAgB,CAAC,kBAAkB,EACjD,IAAI,EAAE,2BAA2B,CAAC,kBAAkB,CAAC,EAAE,GACtD,uBAAuB,CA8BzB"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { cellToParent } from 'quadbin';
|
|
2
|
+
export function aggregateTile(tile, aggregationLevels, properties = [], getPosition, getWeight) {
|
|
3
|
+
if (!tile.content)
|
|
4
|
+
return;
|
|
5
|
+
// Aggregate on demand and cache result
|
|
6
|
+
if (!tile.userData)
|
|
7
|
+
tile.userData = {};
|
|
8
|
+
if (tile.userData[aggregationLevels])
|
|
9
|
+
return;
|
|
10
|
+
const out = {};
|
|
11
|
+
for (const cell of tile.content) {
|
|
12
|
+
let id = cell.id;
|
|
13
|
+
const position = typeof getPosition === 'function' ? getPosition(cell, {}) : getPosition;
|
|
14
|
+
// Aggregate by parent id
|
|
15
|
+
for (let i = 0; i < aggregationLevels - 1; i++) {
|
|
16
|
+
id = cellToParent(id);
|
|
17
|
+
}
|
|
18
|
+
// Unfortunately TS doesn't support Record<bigint, any>
|
|
19
|
+
// https://github.com/microsoft/TypeScript/issues/46395
|
|
20
|
+
const parentId = Number(id);
|
|
21
|
+
if (!(parentId in out)) {
|
|
22
|
+
out[parentId] = { id, count: 0, position: [0, 0] };
|
|
23
|
+
for (const { name, aggregation } of properties) {
|
|
24
|
+
if (aggregation === 'any') {
|
|
25
|
+
// Just pick first value for ANY
|
|
26
|
+
out[parentId][name] = cell.properties[name];
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
out[parentId][name] = 0;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Layout props
|
|
34
|
+
const prevTotalW = out[parentId].count;
|
|
35
|
+
out[parentId].count += typeof getWeight === 'function' ? getWeight(cell, {}) : getWeight;
|
|
36
|
+
const totalW = out[parentId].count;
|
|
37
|
+
const W = totalW - prevTotalW;
|
|
38
|
+
out[parentId].position[0] = (prevTotalW * out[parentId].position[0] + W * position[0]) / totalW;
|
|
39
|
+
out[parentId].position[1] = (prevTotalW * out[parentId].position[1] + W * position[1]) / totalW;
|
|
40
|
+
// Re-aggregate other properties so clusters can be styled
|
|
41
|
+
for (const { name, aggregation } of properties) {
|
|
42
|
+
const prevValue = out[parentId][name];
|
|
43
|
+
const value = cell.properties[name];
|
|
44
|
+
if (aggregation === 'average') {
|
|
45
|
+
out[parentId][name] = (prevTotalW * prevValue + W * value) / totalW;
|
|
46
|
+
}
|
|
47
|
+
else if (aggregation === 'count' || aggregation === 'sum') {
|
|
48
|
+
out[parentId][name] = prevValue + value;
|
|
49
|
+
}
|
|
50
|
+
else if (aggregation === 'max') {
|
|
51
|
+
out[parentId][name] = Math.max(prevValue, value);
|
|
52
|
+
}
|
|
53
|
+
else if (aggregation === 'min') {
|
|
54
|
+
out[parentId][name] = Math.min(prevValue, value);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
tile.userData[aggregationLevels] = Object.values(out);
|
|
59
|
+
}
|
|
60
|
+
export function extractAggregationProperties(tile) {
|
|
61
|
+
const properties = [];
|
|
62
|
+
const validAggregations = ['any', 'average', 'count', 'min', 'max', 'sum'];
|
|
63
|
+
for (const name of Object.keys(tile.content[0].properties)) {
|
|
64
|
+
let aggregation = name.split('_').pop().toLowerCase();
|
|
65
|
+
if (!validAggregations.includes(aggregation)) {
|
|
66
|
+
aggregation = 'any';
|
|
67
|
+
}
|
|
68
|
+
properties.push({ name: name, aggregation });
|
|
69
|
+
}
|
|
70
|
+
return properties;
|
|
71
|
+
}
|
|
72
|
+
export function computeAggregationStats(data, properties) {
|
|
73
|
+
const stats = {};
|
|
74
|
+
for (const { name, aggregation } of properties) {
|
|
75
|
+
stats[name] = { min: Infinity, max: -Infinity };
|
|
76
|
+
if (aggregation !== 'any') {
|
|
77
|
+
for (const d of data) {
|
|
78
|
+
stats[name].min = Math.min(stats[name].min, d[name]);
|
|
79
|
+
stats[name].max = Math.max(stats[name].max, d[name]);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return stats;
|
|
84
|
+
}
|
|
85
|
+
const EMPTY_UINT16ARRAY = new Uint16Array();
|
|
86
|
+
const EMPTY_BINARY_PROPS = {
|
|
87
|
+
positions: { value: new Float32Array(), size: 2 },
|
|
88
|
+
properties: [],
|
|
89
|
+
numericProps: {},
|
|
90
|
+
featureIds: { value: EMPTY_UINT16ARRAY, size: 1 },
|
|
91
|
+
globalFeatureIds: { value: EMPTY_UINT16ARRAY, size: 1 }
|
|
92
|
+
};
|
|
93
|
+
export function clustersToBinary(data) {
|
|
94
|
+
const positions = new Float32Array(data.length * 2);
|
|
95
|
+
const featureIds = new Uint16Array(data.length);
|
|
96
|
+
for (let i = 0; i < data.length; i++) {
|
|
97
|
+
positions.set(data[i].position, 2 * i);
|
|
98
|
+
featureIds[i] = i;
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
shape: 'binary-feature-collection',
|
|
102
|
+
points: {
|
|
103
|
+
type: 'Point',
|
|
104
|
+
positions: { value: positions, size: 2 },
|
|
105
|
+
properties: data,
|
|
106
|
+
numericProps: {},
|
|
107
|
+
featureIds: { value: featureIds, size: 1 },
|
|
108
|
+
globalFeatureIds: { value: featureIds, size: 1 }
|
|
109
|
+
},
|
|
110
|
+
lines: {
|
|
111
|
+
type: 'LineString',
|
|
112
|
+
pathIndices: { value: EMPTY_UINT16ARRAY, size: 1 },
|
|
113
|
+
...EMPTY_BINARY_PROPS
|
|
114
|
+
},
|
|
115
|
+
polygons: {
|
|
116
|
+
type: 'Polygon',
|
|
117
|
+
polygonIndices: { value: EMPTY_UINT16ARRAY, size: 1 },
|
|
118
|
+
primitivePolygonIndices: { value: EMPTY_UINT16ARRAY, size: 1 },
|
|
119
|
+
...EMPTY_BINARY_PROPS
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TileReader } from "./carto-raster-tile.js";
|
|
2
2
|
import { parsePbf } from "./tile-loader-utils.js";
|
|
3
3
|
import { getWorkerUrl } from "../../utils.js";
|
|
4
|
-
const VERSION = typeof "9.0.
|
|
4
|
+
const VERSION = typeof "9.0.24" !== 'undefined' ? "9.0.24" : 'latest';
|
|
5
5
|
const id = 'cartoRasterTile';
|
|
6
6
|
const DEFAULT_OPTIONS = {
|
|
7
7
|
cartoRasterTile: {
|
|
@@ -2,7 +2,7 @@ import { TileReader } from "./carto-spatial-tile.js";
|
|
|
2
2
|
import { parsePbf } from "./tile-loader-utils.js";
|
|
3
3
|
import { getWorkerUrl } from "../../utils.js";
|
|
4
4
|
import { binaryToSpatialjson } from "./spatialjson-utils.js";
|
|
5
|
-
const VERSION = typeof "9.0.
|
|
5
|
+
const VERSION = typeof "9.0.24" !== 'undefined' ? "9.0.24" : 'latest';
|
|
6
6
|
const id = 'cartoSpatialTile';
|
|
7
7
|
const DEFAULT_OPTIONS = {
|
|
8
8
|
cartoSpatialTile: {
|
|
@@ -2,7 +2,7 @@ import earcut from 'earcut';
|
|
|
2
2
|
import { TileReader } from "./carto-tile.js";
|
|
3
3
|
import { parsePbf } from "./tile-loader-utils.js";
|
|
4
4
|
import { getWorkerUrl } from "../../utils.js";
|
|
5
|
-
const VERSION = typeof "9.0.
|
|
5
|
+
const VERSION = typeof "9.0.24" !== 'undefined' ? "9.0.24" : 'latest';
|
|
6
6
|
const id = 'cartoVectorTile';
|
|
7
7
|
const DEFAULT_OPTIONS = {
|
|
8
8
|
cartoVectorTile: {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { AccessorFunction } from '@deck.gl/core';
|
|
1
|
+
import { AccessorFunction, Color } from '@deck.gl/core';
|
|
2
2
|
import { Feature } from 'geojson';
|
|
3
|
-
import { Color } from "./palette.js";
|
|
4
3
|
import { AttributeSelector } from "./utils.js";
|
|
5
4
|
/**
|
|
6
5
|
* Helper function for quickly creating a color bins style based on `d3` `scaleThreshold`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"color-bins-style.d.ts","sourceRoot":"","sources":["../../src/style/color-bins-style.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,gBAAgB,EAAC,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"color-bins-style.d.ts","sourceRoot":"","sources":["../../src/style/color-bins-style.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,gBAAgB,EAAE,KAAK,EAAC,MAAM,eAAe,CAAC;AACtD,OAAO,EAAC,OAAO,EAAC,MAAM,SAAS,CAAC;AAGhC,OAAO,EAAC,iBAAiB,EAAe,mBAAgB;AAExD;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,KAAK,GAAG,OAAO,EAAE,EACjD,IAAI,EACJ,MAAM,EACN,MAAwB,EACxB,SAAsB,EACvB,EAAE;IACD,2CAA2C;IAC3C,IAAI,EAAE,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAEvC,yDAAyD;IACzD,MAAM,EAAE,MAAM,EAAE,CAAC;IAEjB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,EAAE,CAAC;IAE1B,uDAAuD;IACvD,SAAS,CAAC,EAAE,KAAK,CAAC;CACnB,GAAG,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,CAWjC"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { AccessorFunction } from '@deck.gl/core';
|
|
1
|
+
import { AccessorFunction, Color } from '@deck.gl/core';
|
|
2
2
|
import { Feature } from 'geojson';
|
|
3
|
-
import { Color } from "./palette.js";
|
|
4
3
|
import { AttributeSelector } from "./utils.js";
|
|
5
4
|
/**
|
|
6
5
|
* Helper function for quickly creating a color category style.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"color-categories-style.d.ts","sourceRoot":"","sources":["../../src/style/color-categories-style.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,gBAAgB,EAAC,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"color-categories-style.d.ts","sourceRoot":"","sources":["../../src/style/color-categories-style.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,gBAAgB,EAAE,KAAK,EAAC,MAAM,eAAe,CAAC;AACtD,OAAO,EAAC,OAAO,EAAC,MAAM,SAAS,CAAC;AAGhC,OAAO,EAAC,iBAAiB,EAAe,mBAAgB;AAExD;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,KAAK,GAAG,OAAO,EAAE,EACvD,IAAI,EACJ,MAAM,EACN,MAAwB,EACxB,SAAsB,EACtB,WAA0B,EAC3B,EAAE;IACD,0CAA0C;IAC1C,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;IAEzD,yDAAyD;IACzD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;IAE5B;;;;;OAKG;IACH,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE,CAAC;IAEzB,uDAAuD;IACvD,SAAS,CAAC,EAAE,KAAK,CAAC;IAElB,sFAAsF;IACtF,WAAW,CAAC,EAAE,KAAK,CAAC;CACrB,GAAG,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,CAgBjC"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { AccessorFunction } from '@deck.gl/core';
|
|
1
|
+
import { AccessorFunction, Color } from '@deck.gl/core';
|
|
2
2
|
import { Feature } from 'geojson';
|
|
3
|
-
import { Color } from "./palette.js";
|
|
4
3
|
import { AttributeSelector } from "./utils.js";
|
|
5
4
|
/**
|
|
6
5
|
* Helper function for quickly creating a color continuous style.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"color-continuous-style.d.ts","sourceRoot":"","sources":["../../src/style/color-continuous-style.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,gBAAgB,EAAC,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"color-continuous-style.d.ts","sourceRoot":"","sources":["../../src/style/color-continuous-style.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,gBAAgB,EAAE,KAAK,EAAC,MAAM,eAAe,CAAC;AAEtD,OAAO,EAAC,OAAO,EAAC,MAAM,SAAS,CAAC;AAGhC,OAAO,EAAC,iBAAiB,EAAe,mBAAgB;AAExD;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,KAAK,GAAG,OAAO,EAAE,EACvD,IAAI,EACJ,MAAM,EACN,MAAwB,EACxB,SAAsB,EACvB,EAAE;IACD,2CAA2C;IAC3C,IAAI,EAAE,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAEvC,iDAAiD;IACjD,MAAM,EAAE,MAAM,EAAE,CAAC;IAEjB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,EAAE,CAAC;IAE1B,sDAAsD;IACtD,SAAS,CAAC,EAAE,KAAK,CAAC;CACnB,GAAG,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,CAUjC"}
|
package/dist/style/palette.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"palette.d.ts","sourceRoot":"","sources":["../../src/style/palette.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"palette.d.ts","sourceRoot":"","sources":["../../src/style/palette.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAEpC,eAAO,MAAM,eAAe,WAAW,CAAC;AACxC,eAAO,MAAM,UAAU,EAAE,KAAuB,CAAC;AACjD,eAAO,MAAM,YAAY,EAAE,KAAuB,CAAC;AAOnD,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,KAAK,EAAE,CA0B/E;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CA2C3C"}
|