From a5afc9926d3606fca567b3056d31f087c92bf44a Mon Sep 17 00:00:00 2001 From: Kanahiro Date: Sun, 7 Jan 2024 00:01:42 +0900 Subject: [PATCH 1/3] wip: cluster --- components/PrintableMap.vue | 19 ++++++++++++++++--- package.json | 3 ++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/components/PrintableMap.vue b/components/PrintableMap.vue index 0fed5a0b..4fbc8a99 100644 --- a/components/PrintableMap.vue +++ b/components/PrintableMap.vue @@ -144,6 +144,8 @@ import "simplebar/dist/simplebar.min.css"; import MapLibre from "maplibre-gl"; import { getNowYMD } from "~/lib/displayHelper"; +import clusterDbscan from '@turf/clusters-dbscan'; + const crc16 = require("js-crc").crc16; let helper; export default { @@ -193,12 +195,23 @@ export default { return newConfig; }, inBoundsMarkers() { - const inBoundsMarkers = this.layers + + const features = this.layers .filter(l => l.source.show && this.checkedArea.includes(l.source.title)) .map(l => l.markers).flat() - .filter((marker) => { + .map(m => m.feature); + + const gj = { + type: 'FeatureCollection', + features + } + + const clustered = clusterDbscan(gj, 1000, { minPoints: 2 }); + console.log(clustered) + const inBoundsMarkers = clustered.features + .filter((feature) => { if (!this.bounds) return true; - return helper.inBounds(marker.feature.geometry.coordinates, this.bounds); + return helper.inBounds(feature.geometry.coordinates, this.bounds); }); return inBoundsMarkers; }, diff --git a/package.json b/package.json index 93858c24..661c5c8e 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@mapbox/togeojson": "^0.16.0", "@nuxt/typescript-runtime": "^0.1.7", "@nuxtjs/axios": "^5.13.1", + "@turf/clusters-dbscan": "^6.5.0", "@types/maplibre-gl": "^1.13.0", "geojson": "^0.5.0", "js-crc": "^0.2.0", @@ -93,4 +94,4 @@ "ts-loader": "^6.2.2", "typescript": "^5.3.3" } -} \ No newline at end of file +} From d11e30f962376ad5e404960cc560bdd06959c5b0 Mon Sep 17 00:00:00 2001 From: Kanahiro Date: Sun, 7 Jan 2024 00:58:07 +0900 Subject: [PATCH 2/3] add supercluster --- package.json | 2 +- yarn.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 661c5c8e..112abca1 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,6 @@ "@mapbox/togeojson": "^0.16.0", "@nuxt/typescript-runtime": "^0.1.7", "@nuxtjs/axios": "^5.13.1", - "@turf/clusters-dbscan": "^6.5.0", "@types/maplibre-gl": "^1.13.0", "geojson": "^0.5.0", "js-crc": "^0.2.0", @@ -39,6 +38,7 @@ "nuxt": "^2.14.7", "nuxt-i18n": "^6.20.4", "simplebar-vue": "^1.6.0", + "supercluster": "7.1.5", "ts-node": "^8.10.2", "viewport-units-buggyfill": "^0.6.2", "vue": "^2.7.0", diff --git a/yarn.lock b/yarn.lock index 7eb2a5cb..ddc5768d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11908,7 +11908,7 @@ stylehacks@^6.0.1: browserslist "^4.21.4" postcss-selector-parser "^6.0.4" -supercluster@^7.1.0: +supercluster@7.1.5, supercluster@^7.1.0: version "7.1.5" resolved "https://registry.yarnpkg.com/supercluster/-/supercluster-7.1.5.tgz#65a6ce4a037a972767740614c19051b64b8be5a3" integrity sha512-EulshI3pGUM66o6ZdH3ReiFcvHpM3vAigyK+vcxdjpJyEbIIrtbmBdY23mGgnI24uXiGFvrGq9Gkum/8U7vJWg== From 8021af2a3d0863612fbd9d2105bd059bcc469abb Mon Sep 17 00:00:00 2001 From: Kanahiro Date: Sun, 7 Jan 2024 00:58:22 +0900 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20=E4=B8=80=E5=AE=9A=E4=B8=8A?= =?UTF-8?q?=E3=81=AE=E3=82=BA=E3=83=BC=E3=83=A0=E3=81=A7=E3=82=AF=E3=83=A9?= =?UTF-8?q?=E3=82=B9=E3=82=BF=E3=83=AA=E3=83=B3=E3=82=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/PrintableMap.vue | 44 +++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/components/PrintableMap.vue b/components/PrintableMap.vue index 4fbc8a99..e6384c0c 100644 --- a/components/PrintableMap.vue +++ b/components/PrintableMap.vue @@ -142,10 +142,9 @@ div import "maplibre-gl/dist/maplibre-gl.css"; import "simplebar/dist/simplebar.min.css"; import MapLibre from "maplibre-gl"; +import Supercluster from 'supercluster'; import { getNowYMD } from "~/lib/displayHelper"; -import clusterDbscan from '@turf/clusters-dbscan'; - const crc16 = require("js-crc").crc16; let helper; export default { @@ -195,25 +194,38 @@ export default { return newConfig; }, inBoundsMarkers() { + if (!this.bounds) return []; + // SuperClusterに食わせるためにGeoJSON-Featureの配列を作成 const features = this.layers - .filter(l => l.source.show && this.checkedArea.includes(l.source.title)) + .filter(l => l.source.show && this.checkedArea.includes(l.source.title)) // 表示中のソースのみ .map(l => l.markers).flat() - .map(m => m.feature); + .filter((marker) => helper.inBounds(marker.feature.geometry.coordinates, this.bounds)) // 表示範囲内のマーカーのみ + .map(m => ({...m.feature, properties: {...m.feature.properties, category: m.category}})); // categoryを保存 - const gj = { - type: 'FeatureCollection', - features - } - - const clustered = clusterDbscan(gj, 1000, { minPoints: 2 }); - console.log(clustered) - const inBoundsMarkers = clustered.features - .filter((feature) => { - if (!this.bounds) return true; - return helper.inBounds(feature.geometry.coordinates, this.bounds); + // SuperClusterでクラスタリング + const index = new Supercluster({ + radius: 20, // px: クラスタリングする範囲 + maxZoom: 9 // クラスタリングする最大のズームレベル + }); + index.load(features); + const clustered = index.getClusters([-180, -85, 180, 85], Math.floor(this.map.map.getZoom())); + + // システムに準拠した構造に変換: Array<{feature: GeoJSON-Feature, category: カテゴリ名}> + const markers = clustered + .map((feature) => { + let _feature = feature; + if (feature.properties.cluster) { + _feature = index.getLeaves(feature.properties.cluster_id, 1)[0]; + } + const marker = { + feature: _feature, + category: _feature.properties.category, + }; + return marker; }); - return inBoundsMarkers; + + return markers; }, displayMarkersGroupByCategory() { const resultGroupBy = this.inBoundsMarkers.reduce((groups, current) => {