diff --git a/src/components/three/ModelViewer.tsx b/src/components/three/ModelViewer.tsx index e3a3437..b0e6853 100644 --- a/src/components/three/ModelViewer.tsx +++ b/src/components/three/ModelViewer.tsx @@ -384,16 +384,28 @@ function useLabelDistanceFactor(position: [number, number, number]): number { const dist = camera.position.distanceTo(v); const perspCam = camera as THREE.PerspectiveCamera; const fov = (perspCam.fov ?? 50) * (Math.PI / 180); - const worldPerPixel = (2 * dist * Math.tan(fov / 2)) / size.height; + const height = size.height || 1; + const worldPerPixel = (2 * dist * Math.tan(fov / 2)) / height; // distanceFactor scales the html so it stays ~140 px tall at this distance - ref.current = Math.max(0.05, worldPerPixel * 140); + ref.current = isNaN(worldPerPixel) || !isFinite(worldPerPixel) ? 1.5 : Math.max(0.05, worldPerPixel * 140); }); return ref.current; } -function MeasurementLabel({ position, text, variant, fixed = false }: { position: [number, number, number]; text: string; variant: 'success' | 'primary' | 'accent'; fixed?: boolean }) { +function DynamicLabel({ position, text, borderClass, textClass }: { position: [number, number, number]; text: string; borderClass: string; textClass: string }) { const dfDynamic = useLabelDistanceFactor(position); - const df = fixed ? dfDynamic : 1.5; + return ( + +
+ + {text} + +
+ + ); +} + +function MeasurementLabel({ position, text, variant, fixed = false }: { position: [number, number, number]; text: string; variant: 'success' | 'primary' | 'accent'; fixed?: boolean }) { const borderClass = variant === 'success' ? 'border-success/60' : variant === 'accent' @@ -404,8 +416,11 @@ function MeasurementLabel({ position, text, variant, fixed = false }: { position : variant === 'accent' ? 'text-amber-400' : 'text-primary'; - return ( - + + return fixed ? ( + + ) : ( +
{text} @@ -473,15 +488,12 @@ function ModelMeasurements({ modelId }: { modelId: string }) { /** Renders snap indicator, hover tooltip, pending point and any *legacy* * world-frame measurements that aren't attached to a specific model. */ -function HoverLabelOverlay({ hoverInfo }: { hoverInfo: HoverInfo | null }) { - const visible = !!hoverInfo; - const position = hoverInfo?.position ?? [0, 0, 0]; - const text = hoverInfo - ? hoverInfo.type === 'hole' - ? `Ø ${hoverInfo.value.toFixed(1)}` - : `${hoverInfo.value.toFixed(1)} mm` - : ''; - const variant = hoverInfo?.type === 'hole' ? 'accent' : 'primary'; +function HoverLabelOverlay({ hoverInfo }: { hoverInfo: HoverInfo }) { + const position = hoverInfo.position; + const text = hoverInfo.type === 'hole' + ? `Ø ${hoverInfo.value.toFixed(1)}` + : `${hoverInfo.value.toFixed(1)} mm`; + const variant = hoverInfo.type === 'hole' ? 'accent' : 'primary'; const dfDynamic = useLabelDistanceFactor(position); @@ -500,8 +512,6 @@ function HoverLabelOverlay({ hoverInfo }: { hoverInfo: HoverInfo | null }) { zIndexRange={[100, 0]} style={{ pointerEvents: 'none', - display: visible ? 'block' : 'none', - opacity: visible ? 1 : 0, }} >
@@ -530,7 +540,9 @@ function MeasurementOverlay() { )} {/* Hover auto-detect tooltip (works both inside and outside measure mode) */} - + {hoverInfo && ( + + )} {/* Pending first point (always in world coords) */} {measurePoints.length === 1 && (