viewbox drag now visible on playback annotator.

This commit is contained in:
Ruben van de Ven 2022-03-29 15:07:18 +02:00
parent 949a16b01f
commit 6d7a223a69
4 changed files with 82 additions and 14 deletions

View File

@ -171,6 +171,7 @@ class AnimationSlice:
dwg = svgwrite.Drawing(fn, size=(box.width, box.height))
dwg.viewbox(box.x, box.y, box.width, box.height)
self.add_to_dwg(dwg)
dwg.defs.add(dwg.style("path{stroke-width:1mm;stroke-linecap: round;}"))
return dwg
def get_as_svg(self) -> str:
@ -325,6 +326,7 @@ class AnnotationIndex:
self.shelve = {}
def refresh(self):
logger.info("refreshing")
# reset the index
for key in list(self.shelve.keys()):
print(key)

View File

@ -40,7 +40,7 @@
</ul> -->
<hr>
<a href="?refresh">Reload index</a>
<a href="?refresh=1">Reload index</a>
</body>
<script>
let images = document.querySelectorAll('[data-audio]');

View File

@ -279,7 +279,7 @@ class AnimationHandler(tornado.web.RequestHandler):
self.config.storage, os.path.basename(
filename) + ".json_appendable"
)
drawing = {"file": filename, "shape": []}
drawing = {"file": filename, "shape": [], "viewboxes": []}
with open(path, "r") as fp:
events = json.loads("[" + fp.read() + "]")
for i, event in enumerate(events):
@ -292,7 +292,7 @@ class AnimationHandler(tornado.web.RequestHandler):
# ignore double metadatas, which appear when continuaing an existing drawing
continue
if event["event"] == "viewbox":
pass
drawing["viewboxes"].extend(event['viewboxes'])
if event["event"] == "stroke":
# points = []
# for i in range(int(len(stroke) / 4)):
@ -496,9 +496,9 @@ class IndexHandler(tornado.web.RequestHandler):
def get(self):
do_refresh = bool(self.get_query_argument('refresh', False))
if do_refresh:
self.logger.info("Reloading Annotation Index")
logger.info("Reloading Annotation Index")
self.index.refresh()
self.logger.info("\treloaded annotation index")
logger.info("\treloaded annotation index")
self.render("templates/index.html", index=self.index)

View File

