Better UI
This commit is contained in:
parent
51fc44a60c
commit
0e27037736
|
@ -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,26 +45,81 @@
|
||||||
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>
|
||||||
|
<div id="navbar" class="row"></div>
|
||||||
|
<div class="main">
|
||||||
<h1 class="centered">Annotator</h1>
|
<h1 class="centered">Annotator</h1>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<h2 class="centered">Previous frame (<span id="img-1-index">1</span>)</h2>
|
<h2 class="centered">Previous frame (<span id="img-1-index">1</span>)</h2>
|
||||||
<img id="img-1">
|
<img class="notselected" id="img-1">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<h2 class="centered">Current frame (<span id="img-2-index">2</span>)</h2>
|
<h2 class="centered">Current frame (<span id="img-2-index">2</span>)</h2>
|
||||||
<img id="img-2">
|
<img class="selected" id="img-2">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="column">
|
||||||
|
<h3 class="centered">Shorcuts:</h3>
|
||||||
|
<table id="shortcuts" class="centered">
|
||||||
|
<tr id="shortcuts-index">
|
||||||
|
</tr>
|
||||||
|
<tr id="shortcuts-value">
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="column">
|
||||||
<h3>Annotations:</h3>
|
<h3>Annotations:</h3>
|
||||||
<div id="annotations">
|
<div id="annotations">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<script src="/static/main.js"></script>
|
<script src="/static/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue