From 4ffb52afbf9abfc4751a4338b4b84abf8a82a7b4 Mon Sep 17 00:00:00 2001 From: Floke Date: Wed, 4 Feb 2026 13:31:11 +0000 Subject: [PATCH] feat([2fd88f42]): add marker clustering to points view --- heatmap-tool/frontend/package-lock.json | 37 ++++++++++++ heatmap-tool/frontend/package.json | 2 + heatmap-tool/frontend/src/App.tsx | 2 + .../frontend/src/components/MapDisplay.tsx | 57 ++++++++++++------- 4 files changed, 76 insertions(+), 22 deletions(-) diff --git a/heatmap-tool/frontend/package-lock.json b/heatmap-tool/frontend/package-lock.json index 5b577c65..0afff82e 100644 --- a/heatmap-tool/frontend/package-lock.json +++ b/heatmap-tool/frontend/package-lock.json @@ -14,11 +14,13 @@ "react": "^19.2.0", "react-dom": "^19.2.0", "react-leaflet": "^5.0.0", + "react-leaflet-cluster": "^4.0.0", "react-leaflet-heatmap-layer-v3": "^3.0.3-beta-1" }, "devDependencies": { "@eslint/js": "^9.39.1", "@types/leaflet": "^1.9.21", + "@types/leaflet.markercluster": "^1.5.6", "@types/node": "^24.10.1", "@types/react": "^19.2.5", "@types/react-dom": "^19.2.3", @@ -1459,6 +1461,16 @@ "@types/geojson": "*" } }, + "node_modules/@types/leaflet.markercluster": { + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/@types/leaflet.markercluster/-/leaflet.markercluster-1.5.6.tgz", + "integrity": "sha512-I7hZjO2+isVXGYWzKxBp8PsCzAYCJBc29qBdFpquOCkS7zFDqUsUvkEOyQHedsk/Cy5tocQzf+Ndorm5W9YKTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/leaflet": "^1.9" + } + }, "node_modules/@types/node": { "version": "24.10.10", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.10.tgz", @@ -2855,6 +2867,15 @@ "resolved": "https://registry.npmjs.org/leaflet.heat/-/leaflet.heat-0.2.0.tgz", "integrity": "sha512-Cd5PbAA/rX3X3XKxfDoUGi9qp78FyhWYurFg3nsfhntcM/MCNK08pRkf4iEenO1KNqwVPKCmkyktjW3UD+h9bQ==" }, + "node_modules/leaflet.markercluster": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/leaflet.markercluster/-/leaflet.markercluster-1.5.3.tgz", + "integrity": "sha512-vPTw/Bndq7eQHjLBVlWpnGeLa3t+3zGiuM7fJwCkiMFq+nmRuG3RI3f7f4N4TDX7T4NpbAXpR2+NTRSEGfCSeA==", + "license": "MIT", + "peerDependencies": { + "leaflet": "^1.3.1" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -3178,6 +3199,22 @@ "react-dom": "^19.0.0" } }, + "node_modules/react-leaflet-cluster": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/react-leaflet-cluster/-/react-leaflet-cluster-4.0.0.tgz", + "integrity": "sha512-Lu75+KOu2ruGyAx8LoCQvlHuw+3CLLJQGEoSk01ymsDN/YnCiRV6ChkpsvaruVyYBPzUHwiskFw4Jo7WHj5qNw==", + "license": "SEE LICENSE IN ", + "dependencies": { + "leaflet.markercluster": "^1.5.3" + }, + "peerDependencies": { + "@react-leaflet/core": "^3.0.0", + "leaflet": "^1.9.0", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-leaflet": "^5.0.0" + } + }, "node_modules/react-leaflet-heatmap-layer-v3": { "version": "3.0.3-beta-1", "resolved": "https://registry.npmjs.org/react-leaflet-heatmap-layer-v3/-/react-leaflet-heatmap-layer-v3-3.0.3-beta-1.tgz", diff --git a/heatmap-tool/frontend/package.json b/heatmap-tool/frontend/package.json index d12f1c87..917754e3 100644 --- a/heatmap-tool/frontend/package.json +++ b/heatmap-tool/frontend/package.json @@ -16,11 +16,13 @@ "react": "^19.2.0", "react-dom": "^19.2.0", "react-leaflet": "^5.0.0", + "react-leaflet-cluster": "^4.0.0", "react-leaflet-heatmap-layer-v3": "^3.0.3-beta-1" }, "devDependencies": { "@eslint/js": "^9.39.1", "@types/leaflet": "^1.9.21", + "@types/leaflet.markercluster": "^1.5.6", "@types/node": "^24.10.1", "@types/react": "^19.2.5", "@types/react-dom": "^19.2.3", diff --git a/heatmap-tool/frontend/src/App.tsx b/heatmap-tool/frontend/src/App.tsx index a21e4807..cdd8fb3e 100644 --- a/heatmap-tool/frontend/src/App.tsx +++ b/heatmap-tool/frontend/src/App.tsx @@ -1,6 +1,8 @@ import { useState } from 'react'; import axios from 'axios'; import './App.css'; +import 'react-leaflet-cluster/dist/assets/MarkerCluster.css'; +import 'react-leaflet-cluster/dist/assets/MarkerCluster.Default.css'; import FileUpload from './components/FileUpload'; import FilterPanel from './components/FilterPanel'; import MapDisplay from './components/MapDisplay'; diff --git a/heatmap-tool/frontend/src/components/MapDisplay.tsx b/heatmap-tool/frontend/src/components/MapDisplay.tsx index 42d535c3..f0006744 100644 --- a/heatmap-tool/frontend/src/components/MapDisplay.tsx +++ b/heatmap-tool/frontend/src/components/MapDisplay.tsx @@ -28,31 +28,44 @@ const MapDisplay: React.FC = ({ heatmapData, radiusMultiplier, return '#66bd63'; // Green }; +import MarkerClusterGroup from 'react-leaflet-cluster'; + +// ... (imports and interface definitions) + +const MapDisplay: React.FC = ({ heatmapData, radiusMultiplier, viewMode }) => { + // ... (helper functions and state) + const renderPoints = () => ( - heatmapData.map((point, idx) => ( - - - PLZ: {point.plz}
- Count: {point.count} - {point.attributes_summary && Object.entries(point.attributes_summary).map(([attr, values]) => ( -
- {attr}: {values.join(', ')} -
- ))} -
-
- )) + + {heatmapData.map((point, idx) => ( + + + PLZ: {point.plz}
+ Count: {point.count} + {point.attributes_summary && Object.entries(point.attributes_summary).map(([attr, values]) => ( +
+ {attr}: {values.join(', ')} +
+ ))} +
+
+ ))} +
); + // ... (rest of the component) +}; + + const renderHeatmap = () => (