【发布时间】:2017-06-28 02:19:27
【问题描述】:
我遇到需要剪辑图像或视频的情况。图像或视频需要能够重叠。我们最初使用 SVG 进行了尝试,但由于各种原因,效果不佳,所以现在我们在 Canvas 中进行。
这对于图像来说效果很好,但对于视频来说,浏览器在大约 2 分钟后几乎会突然停止。 (您不会从示例代码或链接中看到,我们还在视频不在视图中以及选项卡不在视图中时暂停视频。)
这是一个链接:http://codepen.io/paceaux/pen/egLOeR
主要关注的是这种方法:
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();
});
}
}
您会发现浏览器立即变慢。我不建议长时间看那个 codepen,因为到处都会变得非常缓慢。
我正在使用"backCanvas" technique,但这似乎让事情变得更糟。
我也尝试使用Path2D() 来保存剪辑路径,但这似乎也没有多大帮助。
wedgeTop: (context, wedgeHeight = defaults.wedgeHeight) => {
var wedge = new Path2D();
wedge.moveTo(this.dimensions.width, 0);
wedge.lineTo(this.dimensions.width, this.dimensions.height);
wedge.lineTo(0, this.dimensions.height);
wedge.lineTo(0, wedgeHeight);
wedge.closePath();
context.clip(wedge);
},
我还缺少其他优化吗? (保存视频的大小)。
let imageFrames = function () {
let defaults = {
wedgeHeight: 50
};
return {
defaults: defaults,
//all wedges draw paths clockwise: top right, bottom right, bottom left, top left
wedgeTop: (context, wedgeHeight = defaults.wedgeHeight) => {
var wedge = new Path2D();
wedge.moveTo(this.dimensions.width, 0);
wedge.lineTo(this.dimensions.width, this.dimensions.height);
wedge.lineTo(0, this.dimensions.height);
wedge.lineTo(0, wedgeHeight);
wedge.closePath();
context.clip(wedge);
},
wedgeTopReverse: (context, wedgeHeight = defaults.wedgeHeight) => {
var wedge = new Path2D();
wedge.moveTo(this.dimensions.width, wedgeHeight);
wedge.lineTo(this.dimensions.width, this.dimensions.height);
wedge.lineTo(0, this.dimensions.height);
wedge.lineTo(0, 0);
wedge.closePath();
context.clip(wedge);
},
wedgeBottom: (context, wedgeHeight = defaults.wedgeHeight) => {
var wedge = new Path2D();
wedge.moveTo(this.dimensions.width, 0);
wedge.lineTo(this.dimensions.width, this.dimensions.height - wedgeHeight);
wedge.lineTo(0, this.dimensions.height);
wedge.lineTo(0,0);
wedge.closePath();
context.clip(wedge);
},
wedgeBottomReverse: (context, wedgeHeight = defaults.wedgeHeight) => {
var wedge = new Path2D();
wedge.moveTo(this.dimensions.width, 0);
wedge.lineTo(this.dimensions.width, this.dimensions.height);
wedge.lineto(0, this.dimensions.height - wedgeHeight);
wedge.lineTo(0, 0);
wedge.closePath();
context.clip(wedge);
}
};
};
class ImageCanvasModule {
constructor(module) {
this.module = module;
this.imageFrames = imageFrames.call(this);
if(this.isVideo) {
/*drawFrame has a check where it'll only draw on reqAnimationFrame if video.paused === false,
so we need to fire drawFrame on both events because that boolean will be false when it's paused, thus cancelling the animation frame
*/
this.media.addEventListener('play', ()=>{
this.drawOnCanvas();
});
this.media.addEventListener('pause', ()=> {
this.drawOnCanvas();
});
}
}
get isPicture() {
return (this.module.nodeName === 'PICTURE');
}
get isVideo() {
return (this.module.nodeName === 'VIDEO');
}
get media() {
return this.isPicture ? this.module.querySelector('img') : this.module;
}
get context() {
return this.canvas.getContext('2d');
}
get dimensions() {
return {
width: this.module.offsetWidth,
height: this.module.offsetHeight
};
}
createCanvas () {
let canvas = document.createElement('canvas');
this.module.parentNode.insertBefore(canvas, this.module.nextSibling);
canvas.className = this.module.className;
this.canvas = canvas;
this.createBackContext();
}
createBackContext () {
this.backCanvas = document.createElement('canvas');
this.backContext = this.backCanvas.getContext('2d');
this.backCanvas.width = this.dimensions.width;
this.backCanvas.height = this.backCanvas.height;
}
sizeCanvas () {
this.canvas.height = this.dimensions.height;
this.canvas.width = this.dimensions.width;
this.backCanvas.height = this.dimensions.height;
this.backCanvas.width = this.dimensions.width;
}
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();
});
}
}
drawOnCanvas () {
this.sizeCanvas();
this.drawFrame();
}
hideOriginal () {
//don't use display: none .... you can't get image dimensions when you do that.
this.module.style.opacity = 0;
}
}
console.clear();
window.addEventListener('DOMContentLoaded', ()=> {
var els = document.querySelectorAll('.canvasify');
var canvasified = [];
for (el of els) {
if (el.dataset.imageFrame) {
let imageModule = new ImageCanvasModule(el);
imageModule.createCanvas();
imageModule.drawOnCanvas();
imageModule.hideOriginal();
canvasified.push(imageModule);
}
}
console.log(canvasified);
});
body {
background-color: #333;
}
.container {
height: 600px;
width: 100%;
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
}
.container + .container {
margin-top: -150px;
}
.canvasify {
position:absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
z-index: -1;
}
video {
width: 100%
}
h1 {
font-size: 2em;
color: #ddd;
}
<div class="container">
<img class="canvasify" data-image-frame="wedgeTop" src="http://placekitten.com/1280/500" />
<h1>Kitty with a clipped top</h1>
</div>
<div class="container">
<video controls muted class="canvasify" loop autoplay data-image-frame="wedgeTop">
<source src="https://poc5.ssl.cdn.sdlmedia.com/web/635663565028367012PU.mp4">
</video>
<h1>video with a clipped top that overlaps the image above</h1>
</div>
问题在于 codepen(以及运行此代码的其他页面)非常慢。我错过了哪些优化,或者使用不正确?
【问题讨论】:
-
“重叠”是什么意思?不确定是什么问题?
-
问题是页面运行速度极慢。 “重叠”意味着视频中的图像应该被剪裁,并与位于其上方的图像重叠。使其看起来像视频/图像不是矩形,而是以角度切割。
-
还是没有。我正在寻找您在 codepen 中看到的内容。两个独立的容器。一个可能包含图像。另一个可能包含视频。每个容器都会有视频或图像,并且会以一定角度“剪辑”。来自 HTML 的文本将位于图像/视频之上。因此,一个容器中图像的底部边缘将直观地显示在可能是视频的顶部边缘下方。我不需要关于如何操作的帮助(我已经完成了,并且它有效)我需要帮助以使页面表现更好。
-
好的...只是检查o_o(我链接的示例代码是否也产生了滞后?)
-
“我需要帮助以使页面性能更好。” 如果只呈现图像和视频,为什么需要
canvas和requestAnimationFrame?目前如何衡量绩效?
标签: javascript canvas html5-canvas html5-video