【问题标题】:Overlaying canvas on a video, canvas is not reading video height and width attributes在视频上覆盖画布,画布不读取视频的高度和宽度属性
【发布时间】:2021-04-05 15:47:10
【问题描述】:

所以我试图在 500x500 视频上覆盖 HTML 画布元素。我一直希望视频为 500x500。在我的代码中,我将画布的高度和宽度设置为与视频的高度和宽度相同,以便它们相互重叠。不幸的是,每当我运行它时,canvas 元素总是输出 800 的宽度和 600 的高度。我相信这可能与原始视频的大小有关。但是,我真的不确定为什么我的画布元素不会接受这些值。我也尝试直接将我的画布高度和宽度设置为 500,但是当我这样做时,它不会覆盖在视频的正上方。我只是想知道是否有人知道为什么会发生这种情况,以及在我的代码中是否有什么让你印象深刻的地方,我正在设置导致这种情况发生的这些元素。在制作这篇文章之前,我还查看了其他堆栈溢出帖子,并尝试从这些解决方案中获取一些上下文,但对我来说还没有任何效果。

这是我的 .php 文件:

document.getElementById("bounding-tool").addEventListener("click", function() {
    const canvas = document.getElementById("canvas");
    canvas.style.visibility = "visible";
    canvas.style.opacity = 0;
    //canvas.style.position = relative;
})


function create_canvas() {
    const video_frame = document.getElementById("video_frame");
    //const video = document.getElementById("video");

    const video = document.querySelector("video#video, #video video");

    //let rect = video.getBoundingClientRect();
    //console.log(rect.bottom, rect.left, rect.top, rect.right)
    video.addEventListener('loadedmetadata', (event) => {
  
        const canvas = document.getElementById("canvas");

        canvas.height = 438;
        canvas.width = 584;
        
        
        const { videoWidth, videoHeight } = video;
  
        // We're assuming that the width is the larger than the height of video.
        const shrinkFactor = canvas.height / videoHeight * 100;

        const dimensions = {
            width: Math.floor(videoWidth / 100 * shrinkFactor),
            height: Math.floor(videoHeight / 100 * shrinkFactor)
        };

        const offset = (dimensions.width - canvas.width) / 2;
        
        var context = canvas.getContext('2d');
        const loop = () => {
        context.save();
        context.fillRect(0,0,video.VideoHeight,video.videoWidth);
        context.drawImage(video,0,0,video.VideoHeight,video.videoWidth);
        
        create_bounding_tool(canvas);

        video_frame.append(canvas);
        canvas.style.visibility = "hidden";
            //canvas.style.opacity = "0";
        
        context.restore();
           context.fillRect(0,0,canvas.height,canvas.width);
        
        // bind event handler to clear button
      
        //context.clearRect(0, 0, canvas.width, canvas.height);*/
    }
    loop();
        
    });

}
#video_frame{
display: inline-flex;   
position: relative;
margin-left: 7em;
width: 584px;
height: 438px;
flex: 0 0 584px;
margin-right: 0.5rem;

 margin-top: 7em;


}

#playback_frame{
    display:flex;
}

#video{
    
  width: 100%;
  height: 100%;
  object-fit: cover;
  /*opacity: 0.5;*/
  border: 4px solid #0033A0;
 
    /*box-shadow: 0px 0px 7px grey;*/
}


#canvas{
  
  position: absolute;
/*  margin-top: 4.4em;*/
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  /*pointer-events: none;*/
  opacity: 0.5;
  border: 5px solid red;
}
<head>
<title> </title>
    <meta charset="UTF-8">
    <meta name="description" content="Video Determiner">
    <meta name="keywords" content="Video Determiner" />
    <meta name="author" content="Video Determiner" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link href="../css/style.css" rel="stylesheet">
    <link href="https://vjs.zencdn.net/7.10.2/video-js.css" rel="stylesheet" />
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/videojs-seek-buttons/dist/videojs-seek-buttons.css"/>
</head>
    
        <div id="video_frame">
       <video class = "video-js vjs-big-play-centered" controls id="video" width = "584" height = "438" data-setup="{}">
      <source id ="source" src="http://grochtdreis.de/fuer-jsfiddle/video/sintel_trailer-480.mp4" type="video/mp4"">
       <p class="vjs-no-js"> To view this video please enable                  JavaScript, and consider upgrading to a web browser that
       <a href="https://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
      </video>
    <canvas class = "video-wrapper_canvas" id = "canvas"></canvas>
            
 </div>

