From 8be08ce9d687ec930b43a55b5db0283801836cf2 Mon Sep 17 00:00:00 2001 From: Ruben van de Ven Date: Thu, 23 Feb 2023 18:28:16 +0100 Subject: [PATCH] More player controls --- app/www/annotate.js | 118 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 92 insertions(+), 26 deletions(-) diff --git a/app/www/annotate.js b/app/www/annotate.js index 499bd34..bac1b56 100644 --- a/app/www/annotate.js +++ b/app/www/annotate.js @@ -144,7 +144,7 @@ class Annotator extends EventTarget { ms += v * factor; factor *= 60; }); - return `${ ms } `; + return `${ms} `; } }); @@ -153,6 +153,7 @@ class Annotator extends EventTarget { this.svgEl = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); this.wrapperEl.appendChild(this.svgEl); this.wrapperEl.classList.add(this.config.is_player ? "svganim_player" : "svganim_annotator"); + this.wrapperEl.classList.add(this.config.crop_to_fit ? "cropped-to-selection" : "follow-drawing"); this.controlsEl = document.createElement('div'); @@ -193,7 +194,7 @@ class Annotator extends EventTarget { ev.preventDefault(); // we don't want to spacebar, as this is captured in the overall keydown event }) - if(!this.config.is_player){ + if (!this.config.is_player) { this.scrubberEl = document.createElement('div'); this.scrubberEl.classList.add('scrubber') this.controlsEl.appendChild(this.scrubberEl); @@ -202,6 +203,31 @@ class Annotator extends EventTarget { this.annotationsEl = document.createElement('div'); this.annotationsEl.classList.add('annotations') this.controlsEl.appendChild(this.annotationsEl); + } else { + const extraEl = document.createElement('details'); + extraEl.classList.add('controls--extra'); + + const summaryEl = document.createElement('summary'); + summaryEl.innerHTML = "…"; + extraEl.appendChild(summaryEl); + + const extraControlsEl = document.createElement('ul'); + + // TODO: add handlers + const toggleFutureEl = document.createElement('li'); + toggleFutureEl.innerText = "Show preview" + toggleFutureEl.addEventListener('click', () => this.wrapperEl.classList.toggle('hide-drawing-preview')); + extraControlsEl.appendChild(toggleFutureEl); + + const toggleCropPlayerEl = document.createElement('li'); + toggleCropPlayerEl.innerText = "Crop to selection"; + toggleCropPlayerEl.addEventListener('click', () => this.toggleCrop()); + extraControlsEl.appendChild(toggleCropPlayerEl); + + extraEl.appendChild(extraControlsEl); + + this.playbackControlsEl.appendChild(extraEl); + } @@ -340,7 +366,7 @@ class Annotator extends EventTarget { if (this.selectedAnnotationI == annotation_i) { this.annotationEl.classList.add('selected'); } - this.annotationEl.title = `[${ annotation.tag }] ${ annotation.comment } `; + this.annotationEl.title = `[${annotation.tag}] ${annotation.comment} `; this.annotationEl.addEventListener('mouseover', (e) => { @@ -426,7 +452,7 @@ class Annotator extends EventTarget { // draw full stroke of annotation console.debug('setInOut'); this.drawStrokePosition(this.inPointPosition, this.outPointPosition); - console.debug([`${ this.inPointTimeMs } `, `${ this.outPointTimeMs } `]) + console.debug([`${this.inPointTimeMs} `, `${this.outPointTimeMs} `]) this.slider.set([this.inPointTimeMs, this.outPointTimeMs]); // console.debug(this.selectedAnnotation); @@ -461,7 +487,7 @@ class Annotator extends EventTarget { .then(data => { if (!this.config.is_player) { - const metadata_req = new Request(`/ annotations / ${ data.file } `, { + const metadata_req = new Request(`/ annotations / ${data.file} `, { method: 'GET', }); return fetch(metadata_req) @@ -479,17 +505,17 @@ class Annotator extends EventTarget { }) .then(() => { // play on click for player - if(this.config.is_player) { + if (this.config.is_player) { this.svgEl.addEventListener('click', (ev) => { console.debug('clicked for play/pause'); this.playPause(); }); } - + // autoplay if necessary - if(this.config.autoplay){ + if (this.config.autoplay) { this.play(); // play should remove loading - } else{ + } else { this.wrapperEl.classList.remove('loading'); } }) @@ -727,7 +753,7 @@ class Annotator extends EventTarget { // bgEl.setAttribute("height", this.dimensions[1]); // bgEl.classList.add('background'); // this.svgEl.prepend(bgEl); - + this.firstFrameTime = this.strokes.length == 0 ? 0 : this.strokes[0].points[0][3]; this.lastFrameTime = this.getFinalFrameTime(); this.playheadEl.max = this.lastFrameTime; @@ -846,7 +872,7 @@ class Annotator extends EventTarget { titleEl.title = this.title ?? "[click to add title for this diagram]" titleEl.addEventListener('click', (ev) => { const title = prompt("Change the title for the drawing", this.title ?? ""); - if(title === null) return; //cancel + if (title === null) return; //cancel titleEl.innerText = title.length ? title : "[add title]"; this.title = title.length ? title : null; this.updateState(); @@ -896,7 +922,7 @@ class Annotator extends EventTarget { } - + this.audioEl.addEventListener('loadedmetadata', (ev) => { @@ -987,7 +1013,7 @@ class Annotator extends EventTarget { } getFinalFrameTime() { - if(this.strokes.length == 0) return null; // when no strokes are loaded (eg. for annotation) + if (this.strokes.length == 0) return null; // when no strokes are loaded (eg. for annotation) const points = this.strokes[this.strokes.length - 1].points; return points[points.length - 1][3]; } @@ -1073,30 +1099,35 @@ class Annotator extends EventTarget { updateViewbox() { if (this.config.crop_to_fit) { - this.svgEl.setAttribute('viewBox', `${ this.bounding_box.x } ${ this.bounding_box.y } ${ this.bounding_box.width } ${ this.bounding_box.height } `); + this.svgEl.setAttribute('viewBox', `${this.bounding_box.x} ${this.bounding_box.y} ${this.bounding_box.width} ${this.bounding_box.height} `); } else { - let x,y,w,h; - if(this.currentViewboxI !== null) { + let x, y, w, h; + if (this.currentViewboxI !== null) { x = this.viewboxes[this.currentViewboxI].x, - y = this.viewboxes[this.currentViewboxI].y, - w = this.dimensions[0], - h = this.dimensions[1]; + y = this.viewboxes[this.currentViewboxI].y, + w = this.dimensions[0], + h = this.dimensions[1]; } else { x = 0, - y = 0, - w = this.dimensions[0], - h = this.dimensions[1]; + y = 0, + w = this.dimensions[0], + h = this.dimensions[1]; } - this.svgEl.setAttribute('viewBox', `${ x } ${ y } ${ w } ${ h } `); + this.svgEl.setAttribute('viewBox', `${x} ${y} ${w} ${h} `); } } setCrop(crop_to_fit) { this.config.crop_to_fit = Boolean(crop_to_fit); + if (this.config.crop_to_fit) { + this.wrapperEl.classList.add('cropped-to-selection'); + } else { + this.wrapperEl.classList.remove('cropped-to-selection'); + } this.updateViewbox(); } - toggleCrop(){ + toggleCrop() { this.setCrop(!this.config.crop_to_fit); } @@ -1629,12 +1660,47 @@ class AnnotationPlayer extends HTMLElement { opacity: .1; stroke: gray !important; } + + .hide-drawing-preview g.after path, .hide-drawing-preview path.before_in{ + opacity:0; + } .gray { position: absolute; background: rgba(255, 255, 255, 0.7); } + summary{ + list-style: none; + cursor: pointer; + padding: 0 5px; + } + + details > ul{ + position: absolute; + bottom: 30px; + background: rgba(0,0,0, .5); + border-radius: 3px; + right: 0; + padding: 5px; + margin: 0; + list-style: none; + font-size: 10pt; + } + + details > ul li:hover{ + cursor: pointer; + text-decoration: underline; + } + + .play:not(.hide-drawing-preview) details > ul li:first-child{ + /*text-decoration: line-through;*/ + font-weight:bold; + } + .play.cropped-to-selection details > ul li:nth-child(2){ + /*text-decoration: line-through;*/ + font-weight:bold; + } `; @@ -1660,8 +1726,8 @@ class AnnotationPlayer extends HTMLElement { attributeChangedCallback(name, oldValue, newValue) { console.log(name, oldValue, newValue); - if(name == 'data-no-crop'){ - if(!this.annotator) { + if (name == 'data-no-crop') { + if (!this.annotator) { return; } this.annotator.setCrop(!this.hasAttribute('data-no-crop'));