diff --git a/frontend/src/AngleMeasureOverlay.jsx b/frontend/src/AngleMeasureOverlay.jsx index ceca6af..31bae8a 100644 --- a/frontend/src/AngleMeasureOverlay.jsx +++ b/frontend/src/AngleMeasureOverlay.jsx @@ -1,5 +1,7 @@ import React, { useRef, useState, useCallback } from 'react'; +export const CAPTURE_SELECTOR = '.angle-overlay'; + import { getAngleLabelBasePosition, getAngleLabelPosition, diff --git a/frontend/src/CropBoxOverlay.jsx b/frontend/src/CropBoxOverlay.jsx index 858703b..38bc5cd 100644 --- a/frontend/src/CropBoxOverlay.jsx +++ b/frontend/src/CropBoxOverlay.jsx @@ -1,5 +1,7 @@ import React, { useRef, useState, useCallback } from 'react'; +export const CAPTURE_SELECTOR = '.crop-overlay'; + export default function CropBoxOverlay({ image, x1, y1, x2, y2, aLocked, bLocked, diff --git a/frontend/src/CrossSectionOverlay.jsx b/frontend/src/CrossSectionOverlay.jsx index 85f0e0f..d72fbf2 100644 --- a/frontend/src/CrossSectionOverlay.jsx +++ b/frontend/src/CrossSectionOverlay.jsx @@ -1,5 +1,7 @@ import React, { useRef, useState, useCallback } from 'react'; +export const CAPTURE_SELECTOR = '.cs-overlay'; + /** * Image preview with two endpoint markers for cross-section line control. * Markers are draggable when unlocked (no COORD input connected), diff --git a/frontend/src/LinePlotOverlay.jsx b/frontend/src/LinePlotOverlay.jsx index d7b5e21..b088154 100644 --- a/frontend/src/LinePlotOverlay.jsx +++ b/frontend/src/LinePlotOverlay.jsx @@ -1,9 +1,18 @@ import React, { useEffect, useRef, useState, useCallback } from 'react'; import { getAxisScale } from './valueFormatting'; +export const CAPTURE_SELECTOR = '.lineplot-overlay'; + const ASPECT_RATIO = 3.2 / 2.2; 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)); } @@ -263,6 +272,8 @@ export default function LinePlotOverlay({ cy={cursorA.y} r={markerRadius} className={`lineplot-marker ${aLocked ? 'lineplot-marker-locked' : ''}`} + fill={aLocked ? MARKER_LOCKED_COLOR : MARKER_FILL} + stroke={aLocked ? MARKER_LOCKED_COLOR : MARKER_STROKE} /> A @@ -282,6 +294,8 @@ export default function LinePlotOverlay({ cy={cursorB.y} r={markerRadius} className={`lineplot-marker ${bLocked ? 'lineplot-marker-locked' : ''}`} + fill={bLocked ? MARKER_LOCKED_COLOR : MARKER_FILL} + stroke={bLocked ? MARKER_LOCKED_COLOR : MARKER_STROKE} /> B diff --git a/frontend/src/MarkupOverlay.jsx b/frontend/src/MarkupOverlay.jsx index 5870a14..35a5b8d 100644 --- a/frontend/src/MarkupOverlay.jsx +++ b/frontend/src/MarkupOverlay.jsx @@ -1,4 +1,6 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; + +export const CAPTURE_SELECTOR = '.markup-overlay'; import { getArrowGeometry, MARKUP_DEFAULT_COLOR, diff --git a/frontend/src/ThresholdHistogram.jsx b/frontend/src/ThresholdHistogram.jsx index 29e254b..17a8270 100644 --- a/frontend/src/ThresholdHistogram.jsx +++ b/frontend/src/ThresholdHistogram.jsx @@ -1,9 +1,18 @@ import React, { useEffect, useRef, useState, useCallback } from 'react'; import { getAxisScale } from './valueFormatting'; +export const CAPTURE_SELECTOR = '.lineplot-overlay'; + const ASPECT_RATIO = 3.2 / 2.2; 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 round4(v) { return parseFloat(v.toFixed(4)); } function trimZeros(t) { return t.replace(/(?:\.0+|(\.\d+?)0+)$/, '$1'); } @@ -201,6 +210,8 @@ export default function ThresholdHistogram({ overlay, threshold, thresholdConnec cy={markerY} r={markerRadius} className={`lineplot-marker ${locked ? 'lineplot-marker-locked' : ''}`} + fill={locked ? MARKER_LOCKED_COLOR : MARKER_FILL} + stroke={locked ? MARKER_LOCKED_COLOR : MARKER_STROKE} /> T diff --git a/frontend/src/workflowCapture.js b/frontend/src/workflowCapture.js index 7b59aa7..7794e6d 100644 --- a/frontend/src/workflowCapture.js +++ b/frontend/src/workflowCapture.js @@ -1,10 +1,17 @@ import { toBlob } from 'html-to-image'; 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 = [ - '.lineplot-overlay', - '.cs-overlay', - '.crop-overlay', + ...new Set([linePlotSelector, thresholdSelector, csSelector, cropSelector, markupSelector, angleSelector]), ]; function encodeBase64(bytes) {