Skip to content

Commit 8647f18

Browse files
committed
fix aggregation layers - hightlight outlines
Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>
1 parent fbedc0d commit 8647f18

File tree

6 files changed

+134
-8
lines changed

6 files changed

+134
-8
lines changed

src/deckgl-layers/src/grid-layer/enhanced-cpu-grid-layer.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,40 @@ import {GridLayer} from '@deck.gl/aggregation-layers';
77
* In deck.gl 9, GridLayer natively supports CPU aggregation via gpuAggregation: false,
88
* custom getColorValue/getElevationValue accessors, percentile filtering, and scale types.
99
* The custom CPUAggregator override from deck.gl 8 is no longer needed.
10+
*
11+
* We override getPickingInfo to add `cellOutline` — an array of [lng, lat] coordinates
12+
* computed in common space so the outline aligns with rendered cells at all latitudes.
1013
*/
1114
export default class ScaleEnhancedGridLayer extends GridLayer<any> {
1215
static defaultProps = {
1316
...GridLayer.defaultProps,
1417
gpuAggregation: false
1518
};
19+
20+
getPickingInfo(params: any) {
21+
const info = super.getPickingInfo(params);
22+
if (info.object) {
23+
const {cellOriginCommon, cellSizeCommon, aggregatorViewport} = this.state as any;
24+
const coverage = this.props.coverage ?? 1;
25+
if (cellOriginCommon && cellSizeCommon && aggregatorViewport) {
26+
const {col, row} = info.object;
27+
// Cell center in common space
28+
const cx = (col + 0.5) * cellSizeCommon[0] + cellOriginCommon[0];
29+
const cy = (row + 0.5) * cellSizeCommon[1] + cellOriginCommon[1];
30+
const hw = 0.5 * coverage * cellSizeCommon[0]; // half-width
31+
const hh = 0.5 * coverage * cellSizeCommon[1]; // half-height
32+
33+
info.object.cellOutline = [
34+
aggregatorViewport.unprojectFlat([cx - hw, cy - hh]),
35+
aggregatorViewport.unprojectFlat([cx + hw, cy - hh]),
36+
aggregatorViewport.unprojectFlat([cx + hw, cy + hh]),
37+
aggregatorViewport.unprojectFlat([cx - hw, cy + hh]),
38+
aggregatorViewport.unprojectFlat([cx - hw, cy - hh])
39+
];
40+
}
41+
}
42+
return info;
43+
}
1644
}
1745

1846
ScaleEnhancedGridLayer.layerName = 'ScaleEnhancedGridLayer';

src/deckgl-layers/src/hexagon-layer/enhanced-hexagon-layer.ts

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,57 @@
33

44
import {HexagonLayer} from '@deck.gl/aggregation-layers';
55

6+
const THIRD_PI = Math.PI / 3;
7+
const HexbinVertices = Array.from({length: 6}, (_, i) => {
8+
const angle = i * THIRD_PI;
9+
return [Math.sin(angle), -Math.cos(angle)];
10+
});
11+
12+
function getHexbinCentroid(id: [number, number], radius: number): [number, number] {
13+
const DIST_X = 2 * Math.sin(THIRD_PI);
14+
const DIST_Y = 1.5;
15+
return [(id[0] + (id[1] & 1) / 2) * radius * DIST_X, id[1] * radius * DIST_Y];
16+
}
17+
618
/**
719
* In deck.gl 9, HexagonLayer natively supports CPU aggregation via gpuAggregation: false,
820
* custom getColorValue/getElevationValue accessors, percentile filtering, and scale types.
9-
* The custom CPUAggregator override from deck.gl 8 is no longer needed.
21+
*
22+
* We override getPickingInfo to add `cellOutline` — an array of [lng, lat] coordinates
23+
* computed in common space so the outline aligns with rendered cells at all latitudes.
1024
*/
1125
export default class ScaleEnhancedHexagonLayer extends HexagonLayer<any> {
1226
static defaultProps = {
1327
...HexagonLayer.defaultProps,
1428
gpuAggregation: false
1529
};
30+
31+
getPickingInfo(params: any) {
32+
const info = super.getPickingInfo(params);
33+
if (info.object) {
34+
const {radiusCommon, hexOriginCommon, aggregatorViewport} = this.state as any;
35+
const coverage = this.props.coverage ?? 1;
36+
if (radiusCommon && aggregatorViewport) {
37+
const centroid = getHexbinCentroid(
38+
[info.object.col, info.object.row],
39+
radiusCommon
40+
);
41+
const ox = hexOriginCommon?.[0] ?? 0;
42+
const oy = hexOriginCommon?.[1] ?? 0;
43+
const r = radiusCommon * coverage;
44+
45+
const outline: number[][] = [];
46+
for (let i = 0; i < 6; i++) {
47+
const vx = centroid[0] + r * HexbinVertices[i][0] + ox;
48+
const vy = centroid[1] + r * HexbinVertices[i][1] + oy;
49+
outline.push(aggregatorViewport.unprojectFlat([vx, vy]));
50+
}
51+
outline.push(outline[0]);
52+
info.object.cellOutline = outline;
53+
}
54+
}
55+
return info;
56+
}
1657
}
1758

1859
ScaleEnhancedHexagonLayer.layerName = 'ScaleEnhancedHexagonLayer';

