From 8476d83e57d83f5db55f9113e09ceb5716b8b378 Mon Sep 17 00:00:00 2001 From: Christoph Bornkessel Date: Thu, 1 Sep 2022 19:33:18 +0200 Subject: [PATCH 1/4] create function to get the zoom level where a point gets unclustered --- README.md | 4 ++++ index.js | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/README.md b/README.md index df5dbb65..ab16c78e 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,10 @@ and `offset` is the amount of points to skip (for pagination). Returns the zoom on which the cluster expands into several children (useful for "click to zoom" feature) given the cluster's `cluster_id`. +#### `getPointUnclusterZoom(point)` + +Returns the zoom on which a point appears unclustered. The point must be provided as array with `[Lng, Lat]`. + ## Options | Option | Default | Description | diff --git a/index.js b/index.js index dc2601ba..24f75997 100644 --- a/index.js +++ b/index.js @@ -167,6 +167,27 @@ export default class Supercluster { return expansionZoom; } + getPointUnclusterZoom(point) { + const [lng, lat] = point; + const pointX = fround(lngX(lng)); + const pointY = fround(latY(lat)); + + let expansionZoom = 0; + while (expansionZoom <= this.options.maxZoom) { + const tree = this.trees[expansionZoom]; + + const unclustered = tree.points.some( + treePoint => !treePoint.id && treePoint.x === pointX && treePoint.y === pointY + ); + + if (unclustered) return expansionZoom; + + expansionZoom++; + } + + return expansionZoom; + } + _appendLeaves(result, clusterId, limit, offset, skipped) { const children = this.getChildren(clusterId); From b825ae1c4caad2a302e34e9a29b8ea1b77406cd7 Mon Sep 17 00:00:00 2001 From: Christoph Bornkessel Date: Mon, 5 Sep 2022 16:55:17 +0200 Subject: [PATCH 2/4] improved logic of getPointUnclusterZoom function --- index.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 24f75997..6e762730 100644 --- a/index.js +++ b/index.js @@ -172,14 +172,15 @@ export default class Supercluster { const pointX = fround(lngX(lng)); const pointY = fround(latY(lat)); - let expansionZoom = 0; + let expansionZoom = this.options.minZoom; while (expansionZoom <= this.options.maxZoom) { const tree = this.trees[expansionZoom]; - const unclustered = tree.points.some( - treePoint => !treePoint.id && treePoint.x === pointX && treePoint.y === pointY - ); + const pointIdxs = tree.within(pointX, pointY, 0); + const unclustered = pointIdxs.some( + idx => tree.points[idx].parentId !== -1 + ); if (unclustered) return expansionZoom; expansionZoom++; From 033a66ca49033496a9e25f55446f12a58e9cdec3 Mon Sep 17 00:00:00 2001 From: Christoph Bornkessel Date: Fri, 16 Sep 2022 10:50:05 +0200 Subject: [PATCH 3/4] minor bug fix to prevent exceeding the max zoom level --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 6e762730..a151c9d2 100644 --- a/index.js +++ b/index.js @@ -173,7 +173,7 @@ export default class Supercluster { const pointY = fround(latY(lat)); let expansionZoom = this.options.minZoom; - while (expansionZoom <= this.options.maxZoom) { + while (expansionZoom < this.options.maxZoom) { const tree = this.trees[expansionZoom]; const pointIdxs = tree.within(pointX, pointY, 0); From 94ed77d44537c38bac69ae01106235c00069ec21 Mon Sep 17 00:00:00 2001 From: Christoph Bornkessel Date: Wed, 26 Apr 2023 22:22:58 +0200 Subject: [PATCH 4/4] updates getPointUnclusterZoom function to latest supercluster version adds unit test for point uncluster function --- index.js | 2 +- test/test.js | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index c06614af..b86c58a9 100644 --- a/index.js +++ b/index.js @@ -203,7 +203,7 @@ export default class Supercluster { const pointIdxs = tree.within(pointX, pointY, 0); const unclustered = pointIdxs.some( - idx => tree.points[idx].parentId !== -1 + idx => tree.data[idx].parentId !== -1 ); if (unclustered) return expansionZoom; diff --git a/test/test.js b/test/test.js index 74671ff0..59525495 100644 --- a/test/test.js +++ b/test/test.js @@ -172,3 +172,17 @@ test('makes sure unclustered point coords are not rounded', () => { assert.deepEqual(index.getTile(20, 1028744, 656754).features[0].geometry[0], [421, 281]); }); + +test('returns point uncluster zoom level', () => { + const points = [ + {type: 'Feature', geometry: {type: 'Point', coordinates: [173, 53]}}, + {type: 'Feature', geometry: {type: 'Point', coordinates: [174, 54]}} + ]; + const index = new Supercluster({maxZoom: 19}).load(points); + const cluster = index.getClusters([172, 52, 175, 55], 1)[0]; + + const clusterExpansionZoom = index.getClusterExpansionZoom(cluster.id); + const pointUnclusterZoom = index.getPointUnclusterZoom(points[0].geometry.coordinates); + + assert.deepEqual(clusterExpansionZoom, pointUnclusterZoom); +});