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

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

Fix word selection in time editor
Improve initial timing metadata for new words

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