在 Javascript 中将图形运动与视频同步

Sync motion of graphics with video in Javascript

我想在浏览器上构建一个小应用程序 运行(使用 Chrome),将嵌入的视频与一些图形同步。我从这里得到灵感https://www.youtube.com/watch?v=_AD2ciZ-0UI做了个小测试

我在这里尝试播放视频并相应地以同步方式“移动”矩形的位置:

<!DOCTYPE html> 
<html> 
<body> 
<video id="myvideo" width="400" controls>
  <source src="http://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4"></source>
</video>
<svg id="myrect" viewBox="0 0 200 200" > <rect  x=10 y=8 width=5 height=20 
        fill-opacity=0.0 
        style="stroke-width:0.5;stroke:rgb(0,0,0)"/> </svg>
<script>
  var m = 10 ;
  var myvideo = document.getElementById('myvideo')
  var rect = document.getElementById('myrect');
  myvideo.addEventListener('play', function() {
    timerID=window.setInterval(function (){
         m=parseInt(myvideo.currentTime);
         console.log(m);
         rect.setAttribute('x',m);
    },100)
  })
  </script>
</body> 
</html>

不幸的是,当 运行 时,我看到变量“m”正确递增(查看控制台中的值),但矩形没有移动。我做错了什么?

@VC.ONE 回答后更新。

这是来自@vc.one 的工作版本,略有修改。细微的修改是矩形现在以与进度条同步的方式移动到视频下方。这种方法似乎有效,但看起来矩形跟随进度条有一些延迟,特别是当它被快速拖动时。如何提高这段代码的响应能力? (我也愿意使用其他 platforms/programs )

<!DOCTYPE html> 
<html> 
    <head>
        <style>
body {
      display: flex;
      align-items: center;
      justify-content: center;
      margin: 0 auto;
      background-color: #f1f1f1;
    } 
        </style>
    </head>
<body> 

<div> 
<video id="myvideo" width="720" controls>
  <source src="mov_bbb.mp4" type="video/mp4"></source>
</video>
<svg id="mysvgrect"  viewBox="0 0 200 200" > <rect id="myrect"  x=4 y=0 width=5 height=15
        fill-opacity=0.0 
        style="stroke-width:0.5;stroke:rgb(0,0,0)"/> </svg>
</div>

<script>
var timerID;
var m = 10;
var speed = 0;
const rect = document.getElementById('myrect');
const myvideo = document.getElementById('myvideo');
myvideo.addEventListener('timeupdate', function() { moveShape() } );
myvideo.addEventListener('play', function() { handle_Play() } );

function moveShape()
{
   speed = 188/myvideo.duration ;
    m = 4 + ( speed * (myvideo.currentTime) );
    rect.style.x = m; //# direct access to "x" Style
    //rect.setAttribute('x', m); //# alt way to access same "x" Style
}
function handle_Play()
{
    //# if needed (may clog the console with constant messages every 100 ms)
    //timerID = window.setInterval( doTimer(), 100);
}

function doTimer()
{
    m = parseInt( myvideo.currentTime );
    console.log("video secs : " + m);
}
</script>
</body> 
</html>

使用 setInterval 更新工作版本:

经过一些尝试,我再次尝试使用 setInterval,就同步速度而言,我认为效果更好:

<!DOCTYPE html> 
<html> 
    <head>
        <style>
body {
      display: flex;
      align-items: center;
      justify-content: center;
      margin: 0 auto;
      background-color: #f1f1f1;
    } 
        </style>
    </head>
<body> 

<div> 
<video id="myvideo" width="720" controls>
  <source src="video.mp4" type="video/mp4"></source>
</video>
<svg id="mysvgrect"  viewBox="0 0 200 200" > <rect id="myrect"  x=4 y=0 width=5 height=15
        fill-opacity=0.0 
        style="stroke-width:0.5;stroke:rgb(0,0,0)"/> </svg>
</div>

<script>
var timerID;
var m = 10;
var speed = 0;
const rect = document.getElementById('myrect');
const myvideo = document.getElementById('myvideo');

setInterval(function () {
    speed = 188/myvideo.duration ;
    m = 4 + ( speed * (myvideo.currentTime) );
    rect.style.x = m; // will get you a lot more updates.
}, 30);

</script>
</body> 
</html>

我认为的主要区别在于,使用 setInterval 可以更好地控制函数调用的频率(例如,这里我设置了 30 毫秒),而使用 timeupdate 我没有发现这种可能性。但我不确定缺点。请就您对此解决方案的看法发表任何评论...(对于那些感兴趣的人,setInterval 也对更新频率有限制,https://www.w3schools.com/jsref/met_win_setinterval.asp,即 10 毫秒)

  • 考虑为 <rect> 元素提供自己的唯一 ID 以直接访问它。
  • 使用视频 API 的 timeupdate 事件根据视频时间移动形状。

尝试这样的事情(ps:注意 rect id="myrect"svg id="mysvgrect"):

<!DOCTYPE html> 
<html> 
<body> 
<video id="myvideo" width="400" controls>
  <source src="http://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4"></source>
</video>
<svg id="mysvgrect" viewBox="0 0 200 200" > <rect id="myrect" x=10 y=8 width=5 height=20 
        fill-opacity=0.0 
        style="stroke-width:0.5;stroke:rgb(0,0,0)"/> </svg>
<script>

var timerID;
var m = 10;
var speed = 0;
const rect = document.getElementById('myrect');

const myvideo = document.getElementById('myvideo');
myvideo.addEventListener('timeupdate', function() { moveShape() } );
myvideo.addEventListener('play', function() { handle_Play() } );


function moveShape()
{
   speed = 9.8;
    m = 10 + ( speed * (myvideo.currentTime) );
    rect.style.x = m; //# direct access to "x" Style
    //rect.setAttribute('x', m); //# alt way to access same "x" Style
}

function handle_Play()
{
    //# if needed (may clog the console with constant messages every 100 ms)
    //timerID = window.setInterval( doTimer(), 100);
}

function doTimer()
{
    m = parseInt( myvideo.currentTime );
    console.log("video secs : " + m);
}
  
</script>

</body> 
</html>