import styles from './scale-bar.module.css'; interface ScaleBarProps { readonly zoom: number; } /** Fixed pixel width of the scale bar on screen. */ const BAR_WIDTH_PX = 100; /** * Compute a "nice" real-world distance for the scale bar * and the corresponding pixel width to display. */ function computeScaleInfo(zoom: number): { label: string; barPx: number } { // zoom = pixels per meter // BAR_WIDTH_PX pixels = BAR_WIDTH_PX / zoom meters const rawMeters = BAR_WIDTH_PX / zoom; // Find the nearest "nice" value const niceValues = [ 0.01, 0.02, 0.05, 0.1, 0.2, 0.25, 0.5, 1, 2, 5, 10, 20, 50, 100, ]; let bestValue = niceValues[0]; let bestDiff = Math.abs(rawMeters - bestValue); for (const v of niceValues) { const diff = Math.abs(rawMeters - v); if (diff < bestDiff) { bestDiff = diff; bestValue = v; } } const barPx = bestValue * zoom; let label: string; if (bestValue >= 1) { label = `${bestValue}m`; } else { label = `${Math.round(bestValue * 100)}cm`; } return { label, barPx }; } export function ScaleBar({ zoom }: ScaleBarProps) { const { label, barPx } = computeScaleInfo(zoom); return (
{label}
); }