wavesurfer.js 6.5.1 → 7.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/.eslintrc.json +24 -0
  2. package/.prettierrc +8 -0
  3. package/README.md +26 -117
  4. package/dist/base-plugin.d.ts +10 -0
  5. package/dist/base-plugin.js +13 -0
  6. package/dist/decoder.d.ts +10 -0
  7. package/dist/decoder.js +43 -0
  8. package/dist/event-emitter.d.ts +11 -0
  9. package/dist/event-emitter.js +21 -0
  10. package/dist/fetcher.d.ts +4 -0
  11. package/dist/fetcher.js +17 -0
  12. package/dist/index.d.ts +92 -0
  13. package/dist/index.js +166 -0
  14. package/dist/player-webaudio.d.ts +8 -0
  15. package/dist/player-webaudio.js +31 -0
  16. package/dist/player.d.ts +16 -0
  17. package/dist/player.js +40 -0
  18. package/dist/plugins/regions.d.ts +48 -0
  19. package/dist/plugins/regions.js +183 -0
  20. package/dist/renderer.d.ts +34 -0
  21. package/dist/renderer.js +193 -0
  22. package/dist/timer.d.ts +10 -0
  23. package/dist/timer.js +17 -0
  24. package/examples/audio.ogg +0 -0
  25. package/examples/bars.js +19 -0
  26. package/examples/basic.js +8 -0
  27. package/examples/gradient.js +28 -0
  28. package/examples/regions.js +63 -0
  29. package/examples/video.js +19 -0
  30. package/examples/webaudio.js +14 -0
  31. package/package.json +19 -99
  32. package/src/base-plugin.ts +20 -0
  33. package/src/decoder.ts +41 -0
  34. package/src/event-emitter.ts +35 -0
  35. package/src/fetcher.ts +7 -0
  36. package/src/index.ts +252 -0
  37. package/src/player-webaudio.ts +34 -0
  38. package/src/player.ts +50 -0
  39. package/src/plugins/regions.ts +240 -0
  40. package/src/renderer.ts +250 -0
  41. package/src/timer.ts +27 -0
  42. package/tsconfig.json +105 -0
  43. package/tutorial/index.html +47 -0
  44. package/tutorial/src/editor.js +70 -0
  45. package/tutorial/src/init.js +66 -0
  46. package/tutorial/src/url.js +25 -0
  47. package/tutorial/style.css +211 -0
  48. package/yarn-error.log +1049 -0
  49. package/LICENSE +0 -29
  50. package/dist/plugin/wavesurfer.cursor.js +0 -418
  51. package/dist/plugin/wavesurfer.cursor.js.map +0 -1
  52. package/dist/plugin/wavesurfer.cursor.min.js +0 -7
  53. package/dist/plugin/wavesurfer.cursor.min.js.map +0 -1
  54. package/dist/plugin/wavesurfer.elan.js +0 -381
  55. package/dist/plugin/wavesurfer.elan.js.map +0 -1
  56. package/dist/plugin/wavesurfer.elan.min.js +0 -7
  57. package/dist/plugin/wavesurfer.elan.min.js.map +0 -1
  58. package/dist/plugin/wavesurfer.markers.js +0 -520
  59. package/dist/plugin/wavesurfer.markers.js.map +0 -1
  60. package/dist/plugin/wavesurfer.markers.min.js +0 -7
  61. package/dist/plugin/wavesurfer.markers.min.js.map +0 -1
  62. package/dist/plugin/wavesurfer.mediasession.js +0 -181
  63. package/dist/plugin/wavesurfer.mediasession.js.map +0 -1
  64. package/dist/plugin/wavesurfer.mediasession.min.js +0 -7
  65. package/dist/plugin/wavesurfer.mediasession.min.js.map +0 -1
  66. package/dist/plugin/wavesurfer.microphone.js +0 -466
  67. package/dist/plugin/wavesurfer.microphone.js.map +0 -1
  68. package/dist/plugin/wavesurfer.microphone.min.js +0 -7
  69. package/dist/plugin/wavesurfer.microphone.min.js.map +0 -1
  70. package/dist/plugin/wavesurfer.minimap.js +0 -440
  71. package/dist/plugin/wavesurfer.minimap.js.map +0 -1
  72. package/dist/plugin/wavesurfer.minimap.min.js +0 -7
  73. package/dist/plugin/wavesurfer.minimap.min.js.map +0 -1
  74. package/dist/plugin/wavesurfer.playhead.js +0 -300
  75. package/dist/plugin/wavesurfer.playhead.js.map +0 -1
  76. package/dist/plugin/wavesurfer.playhead.min.js +0 -7
  77. package/dist/plugin/wavesurfer.playhead.min.js.map +0 -1
  78. package/dist/plugin/wavesurfer.regions.js +0 -1335
  79. package/dist/plugin/wavesurfer.regions.js.map +0 -1
  80. package/dist/plugin/wavesurfer.regions.min.js +0 -7
  81. package/dist/plugin/wavesurfer.regions.min.js.map +0 -1
  82. package/dist/plugin/wavesurfer.spectrogram.js +0 -736
  83. package/dist/plugin/wavesurfer.spectrogram.js.map +0 -1
  84. package/dist/plugin/wavesurfer.spectrogram.min.js +0 -7
  85. package/dist/plugin/wavesurfer.spectrogram.min.js.map +0 -1
  86. package/dist/plugin/wavesurfer.timeline.js +0 -649
  87. package/dist/plugin/wavesurfer.timeline.js.map +0 -1
  88. package/dist/plugin/wavesurfer.timeline.min.js +0 -7
  89. package/dist/plugin/wavesurfer.timeline.min.js.map +0 -1
  90. package/dist/wavesurfer-html-init.js +0 -381
  91. package/dist/wavesurfer-html-init.js.map +0 -1
  92. package/dist/wavesurfer-html-init.min.js +0 -7
  93. package/dist/wavesurfer-html-init.min.js.map +0 -1
  94. package/dist/wavesurfer.js +0 -6145
  95. package/dist/wavesurfer.js.map +0 -1
  96. package/dist/wavesurfer.min.js +0 -7
  97. package/dist/wavesurfer.min.js.map +0 -1
  98. package/src/drawer.canvasentry.js +0 -427
  99. package/src/drawer.js +0 -413
  100. package/src/drawer.multicanvas.js +0 -617
  101. package/src/html-init.js +0 -241
  102. package/src/mediaelement-webaudio.js +0 -77
  103. package/src/mediaelement.js +0 -443
  104. package/src/peakcache.js +0 -127
  105. package/src/plugin/cursor/index.js +0 -350
  106. package/src/plugin/elan/index.js +0 -307
  107. package/src/plugin/markers/index.js +0 -436
  108. package/src/plugin/mediasession/index.js +0 -94
  109. package/src/plugin/microphone/index.js +0 -415
  110. package/src/plugin/minimap/index.js +0 -403
  111. package/src/plugin/playhead/index.js +0 -226
  112. package/src/plugin/regions/index.js +0 -478
  113. package/src/plugin/regions/region.js +0 -875
  114. package/src/plugin/spectrogram/fft.js +0 -222
  115. package/src/plugin/spectrogram/index.js +0 -522
  116. package/src/plugin/timeline/index.js +0 -600
  117. package/src/util/absMax.js +0 -16
  118. package/src/util/clamp.js +0 -11
  119. package/src/util/fetch.js +0 -222
  120. package/src/util/frame.js +0 -13
  121. package/src/util/get-id.js +0 -22
  122. package/src/util/index.js +0 -14
  123. package/src/util/max.js +0 -16
  124. package/src/util/min.js +0 -16
  125. package/src/util/observer.js +0 -144
  126. package/src/util/orientation.js +0 -98
  127. package/src/util/prevent-click.js +0 -19
  128. package/src/util/request-animation-frame.js +0 -15
  129. package/src/util/silence-mode.js +0 -42
  130. package/src/util/style.js +0 -16
  131. package/src/wavesurfer.js +0 -1797
  132. package/src/webaudio.js +0 -779
