cyberai-1 commited on
Commit
524ee4b
Β·
1 Parent(s): 6506943

update data video box

Browse files
Files changed (1) hide show
  1. index.html +86 -18
index.html CHANGED
@@ -292,16 +292,48 @@ header {
292
  /* ── VIDEO PANEL ── */
293
  #videoPanel { display:none;padding:32px; }
294
 
295
- .video-layout { display:grid;grid-template-columns:1fr 320px;gap:20px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
 
297
- .video-wrap { position:relative;background:#000;border-radius:6px;overflow:hidden;border:1px solid var(--border);width:100%;height:100%; }
298
  #videoEl { display:block;width:100%;height:100%;object-fit:contain; }
299
  #overlayCanvas {
300
  position:absolute;top:0;left:0;width:100%;height:100%;
301
  pointer-events:none;
302
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
303
 
304
- .video-sidebar { display:flex;flex-direction:column;gap:14px; }
305
 
306
  .vid-ctrl {
307
  background:var(--s1);border:1px solid var(--border);border-radius:6px;padding:18px;
@@ -355,11 +387,26 @@ header {
355
 
356
  .no-video {
357
  display:flex;flex-direction:column;align-items:center;justify-content:center;
358
- min-height:360px;gap:12px;opacity:.35;
359
  }
360
  .no-video-icon { font-size:48px; }
361
  .no-video-txt { font-family:var(--mono);font-size:12px;letter-spacing:2px; }
362
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363
  /* ── CANVAS CHARTS (timeline) ── */
364
  #timelineCanvas { width:100%;height:130px;display:block; }
365
 
@@ -535,8 +582,8 @@ header {
535
  <div class="video-layout">
536
 
537
  <div>
538
- <div class="video-wrap" id="videoWrap">
539
- <div class="no-video" id="noVideo">
540
  <div class="no-video-icon">🎬</div>
541
  <div class="no-video-txt">NO VIDEO LOADED</div>
542
  <div style="font-family:var(--mono);font-size:10px;color:var(--dim);margin-top:6px">
@@ -545,6 +592,7 @@ header {
545
  </div>
546
  <video id="videoEl" style="display:none" controls></video>
547
  <canvas id="overlayCanvas"></canvas>
 
548
  </div>
549
  </div>
550
 
@@ -784,6 +832,11 @@ function classUniqueCounts(rows) {
784
  return Object.fromEntries(Object.entries(byClass).map(([cls, ids]) => [cls, ids.size]));
785
  }
786
 
 
 
 
 
 
787
  function annotateRows(rows, meta={}) {
788
  const key = sourceKeyFromMeta(meta);
789
  return rows.map(row => ({
@@ -1074,9 +1127,9 @@ function renderSceneTable() {
1074
  const frames = new Set(rows.map(r => r.frame)).size;
1075
  const uniqueObjs = data.trackIds.size;
1076
  const duration = Math.max(...rows.map(r => parseFloat(r.timestamp_sec||0))).toFixed(1);
1077
- const cars = new Set(rows.filter(r => r.class_name==='car').map(objectKey)).size;
1078
- const persons = new Set(rows.filter(r => r.class_name==='person').map(objectKey)).size;
1079
- const heavy = new Set(rows.filter(r => r.class_name==='bus'||r.class_name==='truck').map(objectKey)).size;
1080
  const avgConf = (rows.reduce((s,r)=>s+parseFloat(r.confidence||0),0)/rows.length*100).toFixed(1);
1081
  const down = rows.filter(r => r.direction==='down').length;
1082
  const up = rows.filter(r => r.direction==='up').length;
@@ -1134,7 +1187,7 @@ function selectScene(sc, el) {
1134
  const vid = document.getElementById('videoEl');
1135
  vid.pause();
1136
  vid.style.display = 'none';
1137
- document.getElementById('noVideo').style.display = 'flex';
1138
  document.getElementById('vidName').textContent = '';
1139
  document.getElementById('liveCounts').innerHTML =
1140
  '<div style="font-family:var(--mono);font-size:10px;color:var(--dim);text-align:center;padding:8px">Choose a video for this scene</div>';
@@ -1205,18 +1258,19 @@ function loadRemoteVideo(file) {
1205
  vid.pause();
1206
  vid.src = file.url;
1207
  vid.style.display = 'block';
1208
- document.getElementById('noVideo').style.display = 'none';
1209
  document.getElementById('vidName').textContent = `${file.name} (${file.repo}${file.folder ? ' / ' + file.folder : ''})`;
1210
  document.getElementById('liveCounts').innerHTML =
1211
  '<div style="font-family:var(--mono);font-size:10px;color:var(--dim);text-align:center;padding:8px">Play the selected video to see live counts</div>';
1212
 
1213
  vid.onloadedmetadata = () => {
1214
- const wrap = document.getElementById('videoWrap');
1215
  const canvas = document.getElementById('overlayCanvas');
1216
  canvas.style.width = wrap.offsetWidth + 'px';
1217
  canvas.style.height = wrap.offsetHeight + 'px';
1218
  canvas.width = wrap.offsetWidth * window.devicePixelRatio;
1219
  canvas.height = wrap.offsetHeight * window.devicePixelRatio;
 
1220
  };
1221
  vid.ontimeupdate = onVideoTimeUpdate;
1222
  }
@@ -1234,11 +1288,11 @@ function loadVideo(input) {
1234
  const vid = document.getElementById('videoEl');
1235
  vid.src = url;
1236
  vid.style.display = 'block';
1237
- document.getElementById('noVideo').style.display = 'none';
1238
  document.getElementById('vidName').textContent = file.name;
1239
 
1240
  vid.onloadedmetadata = () => {
1241
- const wrap = document.getElementById('videoWrap');
1242
  const canvas = document.getElementById('overlayCanvas');
1243
 
1244
  // Match canvas display size to wrapper
@@ -1249,6 +1303,7 @@ function loadVideo(input) {
1249
  canvas.width = wrap.offsetWidth * window.devicePixelRatio;
1250
  canvas.height = wrap.offsetHeight * window.devicePixelRatio;
1251
 
 
1252
  toast(`Video loaded: ${vid.videoWidth}Γ—${vid.videoHeight}`, 'ok');
1253
  };
1254
 
@@ -1257,9 +1312,22 @@ function loadVideo(input) {
1257
 
1258
  let lastDrawnFrame = -1;
1259
 
 
 
 
 
 
 
 
 
 
 
 
 
1260
  function onVideoTimeUpdate() {
1261
  if (!activeScene) return;
1262
  const vid = document.getElementById('videoEl');
 
1263
  const fps = detectFPS(activeScene);
1264
  const frameNum = Math.round(vid.currentTime * fps);
1265
  if (frameNum === lastDrawnFrame) return;
@@ -1281,7 +1349,7 @@ function drawOverlay(frameNum) {
1281
  const canvas = document.getElementById('overlayCanvas');
1282
  const ctx = canvas.getContext('2d');
1283
  const vid = document.getElementById('videoEl');
1284
- const wrap = document.getElementById('videoWrap');
1285
 
1286
  // Get actual display dimensions
1287
  const displayWidth = wrap.offsetWidth;
@@ -1719,9 +1787,9 @@ function renderFilteredSceneTable() {
1719
  const frames = new Set(sceneRows.map(r => r.frame)).size;
1720
  const uniqueObjs = new Set(sceneRows.map(objectKey)).size;
1721
  const duration = Math.max(...sceneRows.map(r => parseFloat(r.timestamp_sec||0))).toFixed(1);
1722
- const cars = new Set(sceneRows.filter(r => r.class_name==='car').map(objectKey)).size;
1723
- const persons = new Set(sceneRows.filter(r => r.class_name==='person').map(objectKey)).size;
1724
- const heavy = new Set(sceneRows.filter(r => r.class_name==='bus'||r.class_name==='truck').map(objectKey)).size;
1725
  const avgConf = (sceneRows.reduce((s,r)=>s+parseFloat(r.confidence||0),0)/sceneRows.length*100).toFixed(1);
1726
  const down = sceneRows.filter(r => r.direction==='down').length;
1727
  const up = sceneRows.filter(r => r.direction==='up').length;
 
292
  /* ── VIDEO PANEL ── */
293
  #videoPanel { display:none;padding:32px; }
294
 
295
+ .video-layout {
296
+ display:flex;
297
+ align-items:stretch;
298
+ gap:20px;
299
+ min-height:calc(100vh - 125px);
300
+ }
301
+
302
+ #view-video {
303
+ min-width:0;
304
+ flex:1;
305
+ display:flex;
306
+ align-items:center;
307
+ justify-content:center;
308
+ background:#030608;
309
+ overflow:hidden;
310
+ position:relative;
311
+ border:1px solid var(--border);
312
+ border-radius:6px;
313
+ min-height:420px;
314
+ }
315
 
 
316
  #videoEl { display:block;width:100%;height:100%;object-fit:contain; }
317
  #overlayCanvas {
318
  position:absolute;top:0;left:0;width:100%;height:100%;
319
  pointer-events:none;
320
  }
321
+ #bufferInfo {
322
+ position:absolute;
323
+ right:12px;
324
+ bottom:12px;
325
+ z-index:2;
326
+ padding:4px 8px;
327
+ background:rgba(3,6,8,.72);
328
+ border:1px solid rgba(24,32,48,.9);
329
+ border-radius:3px;
330
+ color:var(--dim);
331
+ font-family:var(--mono);
332
+ font-size:10px;
333
+ letter-spacing:1px;
334
+ }
335
 
336
+ .video-sidebar { display:flex;flex:0 0 320px;flex-direction:column;gap:14px; }
337
 
338
  .vid-ctrl {
339
  background:var(--s1);border:1px solid var(--border);border-radius:6px;padding:18px;
 
387
 
388
  .no-video {
389
  display:flex;flex-direction:column;align-items:center;justify-content:center;
390
+ width:100%;min-height:360px;gap:12px;opacity:.35;
391
  }
392
  .no-video-icon { font-size:48px; }
393
  .no-video-txt { font-family:var(--mono);font-size:12px;letter-spacing:2px; }
394
 
395
+ @media (max-width: 900px) {
396
+ .video-layout {
397
+ flex-direction:column;
398
+ min-height:0;
399
+ }
400
+ #view-video {
401
+ flex:none;
402
+ min-height:320px;
403
+ aspect-ratio:16 / 9;
404
+ }
405
+ .video-sidebar {
406
+ flex:0 0 auto;
407
+ }
408
+ }
409
+
410
  /* ── CANVAS CHARTS (timeline) ── */
411
  #timelineCanvas { width:100%;height:130px;display:block; }
412
 
 
582
  <div class="video-layout">
583
 
584
  <div>
585
+ <div class="video-wrap" id="view-video">
586
+ <div class="no-video no-signal" id="noSignal">
587
  <div class="no-video-icon">🎬</div>
588
  <div class="no-video-txt">NO VIDEO LOADED</div>
589
  <div style="font-family:var(--mono);font-size:10px;color:var(--dim);margin-top:6px">
 
592
  </div>
593
  <video id="videoEl" style="display:none" controls></video>
594
  <canvas id="overlayCanvas"></canvas>
595
+ <div id="bufferInfo">BUF: 0</div>
596
  </div>
597
  </div>
598
 
 
832
  return Object.fromEntries(Object.entries(byClass).map(([cls, ids]) => [cls, ids.size]));
833
  }
834
 
835
+ function uniqueClassCount(rows, keys) {
836
+ const wanted = new Set(keys);
837
+ return new Set(rows.filter(r => wanted.has(r.class_name)).map(objectKey)).size;
838
+ }
839
+
840
  function annotateRows(rows, meta={}) {
841
  const key = sourceKeyFromMeta(meta);
842
  return rows.map(row => ({
 
1127
  const frames = new Set(rows.map(r => r.frame)).size;
1128
  const uniqueObjs = data.trackIds.size;
1129
  const duration = Math.max(...rows.map(r => parseFloat(r.timestamp_sec||0))).toFixed(1);
1130
+ const cars = uniqueClassCount(rows, ['car']);
1131
+ const persons = uniqueClassCount(rows, ['person']);
1132
+ const heavy = uniqueClassCount(rows, ['bus', 'truck']);
1133
  const avgConf = (rows.reduce((s,r)=>s+parseFloat(r.confidence||0),0)/rows.length*100).toFixed(1);
1134
  const down = rows.filter(r => r.direction==='down').length;
1135
  const up = rows.filter(r => r.direction==='up').length;
 
1187
  const vid = document.getElementById('videoEl');
1188
  vid.pause();
1189
  vid.style.display = 'none';
1190
+ document.getElementById('noSignal').style.display = 'flex';
1191
  document.getElementById('vidName').textContent = '';
1192
  document.getElementById('liveCounts').innerHTML =
1193
  '<div style="font-family:var(--mono);font-size:10px;color:var(--dim);text-align:center;padding:8px">Choose a video for this scene</div>';
 
1258
  vid.pause();
1259
  vid.src = file.url;
1260
  vid.style.display = 'block';
1261
+ document.getElementById('noSignal').style.display = 'none';
1262
  document.getElementById('vidName').textContent = `${file.name} (${file.repo}${file.folder ? ' / ' + file.folder : ''})`;
1263
  document.getElementById('liveCounts').innerHTML =
1264
  '<div style="font-family:var(--mono);font-size:10px;color:var(--dim);text-align:center;padding:8px">Play the selected video to see live counts</div>';
1265
 
1266
  vid.onloadedmetadata = () => {
1267
+ const wrap = document.getElementById('view-video');
1268
  const canvas = document.getElementById('overlayCanvas');
1269
  canvas.style.width = wrap.offsetWidth + 'px';
1270
  canvas.style.height = wrap.offsetHeight + 'px';
1271
  canvas.width = wrap.offsetWidth * window.devicePixelRatio;
1272
  canvas.height = wrap.offsetHeight * window.devicePixelRatio;
1273
+ updateBufferInfo();
1274
  };
1275
  vid.ontimeupdate = onVideoTimeUpdate;
1276
  }
 
1288
  const vid = document.getElementById('videoEl');
1289
  vid.src = url;
1290
  vid.style.display = 'block';
1291
+ document.getElementById('noSignal').style.display = 'none';
1292
  document.getElementById('vidName').textContent = file.name;
1293
 
1294
  vid.onloadedmetadata = () => {
1295
+ const wrap = document.getElementById('view-video');
1296
  const canvas = document.getElementById('overlayCanvas');
1297
 
1298
  // Match canvas display size to wrapper
 
1303
  canvas.width = wrap.offsetWidth * window.devicePixelRatio;
1304
  canvas.height = wrap.offsetHeight * window.devicePixelRatio;
1305
 
1306
+ updateBufferInfo();
1307
  toast(`Video loaded: ${vid.videoWidth}Γ—${vid.videoHeight}`, 'ok');
1308
  };
1309
 
 
1312
 
1313
  let lastDrawnFrame = -1;
1314
 
1315
+ function updateBufferInfo() {
1316
+ const vid = document.getElementById('videoEl');
1317
+ const el = document.getElementById('bufferInfo');
1318
+ if (!vid || !el || !vid.duration || !vid.buffered.length) {
1319
+ if (el) el.textContent = 'BUF: 0';
1320
+ return;
1321
+ }
1322
+ const end = vid.buffered.end(vid.buffered.length - 1);
1323
+ const pct = Math.min(100, Math.round((end / vid.duration) * 100));
1324
+ el.textContent = `BUF: ${pct}`;
1325
+ }
1326
+
1327
  function onVideoTimeUpdate() {
1328
  if (!activeScene) return;
1329
  const vid = document.getElementById('videoEl');
1330
+ updateBufferInfo();
1331
  const fps = detectFPS(activeScene);
1332
  const frameNum = Math.round(vid.currentTime * fps);
1333
  if (frameNum === lastDrawnFrame) return;
 
1349
  const canvas = document.getElementById('overlayCanvas');
1350
  const ctx = canvas.getContext('2d');
1351
  const vid = document.getElementById('videoEl');
1352
+ const wrap = document.getElementById('view-video');
1353
 
1354
  // Get actual display dimensions
1355
  const displayWidth = wrap.offsetWidth;
 
1787
  const frames = new Set(sceneRows.map(r => r.frame)).size;
1788
  const uniqueObjs = new Set(sceneRows.map(objectKey)).size;
1789
  const duration = Math.max(...sceneRows.map(r => parseFloat(r.timestamp_sec||0))).toFixed(1);
1790
+ const cars = uniqueClassCount(sceneRows, ['car']);
1791
+ const persons = uniqueClassCount(sceneRows, ['person']);
1792
+ const heavy = uniqueClassCount(sceneRows, ['bus', 'truck']);
1793
  const avgConf = (sceneRows.reduce((s,r)=>s+parseFloat(r.confidence||0),0)/sceneRows.length*100).toFixed(1);
1794
  const down = sceneRows.filter(r => r.direction==='down').length;
1795
  const up = sceneRows.filter(r => r.direction==='up').length;