@ -476,23 +476,26 @@ class Annotator extends EventTarget {
}
this.filename = drawing.file;
this.strokes = drawing.shape.map(s => new Stroke(s['color'], s['points']));
this.viewboxes = drawing.viewboxes;
this.currentPathI = null;
this.currentPointI = null;
this.currentViewboxI = null;
this.dimensions = drawing.dimensions;
this.svgEl.setAttribute('viewBox', `0 0 ${this.dimensions[0]} ${this.dimensions[1]}`)
let bgEl = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
bgEl.setAttribute("x", 0);
bgEl.setAttribute("y", 0);
bgEl.setAttribute("width", this.dimensions[0]);
bgEl.setAttribute("height", this.dimensions[1]);
bgEl.classList.add('background');
this.svgEl.prepend(bgEl);
// let bgEl = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
// bgEl.setAttribute("x", 0);
// bgEl.setAttribute("y", 0);
// bgEl.setAttribute("width", this.dimensions[0]);
// bgEl.setAttribute("height", this.dimensions[1]);
// bgEl.classList.add('background');
// this.svgEl.prepend(bgEl);
this.firstFrameTime = this.strokes[0].points[0][3];
this.lastFrameTime = this.getFinalFrameTime();
this.playheadEl.max = this.lastFrameTime;
this.nextFrameTimeout = null;
this.nextViewboxTimeout = null;
this._setPausedFlag(true);
this.formatter = wNumb({
@ -740,6 +743,15 @@ class Annotator extends EventTarget {
// this.currentTime = path.points[point_i][3];
}
setViewboxPosition(box_i) {
if(this.currentViewboxI == box_i){
return;
}
this.currentViewboxI = box_i
const b = this.viewboxes[box_i];
this.svgEl.setAttribute('viewBox', `${b.x} ${b.y} ${this.dimensions[0]} ${this.dimensions[1]}`)
}
getNextPosition(path_i, point_i) {
const path = this.strokes[path_i];
let next_path, next_point;
@ -790,6 +802,32 @@ class Annotator extends EventTarget {
this.nextFrameTimeout = setTimeout(() => this.playStrokePosition(next_path, next_point, true), dt);
}
playViewboxPosition(box_i, allow_interrupt) {
if (allow_interrupt) {
if (!this.videoIsPlaying) {
console.log('not playing because of interrupt');
return;
}
}
// else {
// this.videoIsPlaying = true;
// }
this.setViewboxPosition(box_i);
const next_box_i = box_i+1;
if(this.viewboxes.length <= next_box_i){
console.debug('done playing viewbox');
return;
}
const t = this.viewboxes[next_box_i].t;
// calculate interval based on playback start to avoid drifting of time
const dt = t - (window.performance.now() - this.startTimeMs);
this.nextViewboxTimeout = setTimeout(() => this.playViewboxPosition(next_box_i, true), dt);
}
scrubTo(ms) {
// const [path_i, point_i] = this.findPositionForTime(ms);
// console.log(path_i, point_i);
@ -816,6 +854,7 @@ class Annotator extends EventTarget {
_interruptPlayback() {
clearTimeout(this.nextFrameTimeout);
clearTimeout(this.nextViewboxTimeout);
clearTimeout(this.audioEndTimeout);
clearTimeout(this.audioStartTimeout);
clearTimeout(this.startVideoTimeout);
@ -835,12 +874,18 @@ class Annotator extends EventTarget {
this._seekByTimeMs(this._currentTimeMs); // prevent playback issue for initial load
this.startTimeMs = window.performance.now() - this._currentTimeMs;
// strokes
if (this._currentTimeMs < 0) {
this.startVideoTimeout = setTimeout((e) => this.playStrokePosition(this.currentPathI, this.currentPointI), this._currentTimeMs * -1);
} else {
this.playStrokePosition(this.currentPathI, this.currentPointI);
} this.playAudioSegment(this._currentTimeMs, this.outPointTimeMs);
}
// viewboxes
// const nextViewboxI = Math.max(this.currentViewboxI++, this.viewboxes.length-1);
this.playViewboxPosition(this.currentViewboxI);
// audio
this.playAudioSegment(this._currentTimeMs, this.outPointTimeMs);
// this.playStrokePosition(this.currentPathI, this.currentPointI);
this._setPausedFlag(false);
@ -927,6 +972,7 @@ class Annotator extends EventTarget {
this.dispatchEvent(new CustomEvent('seeking', { detail: time }));
this._currentTimeMs = Number.parseFloat(time) * 1000;
[this.currentPathI, this.currentPointI] = this.findPositionForTime(this._currentTimeMs);
this.playheadEl.value = this._currentTimeMs;
this._updateFrame();
this.dispatchEvent(new CustomEvent('seeked', { detail: this.currentTime }));
@ -934,6 +980,7 @@ class Annotator extends EventTarget {
_updateFrame() {
this.drawStrokePosition(this.inPointPosition, [this.currentPathI, this.currentPointI]);
this.setViewboxPosition(this.findViewboxForTime(this._currentTimeMs));
}
/**
@ -996,5 +1043,24 @@ class Annotator extends EventTarget {
return [path_i, point_i];
}
findViewboxForTime(ms){
ms = Math.min(Math.max(ms, 0), this.lastFrameTime);
// console.log('scrub to', ms)
let box_i = 0;
this.viewboxes.every((viewbox, index) => {
const startAt = viewbox.t;
if (startAt > ms) {
return false; // too far
} else {
// in case nothings comes after, we store the last best option thus far
box_i = index;
return true;
}
});
return box_i;
}
}