src/layers/src/aggregation-layer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ export default class AggregationLayer extends Layer {
365365
highlightColor: HIGHLIGH_COLOR_3D,
366366
// gpu data filtering is not supported in aggregation layer
367367
extensions: [],
368-
autoHighlight: true
368+
autoHighlight: this.config.visConfig.enable3d
369369
};
370370
}
371371

src/layers/src/grid-layer/grid-layer.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-License-Identifier: MIT
22
// Copyright contributors to the kepler.gl project
33

4+
import {GeoJsonLayer} from '@deck.gl/layers';
45
import {EnhancedGridLayer} from '@kepler.gl/deckgl-layers';
56
import AggregationLayer, {AggregationLayerConfig} from '../aggregation-layer';
67
import GridLayerIcon from './grid-layer-icon';
@@ -97,19 +98,46 @@ export default class GridLayer extends AggregationLayer {
9798
}
9899

99100
renderLayer(opts) {
100-
const {data} = opts;
101+
const {data, objectHovered, mapState} = opts;
101102

102103
const defaultAggregationLayerProps = this.getDefaultAggregationLayerProp(opts);
104+
const zoomFactor = this.getZoomFactor(mapState);
103105
const {visConfig} = this.config;
104106
const cellSize = visConfig.worldUnitSize * 1000;
107+
const hoveredObject = this.hasHoveredObject(objectHovered);
108+
109+
// Use cellOutline computed in common space by ScaleEnhancedGridLayer.getPickingInfo
110+
// so the outline aligns with rendered cells at all latitudes.
111+
const outlineCoords = hoveredObject?.cellOutline;
105112

106113
return [
107114
new EnhancedGridLayer({
108115
...defaultAggregationLayerProps,
109116
...data,
110117
wrapLongitude: false,
111118
cellSize
112-
})
119+
}),
120+
121+
// render an outline of each cell if not extruded
122+
...(outlineCoords && !visConfig.enable3d
123+
? [
124+
new GeoJsonLayer({
125+
...this.getDefaultHoverLayerProps(),
126+
visible: defaultAggregationLayerProps.visible,
127+
wrapLongitude: false,
128+
data: [
129+
{
130+
geometry: {
131+
coordinates: outlineCoords,
132+
type: 'LineString'
133+
}
134+
}
135+
],
136+
getLineColor: this.config.highlightColor,
137+
lineWidthScale: 8 * zoomFactor
138+
})
139+
]
140+
: [])
113141
];
114142
}
115143
}

src/layers/src/hexagon-layer/hexagon-layer.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-License-Identifier: MIT
22
// Copyright contributors to the kepler.gl project
33

4+
import {GeoJsonLayer} from '@deck.gl/layers';
45
import AggregationLayer, {AggregationLayerConfig} from '../aggregation-layer';
56
import {EnhancedHexagonLayer} from '@kepler.gl/deckgl-layers';
67
import HexagonLayerIcon from './hexagon-layer-icon';
@@ -105,19 +106,46 @@ export default class HexagonLayer extends AggregationLayer {
105106
}
106107

107108
renderLayer(opts) {
108-
const {data} = opts;
109+
const {data, objectHovered, mapState} = opts;
109110

110111
const defaultAggregationLayerProps = this.getDefaultAggregationLayerProp(opts);
112+
const zoomFactor = this.getZoomFactor(mapState);
111113
const {visConfig} = this.config;
112114
const radius = visConfig.worldUnitSize * 1000;
115+
const hoveredObject = this.hasHoveredObject(objectHovered);
116+
117+
// Use cellOutline computed in common space by ScaleEnhancedHexagonLayer.getPickingInfo
118+
// so the outline aligns with rendered cells at all latitudes.
119+
const outlineCoords = hoveredObject?.cellOutline;
113120

114121
return [
115122
new EnhancedHexagonLayer({
116123
...defaultAggregationLayerProps,
117124
...data,
118125
wrapLongitude: false,
119126
radius
120-
})
127+
}),
128+
129+
// render an outline of each hexagon if not extruded
130+
...(outlineCoords && !visConfig.enable3d
131+
? [
132+
new GeoJsonLayer({
133+
...this.getDefaultHoverLayerProps(),
134+
visible: defaultAggregationLayerProps.visible,
135+
wrapLongitude: false,
136+
data: [
137+
{
138+
geometry: {
139+
coordinates: outlineCoords,
140+
type: 'LineString'
141+
}
142+
}
143+
],
144+
getLineColor: this.config.highlightColor,
145+
lineWidthScale: 8 * zoomFactor
146+
})
147+
]
148+
: [])
121149
];
122150
}
123151
}

src/layers/src/hexagon-layer/hexagon-utils.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import type {Centroid} from '@kepler.gl/common-utils';
77

88
export function hexagonToPolygonGeo(object, properties, radius, mapState, coordinate?) {
99
const viewport = new WebMercatorViewport(mapState);
10-
const position = object.position || coordinate;
11-
if (!Array.isArray(position)) {
10+
const pos = object.position || coordinate;
11+
const position = pos ? Array.from(pos) : null;
12+
if (!position || position.length < 2) {
1213
return null;
1314
}
1415

0 commit comments

Comments
 (0)