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

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

Properly identify surrounding words

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 wordIndex: Number,
65 upperBound: Number
66 },
67 data() {
68 return {
69 isMounted: false,
70 mySurroundingWords: []
71 }
72 },
73 emits: [ "update:word", "update:word" ],
74 computed: {
75 minTime() {
76 if (this.surroundingWords.length === 0) {
77 return 0;
78 }
79
80 return Util.formatSecondsTimeString(this.surroundingWords[0].startTime, false, 2);
81 },
82 maxTime() {
83 if (this.surroundingWords.length === 0) {
84 return 0;
85 }
86
87 return Util.formatSecondsTimeString(this.surroundingWords[this.surroundingWords.length - 1].endTime, false, 2);
88 }
89 },
90 watch: {
91 surroundingWords() {
92 this.scaleWords();
93 }
94 },
95 methods: {
96 scaleWords() {
97 if (!this.isMounted) {
98 return;
99 }
100
101 const myWords = [];
102 if (this.surroundingWords.length === 0) {
103 return myWords;
104 }
105
106 const audioLength = this.surroundingWords[this.surroundingWords.length - 1].endTime - this.surroundingWords[0].startTime;
107 const sliderLengthPx = this.$refs.slider.offsetWidth;
108
109 const scalingFactor = sliderLengthPx / audioLength;
110
111 const offset = this.surroundingWords[0].startTime * scalingFactor;
112
113 for (const word of this.surroundingWords) {
114 const left = (word.startTime * scalingFactor - offset);
115 const length = (word.endTime - word.startTime) * scalingFactor;
116
117 myWords.push(new Word(word.word, word.startTime, word.endTime, left, length));
118 }
119
120 this.mySurroundingWords = myWords;
121 }
122 },
123 mounted() {
124 this.isMounted = true;
125 this.scaleWords();
126 }
127}
128</script>
Note: See TracBrowser for help on using the repository browser.