The progress bar is not smooth

I believe that most of the front-end students have written their own audio and video players, the implementation is not complicated. Recently in the small program, made a similar micro blog brush video demand. A part of the function requires the implementation of a customized progress bar. After finishing the first version, I found that the progress bar was not smooth, and then I wanted to check the Internet to see if there was a good solution, but finally I did not find a suitable one. So I want to see how the “weibo” progress bar in the micro channel applet is, but the result is also a very stiff animation. Here is a GIF. We can also search the micro channel applet’s weibo by ourselves and find a video to see the effect.

Conventional scheme

Finally, we decided to optimize this problem, and let’s start with our existing general solution.

  • Listen for TimeUpdate events
  • CurrentTime/Duration * 100
  • Progress bar Width property sets the percentage of progress

The existing scheme relies on events to get the current playback time, and this event is triggered every 100 ~ 350 milliseconds. The following is the queue of event objects I recorded for the applet.

[{" detail ": {" currentTime" : 0.10509, "duration" : 5.83}}, {" detail ": {" currentTime" : 0.364527, "duration" : 5.83}}, {" detail ": {" currentTime" : 0.613648, "duration" : 5.83}},]Copy the code

The current problem is that the progress bar will be updated every time the event is obtained. There is no excessive animation effect and it is very stiff. The following is the progress bar change process of 5s total time:

Core code:

const onProgress = (e, $dom) => {
    const updateFunc = (percent) => {
        $dom.style.width = percent+'%'
    }
    let percent = ((e.detail.currentTime / e.detail.duration) * 100).toFixed(1)
    updateFunc(percent)
}
Copy the code

transition

It was easy to think of using CSS animation properties for optimization. For flexibility, I chose Transition. Transition defines the animation duration, and when we change width, transition animates the progress bar width for a given amount of time. First of all, the animation execution time must be fixed, and it is best not to change width until the end of the previous execution time, otherwise it will cause conflicts and the animation will be very strange.

  • Select a reasonable transition execution time: 0.5 seconds
  • According to the current total duration, calculate the percentage of 0.5s in the progress bar (100/duration/2)
  • For the first TimeUpdate event, perform width change and set the progress bar to 0.5s: width = 100/duration/2
  • Non-first TimeUpdate event, the percentage of the current progress bar is updated whenever currentTime exceeds the previous progress bar position

If this sounds a little confusing, let’s draw a picture:

  1. When the TimeUpdate event is triggered for the first time for 0.1336 seconds, we set width to 0.5 seconds, so that the progress bar moves in sync with the video, with a slight difference of 0.1 seconds from the actual progress. UpdateTime also fires multiple times between 0.5s of animation execution,
  2. When currentTime (0.7123s, also random) of UpdateTime is greater than 0.5s of last time and the position of the progress bar is also around 0.5s, we trigger the next 0.5s animation again, that is, we set width to 1s of the progress bar position
  3. For the next iteration currentTime>1s, width is set to 1.5s, and so on.

Core code:

const playControl = { percent: 0, time: 0, duration: 0, first: true } const onProgress = (e, $dom) => { const updateFunc = (percent) => { playControl.percent = percent playControl.time = e.detail.currentTime $dom.style.width = percent+'%'} if (playcontrol.first) {playcontrol.duration = e.daile.duration playControl.first = false updateFunc(100 / e.detail.duration / 2) } else { let percent = ((e.detail.currentTime / e.detail.duration) * 100).toFixed(1) if (percent - playControl.percent > 0 || e.detail.currentTime >= e.detail.duration)  { updateFunc(percent) } } }Copy the code

Final effect comparison (PS: GIF effect is damaged)

Does the 60s version look similar to the regular version? If you block the other 60s and compare them back and forth, you’ll find some differences.

It’s still a little hard to explain, or do you not understand? Go directly to github repository code, which can be run directly:Github.com/zimv/smooth…

This scheme will have a short delay in some scenes, such as pause, drag, etc. Personally, I think the benefits outweigh the disadvantages.