【问题讨论】:

  • 如果视频是 800x600 并且您将其显示在 500x500 的框中,那么您可能会显示视频的中心,左侧和右侧下降 150px,顶部和顶部下降 50px底部。画布不知道这些边距。因此,要修复它,您需要在 x 轴上移动 150 像素,在 y 轴上移动 50 像素,以获得正确的叠加坐标。
  • 我明白你在说什么,但我该如何移动 x 和 y 轴上的所有内容以获取这些边距?我只是不明白如何在语法上对画布元素进行处理,那是通过使用填充吗? @EmielZuurbier
  • 你能做一个可运行的sn-p吗?这样我们就可以运行您的代码并根据您的需要对其进行修改。
  • jsfiddle.net/user3420/ncuxoq9s/11@EmielZuurbier 我做了一个可运行的 sn-p 但不幸的是我无法让它完全像它在我自己的本地服务器上运行一样,因为文件中还有其他组件需要调用其他js脚本的使用。
  • 好的,没关系。目前,视频未扩展到 500x500 容器。你是想让它填满容器吗?您能否详细说明结果应该如何?

标签: javascript html css canvas


【解决方案1】:

我在下面做了一个演示,它显示了带有画布覆盖的视频元素。画布以与视频本身相同的位置和大小渲染视频。如果你运行代码 sn-p 然后整页你会得到最好的结果。

为确保视频和画布大小相同,请将容器设置为 500x500,并将视频和画布设置为 100% 的宽度和高度。

我已经使用object-fit: cover; 让视频完全扩展了容器的宽度和高度。

现在,视频可能比 500x500 大很多,因此我们需要将(例如)1920x1080 视频转换为 500x500 视口。为此,我们需要进行一些计算。

我们从计算收缩系数开始。视频的高度将与画布的高度相同,但视频的宽度必须缩小相同数量的像素,以确保视频的纵横比保持不变。

因此我们计算height of canvas / height of video x 100。这为我们提供了视频必须缩小以适应画布高度同时保持正确纵横比的百分比。

现在,由于视频的宽度仍然大于画布的宽度,我们需要将视频向左偏移一点以使视频居中。我们通过(new video width - canvas width) / 2 做到这一点。这是视频需要向左移动的像素数。

使用这些值在具有正确尺寸的画布元素中绘制视频。

const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
canvas.height = 500;
canvas.width = 500;

const context = canvas.getContext('2d');

video.addEventListener('loadedmetadata', () => {
  const { videoWidth, videoHeight } = video;
  
  // We're assuming that the width is the larger than the height of video.
  const shrinkFactor = canvas.height / videoHeight * 100;

  const dimensions = {
    width: Math.floor(videoWidth / 100 * shrinkFactor),
    height: Math.floor(videoHeight / 100 * shrinkFactor)
  };

  const offset = (dimensions.width - canvas.width) / 2;

  const loop = () => {
    context.clearRect(
      0, 
      0, 
      canvas.width, 
      canvas.height
    );

    context.drawImage(
      video, 
      0 - offset, // Move it to the left to compensate for the width.
      0,
      dimensions.width,
      dimensions.height
    );

    requestAnimationFrame(loop);
  };

  loop();
});


const compare = document.getElementById('compare');
compare.addEventListener('input', event => {
  const value = event.target.value;
  video.style.opacity = 1 - Number(value);
  canvas.style.opacity = value;
});
body {
  display: flex;
  align-items: flex-start;
}

.video-wrapper {
  position: relative;
  width: 500px;
  height: 500px;
  flex: 0 0 500px;
  margin-right: 0.5rem;
}

.video-wrapper__video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.5;
  border: 5px solid blue;
}

.video-wrapper__canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  opacity: 0.5;
  border: 5px solid red;
}

.slider {
  padding: 1rem;
  border: 1px solid #d0d0d0;
  border-radius: 3px;
  background-color: #f0f0f0;
  margin-left: 0.5rem;
}

.slider label {
  display: flex;
  font-family: sans-serif;
}

.label-video {
  color: blue;
}

.label-canvas {
  color: red;
}
<div class="video-wrapper">
  <video class="video-js vjs-big-play-centered video-wrapper__video" controls id="video" width="500" height="500" data-setup="{}">
    <source src="http://grochtdreis.de/fuer-jsfiddle/video/sintel_trailer-480.mp4"/>
  </video>
  <canvas class="video-wrapper__canvas" id="canvas"></canvas>
</div>

<div class="slider">
  <label>
    <span class="label-video">Video</span>
    <input id="compare" type="range" min="0.1" max="0.9" step="0.1" value="0.5">
    <span class="label-canvas">Canvas</span>
  </label>
</div>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-01
    • 1970-01-01
    • 2021-10-07
    • 1970-01-01
    • 1970-01-01
    • 2013-05-10
    • 2016-09-24
    • 1970-01-01
    相关资源
    最近更新 更多