Spaces:
Runtime error
Runtime error
draggable_js = """ | |
() => { | |
window.canvas = document.getElementById('canvas'); | |
window.ctx = canvas.getContext('2d'); | |
window.rects = []; | |
window.mouseX; | |
window.mouseY; | |
window.closeEnough = 10; | |
window.keys = {}; | |
window.hover = false; | |
window.TL = 0; | |
window.TR = 1; | |
window.BL = 2; | |
window.BR = 3; | |
window.init = () => { | |
window.frames = JSON.parse(document.getElementById("annotation_info").innerHTML); | |
window.frame_index = 0; | |
document.addEventListener('keydown', keydown); | |
document.addEventListener('keyup', keyup); | |
show_frame(); | |
} | |
window.prev_frame = () => { | |
window.frame_index = Math.max(window.frame_index - 1, 0); | |
show_frame(); | |
} | |
window.next_frame = () => { | |
window.frame_index = Math.min(window.frame_index + 1, window.frames.length - 1); | |
show_frame(); | |
} | |
window.show_frame = () => { | |
const frame_info = window.frames[window.frame_index]; | |
const annotations = frame_info['annotations']; | |
const frame = frame_info['frame']; | |
window.annotations = []; | |
for (const annotation of annotations) { | |
const bbox = annotation['bbox'] | |
window.annotations.push({ | |
rect: { | |
startX: bbox.left, | |
startY: bbox.top, | |
w: bbox.right - bbox.left, | |
h: bbox.bottom - bbox.top | |
}, | |
id: annotation.id, | |
conf: annotation.conf | |
}) | |
} | |
console.log(window.annotations) | |
window.dragging = false; | |
document.getElementById("annotation_img").src = "data:image/png;base64," + frame; | |
} | |
window.draw = () => { | |
ctx = window.ctx; | |
canvas = window.canvas; | |
canvas.width = document.getElementById("annotation_img").width; | |
canvas.height = document.getElementById("annotation_img").height; | |
canvas.style = "" | |
annotations = window.annotations; | |
ctx.clearRect(0, 0, canvas.width, canvas.height); | |
ctx.drawImage(document.getElementById("annotation_img"), 0, 0); | |
for (const annotation of annotations) { | |
//ctx.globalAlpha = annotation.conf | |
const rect = annotation.rect; | |
ctx.strokeStyle = color_from_id(annotation.id); | |
ctx.strokeRect(rect.startX, rect.startY, rect.w, rect.h); | |
ctx.font = "15px Arial"; | |
ctx.fillStyle = color_from_id(annotation.id); | |
ctx.textAlign = "right"; | |
ctx.fillText(annotation.id, rect.startX + rect.w, rect.startY - 3); | |
} | |
if (hover && !dragging) { | |
annotation = hover.annotation; | |
rect = annotation.rect; | |
handles = [ | |
[rect.startX, rect.startY], | |
[rect.startX + rect.w, rect.startY], | |
[rect.startX, rect.startY + rect.h], | |
[rect.startX + rect.w, rect.startY + rect.h] | |
]; | |
handle = handles[hover.corner]; | |
ctx.fillStyle = color_from_id(annotation.id); | |
ctx.beginPath(); | |
s = 6; | |
ctx.rect(handle[0]-s/2, handle[1]-s/2, s, s); | |
ctx.fill(); | |
} | |
prettify_annotation(); | |
} | |
color_from_id = (id) => { | |
return 'hsl(' + Math.floor((id*id)*57 % 360) + ', 100%, 50%)' | |
} | |
window.prettify_annotation = () => { | |
label_style = "style='width: calc(16% - 6px); display: inline-block; text-align:center; font-weight: bold;'"; | |
input_style_base = "style='width: calc(16% - 6px); display: inline-block; padding: 5px;'"; | |
input_style_selected = "style='width: calc(16% - 6px); display: inline-block; padding: 5px; border-width: 3px; border-color: orange; border-radius: 5px;'"; | |
html = "" | |
for (const annotation of window.annotations) { | |
input_style = (window.hover && annotation === window.hover.annotation) ? input_style_selected : input_style_base; | |
html += ` | |
<div style='margin: 0 0 20px 10px'> | |
<div> | |
<label ${label_style}>${"id"}</label> | |
<label ${label_style}>${"x"}</label> | |
<label ${label_style}>${"y"}</label> | |
<label ${label_style}>${"w"}</label> | |
<label ${label_style}>${"h"}</label> | |
<label ${label_style}>${"conf"}</label> | |
</div> | |
<div style='height:40px'> | |
<input ${input_style} type='text' value='${annotation.id}'> | |
<input ${input_style} type='text' value='${annotation.rect.startX}'> | |
<input ${input_style} type='text' value='${annotation.rect.startY}'> | |
<input ${input_style} type='text' value='${annotation.rect.w}'> | |
<input ${input_style} type='text' value='${annotation.rect.h}'> | |
<input ${input_style} type='text' value='${annotation.conf}'> | |
</div> | |
</div>`; | |
} | |
document.getElementById("annotation_display").innerHTML = html; | |
} | |
window.keyup = (e) => { | |
delete keys[e.key.toLowerCase()]; | |
} | |
window.keydown = (e) => { | |
console.log(e.key.toLowerCase()) | |
keys[e.key.toLowerCase()] = true; | |
// if pressing x, delete hovered annotation | |
if (keys['x'] && window.hover) delete_annotation(window.hover.annotation); | |
if (keys['arrowright'] || keys['d']) next_frame(); | |
if (keys['arrowleft'] || keys['a']) prev_frame(); | |
} | |
window.mouse_down = (e) => { | |
update_mouse(e); | |
// If holding 'n', create new annotation | |
if (keys['n']) return create_annotation(); | |
// else, start dragging hovered object | |
window.dragging = window.hover; | |
console.log(dragging) | |
window.draw() | |
} | |
window.mouse_up = () => { | |
console.log("mouseUp") | |
window.dragging = false; | |
} | |
window.mouse_move = (e) => { | |
ctx = window.ctx; | |
canvas = window.canvas; | |
dragging = window.dragging; | |
update_mouse(e); | |
if (!dragging) return window.draw(); | |
annotation = dragging.annotation; | |
rect = annotation.rect | |
corner = dragging.corner; | |
if (corner == window.TL) { | |
rect.w += rect.startX - mouseX; | |
rect.h += rect.startY - mouseY; | |
rect.startX = mouseX; | |
rect.startY = mouseY; | |
} else if (corner == window.TR) { | |
rect.w = mouseX - rect.startX; | |
rect.h += rect.startY - mouseY; | |
rect.startY = mouseY; | |
} else if (corner == window.BL) { | |
rect.w += rect.startX - mouseX; | |
rect.h = mouseY - rect.startY; | |
rect.startX = mouseX; | |
} else if (corner == window.BR) { | |
rect.w = mouseX - rect.startX; | |
rect.h = mouseY - rect.startY | |
} | |
rect.startX = Math.round(rect.startX); | |
rect.startY = Math.round(rect.startY); | |
rect.w = Math.round(rect.w); | |
rect.h = Math.round(rect.h); | |
// If w < 0 we have swapped sides, switch to horizontally opposite corner | |
if (rect.w < 0) { | |
rect.w = -rect.w; | |
if (corner == window.TL) corner = window.TR; | |
else if (corner == window.TR) corner = window.TL; | |
else if (corner == window.BL) corner = window.BR; | |
else if (corner == window.BR) corner = window.BL; | |
} | |
//If h < 0 we have swapped sides, switch to vertically opposite corner | |
if (rect.h < 0) { | |
rect.h = -rect.h; | |
if (corner == window.TL) corner = window.BL; | |
else if (corner == window.BL) corner = window.TL; | |
else if (corner == window.TR) corner = window.BR; | |
else if (corner == window.BR) corner = window.TR; | |
} | |
if (dragging.corner !== corner) console.log(dragging.corner + " -> " + corner); | |
dragging.corner = corner; | |
window.draw() | |
} | |
update_mouse = (e) => { | |
bodyRect = document.body.getBoundingClientRect(); | |
canvasRect = e.target.getBoundingClientRect(); | |
offset_x = canvasRect.left - bodyRect.left; | |
offset_y = canvasRect.top - bodyRect.top; | |
mouseX = e.pageX - offset_x; | |
mouseY = e.pageY - offset_y; | |
function sqDistance(x, y) { | |
dx = mouseX - x; | |
dy = mouseY - y; | |
return dx*dx + dy*dy; | |
} | |
window.hover = false; | |
threshold = 100; | |
for (const annotation of annotations) { | |
rect = annotation.rect; | |
square_dists = [ | |
sqDistance(rect.startX, rect.startY), | |
sqDistance(rect.startX + rect.w, rect.startY), | |
sqDistance(rect.startX, rect.startY + rect.h), | |
sqDistance(rect.startX + rect.w, rect.startY + rect.h), | |
] | |
min_dist = Math.min(...square_dists); | |
if (min_dist > threshold) continue; | |
threshold = min_dist; | |
corner = square_dists.indexOf(min_dist); | |
window.hover = { corner, annotation } | |
} | |
} | |
create_annotation = () => { | |
new_annotation = { | |
rect: { | |
startX: mouseX, | |
startY: mouseY, | |
w: 0, | |
h: 0 | |
}, | |
color: "rgb(255, 0, 0)", | |
id: 1, | |
conf: 1 | |
}; | |
annotations.push(new_annotation); | |
window.dragging = { | |
annotation: new_annotation, | |
corner: window.BL | |
} | |
window.draw() | |
} | |
delete_annotation = (annotation) => { | |
window.annotations = window.annotations.filter(function (a) { | |
return a !== annotation; | |
}); | |
window.dragging = false; | |
window.hover = false; | |
window.draw(); | |
} | |
window.init(); | |
} | |
""" | |