Skip to content

Commit 735bfc0

Browse files
igorDykhtaIhor Dykhta
andauthored
fix: Fix PointLayer polygon filtering for GeoJSON column mode (#3410)
* fix: Fix PointLayer polygon filtering for GeoJSON column mode Signed-off-by: Ihor Dykhta <ihordykhta@Ihors-MacBook-Pro.local> * fix highlighting for point layer in geojson mode Signed-off-by: Ihor Dykhta <ihordykhta@Ihors-MacBook-Pro.local> * improve Signed-off-by: Ihor Dykhta <ihordykhta@Ihors-MacBook-Pro.local> --------- Signed-off-by: Ihor Dykhta <ihordykhta@Ihors-MacBook-Pro.local> Co-authored-by: Ihor Dykhta <ihordykhta@Ihors-MacBook-Pro.local>
1 parent 06f59ea commit 735bfc0

3 files changed

Lines changed: 80 additions & 1 deletion

File tree

src/layers/src/point-layer/point-layer.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ export default class PointLayer extends Layer {
441441
pushPointPosition(data, pos, index, neighbors);
442442
} else {
443443
// COLUMN_MODE_GEOJSON mode - point from geojson coordinates
444-
const coordinates = this.dataToFeature[i];
444+
const coordinates = this.dataToFeature[index];
445445
// if multi points
446446
if (coordinates && Array.isArray(coordinates[0])) {
447447
coordinates.forEach(coord => {
@@ -647,6 +647,14 @@ export default class PointLayer extends Layer {
647647
objectInfo.index >= 0 &&
648648
this.dataContainer
649649
) {
650+
if (this.config.columnMode === COLUMN_MODE_GEOJSON) {
651+
const coordinates = this.dataToFeature[objectInfo.index];
652+
if (!coordinates) return null;
653+
const position = Array.isArray(coordinates[0])
654+
? (coordinates as number[][])[0]
655+
: coordinates;
656+
return {index: objectInfo.index, position};
657+
}
650658
return {
651659
index: objectInfo.index,
652660
position: this.getPositionAccessor(this.dataContainer)(objectInfo)

src/utils/src/filter-utils.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,23 @@ export const getPolygonFilterFunctor = (layer, filter, dataContainer) => {
382382
switch (layer.type) {
383383
case LAYER_TYPES.point:
384384
case LAYER_TYPES.icon:
385+
if (layer.config?.columnMode === 'geojson' && layer.dataToFeature?.length) {
386+
return data => {
387+
const coordinates = layer.dataToFeature[data.index];
388+
if (!coordinates) return false;
389+
if (Array.isArray(coordinates[0])) {
390+
return (coordinates as number[][]).some(
391+
coord =>
392+
coord.length >= 2 && coord.every(Number.isFinite) && isInPolygon(coord, filter.value)
393+
);
394+
}
395+
return (
396+
coordinates.length >= 2 &&
397+
coordinates.every(Number.isFinite) &&
398+
isInPolygon(coordinates, filter.value)
399+
);
400+
};
401+
}
385402
return data => {
386403
const pos = getPosition(data);
387404
return pos.every(Number.isFinite) && isInPolygon(pos, filter.value);

test/node/utils/filter-utils-test.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
validatePolygonFilter,
1515
generatePolygonFilter,
1616
isInPolygon,
17+
getPolygonFilterFunctor,
1718
diffFilters,
1819
getTimestampFieldDomain,
1920
scaleSourceDomainToDestination,
@@ -662,3 +663,56 @@ test('filterUtils -> mergeFilterWithTimeline', t => {
662663

663664
t.end();
664665
});
666+
667+
test('filterUtils -> getPolygonFilterFunctor -> point layer with dataToFeature (GeoJSON column mode)', t => {
668+
const squarePolygon = {
669+
type: 'Feature',
670+
properties: {},
671+
geometry: {
672+
type: 'Polygon',
673+
coordinates: [[[-1, -1], [1, -1], [1, 1], [-1, 1], [-1, -1]]]
674+
}
675+
};
676+
677+
const filter = {value: squarePolygon};
678+
679+
// Point layer with dataToFeature (GeoJSON column mode)
680+
const layerWithDataToFeature = {
681+
type: 'point',
682+
config: {columnMode: 'geojson'},
683+
getPositionAccessor: () => () => null,
684+
dataToFeature: {
685+
length: 6,
686+
0: [0.5, 0.5], // inside
687+
1: [10, 10], // outside
688+
2: [[10, 10], [0.2, 0.2]], // MultiPoint: one inside
689+
3: [[10, 10], [20, 20]], // MultiPoint: all outside
690+
4: [], // empty coordinates (e.g. empty GeometryCollection)
691+
5: [[], [0.5, 0.5]] // MultiPoint with one empty coord pair
692+
}
693+
};
694+
695+
const fn = getPolygonFilterFunctor(layerWithDataToFeature, filter, null);
696+
697+
t.equal(fn({index: 0}), true, 'Single point inside polygon should return true');
698+
t.equal(fn({index: 1}), false, 'Single point outside polygon should return false');
699+
t.equal(fn({index: 2}), true, 'MultiPoint with at least one point inside should return true');
700+
t.equal(fn({index: 3}), false, 'MultiPoint with all points outside should return false');
701+
t.equal(fn({index: 4}), false, 'Empty coordinates should return false');
702+
t.equal(fn({index: 5}), true, 'MultiPoint with one empty and one valid inside should return true');
703+
704+
// Point layer without dataToFeature (standard column mode)
705+
const layerWithoutDataToFeature = {
706+
type: 'point',
707+
config: {columnMode: 'points'},
708+
getPositionAccessor: () => d => d.position,
709+
dataToFeature: []
710+
};
711+
712+
const fn2 = getPolygonFilterFunctor(layerWithoutDataToFeature, filter, null);
713+
714+
t.equal(fn2({position: [0.5, 0.5]}), true, 'Standard mode: point inside should return true');
715+
t.equal(fn2({position: [10, 10]}), false, 'Standard mode: point outside should return false');
716+
717+
t.end();
718+
});

0 commit comments

Comments
 (0)