Zhen Ye Claude Opus 4.6 commited on
Commit
3015ea3
·
1 Parent(s): 7124ca1

feat: click-to-select tracks on video overlay

Browse files

Add click handler on engage overlay canvas for selecting tracked objects
directly in the video. Hit-tests against track bboxes with smallest-area
priority for overlapping objects, dispatches track-selected event.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

frontend/js/core/video.js CHANGED
@@ -212,6 +212,7 @@ APP.core.video.resizeOverlays = function () {
212
  const h = videoEngage.videoHeight || state.frame.h;
213
  engageOverlay.width = w;
214
  engageOverlay.height = h;
 
215
  }
216
 
217
  if (frameOverlay) {
 
212
  const h = videoEngage.videoHeight || state.frame.h;
213
  engageOverlay.width = w;
214
  engageOverlay.height = h;
215
+ engageOverlay.style.pointerEvents = "auto";
216
  }
217
 
218
  if (frameOverlay) {
frontend/js/main.js CHANGED
@@ -12,7 +12,7 @@ document.addEventListener("DOMContentLoaded", () => {
12
  const { load: loadDemo, getFrameData: getDemoFrameData, enable: enableDemo } = APP.core.demo;
13
 
14
  // UI Renderers
15
- const { renderFrameOverlay, renderEngageOverlay } = APP.ui.overlays;
16
  const { renderFrameTrackList } = APP.ui.cards;
17
  const { tickAgentCursor, moveCursorToRect } = APP.ui.cursor;
18
  const { matchAndUpdateTracks, predictTracks } = APP.core.tracker;
@@ -60,6 +60,9 @@ document.addEventListener("DOMContentLoaded", () => {
60
  syncKnobDisplays();
61
  setHfStatus("idle");
62
 
 
 
 
63
  // Start main loop
64
  requestAnimationFrame(loop);
65
 
 
12
  const { load: loadDemo, getFrameData: getDemoFrameData, enable: enableDemo } = APP.core.demo;
13
 
14
  // UI Renderers
15
+ const { renderFrameOverlay, renderEngageOverlay, initClickHandler } = APP.ui.overlays;
16
  const { renderFrameTrackList } = APP.ui.cards;
17
  const { tickAgentCursor, moveCursorToRect } = APP.ui.cursor;
18
  const { matchAndUpdateTracks, predictTracks } = APP.core.tracker;
 
60
  syncKnobDisplays();
61
  setHfStatus("idle");
62
 
63
+ // Enable click-to-select on engage overlay
64
+ initClickHandler();
65
+
66
  // Start main loop
67
  requestAnimationFrame(loop);
68
 
frontend/js/ui/overlays.js CHANGED
@@ -39,6 +39,45 @@ APP.ui.overlays.renderFrameOverlay = function () {
39
  ctx.clearRect(0, 0, canvas.width, canvas.height);
40
  };
41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  APP.ui.overlays.renderEngageOverlay = function () {
43
  const { state } = APP.core;
44
  const { $ } = APP.core.utils;
 
39
  ctx.clearRect(0, 0, canvas.width, canvas.height);
40
  };
41
 
42
+ APP.ui.overlays.initClickHandler = function () {
43
+ const { $ } = APP.core.utils;
44
+ const canvas = $("#engageOverlay");
45
+ if (!canvas) return;
46
+
47
+ canvas.style.pointerEvents = "auto";
48
+ canvas.style.cursor = "crosshair";
49
+
50
+ canvas.addEventListener("click", (e) => {
51
+ const { state } = APP.core;
52
+ const tracks = state.tracker.tracks;
53
+ if (!tracks || !tracks.length) return;
54
+
55
+ // Convert click to normalized 0-1 coords relative to canvas
56
+ const rect = canvas.getBoundingClientRect();
57
+ const nx = (e.clientX - rect.left) / rect.width;
58
+ const ny = (e.clientY - rect.top) / rect.height;
59
+
60
+ // Hit-test against track bboxes (smallest area wins for overlaps)
61
+ let best = null;
62
+ let bestArea = Infinity;
63
+
64
+ for (const t of tracks) {
65
+ const b = t.bbox;
66
+ if (!b) continue;
67
+ if (nx >= b.x && nx <= b.x + b.w && ny >= b.y && ny <= b.y + b.h) {
68
+ const area = b.w * b.h;
69
+ if (area < bestArea) {
70
+ bestArea = area;
71
+ best = t;
72
+ }
73
+ }
74
+ }
75
+
76
+ const id = best ? best.id : null;
77
+ document.dispatchEvent(new CustomEvent("track-selected", { detail: { id } }));
78
+ });
79
+ };
80
+
81
  APP.ui.overlays.renderEngageOverlay = function () {
82
  const { state } = APP.core;
83
  const { $ } = APP.core.utils;