Three combined additions to the corrected-image viewer: - Circle measurement tool: 2-click placement (center + edge), dedicated hit-test, handle drag preserving radius when grabbing the center. - Annotated PNG exports via two new buttons in the result page: "Download full + measurements" (source resolution, strokes scaled up to read at the same visual weight) and "Download view + measurements" (current pan/zoom). Both respect the existing scale-bar toggle; the view export's bar is sized for canvas-px/mm = image-px/mm × view scale. - Per-image measurement persistence keyed by file hash, mirroring the datum cache. "Clear cache" in the upload step now wipes both. Drawing helpers were refactored to take a RenderCtx (transform + strokeMul + handle/decoration flags) so the same code paths handle live overlay and offscreen export.
41 lines
998 B
TypeScript
41 lines
998 B
TypeScript
import type { Measurement } from "@/types/measurements"
|
|
|
|
const KEY_PREFIX = "skwik-measurements-"
|
|
|
|
export function saveMeasurements(
|
|
hash: string,
|
|
measurements: Measurement[],
|
|
): void {
|
|
try {
|
|
localStorage.setItem(
|
|
KEY_PREFIX + hash,
|
|
JSON.stringify(measurements),
|
|
)
|
|
} catch {
|
|
// localStorage full or unavailable — silently ignore
|
|
}
|
|
}
|
|
|
|
export function loadMeasurements(hash: string): Measurement[] | null {
|
|
try {
|
|
const raw = localStorage.getItem(KEY_PREFIX + hash)
|
|
if (!raw) return null
|
|
return JSON.parse(raw) as Measurement[]
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
export function clearCache(): void {
|
|
const toRemove: string[] = []
|
|
for (let i = 0; i < localStorage.length; i++) {
|
|
const key = localStorage.key(i)
|
|
if (key?.startsWith(KEY_PREFIX)) {
|
|
toRemove.push(key)
|
|
}
|
|
}
|
|
for (const key of toRemove) {
|
|
localStorage.removeItem(key)
|
|
}
|
|
}
|