@@ -1,350 +0,0 @@
1
- /**
2
- * @typedef {Object} CursorPluginParams
3
- * @property {?boolean} deferInit Set to true to stop auto init in `addPlugin()`
4
- * @property {boolean} hideOnBlur=true Hide the cursor when the mouse leaves the
5
- * waveform
6
- * @property {string} width='1px' The width of the cursor
7
- * @property {string} color='black' The color of the cursor
8
- * @property {number|string} opacity='0.25' The opacity of the cursor
9
- * @property {string} style='solid' The border style of the cursor
10
- * @property {number} zIndex=3 The z-index of the cursor element
11
- * @property {object} customStyle An object with custom styles which are applied
12
- * to the cursor element
13
- * @property {boolean} showTime=false Show the time on the cursor.
14
- * @property {object} customShowTimeStyle An object with custom styles which are
15
- * applied to the cursor time element.
16
- * @property {boolean} followCursorY=false Use `true` to make the time on
17
- * the cursor follow the x and the y-position of the mouse. Use `false` to make the
18
- * it only follow the x-position of the mouse.
19
- * @property {function} formatTimeCallback Formats the timestamp on the cursor.
20
- * @property {boolean} isDestroyCalled true if called destroy before the ready event fired
21
- */
22
-
23
- /**
24
- * Displays a thin line at the position of the cursor on the waveform.
25
- *
26
- * @implements {PluginClass}
27
- * @extends {Observer}
28
- * @example
29
- * // es6
30
- * import CursorPlugin from 'wavesurfer.cursor.js';
31
- *
32
- * // commonjs
33
- * var CursorPlugin = require('wavesurfer.cursor.js');
34
- *
35
- * // if you are using <script> tags
36
- * var CursorPlugin = window.WaveSurfer.cursor;
37
- *
38
- * // ... initialising wavesurfer with the plugin
39
- * var wavesurfer = WaveSurfer.create({
40
- * // wavesurfer options ...
41
- * plugins: [
42
- * CursorPlugin.create({
43
- * // plugin options ...
44
- * })
45
- * ]
46
- * });
47
- */
48
- export default class CursorPlugin {
49
- /**
50
- * Cursor plugin definition factory
51
- *
52
- * This function must be used to create a plugin definition which can be
53
- * used by wavesurfer to correctly instantiate the plugin.
54
- *
55
- * @param {CursorPluginParams} params parameters use to initialise the
56
- * plugin
57
- * @return {PluginDefinition} an object representing the plugin
58
- */
59
- static create(params) {
60
- return {
61
- name: 'cursor',
62
- deferInit: params && params.deferInit ? params.deferInit : false,
63
- params: params,
64
- staticProps: {},
65
- instance: CursorPlugin
66
- };
67
- }
68
-
69
- /**
70
- * @type {CursorPluginParams}
71
- */
72
- defaultParams = {
73
- hideOnBlur: true,
74
- width: '1px',
75
- color: 'black',
76
- opacity: '0.25',
77
- style: 'solid',
78
- zIndex: 4,
79
- customStyle: {},
80
- customShowTimeStyle: {},
81
- showTime: false,
82
- followCursorY: false,
83
- formatTimeCallback: null
84
- };
85
-
86
- /**
87
- * @param {object} e Mouse move event
88
- */
89
- _onMousemove = e => {
90
- const event = this.util.withOrientation(e, this.wavesurfer.params.vertical);
91
- const bbox = this.wrapper.getBoundingClientRect();
92
- let y = 0;
93
- let x = this.wrapper.scrollLeft + event.clientX - bbox.left;
94
- const displayTimeWidth = this.displayTime ? this.displayTime.getBoundingClientRect().width : 0;
95
- let flip = bbox.right < event.clientX + displayTimeWidth;
96
-
97
- if (this.params.showTime && this.params.followCursorY) {
98
- // follow y-position of the mouse
99
- y = event.clientY - (bbox.top + bbox.height / 2);
100
- }
101
-
102
- this.updateCursorPosition(x, y, flip);
103
- };
104
-
105
- /**
106
- * @returns {void}
107
- */
108
- _onMouseenter = () => this.showCursor();
109
-
110
- /**
111
- * @returns {void}
112
- */
113
- _onMouseleave = () => this.hideCursor();
114
-
115
- /**
116
- * Construct the plugin class. You probably want to use `CursorPlugin.create`
117
- * instead.
118
- *
119
- * @param {CursorPluginParams} params Plugin parameters
120
- * @param {object} ws Wavesurfer instance
121
- */
122
- constructor(params, ws) {
123
- this.wavesurfer = ws;
124
- this.style = ws.util.style;
125
- this.util = ws.util;
126
- /**
127
- * The cursor HTML element
128
- *
129
- * @type {?HTMLElement}
130
- */
131
- this.cursor = null;
132
- /**
133
- * displays the time next to the cursor
134
- *
135
- * @type {?HTMLElement}
136
- */
137
- this.showTime = null;
138
- /**
139
- * The html container that will display the time
140
- *
141
- * @type {?HTMLElement}
142
- */
143
- this.displayTime = null;
144
- /**
145
- * true when `destroy` was called before `ready` event
146
- * @type {boolean}
147
- */
148
- this.isDestroyCalled = false;
149
-
150
- this.params = Object.assign({}, this.defaultParams, params);
151
- }
152
-
153
- _onReady() {
154
- if (this.isDestroyCalled) {
155
- return;
156
- }
157
- this.wrapper = this.wavesurfer.drawer.wrapper;
158
- this.cursor = this.util.withOrientation(this.wrapper.appendChild(
159
- document.createElement('cursor'),
160
- ), this.wavesurfer.params.vertical);
161
-
162
- this.style(this.cursor,
163
- Object.assign(
164
- {
165
- position: 'absolute',
166
- zIndex: this.params.zIndex,
167
- left: 0,
168
- top: 0,
169
- bottom: 0,
170
- width: '0',
171
- display: 'flex',
172
- borderRightStyle: this.params.style,
173
- borderRightWidth: this.params.width,
174
- borderRightColor: this.params.color,
175
- opacity: this.params.opacity,
176
- pointerEvents: 'none'
177
- },
178
- this.params.customStyle
179
- )
180
- );
181
-
182
- if (this.params.showTime) {
183
- this.showTime = this.util.withOrientation(this.wrapper.appendChild(
184
- document.createElement('showTitle')
185
- ), this.wavesurfer.params.vertical);
186
- this.style(
187
- this.showTime,
188
- Object.assign(
189
- {
190
- position: 'absolute',
191
- zIndex: this.params.zIndex,
192
- left: 0,
193
- top: 0,
194
- bottom: 0,
195
- width: 'auto',
196
- display: 'flex',
197
- opacity: this.params.opacity,
198
- pointerEvents: 'none',
199
- height: '100%'
200
- },
201
- this.params.customStyle
202
- )
203
- );
204
-
205
- this.displayTime = this.util.withOrientation(this.showTime.appendChild(
206
- document.createElement('div'),
207
- ), this.wavesurfer.params.vertical);
208
-
209
- this.style(this.displayTime,
210
- Object.assign(
211
- {
212
- display: 'inline',
213
- pointerEvents: 'none',
214
- margin: 'auto',
215
- visibility: 'hidden' // initial value will be hidden just for measuring purpose
216
- },
217
- this.params.customShowTimeStyle
218
- )
219
- );
220
-
221
- // initial value to measure display width
222
- this.displayTime.innerHTML = this.formatTime(0);
223
- }
224
-
225
- this.wrapper.addEventListener('mousemove', this._onMousemove);
226
- if (this.params.hideOnBlur) {
227
- // ensure elements are hidden initially
228
- this.hideCursor();
229
- this.wrapper.addEventListener('mouseenter', this._onMouseenter);
230
- this.wrapper.addEventListener('mouseleave', this._onMouseleave);
231
- }
232
- }
233
-
234
- /**
235
- * Initialise the plugin (used by the Plugin API)
236
- */
237
- init() {
238
- if (this.wavesurfer.isReady) {
239
- this._onReady();
240
- } else {
241
- this.wavesurfer.once('ready', () => this._onReady());
242
- }
243
- }
244
-
245
- /**
246
- * Destroy the plugin (used by the Plugin API)
247
- */
248
- destroy() {
249
- if (!this.cursorTime || !this.showTime){
250
- this.isDestroyCalled = true;
251
- return;
252
- }
253
- if (this.params.showTime) {
254
- this.showTime && this.showTime.remove();
255
- }
256
- this.cursor && this.cursor.remove();
257
- this.wrapper.removeEventListener('mousemove', this._onMousemove);
258
- if (this.params.hideOnBlur) {
259
- this.wrapper.removeEventListener('mouseenter', this._onMouseenter);
260
- this.wrapper.removeEventListener('mouseleave', this._onMouseleave);
261
- }
262
- }
263
-
264
- /**
265
- * Update the cursor position
266
- *
267
- * @param {number} xpos The x offset of the cursor in pixels
268
- * @param {number} ypos The y offset of the cursor in pixels
269
- * @param {boolean} flip Flag to flip duration text from right to left
270
- */
271
- updateCursorPosition(xpos, ypos, flip = false) {
272
- this.style(this.cursor, {
273
- left: `${xpos}px`
274
- });
275
- if (this.params.showTime) {
276
- const duration = this.wavesurfer.getDuration();
277
- const elementWidth =
278
- this.wavesurfer.drawer.width /
279
- this.wavesurfer.params.pixelRatio;
280
- const scrollWidth = this.wavesurfer.drawer.getScrollX();
281
-
282
- const scrollTime =
283
- (duration / this.wavesurfer.drawer.width) * scrollWidth;
284
-
285
- const timeValue =
286
- Math.max(0, ((xpos - this.wrapper.scrollLeft) / elementWidth) * duration) + scrollTime;
287
- const formatValue = this.formatTime(timeValue);
288
- if (flip) {
289
- const textOffset = this.displayTime.getBoundingClientRect().width;
290
- xpos -= textOffset;
291
- }
292
- this.style(this.showTime, {
293
- left: `${xpos}px`,
294
- top: `${ypos}px`
295
- });
296
- this.style(this.displayTime, {
297
- visibility: 'visible'
298
- });
299
- this.displayTime.innerHTML = `${formatValue}`;
300
- }
301
- }
302
-
303
- /**
304
- * Show the cursor
305
- */
306
- showCursor() {
307
- this.style(this.cursor, {
308
- display: 'flex'
309
- });
310
- if (this.params.showTime) {
311
- this.style(this.showTime, {
312
- display: 'flex'
313
- });
314
- }
315
- }
316
-
317
- /**
318
- * Hide the cursor
319
- */
320
- hideCursor() {
321
- this.style(this.cursor, {
322
- display: 'none'
323
- });
324
- if (this.params.showTime) {
325
- this.style(this.showTime, {
326
- display: 'none'
327
- });
328
- }
329
- }
330
-
331
- /**
332
- * Format the timestamp for `cursorTime`.
333
- *
334
- * @param {number} cursorTime Time in seconds
335
- * @returns {string} Formatted timestamp
336
- */
337
- formatTime(cursorTime) {
338
- cursorTime = isNaN(cursorTime) ? 0 : cursorTime;
339
- if (this.params.formatTimeCallback) {
340
- return this.params.formatTimeCallback(cursorTime);
341
- }
342
- return [cursorTime].map(time =>
343
- [
344
- Math.floor((time % 3600) / 60), // minutes
345
- ('00' + Math.floor(time % 60)).slice(-2), // seconds
346
- ('000' + Math.floor((time % 1) * 1000)).slice(-3) // milliseconds
347
- ].join(':')
348
- );
349
- }
350
- }
@@ -1,307 +0,0 @@
1
- /**
2
- * @typedef {Object} ElanPluginParams
3
- * @property {string|HTMLElement} container CSS selector or HTML element where
4
- * the ELAN information should be rendered.
5
- * @property {string} url The location of ELAN XML data
6
- * @property {?boolean} deferInit Set to true to manually call
7
- * @property {?Object} tiers If set only shows the data tiers with the `TIER_ID`
8
- * in this map.
9
- */
10
-
11
- /**
12
- * Downloads and renders ELAN audio transcription documents alongside the
13
- * waveform.
14
- *
15
- * @implements {PluginClass}
16
- * @extends {Observer}
17
- * @example
18
- * // es6
19
- * import ElanPlugin from 'wavesurfer.elan.js';
20
- *
21
- * // commonjs
22
- * var ElanPlugin = require('wavesurfer.elan.js');
23
- *
24
- * // if you are using <script> tags
25
- * var ElanPlugin = window.WaveSurfer.elan;
26
- *
27
- * // ... initialising wavesurfer with the plugin
28
- * var wavesurfer = WaveSurfer.create({
29
- * // wavesurfer options ...
30
- * plugins: [
31
- * ElanPlugin.create({
32
- * // plugin options ...
33
- * })
34
- * ]
35
- * });
36
- */
37
- export default class ElanPlugin {
38
- /**
39
- * Elan plugin definition factory
40
- *
41
- * This function must be used to create a plugin definition which can be
42
- * used by wavesurfer to correctly instantiate the plugin.
43
- *
44
- * @param {ElanPluginParams} params parameters use to initialise the plugin
45
- * @return {PluginDefinition} an object representing the plugin
46
- */
47
- static create(params) {
48
- return {
49
- name: 'elan',
50
- deferInit: params && params.deferInit ? params.deferInit : false,
51
- params: params,
52
- instance: ElanPlugin
53
- };
54
- }
55
-
56
- Types = {
57
- ALIGNABLE_ANNOTATION: 'ALIGNABLE_ANNOTATION',
58
- REF_ANNOTATION: 'REF_ANNOTATION'
59
- };
60
-
61
- constructor(params, ws) {
62
- this.data = null;
63
- this.params = params;
64
- this.container =
65
- 'string' == typeof params.container
66
- ? document.querySelector(params.container)
67
- : params.container;
68
-
69
- if (!this.container) {
70
- throw Error('No container for ELAN');
71
- }
72
- }
73
-
74
- init() {
75
- this.bindClick();
76
-
77
- if (this.params.url) {
78
- this.load(this.params.url);
79
- }
80
- }
81
-
82
- destroy() {
83
- this.container.removeEventListener('click', this._onClick);
84
- this.container.removeChild(this.table);
85
- }
86
-
87
- load(url) {
88
- this.loadXML(url, xml => {
89
- this.data = this.parseElan(xml);
90
- this.render();
91
- this.fireEvent('ready', this.data);
92
- });
93
- }
94
-
95
- loadXML(url, callback) {
96
- const xhr = new XMLHttpRequest();
97
- xhr.open('GET', url, true);
98
- xhr.responseType = 'document';
99
- xhr.send();
100
- xhr.addEventListener('load', e => {
101
- callback && callback(e.target.responseXML);
102
- });
103
- }
104
-
105
- parseElan(xml) {
106
- const _forEach = Array.prototype.forEach;
107
- const _map = Array.prototype.map;
108
-
109
- const data = {
110
- media: {},
111
- timeOrder: {},
112
- tiers: [],
113
- annotations: {},
114
- alignableAnnotations: []
115
- };
116
-
117
- const header = xml.querySelector('HEADER');
118
- const inMilliseconds =
119
- header.getAttribute('TIME_UNITS') == 'milliseconds';
120
- const media = header.querySelector('MEDIA_DESCRIPTOR');
121
- data.media.url = media.getAttribute('MEDIA_URL');
122
- data.media.type = media.getAttribute('MIME_TYPE');
123
-
124
- const timeSlots = xml.querySelectorAll('TIME_ORDER TIME_SLOT');
125
- const timeOrder = {};
126
- _forEach.call(timeSlots, slot => {
127
- let value = parseFloat(slot.getAttribute('TIME_VALUE'));
128
- // If in milliseconds, convert to seconds with rounding
129
- if (inMilliseconds) {
130
- value = Math.round(value * 1e2) / 1e5;
131
- }
132
- timeOrder[slot.getAttribute('TIME_SLOT_ID')] = value;
133
- });
134
-
135
- data.tiers = _map.call(xml.querySelectorAll('TIER'), tier => ({
136
- id: tier.getAttribute('TIER_ID'),
137
- linguisticTypeRef: tier.getAttribute('LINGUISTIC_TYPE_REF'),
138
- defaultLocale: tier.getAttribute('DEFAULT_LOCALE'),
139
- annotations: _map.call(
140
- tier.querySelectorAll('REF_ANNOTATION, ALIGNABLE_ANNOTATION'),
141
- node => {
142
- const annot = {
143
- type: node.nodeName,
144
- id: node.getAttribute('ANNOTATION_ID'),
145
- ref: node.getAttribute('ANNOTATION_REF'),
146
- value: node
147
- .querySelector('ANNOTATION_VALUE')
148
- .textContent.trim()
149
- };
150
-
151
- if (this.Types.ALIGNABLE_ANNOTATION == annot.type) {
152
- // Add start & end to alignable annotation
153
- annot.start =
154
- timeOrder[node.getAttribute('TIME_SLOT_REF1')];
155
- annot.end =
156
- timeOrder[node.getAttribute('TIME_SLOT_REF2')];
157
- // Add to the list of alignable annotations
158
- data.alignableAnnotations.push(annot);
159
- }
160
-
161
- // Additionally, put into the flat map of all annotations
162
- data.annotations[annot.id] = annot;
163
-
164
- return annot;
165
- }
166
- )
167
- }));
168
-
169
- // Create JavaScript references between annotations
170
- data.tiers.forEach(tier => {
171
- tier.annotations.forEach(annot => {
172
- if (null != annot.ref) {
173
- annot.reference = data.annotations[annot.ref];
174
- }
175
- });
176
- });
177
-
178
- // Sort alignable annotations by start & end
179
- data.alignableAnnotations.sort((a, b) => {
180
- let d = a.start - b.start;
181
- if (d == 0) {
182
- d = b.end - a.end;
183
- }
184
- return d;
185
- });
186
-
187
- data.length = data.alignableAnnotations.length;
188
-
189
- return data;
190
- }
191
-
192
- render() {
193
- // apply tiers filter
194
- let tiers = this.data.tiers;
195
- if (this.params.tiers) {
196
- tiers = tiers.filter(tier => tier.id in this.params.tiers);
197
- }
198
-
199
- // denormalize references to alignable annotations
200
- const backRefs = {};
201
- let indeces = {};
202
- tiers.forEach((tier, index) => {
203
- tier.annotations.forEach(annot => {
204
- if (
205
- annot.reference &&
206
- annot.reference.type == this.Types.ALIGNABLE_ANNOTATION
207
- ) {
208
- if (!(annot.reference.id in backRefs)) {
209
- backRefs[annot.ref] = {};
210
- }
211
- backRefs[annot.ref][index] = annot;
212
- indeces[index] = true;
213
- }
214
- });
215
- });
216
- indeces = Object.keys(indeces).sort();
217
-
218
- this.renderedAlignable = this.data.alignableAnnotations.filter(
219
- alignable => backRefs[alignable.id]
220
- );
221
-
222
- // table
223
- const table = (this.table = document.createElement('table'));
224
- table.className = 'wavesurfer-annotations';
225
-
226
- // head
227
- const thead = document.createElement('thead');
228
- const headRow = document.createElement('tr');
229
- thead.appendChild(headRow);
230
- table.appendChild(thead);
231
- const th = document.createElement('th');
232
- th.textContent = 'Time';
233
- th.className = 'wavesurfer-time';
234
- headRow.appendChild(th);
235
- indeces.forEach(index => {
236
- const tier = tiers[index];
237
- const th = document.createElement('th');
238
- th.className = 'wavesurfer-tier-' + tier.id;
239
- th.textContent = tier.id;
240
- if (this.params.tiers) { th.style.width = this.params.tiers[tier.id]; }
241
- headRow.appendChild(th);
242
- });
243
-
244
- // body
245
- const tbody = document.createElement('tbody');
246
- table.appendChild(tbody);
247
- this.renderedAlignable.forEach(alignable => {
248
- const row = document.createElement('tr');
249
- row.id = 'wavesurfer-alignable-' + alignable.id;
250
- tbody.appendChild(row);
251
-
252
- const td = document.createElement('td');
253
- td.className = 'wavesurfer-time';
254
- td.textContent =
255
- alignable.start.toFixed(1) + '–' + alignable.end.toFixed(1);
256
- row.appendChild(td);
257
-
258
- const backRef = backRefs[alignable.id];
259
- indeces.forEach(index => {
260
- const tier = tiers[index];
261
- const td = document.createElement('td');
262
- const annotation = backRef[index];
263
- if (annotation) {
264
- td.id = 'wavesurfer-annotation-' + annotation.id;
265
- td.dataset.ref = alignable.id;
266
- td.dataset.start = alignable.start;
267
- td.dataset.end = alignable.end;
268
- td.textContent = annotation.value;
269
- }
270
- td.className = 'wavesurfer-tier-' + tier.id;
271
- row.appendChild(td);
272
- });
273
- });
274
-
275
- this.container.innerHTML = '';
276
- this.container.appendChild(table);
277
- }
278
-
279
- bindClick() {
280
- this._onClick = e => {
281
- const ref = e.target.dataset.ref;
282
- if (null != ref) {
283
- const annot = this.data.annotations[ref];
284
- if (annot) {
285
- this.fireEvent('select', annot.start, annot.end);
286
- }
287
- }
288
- };
289
- this.container.addEventListener('click', this._onClick);
290
- }
291
-
292
- getRenderedAnnotation(time) {
293
- let result;
294
- this.renderedAlignable.some(annotation => {
295
- if (annotation.start <= time && annotation.end >= time) {
296
- result = annotation;
297
- return true;
298
- }
299
- return false;
300
- });
301
- return result;
302
- }
303
-
304
- getAnnotationNode(annotation) {
305
- return document.getElementById('wavesurfer-alignable-' + annotation.id);
306
- }
307
- }