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 && (