source: main/trunk/model-interfaces-dev/atea/korero-maori-asr/src/components/WordTimingSelector.vue@ 35454

Last change on this file since 35454 was 35454, checked in by cstephen, 3 years ago

Improve translations
Improve translation test return
Begin adding WordTimingSelector

File size: 3.3 KB
Line 
1<template>
2<div class="word-timing-selector-root">
3 <span>{{ minTime }}</span>
4
5 <div class="words-container" ref="wordsContainer">
6 <input type="range" class="slider-continuous" ref="slider" />
7
8 <div class="surround-word" v-for="word in mySurroundingWords" :key="word.id" :style="{ left: word.left, width: word.length }">
9 <span>{{ word.word }}</span>
10 </div>
11 </div>
12
13 <span>{{ maxTime }}</span>
14</div>
15</template>
16
17<style scoped lang="scss">
18.word-timing-selector-root {
19 display: flex;
20 align-items: center;
21 gap: 1em;
22}
23
24.words-container {
25 flex-grow: 0.5;
26 position: relative;
27 height: 2.5em;
28}
29
30.surround-word {
31 position: absolute;
32 text-align: center;
33
34 user-select: none;
35 text-overflow: ellipsis;
36 white-space: nowrap;
37
38 overflow: hidden;
39 background-color: rgba(var(--bg-color-raw), 0.3);
40 border: 1px solid rgba(var(--bg-color-raw), 0.6);
41}
42</style>
43
44<script>
45import Util from "../js/Util"
46
47class Word {
48 constructor(word, startTime, endTime, left, length) {
49 this.id = Util.generateUuid();
50 this.word = word;
51 this.startTime = startTime;
52 this.endTime = endTime;
53 this.left = `${left}px`;
54 this.length = `${length}px`;
55 }
56}
57
58export default {
59 name: "WordTimingSelector",
60 props: {
61 /** @type {Array<{ word: String, startTime: Number, endTime: Number }>} */
62 surroundingWords: Array,
63 word: { word: String, startTime: Number, endTime: Number },
64 upperBound: Number
65 },
66 data() {
67 return {
68 isMounted: false,
69 mySurroundingWords: []
70 }
71 },
72 emits: [ "update:word", "update:word" ],
73 computed: {
74 minTime() {
75 if (this.surroundingWords.length === 0) {
76 return 0;
77 }
78
79 return Util.formatSecondsTimeString(this.surroundingWords[0].startTime, false, 2);
80 },
81 maxTime() {
82 if (this.surroundingWords.length === 0) {
83 return 0;
84 }
85
86 return Util.formatSecondsTimeString(this.surroundingWords[this.surroundingWords.length - 1].endTime, false, 2);
87 }
88 },
89 watch: {
90 surroundingWords() {
91 this.scaleWords();
92 }
93 },
94 methods: {
95 scaleWords() {
96 if (!this.isMounted) {
97 return;
98 }
99
100 const myWords = [];
101 if (this.surroundingWords.length === 0) {
102 return myWords;
103 }
104
105 const audioLength = this.surroundingWords[this.surroundingWords.length - 1].endTime - this.surroundingWords[0].startTime;
106 const sliderLengthPx = this.$refs.slider.offsetWidth;
107
108 const scalingFactor = sliderLengthPx / audioLength;
109
110 const offset = this.surroundingWords[0].startTime * scalingFactor;
111
112 for (const word of this.surroundingWords) {
113 const left = (word.startTime * scalingFactor - offset);
114 const length = (word.endTime - word.startTime) * scalingFactor;
115
116 myWords.push(new Word(word.word, word.startTime, word.endTime, left, length));
117 }
118
119 this.mySurroundingWords = myWords;
120 }
121 },
122 mounted() {
123 this.isMounted = true;
124 this.scaleWords();
125 }
126}
127</script>
Note: See TracBrowser for help on using the repository browser.