make cursors polymorphic

This commit is contained in:
2026-03-25 23:03:14 -07:00
parent cc3af8e929
commit 8e16f9f0b4
8 changed files with 170 additions and 56 deletions

View File

@@ -27,11 +27,12 @@ import {
const DATA_TYPES = new Set([
'DATA_FIELD', 'IMAGE', 'LINE', 'MEASURE_TABLE', 'RECORD_TABLE', 'ANY_TABLE',
'COORD', 'STATS_SOURCE', 'VALUE_SOURCE', 'COLORMAP', 'SAVE_LAYER', 'FONT', 'FILE_PATH', 'DIRECTORY',
'COORD', 'STATS_SOURCE', 'CURSOR_SOURCE', 'VALUE_SOURCE', 'COLORMAP', 'SAVE_LAYER', 'FONT', 'FILE_PATH', 'DIRECTORY',
]);
const SOCKET_COMPATIBILITY = {
STATS_SOURCE: new Set(['DATA_FIELD', 'IMAGE', 'LINE', 'RECORD_TABLE']),
CURSOR_SOURCE: new Set(['DATA_FIELD', 'LINE']),
ANY_TABLE: new Set(['MEASURE_TABLE', 'RECORD_TABLE']),
VALUE_SOURCE: new Set(['FLOAT', 'MEASURE_TABLE']),
SAVE_LAYER: new Set(['DATA_FIELD', 'IMAGE']),
@@ -50,6 +51,7 @@ const TYPE_COLORS = {
FLOAT: '#7dd3fc',
INT: '#38bdf8',
STATS_SOURCE:'#c084fc',
CURSOR_SOURCE:'#a78bfa',
VALUE_SOURCE:'#60a5fa',
COLORMAP: '#f472b6',
SAVE_LAYER: '#22c55e',

View File

@@ -12,6 +12,7 @@ export default function CrossSectionOverlay({
image, x1, y1, x2, y2,
aLocked, bLocked,
nodeId, onWidgetChange,
showLine = true,
}) {
const containerRef = useRef(null);
const [dragging, setDragging] = useState(null); // 'p1' or 'p2'
@@ -62,13 +63,15 @@ export default function CrossSectionOverlay({
<img src={image} alt="field" draggable={false} className="cs-image" />
{/* Line connecting the two markers */}
<svg className="cs-svg">
<line
x1={`${x1 * 100}%`} y1={`${y1 * 100}%`}
x2={`${x2 * 100}%`} y2={`${y2 * 100}%`}
stroke="#ffd700" strokeWidth="2" strokeDasharray="6 3"
/>
</svg>
{showLine && (
<svg className="cs-svg">
<line
x1={`${x1 * 100}%`} y1={`${y1 * 100}%`}
x2={`${x2 * 100}%`} y2={`${y2 * 100}%`}
stroke="#ffd700" strokeWidth="2" strokeDasharray="6 3"
/>
</svg>
)}
{/* Endpoint markers — locked markers get a different style */}
<div

View File

@@ -12,7 +12,7 @@ const MarkupOverlay = lazy(() => import('./MarkupOverlay'));
const DATA_TYPES = new Set([
'DATA_FIELD', 'IMAGE', 'LINE', 'MEASURE_TABLE', 'RECORD_TABLE', 'ANY_TABLE',
'COORD', 'STATS_SOURCE', 'VALUE_SOURCE', 'COLORMAP', 'SAVE_LAYER', 'FONT', 'FILE_PATH', 'DIRECTORY',
'COORD', 'STATS_SOURCE', 'CURSOR_SOURCE', 'VALUE_SOURCE', 'COLORMAP', 'SAVE_LAYER', 'FONT', 'FILE_PATH', 'DIRECTORY',
]);
const SOCKET_WIDGET_TYPES = new Set(['FLOAT', 'INT']);
@@ -27,6 +27,7 @@ const TYPE_COLORS = {
FLOAT: '#7dd3fc',
INT: '#38bdf8',
STATS_SOURCE:'#c084fc',
CURSOR_SOURCE:'#a78bfa',
VALUE_SOURCE:'#60a5fa',
COLORMAP: '#f472b6',
SAVE_LAYER: '#22c55e',
@@ -861,6 +862,8 @@ function CustomNode({ id, data }) {
? 'Markup'
: data.overlay?.kind === 'crop_box'
? 'Crop'
: data.overlay?.kind === 'cursor_points'
? 'Cursors'
: data.overlay?.kind === 'line_plot'
? 'Line Plot'
: 'Cross Section');
@@ -1088,6 +1091,19 @@ function CustomNode({ id, data }) {
nodeId={id}
onWidgetChange={ctx.onWidgetChange}
/>
) : data.overlay.kind === 'cursor_points' ? (
<CrossSectionOverlay
image={data.overlay.image}
x1={data.overlay.a_locked ? data.overlay.x1 : (data.widgetValues.x1 ?? data.overlay.x1)}
y1={data.overlay.a_locked ? data.overlay.y1 : (data.widgetValues.y1 ?? data.overlay.y1)}
x2={data.overlay.b_locked ? data.overlay.x2 : (data.widgetValues.x2 ?? data.overlay.x2)}
y2={data.overlay.b_locked ? data.overlay.y2 : (data.widgetValues.y2 ?? data.overlay.y2)}
aLocked={data.overlay.a_locked}
bLocked={data.overlay.b_locked}
nodeId={id}
onWidgetChange={ctx.onWidgetChange}
showLine={false}
/>
) : data.overlay.kind === 'mask_paint' ? (
<MaskPaintOverlay
image={data.overlay.image}

View File

@@ -1,6 +1,6 @@
const DATA_TYPES = new Set([
'DATA_FIELD', 'IMAGE', 'LINE', 'MEASURE_TABLE', 'RECORD_TABLE', 'ANY_TABLE',
'COORD', 'STATS_SOURCE', 'VALUE_SOURCE', 'COLORMAP', 'SAVE_LAYER', 'FONT', 'FILE_PATH', 'DIRECTORY',
'COORD', 'STATS_SOURCE', 'CURSOR_SOURCE', 'VALUE_SOURCE', 'COLORMAP', 'SAVE_LAYER', 'FONT', 'FILE_PATH', 'DIRECTORY',
]);
function getInputName(handleId) {