我最近收到客户的请求,要求提供这个功能,并且必须支持CMS。该技术涉及三个主要思路:
- 绘图函数
- 反复调用相同的绘图函数
- 使用
requestAnimationFrame
来绘制下一帧
假设您已经有一个视频元素,您需要执行以下步骤:
- 隐藏视频元素
- 创建一个高度/宽度与视频元素匹配的画布元素,并将其存储在某个地方
- 获取画布元素的上下文`canvas.getContext('2d')`,并将其存储在某个地方
- 创建绘图函数
- 在该绘图函数中,您将使用
canvas.drawImage(src, x, y)
,其中src
是当前视频帧的编辑版本;
- 在该绘图函数中,使用递归再次调用自身
我可以给您两个此类示例(可用于内容管理系统)。
第一个示例在此:
https://jsfiddle.net/yywL381w/19/
一家名为SDL的公司制作了一个名为Media Manager的工具,用于托管视频。您看到的是一个jQuery插件,它从
data-*
中获取其参数,从Media Manager Rest API发出请求,创建视频并根据
data*
属性添加效果。该插件可以轻松地进行调整,以便与其他来源的视频一起使用。您可以查看
repo以获取更多有关使用的详细信息。
另一个例子在这里:
http://codepen.io/paceaux/pen/egLOeR
那不是一个jQuery插件;而是一个ES6类。您可以使用以下代码创建图像/视频并应用裁剪效果:
let imageModule = new ImageCanvasModule(module);
imageModule.createCanvas();
imageModule.drawOnCanvas();
imageModule.hideOriginal();
在
ImageCanvasModule
类中,你会注意到这个方法:
drawFrame () {
if (this.isVideo && this.media.paused) return false;
let x = 0;
let width = this.media.offsetWidth;
let y = 0;
this.imageFrames[this.module.dataset.imageFrame](this.backContext);
this.backContext.drawImage(this.media, x, y, width, this.canvas.height);
this.context.drawImage(this.backCanvas, 0, 0);
if (this.isVideo) {
window.requestAnimationFrame(()=>{
this.drawFrame();
});
}
}
该类创建了第二个画布用于绘制,这个画布不可见,只是为了减轻浏览器的负担。
"manipulation" 可以被内容管理,
this.imageFrames[this.module.dataset.imageFrame](this.backContext);
"frame" 是存储在图像/视频上的属性(可以由CMS中的模板输出)。它获取imageFrame的名称,并将其作为匹配函数运行。它还发送上下文(因此我可以在需要时在后台画布或主画布之间切换)。
然后,
this.backContext.drawImage(this.media, x, y, width, this.canvas.height);
在后台上下文中绘制图像。
最后,
this.context.drawImage(this.backCanvas, 0, 0);
将其显示在主画布上,我将backcanvas绘制到主画布上。因此,可见的画布具有尽可能少的操作。
最后,因为这是视频,我们想要绘制一个新帧。所以我们让函数调用自身:
if (this.isVideo) {
window.requestAnimationFrame(()=>{
this.drawFrame();
});
这整个设置允许我们使用CMS输出包含用户想要绘制的图像周围框架类型的
data-*
属性。然后JavaScript会生成该图像或视频的画布版本。示例标记可能如下所示:
<video muted loop autoplay data-image-frame="wedgeTop">