@mytec: iter7.2 ready for test
This commit is contained in:
@@ -34,32 +34,41 @@ function rsrpToIntensity(rsrp: number): number {
|
||||
}
|
||||
|
||||
/**
|
||||
* Zoom-compensated heatmap parameters.
|
||||
* Geographic scale-aware heatmap parameters.
|
||||
*
|
||||
* radius & blur are zoom-dependent for visual quality (smooth coverage
|
||||
* at any zoom level). But changing radius changes point overlap, which
|
||||
* shifts apparent color. To compensate:
|
||||
* The key insight: we want each heatmap point to cover a constant
|
||||
* GEOGRAPHIC area (400m radius) regardless of zoom level. Since
|
||||
* leaflet.heat works in pixels, we convert:
|
||||
*
|
||||
* maxIntensity = baseMax * (radius / baselineRadius)
|
||||
* pixelsPerKm = 2^zoom * 6.4 (at equator, simplified)
|
||||
* radiusPixels = targetRadiusKm * pixelsPerKm
|
||||
*
|
||||
* When radius is large (zoomed out, more overlap) → higher max → same color.
|
||||
* When radius is small (zoomed in, less overlap) → lower max → same color.
|
||||
* With progressive clamps for visual quality:
|
||||
* - Low zoom (≤9): min 15px, max 45px (avoid giant blobs)
|
||||
* - High zoom (≥10): min 30px, max 80px (fill gaps between grid points)
|
||||
*
|
||||
* Clamped to [0.4, 0.9] for safety.
|
||||
* maxIntensity is CONSTANT at 0.75 — no compensation needed because
|
||||
* the geographic overlap between adjacent points stays consistent
|
||||
* when radius tracks geographic scale.
|
||||
*/
|
||||
function getHeatmapParams(zoom: number) {
|
||||
const radius = Math.max(12, Math.min(45, 55 - zoom * 2.5));
|
||||
const blur = Math.max(10, Math.min(25, 30 - zoom * 1.2));
|
||||
const pixelsPerKm = Math.pow(2, zoom) * 6.4;
|
||||
const targetRadiusKm = 0.4; // 400 meters
|
||||
const radiusPixels = targetRadiusKm * pixelsPerKm;
|
||||
|
||||
const BASE_MAX = 0.6;
|
||||
const BASELINE_RADIUS = 30;
|
||||
const radiusScale = radius / BASELINE_RADIUS;
|
||||
const maxIntensity = Math.max(0.4, Math.min(0.9, BASE_MAX * radiusScale));
|
||||
// Progressive clamps: wider range at high zoom for smooth fill
|
||||
const minRadius = zoom < 10 ? 15 : 30;
|
||||
const maxRadius = zoom < 10 ? 45 : 80;
|
||||
const radius = Math.max(minRadius, Math.min(maxRadius, radiusPixels));
|
||||
|
||||
const blur = Math.round(radius * 0.6);
|
||||
|
||||
return {
|
||||
radius: Math.round(radius),
|
||||
blur: Math.round(blur),
|
||||
maxIntensity,
|
||||
blur,
|
||||
maxIntensity: 0.75, // CONSTANT — geographic consistency means no compensation needed
|
||||
pixelsPerKm,
|
||||
radiusPixels,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -99,19 +108,22 @@ export default function Heatmap({ points, visible, opacity = 0.7 }: HeatmapProps
|
||||
rsrpToIntensity(p.rsrp),
|
||||
]);
|
||||
|
||||
const { radius, blur, maxIntensity } = getHeatmapParams(mapZoom);
|
||||
const { radius, blur, maxIntensity, pixelsPerKm, radiusPixels } =
|
||||
getHeatmapParams(mapZoom);
|
||||
|
||||
// Debug: log heatmap params (dev only)
|
||||
// Debug: log geographic scale params (dev only)
|
||||
if (import.meta.env.DEV && heatData.length > 0) {
|
||||
const rsrpValues = points.map((p) => p.rsrp);
|
||||
console.log('🔍 Heatmap:', {
|
||||
console.log('🔍 Heatmap Geographic:', {
|
||||
zoom: mapZoom,
|
||||
pixelsPerKm: pixelsPerKm.toFixed(1),
|
||||
targetRadiusKm: 0.4,
|
||||
radiusPixelsRaw: radiusPixels.toFixed(1),
|
||||
radiusClamped: radius,
|
||||
blur,
|
||||
maxIntensity,
|
||||
points: points.length,
|
||||
rsrpRange: `${Math.min(...rsrpValues).toFixed(1)} to ${Math.max(...rsrpValues).toFixed(1)} dBm`,
|
||||
radius,
|
||||
blur,
|
||||
maxIntensity: maxIntensity.toFixed(3),
|
||||
radiusScale: (radius / 30).toFixed(3),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user