fix snapshot export metadata

This commit is contained in:
2026-03-29 20:23:38 -07:00
parent 2846dbc3af
commit dc0d01b8aa
7 changed files with 45 additions and 3 deletions

View File

@@ -1,5 +1,7 @@
import React, { useRef, useState, useCallback } from 'react'; import React, { useRef, useState, useCallback } from 'react';
export const CAPTURE_SELECTOR = '.angle-overlay';
import { import {
getAngleLabelBasePosition, getAngleLabelBasePosition,
getAngleLabelPosition, getAngleLabelPosition,

View File

@@ -1,5 +1,7 @@
import React, { useRef, useState, useCallback } from 'react'; import React, { useRef, useState, useCallback } from 'react';
export const CAPTURE_SELECTOR = '.crop-overlay';
export default function CropBoxOverlay({ export default function CropBoxOverlay({
image, x1, y1, x2, y2, image, x1, y1, x2, y2,
aLocked, bLocked, aLocked, bLocked,

View File

@@ -1,5 +1,7 @@
import React, { useRef, useState, useCallback } from 'react'; import React, { useRef, useState, useCallback } from 'react';
export const CAPTURE_SELECTOR = '.cs-overlay';
/** /**
* Image preview with two endpoint markers for cross-section line control. * Image preview with two endpoint markers for cross-section line control.
* Markers are draggable when unlocked (no COORD input connected), * Markers are draggable when unlocked (no COORD input connected),

View File

@@ -1,9 +1,18 @@
import React, { useEffect, useRef, useState, useCallback } from 'react'; import React, { useEffect, useRef, useState, useCallback } from 'react';
import { getAxisScale } from './valueFormatting'; import { getAxisScale } from './valueFormatting';
export const CAPTURE_SELECTOR = '.lineplot-overlay';
const ASPECT_RATIO = 3.2 / 2.2; const ASPECT_RATIO = 3.2 / 2.2;
const MARGINS = { top: 18, right: 16, bottom: 34, left: 56 }; const MARGINS = { top: 18, right: 16, bottom: 34, left: 56 };
// Hardcoded marker colors so SVG elements render correctly in canvas exports,
// where CSS custom properties (var(--marker) etc.) are not resolved.
const MARKER_FILL = '#ffd700';
const MARKER_STROKE = '#ffffff';
const MARKER_LOCKED_COLOR = '#e91e63';
const MARKER_LABEL_FILL = '#0f172a';
function clamp(v, min, max) { function clamp(v, min, max) {
return Math.max(min, Math.min(max, v)); return Math.max(min, Math.min(max, v));
} }
@@ -263,6 +272,8 @@ export default function LinePlotOverlay({
cy={cursorA.y} cy={cursorA.y}
r={markerRadius} r={markerRadius}
className={`lineplot-marker ${aLocked ? 'lineplot-marker-locked' : ''}`} className={`lineplot-marker ${aLocked ? 'lineplot-marker-locked' : ''}`}
fill={aLocked ? MARKER_LOCKED_COLOR : MARKER_FILL}
stroke={aLocked ? MARKER_LOCKED_COLOR : MARKER_STROKE}
/> />
<text <text
x={cursorA.x} x={cursorA.x}
@@ -271,6 +282,7 @@ export default function LinePlotOverlay({
dominantBaseline="middle" dominantBaseline="middle"
fontSize={markerLabelSize} fontSize={markerLabelSize}
className="lineplot-marker-label" className="lineplot-marker-label"
fill={MARKER_LABEL_FILL}
pointerEvents="none" pointerEvents="none"
> >
A A
@@ -282,6 +294,8 @@ export default function LinePlotOverlay({
cy={cursorB.y} cy={cursorB.y}
r={markerRadius} r={markerRadius}
className={`lineplot-marker ${bLocked ? 'lineplot-marker-locked' : ''}`} className={`lineplot-marker ${bLocked ? 'lineplot-marker-locked' : ''}`}
fill={bLocked ? MARKER_LOCKED_COLOR : MARKER_FILL}
stroke={bLocked ? MARKER_LOCKED_COLOR : MARKER_STROKE}
/> />
<text <text
x={cursorB.x} x={cursorB.x}
@@ -290,6 +304,7 @@ export default function LinePlotOverlay({
dominantBaseline="middle" dominantBaseline="middle"
fontSize={markerLabelSize} fontSize={markerLabelSize}
className="lineplot-marker-label" className="lineplot-marker-label"
fill={MARKER_LABEL_FILL}
pointerEvents="none" pointerEvents="none"
> >
B B

View File

@@ -1,4 +1,6 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
export const CAPTURE_SELECTOR = '.markup-overlay';
import { import {
getArrowGeometry, getArrowGeometry,
MARKUP_DEFAULT_COLOR, MARKUP_DEFAULT_COLOR,

View File

@@ -1,9 +1,18 @@
import React, { useEffect, useRef, useState, useCallback } from 'react'; import React, { useEffect, useRef, useState, useCallback } from 'react';
import { getAxisScale } from './valueFormatting'; import { getAxisScale } from './valueFormatting';
export const CAPTURE_SELECTOR = '.lineplot-overlay';
const ASPECT_RATIO = 3.2 / 2.2; const ASPECT_RATIO = 3.2 / 2.2;
const MARGINS = { top: 18, right: 16, bottom: 34, left: 56 }; const MARGINS = { top: 18, right: 16, bottom: 34, left: 56 };
// Hardcoded marker colors so SVG elements render correctly in canvas exports,
// where CSS custom properties (var(--marker) etc.) are not resolved.
const MARKER_FILL = '#ffd700';
const MARKER_STROKE = '#ffffff';
const MARKER_LOCKED_COLOR = '#e91e63';
const MARKER_LABEL_FILL = '#0f172a';
function clamp(v, min, max) { return Math.max(min, Math.min(max, v)); } function clamp(v, min, max) { return Math.max(min, Math.min(max, v)); }
function round4(v) { return parseFloat(v.toFixed(4)); } function round4(v) { return parseFloat(v.toFixed(4)); }
function trimZeros(t) { return t.replace(/(?:\.0+|(\.\d+?)0+)$/, '$1'); } function trimZeros(t) { return t.replace(/(?:\.0+|(\.\d+?)0+)$/, '$1'); }
@@ -201,6 +210,8 @@ export default function ThresholdHistogram({ overlay, threshold, thresholdConnec
cy={markerY} cy={markerY}
r={markerRadius} r={markerRadius}
className={`lineplot-marker ${locked ? 'lineplot-marker-locked' : ''}`} className={`lineplot-marker ${locked ? 'lineplot-marker-locked' : ''}`}
fill={locked ? MARKER_LOCKED_COLOR : MARKER_FILL}
stroke={locked ? MARKER_LOCKED_COLOR : MARKER_STROKE}
/> />
<text <text
x={markerX} x={markerX}
@@ -209,6 +220,7 @@ export default function ThresholdHistogram({ overlay, threshold, thresholdConnec
dominantBaseline="middle" dominantBaseline="middle"
fontSize={markerLabelSize} fontSize={markerLabelSize}
className="lineplot-marker-label" className="lineplot-marker-label"
fill={MARKER_LABEL_FILL}
pointerEvents="none" pointerEvents="none"
> >
T T

View File

@@ -1,10 +1,17 @@
import { toBlob } from 'html-to-image'; import { toBlob } from 'html-to-image';
import { CANVAS_COLORS } from './constants.js'; import { CANVAS_COLORS } from './constants.js';
import { CAPTURE_SELECTOR as linePlotSelector } from './LinePlotOverlay';
import { CAPTURE_SELECTOR as thresholdSelector } from './ThresholdHistogram';
import { CAPTURE_SELECTOR as csSelector } from './CrossSectionOverlay';
import { CAPTURE_SELECTOR as cropSelector } from './CropBoxOverlay';
import { CAPTURE_SELECTOR as markupSelector } from './MarkupOverlay';
import { CAPTURE_SELECTOR as angleSelector } from './AngleMeasureOverlay';
// Assembled from each overlay component's CAPTURE_SELECTOR export.
// To register a new overlay: export CAPTURE_SELECTOR from its file and add
// an import + entry here. Missing entries produce corrupt ~68-byte PNG output.
export const OVERLAY_CAPTURE_SELECTORS = [ export const OVERLAY_CAPTURE_SELECTORS = [
'.lineplot-overlay', ...new Set([linePlotSelector, thresholdSelector, csSelector, cropSelector, markupSelector, angleSelector]),
'.cs-overlay',
'.crop-overlay',
]; ];
function encodeBase64(bytes) { function encodeBase64(bytes) {