Better UI

This commit is contained in:
Thomas Forgione 2023-02-23 16:04:55 +01:00
parent 51fc44a60c
commit 0e27037736
2 changed files with 152 additions and 23 deletions

View File

@ -7,6 +7,13 @@
font-family: sans-serif; font-family: sans-serif;
} }
.main {
position: fixed;
width: calc(90vw - 20px);
left: calc(10vw + 20px);
right: 0px;
}
.centered { .centered {
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
@ -20,6 +27,13 @@
box-sizing: border-box; box-sizing: border-box;
} }
.column10 {
display: inline-block;
width: 10vw;
padding: 5px;
box-sizing: border-box;
}
.row:after { .row:after {
content: ""; content: "";
display: table; display: table;
@ -31,23 +45,78 @@
max-height: 100%; max-height: 100%;
} }
.selected {
border-style: solid;
border-width: 2px;
border-color: red;
}
.notselected {
border-style: solid;
border-width: 2px;
border-color: rgba(0, 0, 0, 0);
}
#annotations { #annotations {
margin-left: 20px; margin-left: 20px;
height: auto;
}
#navbar {
position: fixed;
border-right: solid;
border-width: 1px;
height: 100vh;
left: 0;
overflow-y: scroll;
width: 10%;
padding: 10px;
}
table, th, td {
border: 1px solid black;
}
td {
text-align: center;
padding: 5px;
}
p {
margin: 0px;
padding: 0px;
} }
</style> </style>
</head> </head>
<body> <body>
<h1 class="centered">Annotator</h1> <div id="navbar" class="row"></div>
<div class="row"> <div class="main">
<div class="column"> <h1 class="centered">Annotator</h1>
<h2 class="centered">Previous frame (<span id="img-1-index">1</span>)</h2> <div class="row">
<img id="img-1"> <div class="column">
<h2 class="centered">Previous frame (<span id="img-1-index">1</span>)</h2>
<img class="notselected" id="img-1">
</div>
<div class="column">
<h2 class="centered">Current frame (<span id="img-2-index">2</span>)</h2>
<img class="selected" id="img-2">
</div>
</div> </div>
<div class="column"> <div class="row">
<h2 class="centered">Current frame (<span id="img-2-index">2</span>)</h2> <div class="column">
<img id="img-2"> <h3 class="centered">Shorcuts:</h3>
<h3>Annotations:</h3> <table id="shortcuts" class="centered">
<div id="annotations"> <tr id="shortcuts-index">
</tr>
<tr id="shortcuts-value">
</tr>
</table>
</div>
<div class="column">
<h3>Annotations:</h3>
<div id="annotations">
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -3,9 +3,9 @@ function findGetParameter(parameterName) {
location.search location.search
.substr(1) .substr(1)
.split("&") .split('&')
.forEach(function(item) { .forEach(function(item) {
tmp = item.split("="); tmp = item.split('=');
if (tmp[0] === parameterName) result = decodeURIComponent(tmp[1]); if (tmp[0] === parameterName) result = decodeURIComponent(tmp[1]);
}); });
return result; return result;
@ -22,22 +22,68 @@ const Events = [
]; ];
class Annotator { class Annotator {
constructor(root, annotations, img1Id, img2Id, annotationId) { constructor(root, annotations) {
this.root = root; this.root = root;
this.annotations = annotations; this.annotations = annotations;
this.maxIndex = Object.keys(this.annotations).length - 1; this.maxIndex = Object.keys(this.annotations).length - 1;
let img1Id = 'img-1';
let img2Id = 'img-2'
let annotationsId = 'annotations';
this.img1Element = document.getElementById(img1Id); this.img1Element = document.getElementById(img1Id);
this.img1IndexElement = document.getElementById(img1Id + '-index'); this.img1IndexElement = document.getElementById(img1Id + '-index');
this.img2Element = document.getElementById(img2Id); this.img2Element = document.getElementById(img2Id);
this.img2IndexElement = document.getElementById(img2Id + '-index'); this.img2IndexElement = document.getElementById(img2Id + '-index');
this.annotationElement = document.getElementById(annotationId); this.annotationElement = document.getElementById(annotationsId);
this.navbar = document.getElementById('navbar');
this.shortcutsIndex = document.getElementById('shortcuts-index');
this.shortcutsValue = document.getElementById('shortcuts-value');
this.setNavbar();
this.setShortcutsInfo();
this.setIndex(0); this.setIndex(0);
this.addShortcuts(); this.addShortcuts();
} }
setShortcutsInfo() {
for (let index = 1; index <= Events.length; index++) {
let elt = document.createElement('td');
elt.innerHTML = index;
this.shortcutsIndex.appendChild(elt);
elt = document.createElement('td');
elt.innerHTML = Events[index - 1];
this.shortcutsValue.appendChild(elt);
}
}
setNavbar() {
for (let frame in this.annotations) {
let div = document.createElement('div');
div.classList.add('column10');
div.classList.add('notselected');
div.id = 'thumbnail-' + frame;
let img = document.createElement('img');
img.setAttribute('src', this.root + '/' + frame + '.jpg');
let text = document.createElement('p');
text.classList.add('centered');
text.innerHTML = frame;
div.appendChild(img);
div.appendChild(text);
div.addEventListener('click', () => {
this.setIndex(frame);
});
this.navbar.appendChild(div);
}
}
formatIndex(index) { formatIndex(index) {
index += ''; index += '';
return index.padStart(4, '0'); return index.padStart(4, '0');
@ -64,10 +110,24 @@ class Annotator {
this.img2IndexElement.innerHTML = this.index + 1 + '/' + this.maxIndex; this.img2IndexElement.innerHTML = this.index + 1 + '/' + this.maxIndex;
} }
let formattedIndex = this.formatIndex(this.index + 1);
// Refresh navbar
for (let key of Object.keys(this.annotations)) {
document.getElementById('thumbnail-' + key).classList.remove('selected');
document.getElementById('thumbnail-' + key).classList.add('notselected');
}
let current = document.getElementById('thumbnail-' + formattedIndex);
current.classList.add('selected');
current.classList.remove('notselected');
current.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' });
// Refresh annotations list // Refresh annotations list
let currentAnnotations = this.annotations[this.formatIndex(this.index + 1)]; let currentAnnotations = this.annotations[formattedIndex];
if (currentAnnotations.length === 0) { if (currentAnnotations.length === 0) {
this.annotationElement.innerHTML = "There is no annotation for this frame"; this.annotationElement.innerHTML = 'There is no annotation for this frame';
} else { } else {
this.annotationElement.innerHTML = '<ul>'; this.annotationElement.innerHTML = '<ul>';
for (let annotation of currentAnnotations) { for (let annotation of currentAnnotations) {
@ -87,7 +147,7 @@ class Annotator {
} }
addShortcuts() { addShortcuts() {
document.addEventListener('keyup', (e) => { document.addEventListener('keyup', async (e) => {
switch (e.code) { switch (e.code) {
case 'ArrowRight': this.increment(e.ctrlKey ? 10 : 1); break; case 'ArrowRight': this.increment(e.ctrlKey ? 10 : 1); break;
case 'ArrowLeft': this.decrement(e.ctrlKey ? 10 : 1); break; case 'ArrowLeft': this.decrement(e.ctrlKey ? 10 : 1); break;
@ -95,12 +155,12 @@ class Annotator {
if (e.code.startsWith('Numpad') || e.code.startsWith('Digit')) { if (e.code.startsWith('Numpad') || e.code.startsWith('Digit')) {
let key = parseInt(e.code[e.code.length - 1], 10); let key = parseInt(e.code[e.code.length - 1], 10);
this.toggle(key); await this.toggle(key);
} }
}); });
} }
toggle(key) { async toggle(key) {
let event = Events[key]; let event = Events[key];
if (event === undefined) { if (event === undefined) {
return; return;
@ -115,12 +175,12 @@ class Annotator {
events.splice(search, 1); events.splice(search, 1);
} }
await this.sync();
this.setIndex(); this.setIndex();
this.sync();
} }
sync() { async sync() {
fetch('/data', { await fetch('/data', {
method: 'POST', method: 'POST',
headers: { headers: {
'Accept': 'application/json', 'Accept': 'application/json',
@ -137,7 +197,7 @@ async function main() {
const root = findGetParameter('root'); const root = findGetParameter('root');
let annotations = await fetch(root + '/annotations.json'); let annotations = await fetch(root + '/annotations.json');
annotations = await annotations.json(); annotations = await annotations.json();
const annotator = new Annotator(root, annotations, 'img-1', 'img-2', 'annotations'); const annotator = new Annotator(root, annotations, );
} }
main(); main();