@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
|
* The key insight: we want each heatmap point to cover a constant
|
||||||
* at any zoom level). But changing radius changes point overlap, which
|
* GEOGRAPHIC area (400m radius) regardless of zoom level. Since
|
||||||
* shifts apparent color. To compensate:
|
* 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.
|
* With progressive clamps for visual quality:
|
||||||
* When radius is small (zoomed in, less overlap) → lower max → same color.
|
* - 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) {
|
function getHeatmapParams(zoom: number) {
|
||||||
const radius = Math.max(12, Math.min(45, 55 - zoom * 2.5));
|
const pixelsPerKm = Math.pow(2, zoom) * 6.4;
|
||||||
const blur = Math.max(10, Math.min(25, 30 - zoom * 1.2));
|
const targetRadiusKm = 0.4; // 400 meters
|
||||||
|
const radiusPixels = targetRadiusKm * pixelsPerKm;
|
||||||
|
|
||||||
const BASE_MAX = 0.6;
|
// Progressive clamps: wider range at high zoom for smooth fill
|
||||||
const BASELINE_RADIUS = 30;
|
const minRadius = zoom < 10 ? 15 : 30;
|
||||||
const radiusScale = radius / BASELINE_RADIUS;
|
const maxRadius = zoom < 10 ? 45 : 80;
|
||||||
const maxIntensity = Math.max(0.4, Math.min(0.9, BASE_MAX * radiusScale));
|
const radius = Math.max(minRadius, Math.min(maxRadius, radiusPixels));
|
||||||
|
|
||||||
|
const blur = Math.round(radius * 0.6);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
radius: Math.round(radius),
|
radius: Math.round(radius),
|
||||||
blur: Math.round(blur),
|
blur,
|
||||||
maxIntensity,
|
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),
|
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) {
|
if (import.meta.env.DEV && heatData.length > 0) {
|
||||||
const rsrpValues = points.map((p) => p.rsrp);
|
const rsrpValues = points.map((p) => p.rsrp);
|
||||||
console.log('🔍 Heatmap:', {
|
console.log('🔍 Heatmap Geographic:', {
|
||||||
zoom: mapZoom,
|
zoom: mapZoom,
|
||||||
|
pixelsPerKm: pixelsPerKm.toFixed(1),
|
||||||
|
targetRadiusKm: 0.4,
|
||||||
|
radiusPixelsRaw: radiusPixels.toFixed(1),
|
||||||
|
radiusClamped: radius,
|
||||||
|
blur,
|
||||||
|
maxIntensity,
|
||||||
points: points.length,
|
points: points.length,
|
||||||
rsrpRange: `${Math.min(...rsrpValues).toFixed(1)} to ${Math.max(...rsrpValues).toFixed(1)} dBm`,
|
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