Skip to content

Commit a364a48

Browse files
authored
Check for correct layerName when highlighting in MVTLayer (visgl#6062)
1 parent 1f6ab32 commit a364a48

File tree

4 files changed

+131
-19
lines changed

4 files changed

+131
-19
lines changed

modules/geo-layers/src/mvt-layer/mvt-layer.js

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -158,16 +158,24 @@ export default class MVTLayer extends TileLayer {
158158
_updateAutoHighlight(info) {
159159
const {uniqueIdProperty} = this.props;
160160

161-
const {hoveredFeatureId} = this.state;
161+
const {hoveredFeatureId, hoveredFeatureLayerName} = this.state;
162162
const hoveredFeature = info.object;
163163
let newHoveredFeatureId;
164+
let newHoveredFeatureLayerName;
164165

165166
if (hoveredFeature) {
166167
newHoveredFeatureId = getFeatureUniqueId(hoveredFeature, uniqueIdProperty);
168+
newHoveredFeatureLayerName = getFeatureLayerName(hoveredFeature);
167169
}
168170

169-
if (hoveredFeatureId !== newHoveredFeatureId && newHoveredFeatureId !== -1) {
170-
this.setState({hoveredFeatureId: newHoveredFeatureId});
171+
if (
172+
hoveredFeatureId !== newHoveredFeatureId ||
173+
hoveredFeatureLayerName !== newHoveredFeatureLayerName
174+
) {
175+
this.setState({
176+
hoveredFeatureId: newHoveredFeatureId,
177+
hoveredFeatureLayerName: newHoveredFeatureLayerName
178+
});
171179
}
172180
}
173181

@@ -188,26 +196,27 @@ export default class MVTLayer extends TileLayer {
188196
}
189197

190198
getHighlightedObjectIndex(tile) {
191-
const {hoveredFeatureId} = this.state;
199+
const {hoveredFeatureId, hoveredFeatureLayerName} = this.state;
192200
const {uniqueIdProperty, highlightedFeatureId, binary} = this.props;
193201
const {data} = tile;
194202

195-
const isFeatureIdPresent =
196-
isFeatureIdDefined(hoveredFeatureId) || isFeatureIdDefined(highlightedFeatureId);
203+
const isHighlighted = isFeatureIdDefined(highlightedFeatureId);
204+
const isFeatureIdPresent = isFeatureIdDefined(hoveredFeatureId) || isHighlighted;
197205

198206
if (!isFeatureIdPresent) {
199207
return -1;
200208
}
201209

202-
const featureIdToHighlight = isFeatureIdDefined(highlightedFeatureId)
203-
? highlightedFeatureId
204-
: hoveredFeatureId;
210+
const featureIdToHighlight = isHighlighted ? highlightedFeatureId : hoveredFeatureId;
205211

206212
// Iterable data
207213
if (Array.isArray(data)) {
208-
return data.findIndex(
209-
feature => getFeatureUniqueId(feature, uniqueIdProperty) === featureIdToHighlight
210-
);
214+
return data.findIndex(feature => {
215+
const isMatchingId = getFeatureUniqueId(feature, uniqueIdProperty) === featureIdToHighlight;
216+
const isMatchingLayer =
217+
isHighlighted || getFeatureLayerName(feature) === hoveredFeatureLayerName;
218+
return isMatchingId && isMatchingLayer;
219+
});
211220

212221
// Non-iterable data
213222
} else if (data && binary) {
@@ -242,7 +251,7 @@ export default class MVTLayer extends TileLayer {
242251
for (const f of features) {
243252
const featureId = getFeatureUniqueId(f.object, this.props.uniqueIdProperty);
244253

245-
if (featureId === -1) {
254+
if (featureId === undefined) {
246255
// we have no id for the feature, we just add to the list
247256
renderedFeatures.push(f.object);
248257
} else if (!featureCache.has(featureId)) {
@@ -299,7 +308,11 @@ function getFeatureUniqueId(feature, uniqueIdProperty) {
299308
return feature.id;
300309
}
301310

302-
return -1;
311+
return undefined;
312+
}
313+
314+
function getFeatureLayerName(feature) {
315+
return feature.properties?.layerName || null;
303316
}
304317

305318
function isFeatureIdDefined(value) {

modules/test-utils/src/index.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ export {toLowPrecision} from './utils/precision';
22
export {default as gl} from './utils/setup-gl';
33

44
// Utilities for update tests (lifecycle tests)
5-
export {testLayer, testLayerAsync, testInitializeLayer} from './lifecycle-test';
5+
export {
6+
testLayer,
7+
testLayerAsync,
8+
testInitializeLayer,
9+
testInitializeLayerAsync
10+
} from './lifecycle-test';
611
export {generateLayerTests} from './generate-layer-tests';
712

813
// Basic utility for rendering multiple scenes (could go into "deck.gl/core")

modules/test-utils/src/lifecycle-test.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,29 @@ function defaultOnError(error, title) {
3535
}
3636
}
3737

38-
export function testInitializeLayer({layer, viewport = testViewport, onError = defaultOnError}) {
38+
function initializeLayerManager({layer, viewport = testViewport, onError = defaultOnError}) {
3939
const layerManager = new LayerManager(gl, {viewport});
4040
layerManager.setProps({
4141
onError: error => onError(error, `initializing ${layer.id}`)
4242
});
4343

4444
layerManager.setLayers([layer]);
45+
return layerManager;
46+
}
47+
48+
export function testInitializeLayer(opts) {
49+
const layerManager = initializeLayerManager(opts);
4550
layerManager.finalize();
51+
return null;
52+
}
4653

54+
export async function testInitializeLayerAsync(opts) {
55+
const layerManager = initializeLayerManager(opts);
56+
const deckRenderer = new DeckRenderer(gl);
57+
while (!opts.layer.isLoaded) {
58+
await update({layerManager, deckRenderer});
59+
}
60+
layerManager.finalize();
4761
return null;
4862
}
4963

test/modules/core/lib/picking.spec.js

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import test from 'tape-catch';
2222
import {processPickInfo} from '@deck.gl/core/lib/picking/pick-info';
2323
import {WebMercatorViewport} from '@deck.gl/core';
2424
import {ScatterplotLayer, GeoJsonLayer} from '@deck.gl/layers';
25-
import {testInitializeLayer} from '@deck.gl/test-utils';
25+
import {MVTLayer} from '@deck.gl/geo-layers';
26+
import {testInitializeLayer, testInitializeLayerAsync} from '@deck.gl/test-utils';
2627

2728
import {equals} from 'math.gl';
2829

@@ -46,6 +47,33 @@ const testCompositeLayer = new GeoJsonLayer({
4647
data: [{type: 'Feature', geometry: {type: 'Point', coordinates: [0, 0]}}]
4748
});
4849

50+
class TestMVTLayer extends MVTLayer {
51+
getTileData() {
52+
return this.props.data;
53+
}
54+
}
55+
56+
TestMVTLayer.componentName = 'TestMVTLayer';
57+
58+
const testMVTLayer = new TestMVTLayer({
59+
id: 'test-mvt-layer',
60+
autoHighlight: true,
61+
data: [
62+
{
63+
id: 12,
64+
type: 'Feature',
65+
geometry: {type: 'Point', coordinates: [0, 0]},
66+
properties: {layerName: 'layerA'}
67+
},
68+
{
69+
id: 12,
70+
type: 'Feature',
71+
geometry: {type: 'Point', coordinates: [0, 0]},
72+
properties: {layerName: 'layerB'}
73+
}
74+
]
75+
});
76+
4977
const parameters = {
5078
mode: 'hover',
5179
viewports: [
@@ -78,7 +106,7 @@ const parameters = {
78106
height: 100
79107
})
80108
],
81-
layers: [testLayer, testLayerWithCallback, testCompositeLayer],
109+
layers: [testLayer, testLayerWithCallback, testCompositeLayer, testMVTLayer],
82110
layerFilter: ({layer, viewport}) => {
83111
if (viewport.id === 'minimap') {
84112
return layer.id !== 'test-layer-with-callback';
@@ -98,10 +126,11 @@ function validateUniforms(actual, expected) {
98126
}
99127

100128
/* eslint-disable max-statements */
101-
test('processPickInfo', t => {
129+
test('processPickInfo', async t => {
102130
testInitializeLayer({layer: testLayer});
103131
testInitializeLayer({layer: testLayerWithCallback});
104132
testInitializeLayer({layer: testCompositeLayer});
133+
await testInitializeLayerAsync({layer: testMVTLayer});
105134

106135
const TEST_CASES = [
107136
{
@@ -202,6 +231,50 @@ test('processPickInfo', t => {
202231
lastPickedInfo: {layerId: 'test-composite-layer-points-circle', index: 0},
203232
testLayerUniforms: {picking_uSelectedColorValid: 0}
204233
},
234+
{
235+
pickInfo: {
236+
pickedColor: [1, 0, 0, 0],
237+
pickedLayer: testMVTLayer.getSubLayers()[0].getSubLayers()[0],
238+
pickedObjectIndex: 0
239+
},
240+
x: 100,
241+
y: 100,
242+
size: 2,
243+
info: {
244+
layer: testMVTLayer,
245+
object: {
246+
id: 12,
247+
type: 'Feature',
248+
geometry: {type: 'Point'},
249+
properties: {layerName: 'layerA'}
250+
}
251+
},
252+
highlightedObjectIndex: 0,
253+
lastPickedInfo: {layerId: 'test-mvt-layer-0-0-1-points-circle', index: 0},
254+
testLayerUniforms: {picking_uSelectedColorValid: 0}
255+
},
256+
{
257+
pickInfo: {
258+
pickedColor: [2, 0, 0, 0],
259+
pickedLayer: testMVTLayer.getSubLayers()[0].getSubLayers()[0],
260+
pickedObjectIndex: 1
261+
},
262+
x: 100,
263+
y: 100,
264+
size: 2,
265+
info: {
266+
layer: testMVTLayer,
267+
object: {
268+
id: 12,
269+
type: 'Feature',
270+
geometry: {type: 'Point'},
271+
properties: {layerName: 'layerB'}
272+
}
273+
},
274+
highlightedObjectIndex: 1,
275+
lastPickedInfo: {layerId: 'test-mvt-layer-0-0-1-points-circle', index: 1},
276+
testLayerUniforms: {picking_uSelectedColorValid: 0}
277+
},
205278
{
206279
pickInfo: {
207280
pickedColor: [1, 0, 0, 0],
@@ -277,11 +350,18 @@ test('processPickInfo', t => {
277350
'currentLayerUniforms'
278351
);
279352
}
353+
354+
if (testCase.highlightedObjectIndex !== undefined) {
355+
const renderedLayer = info.layer.renderLayers()[0][0];
356+
const {highlightedObjectIndex} = renderedLayer.props;
357+
t.deepEqual(highlightedObjectIndex, testCase.highlightedObjectIndex, 'highlightObjectIndex');
358+
}
280359
}
281360

282361
testLayer._finalize();
283362
testLayerWithCallback._finalize();
284363
testCompositeLayer._finalize();
364+
testMVTLayer._finalize();
285365

286366
t.end();
287367
});

0 commit comments

Comments
 (0)