chore: sync annotation UI, shortcuts, and misc updates
This commit is contained in:
1 parent
cf4c3370e1
commit
51e74a253e
11 files changed
+102
-36
No files matched your search
@@ -710,7 +710,7 @@ main.page {
|
||||
|
||||
.shortcuts { margin: 0; display: grid; gap: 5px; font-size: 12px; }
|
||||
.shortcuts > div { display: flex; gap: 10px; align-items: baseline; }
|
||||
.shortcuts dt { flex: none; width: 62px; }
|
||||
.shortcuts dt { flex: none; width: 72px; }
|
||||
.shortcuts dd { margin: 0; color: var(--text-muted); }
|
||||
|
||||
kbd {
|
||||
|
||||
@@ -75,6 +75,17 @@ export default function AnnotationCanvas({
|
||||
|
||||
const additive = useRef(false)
|
||||
|
||||
function handleDoubleClick(event) {
|
||||
if (selecting) return
|
||||
const [x, y] = pointAt(event)
|
||||
if (assistMode) {
|
||||
const seed = [Math.max(0, x - 0.015), Math.max(0, y - 0.015), Math.min(1, x + 0.015), Math.min(1, y + 0.015)]
|
||||
onAssist(seed)
|
||||
} else if (onExemplar) {
|
||||
onExemplar([x, y], !event.shiftKey, { kind: 'point' })
|
||||
}
|
||||
}
|
||||
|
||||
function startDraw(event) {
|
||||
if (event.button !== 0) return
|
||||
const [x, y] = pointAt(event)
|
||||
@@ -218,6 +229,7 @@ export default function AnnotationCanvas({
|
||||
onPointerDown={startDraw}
|
||||
onPointerMove={onPointerMove}
|
||||
onPointerUp={onPointerUp}
|
||||
onDoubleClick={handleDoubleClick}
|
||||
>
|
||||
{/* A preview replaces this class on the frame wholesale, so its stored
|
||||
shapes step aside for the proposals — left on screen they read as
|
||||
@@ -270,7 +282,7 @@ export default function AnnotationCanvas({
|
||||
)
|
||||
})}
|
||||
|
||||
{!selecting && exemplars.map((item, i) => {
|
||||
{!selecting && exemplars.filter((item) => item.kind !== 'point' && item.box).map((item, i) => {
|
||||
const [x0, y0, x1, y1] = item.box
|
||||
return (
|
||||
<rect
|
||||
|
||||
@@ -7,6 +7,10 @@ export default function ShortcutsPanel() {
|
||||
<dt><kbd>Drag</kbd></dt>
|
||||
<dd>Example of this class → preview a re-detect</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt><kbd>Dbl Click</kbd></dt>
|
||||
<dd>Quick exemplar point → preview a re-detect</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt><kbd>Enter</kbd> <kbd>Esc</kbd></dt>
|
||||
<dd>Apply / discard the preview</dd>
|
||||
@@ -15,6 +19,10 @@ export default function ShortcutsPanel() {
|
||||
<dt><kbd>Shift</kbd>+<kbd>Drag</kbd></dt>
|
||||
<dd>Not this → drop it and re-detect</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt><kbd>Shift</kbd>+<kbd>Dbl</kbd></dt>
|
||||
<dd>Quick negative exemplar point</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt><kbd>V</kbd></dt>
|
||||
<dd>Draw ⇄ Select mode</dd>
|
||||
|
||||
@@ -100,9 +100,12 @@ export default function useExemplarPool({ frameId, classId, onApplied, onError,
|
||||
timer.current = setTimeout(() => runRef.current?.(), delay)
|
||||
}, [])
|
||||
|
||||
const add = useCallback((box, positive) => {
|
||||
const add = useCallback((target, positive, { kind = 'box' } = {}) => {
|
||||
if (!frameId) return
|
||||
poolRef.current = [...poolRef.current, { box, positive }]
|
||||
const entry = kind === 'point'
|
||||
? { point: target, positive, kind: 'point' }
|
||||
: { box: target, positive, kind: 'box' }
|
||||
poolRef.current = [...poolRef.current, entry]
|
||||
setExemplars(poolRef.current)
|
||||
setActive(true)
|
||||
// A drag during a pass cannot be in that pass's result, so it always earns
|
||||
|
||||
@@ -500,7 +500,7 @@ export default function ReviewPage({ batchId: rawBatchId, projectId, onProject }
|
||||
? `${pool.exemplars.filter((e) => e.positive).length} example(s), `
|
||||
+ `${pool.exemplars.filter((e) => !e.positive).length} negative — `
|
||||
+ 'tune the filters, then Apply'
|
||||
: 'Drag an example of this class · Shift-drag = not this'}
|
||||
: 'Drag or double-click an example · Shift-drag/click = not this'}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user