Video 视频画面加载到 Canvas 中并限制显示区域与缩放
简介 由于项目需要在视频上放大指定区域播放、视频滚轮缩放、绘制特定内容,H5 原生的 Video 控件无法满足需求。但是同样的 Canvas 也有不如 Video 的弊端,比如全屏。
方法 requestVideoFrameCallback HTMLVideoElement.requestVideoFrameCallback() 用于注册回调,在渲染一帧图像时触发。 参考博客:The requestVideoFrameCallback API
回调播放核心代码 1 2 3 4 5 6 7 8 9 10 const video = document .querySelector("video" );const canvas = document .querySelector("canvas" );const ctx = canvas.getContext("2d" );const updateCanvas = (now, metadata ) => { ctx.drawImage(video, 0 , 0 , width, height); video.requestVideoFrameCallback(updateCanvas); }; video.requestVideoFrameCallback(updateCanvas);
回调播放演示
基于回调的区域裁切 通过创建 Canvas 控件时的 drawImage 方法控制裁切显示区域 参考:Web Api drawImage 例如:裁切起始坐标 150,150,裁切大小 576x324,显示坐标 0,0,显示大小 384x216
核心代码 1 2 3 4 5 6 7 8 9 10 11 12 const startDrawingCutting = () => { const video = document .querySelector("video" ); const canvas = document .getElementById('videoCutting' ); const ctx = canvas.getContext("2d" ); const updateCanvasCutting = (now, metadata ) => { ctx.drawImage(video, 150 , 150 , 576 , 324 , 0 , 0 , 384 , 216 ); video.requestVideoFrameCallback(updateCanvasCutting); }; video.requestVideoFrameCallback(updateCanvasCutting); }; window .addEventListener('load' , startDrawingCutting);
回调裁切演示
Konva.js Konva.js 是适用于桌面/移动端应用的 HTML5 2d canvas 库,将视频添加到 Konva 的舞台中,更适合后期操作。 参考:VideoOnCanvas 将视频加载到 Konva Canvas 中
Konva 播放核心代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 var stage = new Konva.Stage({ container: 'container' , width: width, height: height, }); var layer = new Konva.Layer();stage.add(layer); var video = document .createElement('video' );var image = new Konva.Image({ image: video, draggable: true , x: 0 , y: 0 , }); layer.add(image); var anim = new Konva.Animation(function ( ) { }, layer); video.addEventListener('loadedmetadata' , function (e ) { image.width(width); image.height(height); });
Konva 播放演示
基于 Konva.js 的拖拽和鼠标滚轮缩放
拖拽:创建 Konva 对象时设置 draggable: true 即可拖动 参考 复杂的拖拽区域 可以设置更为详细的拖拽规则
缩放:监听 wheel 方法进行缩放操作
鼠标滚轮缩放核心代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 var scaleBy = 1.04 ;stageZoom.on('wheel' , e => { e.evt.preventDefault(); var oldScale = stageZoom.scaleX(); var mousePointTo = { x: stageZoom.getPointerPosition().x / oldScale - stageZoom.x() / oldScale, y: stageZoom.getPointerPosition().y / oldScale - stageZoom.y() / oldScale }; var newScale = e.evt.deltaY < 0 ? oldScale * scaleBy : oldScale / scaleBy; stageZoom.scale({ x : newScale, y : newScale }); var newPos = { x: -(mousePointTo.x - stageZoom.getPointerPosition().x / newScale) * newScale, y: -(mousePointTo.y - stageZoom.getPointerPosition().y / newScale) * newScale }; stageZoom.position(newPos); stageZoom.batchDraw(); });
拖拽和鼠标滚轮缩放演示