feat([2fd88f42]): add heatmap view with toggle switch
This commit is contained in:
@@ -1,68 +1,81 @@
|
||||
// src/components/MapDisplay.tsx
|
||||
import React from 'react';
|
||||
import { MapContainer, TileLayer, CircleMarker, Tooltip } from 'react-leaflet';
|
||||
import { HeatmapLayer } from 'react-leaflet-heatmap-layer-v3';
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
import type { HeatmapPoint } from '../App';
|
||||
import 'leaflet.heat';
|
||||
import type { HeatmapPoint, MapMode } from '../App';
|
||||
|
||||
interface MapDisplayProps {
|
||||
heatmapData: HeatmapPoint[];
|
||||
radiusMultiplier: number;
|
||||
viewMode: MapMode;
|
||||
}
|
||||
|
||||
const MapDisplay: React.FC<MapDisplayProps> = ({ heatmapData, radiusMultiplier }) => {
|
||||
const MapDisplay: React.FC<MapDisplayProps> = ({ heatmapData, radiusMultiplier, viewMode }) => {
|
||||
const germanyCenter: [number, number] = [51.1657, 10.4515];
|
||||
const maxCount = Math.max(...heatmapData.map(p => p.count), 1);
|
||||
|
||||
// Simple scaling function for marker radius, now with a multiplier
|
||||
const calculateRadius = (count: number) => {
|
||||
// Ensure a base radius so even single points are visible
|
||||
// The multiplier is applied to the dynamic part of the radius
|
||||
return 3 + Math.log(count + 1) * 5 * radiusMultiplier;
|
||||
};
|
||||
|
||||
// Simple color scaling function
|
||||
const getColor = (count: number, maxCount: number) => {
|
||||
const getColor = (count: number) => {
|
||||
const ratio = count / maxCount;
|
||||
if (ratio > 0.8) return '#d73027'; // Red
|
||||
if (ratio > 0.5) return '#fdae61'; // Orange
|
||||
if (ratio > 0.2) return '#fee08b'; // Yellow
|
||||
return '#66bd63'; // Green
|
||||
}
|
||||
};
|
||||
|
||||
const maxCount = Math.max(...heatmapData.map(p => p.count), 1);
|
||||
const renderPoints = () => (
|
||||
heatmapData.map((point, idx) => (
|
||||
<CircleMarker
|
||||
key={idx}
|
||||
center={[point.lat, point.lon]}
|
||||
radius={calculateRadius(point.count)}
|
||||
pathOptions={{
|
||||
color: getColor(point.count),
|
||||
fillColor: getColor(point.count),
|
||||
fillOpacity: 0.7
|
||||
}}
|
||||
>
|
||||
<Tooltip>
|
||||
PLZ: {point.plz} <br />
|
||||
Count: {point.count}
|
||||
</Tooltip>
|
||||
</CircleMarker>
|
||||
))
|
||||
);
|
||||
|
||||
const renderHeatmap = () => (
|
||||
<HeatmapLayer
|
||||
points={heatmapData}
|
||||
longitudeExtractor={(p: HeatmapPoint) => p.lon}
|
||||
latitudeExtractor={(p: HeatmapPoint) => p.lat}
|
||||
intensityExtractor={(p: HeatmapPoint) => p.count}
|
||||
radius={25}
|
||||
blur={20}
|
||||
max={maxCount * 0.1} // Adjust max intensity for better visualization
|
||||
/>
|
||||
);
|
||||
|
||||
if (heatmapData.length === 0) {
|
||||
return (
|
||||
<div style={{ textAlign: 'center', paddingTop: '50px' }}>
|
||||
<p>No data to display on the map.</p>
|
||||
<p>Upload a file and apply filters to see the heatmap.</p>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div style={{ textAlign: 'center', paddingTop: '50px' }}>
|
||||
<p>No data to display on the map.</p>
|
||||
<p>Upload a file and apply filters to see the heatmap.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<MapContainer center={germanyCenter} zoom={6} style={{ height: '100%', width: '100%' }}>
|
||||
<MapContainer key={viewMode} center={germanyCenter} zoom={6} style={{ height: '100%', width: '100%' }}>
|
||||
<TileLayer
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
/>
|
||||
{heatmapData.map((point, idx) => (
|
||||
<CircleMarker
|
||||
key={idx}
|
||||
center={[point.lat, point.lon]}
|
||||
radius={calculateRadius(point.count)}
|
||||
pathOptions={{
|
||||
color: getColor(point.count, maxCount),
|
||||
fillColor: getColor(point.count, maxCount),
|
||||
fillOpacity: 0.7
|
||||
}}
|
||||
>
|
||||
<Tooltip>
|
||||
PLZ: {point.plz} <br />
|
||||
Count: {point.count}
|
||||
</Tooltip>
|
||||
</CircleMarker>
|
||||
))}
|
||||
{viewMode === 'points' ? renderPoints() : renderHeatmap()}
|
||||
</MapContainer>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user