wavesurfer.js icon indicating copy to clipboard operation
wavesurfer.js copied to clipboard

Timeline disappear when zooming

Open SectionSoutienAnalytique opened this issue 1 year ago • 3 comments

Bug description

In the Timeline plugin, when zooming in, the timeline disappears. It does not update correctly. However, as soon as the scrollbar is moved, the timeline updates properly.

Environment

  • Browser: Firefox

Minimal code snippet

// Customized Timeline plugin

import WaveSurfer from 'wavesurfer.js'
import TimelinePlugin from 'wavesurfer.js/dist/plugins/timeline.esm.js'
import ZoomPlugin from 'wavesurfer.js/dist/plugins/zoom.esm.js'

// Create a timeline plugin instance with custom options
const topTimeline = TimelinePlugin.create({
  height: 20,
  insertPosition: 'beforebegin',
  timeInterval: 0.2,
  primaryLabelInterval: 5,
  secondaryLabelInterval: 1,
  style: {
    fontSize: '20px',
    color: '#FFFFFF',
  },
})

// Create a second timeline
const bottomTimeline = TimelinePlugin.create({
  height: 10,
  timeInterval: 0.1,
  primaryLabelInterval: 1,
  style: {
    fontSize: '10px',
    color: '#6A3274',
  },
})

// Create an instance of WaveSurfer
const wavesurfer = WaveSurfer.create({
  container: '#waveform',
  waveColor: 'rgb(200, 0, 200)',
  progressColor: 'rgb(100, 0, 100)',
  url: '/examples/audio/audio.wav',
  minPxPerSec: 100,
  plugins: [topTimeline, bottomTimeline],
})

wavesurfer.registerPlugin(ZoomPlugin.create())

// Play on click
wavesurfer.once('interaction', () => {
  wavesurfer.play()
})

/*
<html>
  <div id="waveform"></div>
  <p>
    📖 <a href="https://wavesurfer.xyz/docs/classes/plugins_timeline.TimelinePlugin">Timeline plugin docs</a>
  </p>
</html>
*/

Expected result

https://github.com/user-attachments/assets/171a6c8c-7319-4217-9552-f6f8632d5867

Obtained result

https://github.com/user-attachments/assets/3f561308-1aab-4e2c-b779-3bb528db9bd9

PR

I fix the issue (like you can see in the Expected result) but I do not know how to create PR

@SectionSoutienAnalytique
I solved this issue by wrapping the container of waveform to timeline plugin wavesurfer.registerPlugin( TimelinePlugin.create({ height: 18, insertPosition: 'beforebegin', style: { fontSize: '12px', color: '#000', }, container: this.wavesurfer.getWrapper(), }), ); This resolves the issue for me

rk9155 avatar Jul 17 '24 12:07 rk9155

Bug description

In the Timeline plugin, when zooming in, the timeline disappears. It does not update correctly. However, as soon as the scrollbar is moved, the timeline updates properly.

Environment

  • Browser: Firefox

Minimal code snippet

// Customized Timeline plugin

import WaveSurfer from 'wavesurfer.js'
import TimelinePlugin from 'wavesurfer.js/dist/plugins/timeline.esm.js'
import ZoomPlugin from 'wavesurfer.js/dist/plugins/zoom.esm.js'

// Create a timeline plugin instance with custom options
const topTimeline = TimelinePlugin.create({
  height: 20,
  insertPosition: 'beforebegin',
  timeInterval: 0.2,
  primaryLabelInterval: 5,
  secondaryLabelInterval: 1,
  style: {
    fontSize: '20px',
    color: '#FFFFFF',
  },
})

// Create a second timeline
const bottomTimeline = TimelinePlugin.create({
  height: 10,
  timeInterval: 0.1,
  primaryLabelInterval: 1,
  style: {
    fontSize: '10px',
    color: '#6A3274',
  },
})

// Create an instance of WaveSurfer
const wavesurfer = WaveSurfer.create({
  container: '#waveform',
  waveColor: 'rgb(200, 0, 200)',
  progressColor: 'rgb(100, 0, 100)',
  url: '/examples/audio/audio.wav',
  minPxPerSec: 100,
  plugins: [topTimeline, bottomTimeline],
})

wavesurfer.registerPlugin(ZoomPlugin.create())

// Play on click
wavesurfer.once('interaction', () => {
  wavesurfer.play()
})

/*
<html>
  <div id="waveform"></div>
  <p>
    📖 <a href="https://wavesurfer.xyz/docs/classes/plugins_timeline.TimelinePlugin">Timeline plugin docs</a>
  </p>
</html>
*/

Expected result

GoodTimeline.mp4

Obtained result

BadTimeline.mp4

PR

I fix the issue (like you can see in the Expected result) but I do not know how to create PR

How did you fix the timeline flashing/disappearing? The suggestion from @rk9155 does not work for me using wavesurfer/react

amblamps avatar Sep 26 '24 23:09 amblamps

It does not work for me neither.

I do not know if it's good but i do not see any problem with another plugin. There is my modification :

//timeline.js

//line 94 add
this.subscriptions.push(this.wavesurfer.on('zoom', () => this.initTimeline()))

// delete line 146 to 174

  private virtualAppend(start: number, container: HTMLElement, element: HTMLElement) {
    let wasVisible = false

    const renderIfVisible = (scrollLeft: number, scrollRight: number) => {
      if (!this.wavesurfer) return
      const width = element.clientWidth
      const isVisible = start > scrollLeft && start + width < scrollRight

      if (isVisible === wasVisible) return
      wasVisible = isVisible

      if (isVisible) {
        container.appendChild(element)
      } else {
        element.remove()
      }
    }

    setTimeout(() => {
      if (!this.wavesurfer) return
      renderIfVisible(0, this.wavesurfer?.getWidth() || 0)
      this.subscriptions.push(
        this.wavesurfer.on('scroll', (_start, _end, scrollLeft, scrollRight) => {
          renderIfVisible(scrollLeft, scrollRight)
        }),
      )
    }, 0)
  }
  
  //line 251 replace this.virtualAppend(offset, timeline, notch)
  //display directly notch
  timeline.appendChild(notch)
  

With this you can see result on the video

I've looked into this a bit myself. This seems to happen when you zoom with a shifted cursor position. From what I can tell, the issue comes from the fact that the wave is reRendered on zoom which causes the timeline plugin to be reinitialized. It seems that the rerender adjusts the scroll window to account for the cursor position but the timeline assumes a 0 starting position and as a result the incorrect notches are rendered.

A change like this fixes the issue without having to remove virtualAppend:

//timeline.js

//Replace line 166: renderIfVisible(0, this.wavesurfer?.getWidth() || 0) with
const leftScroll = this.wavesurfer.getScroll()
const rightScroll = leftScroll + this.wavesurfer.getWidth()
renderIfVisible(leftScroll, rightScroll)

This does seem to fix the issue on my end, however it does cause some flickering due to the deferred execution. Removing the timeout does solve the flickering issue, but I am unsure if this is safe to do.

acieslewicz avatar Oct 22 '24 19:10 acieslewicz