Play back working
This commit is contained in:
parent
4cad6ed741
commit
16d8259866
2 changed files with 142 additions and 30 deletions
|
@ -82,6 +82,18 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.controls button.paused, .controls button.playing{
|
||||||
|
position: absolute;
|
||||||
|
left: 100%;
|
||||||
|
width: 30px;
|
||||||
|
}
|
||||||
|
.controls button.paused::before{
|
||||||
|
content: '⏵';
|
||||||
|
}
|
||||||
|
.controls button.playing::before{
|
||||||
|
content: '⏸';
|
||||||
|
}
|
||||||
|
|
||||||
.controls {
|
.controls {
|
||||||
position: absolute !important;
|
position: absolute !important;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
|
@ -227,6 +239,7 @@
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
width: 100px; /* hides seek head */
|
width: 100px; /* hides seek head */
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<link rel="stylesheet" href="assets/nouislider-15.5.0.css">
|
<link rel="stylesheet" href="assets/nouislider-15.5.0.css">
|
||||||
<link rel="stylesheet" href="core.css">
|
<link rel="stylesheet" href="core.css">
|
||||||
|
|
157
www/annotate.js
157
www/annotate.js
|
@ -1,8 +1,8 @@
|
||||||
class Annotation {
|
class Annotation {
|
||||||
constructor(tag, t_in, t_out) {
|
constructor(tag, t_in, t_out) {
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
this.t_in = t_in;
|
this.t_in = Number.parseFloat(t_in);
|
||||||
this.t_out = t_out;
|
this.t_out = Number.parseFloat(t_out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,6 +132,14 @@ class Annotator extends EventTarget {
|
||||||
this.scrubTo(ev.target.value);
|
this.scrubTo(ev.target.value);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.playPauseEl = document.createElement('button');
|
||||||
|
this.playPauseEl.classList.add('paused');
|
||||||
|
this.controlsEl.appendChild(this.playPauseEl);
|
||||||
|
|
||||||
|
this.playPauseEl.addEventListener("click", (ev) => {
|
||||||
|
this.playPause()
|
||||||
|
})
|
||||||
|
|
||||||
this.scrubberEl = document.createElement('div');
|
this.scrubberEl = document.createElement('div');
|
||||||
this.scrubberEl.classList.add('scrubber')
|
this.scrubberEl.classList.add('scrubber')
|
||||||
this.controlsEl.appendChild(this.scrubberEl);
|
this.controlsEl.appendChild(this.scrubberEl);
|
||||||
|
@ -157,7 +165,7 @@ class Annotator extends EventTarget {
|
||||||
tagEl.classList.add('annotation-rm');
|
tagEl.classList.add('annotation-rm');
|
||||||
tagEl.dataset.tag = 'rm';
|
tagEl.dataset.tag = 'rm';
|
||||||
tagEl.title = "Remove annotation";
|
tagEl.title = "Remove annotation";
|
||||||
tagEl.innerHTML = "×";
|
tagEl.innerHTML = "🚮"; // ×
|
||||||
tagEl.addEventListener('click', (e) => {
|
tagEl.addEventListener('click', (e) => {
|
||||||
if (this.selectedAnnotation) {
|
if (this.selectedAnnotation) {
|
||||||
this.removeAnnotation(this.selectedAnnotationI);
|
this.removeAnnotation(this.selectedAnnotationI);
|
||||||
|
@ -177,7 +185,7 @@ class Annotator extends EventTarget {
|
||||||
this.outPointPosition = null;
|
this.outPointPosition = null;
|
||||||
this.outPointTimeMs = null;
|
this.outPointTimeMs = null;
|
||||||
this._currentTimeMs = 0;
|
this._currentTimeMs = 0;
|
||||||
this.isPlaying = false;
|
this.videoIsPlaying = false;
|
||||||
|
|
||||||
const groups = ['before', 'annotation', 'after']
|
const groups = ['before', 'annotation', 'after']
|
||||||
this.strokeGroups = {};
|
this.strokeGroups = {};
|
||||||
|
@ -199,8 +207,10 @@ class Annotator extends EventTarget {
|
||||||
for (let annotation_i in this.annotations) {
|
for (let annotation_i in this.annotations) {
|
||||||
const annotation = this.annotations[annotation_i];
|
const annotation = this.annotations[annotation_i];
|
||||||
this.annotationEl = document.createElement('div');
|
this.annotationEl = document.createElement('div');
|
||||||
const left = (annotation.t_in / this.lastFrameTime) * 100;
|
const prerollDiff = Number.parseFloat(this.audioOffset < 0 ? this.audioOffset * -1000 : 0);
|
||||||
const right = 100 - (annotation.t_out / this.lastFrameTime) * 100;
|
// console.log('diff', prerollDiff, annotation.t_in, typeof annotation.t_in, this.duration,annotation.t_in + prerollDiff, (annotation.t_in + prerollDiff) / this.duration);
|
||||||
|
const left = ((annotation.t_in + prerollDiff) / (this.duration * 1000)) * 100;
|
||||||
|
const right = 100 - ((annotation.t_out + prerollDiff) / (this.duration * 1000)) * 100;
|
||||||
this.annotationEl.style.left = left + '%';
|
this.annotationEl.style.left = left + '%';
|
||||||
this.annotationEl.style.right = right + '%';
|
this.annotationEl.style.right = right + '%';
|
||||||
|
|
||||||
|
@ -248,6 +258,10 @@ class Annotator extends EventTarget {
|
||||||
|
|
||||||
this.inPointPosition = this.findPositionForTime(this.selectedAnnotation.t_in);
|
this.inPointPosition = this.findPositionForTime(this.selectedAnnotation.t_in);
|
||||||
this.outPointPosition = this.findPositionForTime(this.selectedAnnotation.t_out);
|
this.outPointPosition = this.findPositionForTime(this.selectedAnnotation.t_out);
|
||||||
|
this.inPointTimeMs = this.selectedAnnotation.t_in;
|
||||||
|
this.outPointTimeMs = this.selectedAnnotation.t_out;
|
||||||
|
this._seekByTimeMs(this.selectedAnnotation.t_in);
|
||||||
|
// draw full stroke of annotation:
|
||||||
this.drawStrokePosition(this.inPointPosition, this.outPointPosition);
|
this.drawStrokePosition(this.inPointPosition, this.outPointPosition);
|
||||||
|
|
||||||
this.updateAnnotations(false); //selects the right tag & highlights the annotation
|
this.updateAnnotations(false); //selects the right tag & highlights the annotation
|
||||||
|
@ -256,8 +270,9 @@ class Annotator extends EventTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
deselectAnnotation(keep_position) {
|
deselectAnnotation(keep_position) {
|
||||||
if (this.selectedAnnotation)
|
if (this.selectedAnnotation) {
|
||||||
this._currentTimeMs = this.selectedAnnotation.t_out;
|
this._seekByTimeMs(this.selectedAnnotation.t_out);
|
||||||
|
}
|
||||||
|
|
||||||
this.wrapperEl.classList.remove('selected-annotation');
|
this.wrapperEl.classList.remove('selected-annotation');
|
||||||
|
|
||||||
|
@ -270,6 +285,18 @@ class Annotator extends EventTarget {
|
||||||
this.updateAnnotations(false); // selects the right tag & highlights the annotation
|
this.updateAnnotations(false); // selects the right tag & highlights the annotation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetInOutPoint() {
|
||||||
|
this.inPointPosition = [0, 0];
|
||||||
|
this.inPointTimeMs = null;
|
||||||
|
this.outPointPosition = null;
|
||||||
|
this.outPointTimeMs = null;
|
||||||
|
this._seekByTimeMs(this.audioOffset < 0 ? this.audioOffset * 1000 : 0);
|
||||||
|
// draw full stroke of annotation
|
||||||
|
console.log('reset!');
|
||||||
|
this.drawStrokePosition(this.inPointPosition, [Infinity, Infinity]);
|
||||||
|
this.setUpAnnotator();
|
||||||
|
}
|
||||||
|
|
||||||
load(file) {
|
load(file) {
|
||||||
const request = new Request(file, {
|
const request = new Request(file, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
|
@ -284,6 +311,7 @@ class Annotator extends EventTarget {
|
||||||
fetch(metadata_req)
|
fetch(metadata_req)
|
||||||
.then(response => response.ok ? response.json() : null)
|
.then(response => response.ok ? response.json() : null)
|
||||||
.then(metadata => {
|
.then(metadata => {
|
||||||
|
metadata.annotations = metadata.annotations.map((a) => new Annotation(a.tag, a.t_in, a.t_out))
|
||||||
this.loadStrokes(data, metadata)
|
this.loadStrokes(data, metadata)
|
||||||
})
|
})
|
||||||
.catch(e => console.log(e));
|
.catch(e => console.log(e));
|
||||||
|
@ -367,6 +395,7 @@ class Annotator extends EventTarget {
|
||||||
this.updateAnnotations(true);
|
this.updateAnnotations(true);
|
||||||
|
|
||||||
this._currentTimeMs = t_out;
|
this._currentTimeMs = t_out;
|
||||||
|
this.playheadEl.value = this._currentTimeMs;
|
||||||
this.setUpAnnotator();
|
this.setUpAnnotator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -380,7 +409,7 @@ class Annotator extends EventTarget {
|
||||||
this.inPointPosition = this.findPositionForTime(this.currentTime);
|
this.inPointPosition = this.findPositionForTime(this.currentTime);
|
||||||
this.inPointTimeMs = this._currentTimeMs;
|
this.inPointTimeMs = this._currentTimeMs;
|
||||||
this.outPointPosition = this.findPositionForTime(this.lastFrameTime); // TODO: simplify to get the last frame indexes directly
|
this.outPointPosition = this.findPositionForTime(this.lastFrameTime); // TODO: simplify to get the last frame indexes directly
|
||||||
this.outPointTimeMs = null;
|
this.outPointTimeMs = this.getEndTimeMs();
|
||||||
|
|
||||||
if (this.scrubberEl.noUiSlider) {
|
if (this.scrubberEl.noUiSlider) {
|
||||||
this.slider.destroy();
|
this.slider.destroy();
|
||||||
|
@ -388,7 +417,7 @@ class Annotator extends EventTarget {
|
||||||
|
|
||||||
// console.log(this._currentTimeMs, )
|
// console.log(this._currentTimeMs, )
|
||||||
this.slider = noUiSlider.create(this.scrubberEl, {
|
this.slider = noUiSlider.create(this.scrubberEl, {
|
||||||
start: [this._currentTimeMs, this.lastFrameTime],
|
start: [this._currentTimeMs, this.getEndTimeMs()],
|
||||||
connect: true,
|
connect: true,
|
||||||
range: {
|
range: {
|
||||||
'min': this.audioOffset < 0 ? this.audioOffset * 1000 : 0,
|
'min': this.audioOffset < 0 ? this.audioOffset * 1000 : 0,
|
||||||
|
@ -406,7 +435,7 @@ class Annotator extends EventTarget {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.slider.on("slide", (values, handle) => {
|
this.slider.on("slide", (values, handle) => {
|
||||||
this.isPlaying = false;
|
this.videoIsPlaying = false;
|
||||||
this.inPointPosition = this.findPositionForTime(values[0]);
|
this.inPointPosition = this.findPositionForTime(values[0]);
|
||||||
this.inPointTimeMs = Number.parseFloat(values[0]);
|
this.inPointTimeMs = Number.parseFloat(values[0]);
|
||||||
this.outPointPosition = this.findPositionForTime(values[1]);
|
this.outPointPosition = this.findPositionForTime(values[1]);
|
||||||
|
@ -415,8 +444,8 @@ class Annotator extends EventTarget {
|
||||||
|
|
||||||
// console.log(this.selectedAnnotation);
|
// console.log(this.selectedAnnotation);
|
||||||
if (this.selectedAnnotation) {
|
if (this.selectedAnnotation) {
|
||||||
this.selectedAnnotation.t_in = values[0];
|
this.selectedAnnotation.t_in = Number.parseFloat(values[0]);
|
||||||
this.selectedAnnotation.t_out = values[1];
|
this.selectedAnnotation.t_out = Number.parseFloat(values[1]);
|
||||||
this.updateAnnotations(false);
|
this.updateAnnotations(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -424,8 +453,10 @@ class Annotator extends EventTarget {
|
||||||
if (this.selectedAnnotation) {
|
if (this.selectedAnnotation) {
|
||||||
this.updateAnnotations(true);
|
this.updateAnnotations(true);
|
||||||
}
|
}
|
||||||
this.playAudioSegment(values[0], values[1]);
|
this._seekByTimeMs(values[0]);
|
||||||
})
|
this.play();
|
||||||
|
// this.playAudioSegment(values[0], values[1]);
|
||||||
|
});
|
||||||
|
|
||||||
this.drawStrokePosition(this.inPointPosition, this.outPointPosition);
|
this.drawStrokePosition(this.inPointPosition, this.outPointPosition);
|
||||||
}
|
}
|
||||||
|
@ -437,6 +468,7 @@ class Annotator extends EventTarget {
|
||||||
this.audioFile = metadata.hasOwnProperty('audio') ? metadata.audio.file : null;
|
this.audioFile = metadata.hasOwnProperty('audio') ? metadata.audio.file : null;
|
||||||
this.audioOffset = metadata.hasOwnProperty('audio') ? Number.parseFloat(metadata.audio.offset) : 0;
|
this.audioOffset = metadata.hasOwnProperty('audio') ? Number.parseFloat(metadata.audio.offset) : 0;
|
||||||
this._currentTimeMs = this.audioOffset < 0 ? this.audioOffset * 1000 : 0;
|
this._currentTimeMs = this.audioOffset < 0 ? this.audioOffset * 1000 : 0;
|
||||||
|
this.playheadEl.value = this._currentTimeMs;
|
||||||
//
|
//
|
||||||
// load any saved metadata
|
// load any saved metadata
|
||||||
}
|
}
|
||||||
|
@ -459,6 +491,7 @@ class Annotator extends EventTarget {
|
||||||
this.lastFrameTime = this.getFinalFrameTime();
|
this.lastFrameTime = this.getFinalFrameTime();
|
||||||
this.playheadEl.max = this.lastFrameTime;
|
this.playheadEl.max = this.lastFrameTime;
|
||||||
this.nextFrameTimeout = null;
|
this.nextFrameTimeout = null;
|
||||||
|
this._setPausedFlag(true);
|
||||||
|
|
||||||
this.formatter = wNumb({
|
this.formatter = wNumb({
|
||||||
decimals: 2,
|
decimals: 2,
|
||||||
|
@ -480,6 +513,19 @@ class Annotator extends EventTarget {
|
||||||
this.setupAudioConfig().then(() => {
|
this.setupAudioConfig().then(() => {
|
||||||
// this.setUpAnnotator()
|
// this.setUpAnnotator()
|
||||||
this.updateAnnotations(false);
|
this.updateAnnotations(false);
|
||||||
|
|
||||||
|
document.body.addEventListener('keyup', (ev) => {
|
||||||
|
if (ev.key == ' ') {
|
||||||
|
this.playPause();
|
||||||
|
}
|
||||||
|
if (ev.key == 'Escape') {
|
||||||
|
if (this.selectedAnnotation) {
|
||||||
|
this.deselectAnnotation();
|
||||||
|
} else {
|
||||||
|
this.resetInOutPoint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// this.playStrokePosition(0, 1);
|
// this.playStrokePosition(0, 1);
|
||||||
|
@ -610,7 +656,12 @@ class Annotator extends EventTarget {
|
||||||
console.log(this.audioEl.currentTime, t_start, t_in, t_out);
|
console.log(this.audioEl.currentTime, t_start, t_in, t_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.audioEndTimeout = setTimeout((e) => this.audioEl.pause(), t_diff);
|
this.audioIsPlaying = true; // also state as playing in preroll
|
||||||
|
this.audioEndTimeout = setTimeout((e) => {
|
||||||
|
this.audioEl.pause();
|
||||||
|
this.audioIsPlaying = false;
|
||||||
|
console.debug('done playing audio');
|
||||||
|
}, t_diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
getFinalFrameTime() {
|
getFinalFrameTime() {
|
||||||
|
@ -712,18 +763,19 @@ class Annotator extends EventTarget {
|
||||||
|
|
||||||
playStrokePosition(path_i, point_i, allow_interrupt) {
|
playStrokePosition(path_i, point_i, allow_interrupt) {
|
||||||
if (allow_interrupt) {
|
if (allow_interrupt) {
|
||||||
if (!this.isPlaying) {
|
if (!this.videoIsPlaying) {
|
||||||
console.log('not playing because of interrupt');
|
console.log('not playing because of interrupt');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.isPlaying = true;
|
this.videoIsPlaying = true;
|
||||||
}
|
}
|
||||||
this.drawStrokePosition(this.inPointPosition, [path_i, point_i]);
|
this.drawStrokePosition(this.inPointPosition, [path_i, point_i]);
|
||||||
|
|
||||||
const [next_path, next_point] = this.getNextPosition(path_i, point_i);
|
const [next_path, next_point] = this.getNextPosition(path_i, point_i);
|
||||||
if (next_path === null) {
|
if (next_path === null) {
|
||||||
console.log('done playing');
|
console.debug('done playing video');
|
||||||
|
this.videoIsPlaying = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -742,6 +794,14 @@ class Annotator extends EventTarget {
|
||||||
// this.playHead = ms;
|
// this.playHead = ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
playPause() {
|
||||||
|
if (this.paused) {
|
||||||
|
this.play();
|
||||||
|
} else {
|
||||||
|
this.pause()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compatibility with HTMLMediaElement API
|
* Compatibility with HTMLMediaElement API
|
||||||
* @returns None
|
* @returns None
|
||||||
|
@ -756,7 +816,9 @@ class Annotator extends EventTarget {
|
||||||
clearTimeout(this.audioStartTimeout);
|
clearTimeout(this.audioStartTimeout);
|
||||||
clearTimeout(this.startVideoTimeout);
|
clearTimeout(this.startVideoTimeout);
|
||||||
this.audioEl.pause();
|
this.audioEl.pause();
|
||||||
this.isPlaying = false;
|
this.videoIsPlaying = false;
|
||||||
|
this.audioIsPlaying = false;
|
||||||
|
this._setPausedFlag(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -766,6 +828,7 @@ class Annotator extends EventTarget {
|
||||||
play() {
|
play() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this._interruptPlayback();
|
this._interruptPlayback();
|
||||||
|
this._seekByTimeMs(this._currentTimeMs); // prevent playback issue for initial load
|
||||||
|
|
||||||
this.startTimeMs = window.performance.now() - this._currentTimeMs;
|
this.startTimeMs = window.performance.now() - this._currentTimeMs;
|
||||||
|
|
||||||
|
@ -773,26 +836,57 @@ class Annotator extends EventTarget {
|
||||||
this.startVideoTimeout = setTimeout((e) => this.playStrokePosition(this.currentPathI, this.currentPointI), this._currentTimeMs * -1);
|
this.startVideoTimeout = setTimeout((e) => this.playStrokePosition(this.currentPathI, this.currentPointI), this._currentTimeMs * -1);
|
||||||
} else {
|
} else {
|
||||||
this.playStrokePosition(this.currentPathI, this.currentPointI);
|
this.playStrokePosition(this.currentPathI, this.currentPointI);
|
||||||
}
|
} this.playAudioSegment(this._currentTimeMs, this.outPointTimeMs);
|
||||||
console.log(this._currentTimeMs, this.outPointTimeMs);
|
|
||||||
this.playAudioSegment(this._currentTimeMs, this.outPointTimeMs);
|
|
||||||
// this.playStrokePosition(this.currentPathI, this.currentPointI);
|
// this.playStrokePosition(this.currentPathI, this.currentPointI);
|
||||||
|
this._setPausedFlag(false);
|
||||||
|
|
||||||
this.dispatchEvent(new CustomEvent('play', {}));
|
this.dispatchEvent(new CustomEvent('play', {}));
|
||||||
this._animationFrame();
|
this._animationFrame();
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_setPausedFlag(paused) {
|
||||||
|
this._paused = !!paused; //convert to boolean
|
||||||
|
if (paused) {
|
||||||
|
this.playPauseEl.classList.remove('playing');
|
||||||
|
this.playPauseEl.classList.add('paused');
|
||||||
|
} else {
|
||||||
|
this.playPauseEl.classList.remove('paused');
|
||||||
|
this.playPauseEl.classList.add('playing');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get paused() {
|
||||||
|
return this._paused;
|
||||||
|
}
|
||||||
|
|
||||||
_animationFrame(timestamp) {
|
_animationFrame(timestamp) {
|
||||||
// TODO, move time at end of playStrokePosition to here
|
// TODO, move time at end of playStrokePosition to here
|
||||||
const nextTime = window.performance.now() - this.startTimeMs;
|
const nextTime = window.performance.now() - this.startTimeMs;
|
||||||
const endTime = this.outPointTimeMs ?? this.duration * 1000;
|
const endTime = this.outPointTimeMs ?? this.duration * 1000;
|
||||||
if (nextTime > this.duration * 1000) {
|
let interrupt = false;
|
||||||
|
if (nextTime > endTime) {
|
||||||
|
this._currentTimeMs = endTime;
|
||||||
|
interrupt = true;
|
||||||
|
} else {
|
||||||
|
this._currentTimeMs = nextTime;
|
||||||
}
|
}
|
||||||
this.playheadEl.value = this._currentTimeMs;
|
this.playheadEl.value = this._currentTimeMs;
|
||||||
if (this.isPlaying) {
|
if (!interrupt && (this.videoIsPlaying || this.audioIsPlaying)) {
|
||||||
window.requestAnimationFrame((timestamp) => this._animationFrame(timestamp));
|
window.requestAnimationFrame((timestamp) => this._animationFrame(timestamp));
|
||||||
|
} else {
|
||||||
|
console.debug('finished playback');
|
||||||
|
this._interruptPlayback(true);
|
||||||
|
this.resetPlayhead();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resetPlayhead() {
|
||||||
|
this._seekByTimeMs(this.inPointTimeMs);
|
||||||
|
if (this.selectedAnnotation) {
|
||||||
|
// show the hole selected annotation
|
||||||
|
this.drawStrokePosition(this.inPointPosition, this.outPointPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -816,17 +910,22 @@ class Annotator extends EventTarget {
|
||||||
this.dispatchEvent(new CustomEvent('seeking', {}));
|
this.dispatchEvent(new CustomEvent('seeking', {}));
|
||||||
this._currentTimeMs = this.strokes[point[0]].points[point[1]][2];
|
this._currentTimeMs = this.strokes[point[0]].points[point[1]][2];
|
||||||
[this.currentPathI, this.currentPointI] = point;
|
[this.currentPathI, this.currentPointI] = point;
|
||||||
|
this.playheadEl.value = this._currentTimeMs;
|
||||||
this._updateFrame();
|
this._updateFrame();
|
||||||
// TODO set audio, wait for promise to finish
|
// TODO set audio, wait for promise to finish
|
||||||
this.dispatchEvent(new CustomEvent('seeked', {}));
|
this.dispatchEvent(new CustomEvent('seeked', {}));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
_seekByTimeMs(time) {
|
||||||
|
this._seekByTime(Number.parseFloat(time) / 1000);
|
||||||
|
}
|
||||||
_seekByTime(time) {
|
_seekByTime(time) {
|
||||||
this.dispatchEvent(new CustomEvent('seeking', { time: time }));
|
this.dispatchEvent(new CustomEvent('seeking', { detail: time }));
|
||||||
this._currentTimeMs = Number.parseFloat(time) * 1000;
|
this._currentTimeMs = Number.parseFloat(time) * 1000;
|
||||||
[this.currentPathI, this.currentPointI] = this.findPositionForTime(this._currentTimeMs);
|
[this.currentPathI, this.currentPointI] = this.findPositionForTime(this._currentTimeMs);
|
||||||
|
this.playheadEl.value = this._currentTimeMs;
|
||||||
this._updateFrame();
|
this._updateFrame();
|
||||||
this.dispatchEvent(new CustomEvent('seeked', { time: this.currentTime }));
|
this.dispatchEvent(new CustomEvent('seeked', { detail: this.currentTime }));
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateFrame() {
|
_updateFrame() {
|
||||||
|
@ -854,7 +953,7 @@ class Annotator extends EventTarget {
|
||||||
|
|
||||||
const prerollDuration = this.audioOffset < 0 ? this.audioOffset * -1 : 0;
|
const prerollDuration = this.audioOffset < 0 ? this.audioOffset * -1 : 0;
|
||||||
|
|
||||||
return prerollDuration + this.getEndTimeMs();
|
return prerollDuration + this.getEndTimeMs() / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
findPositionForTime(ms) {
|
findPositionForTime(ms) {
|
||||||
|
|
Loading…
Reference in a new issue