[英]HTML canvas best practices for resizing
使用 HTML5 Canvas(碰撞、绘图)做一个简单的 2d 物理引擎。 我想要一个带有标题导航栏的全屏画布。 如何创建此布局并正确处理调整大小?
我尝试了几种解决方案:
谁能帮助我们引领我们走向圣杯? 最重要的问题是您对调整画布大小最佳实践的看法(我们应该这样做吗?)。 如果是这样,那么在调整画布像素大小和媒体查询、flex/percents 和 javascript 容器测量等之间的争论呢?
示例/尝试:
示例 1:这是我在模型的 v1 中使用的 Javascript 代码。 相应的 HTML 只是一个带有标题和 100% 容器的基本文档,容器内有画布,并被设置为填充容器。
window.onload = function(){
init();
};
window.addEventListener("resize", init);
function init(){
console.log("init");
initCanvas();
drawCircle();
}
function initCanvas() {
var content = document.querySelector(".content");
var canvas = document.querySelector(".myCanvas");
canvas.width = content.clientWidth;
canvas.height = content.clientHeight;
}
示例 2:此 CodePen 是我制作的调整大小画布的示例。 尽管如此,在极端调整大小期间,它仍然会在导航栏下方撤退。
这将取决于您的渲染方式。
requestAnimationFrame
是最佳实践。 通常,对 DOM 进行任何更改的最佳实践是使用requestAnimationFrame
来确保更改与显示硬件的刷新同步呈现。 requestAnimationFrame
还确保只有当页面可见时才会进行更改。 即(如果客户端将选项卡切换到另一个选项卡,您的选项卡将不会触发任何requestAnimationFrame
事件)
最好保持画布分辨率尽可能低。 将画布的分辨率保持在高于显示器的分辨率意味着您将对屏幕外的部分进行大量不必要的渲染,或者如果您通过 CSS 缩放画布,向下或向上采样可能会导致各种不需要的工件。
调整大小事件由各种来源、更改窗口大小的操作系统事件、鼠标事件或来自 Javascript 触发。 这些事件都不会同步到显示器,并且一些调整大小事件可以以非常高的速率触发(鼠标驱动的调整大小可以每秒触发 100 多次)
因为调整画布大小也会清除图像数据并重置上下文状态,所以每次调整大小都需要重新渲染内容。 调整大小事件的快速触发率会使线程过度工作,您将开始丢失事件,页面会感觉滞后,并且您可能会获得未及时更新以用于下一个显示帧的页面部分。
调整大小时,应尽量避免在不需要时调整大小。 因此调整大小的最佳时间是通过requestAnimationFrame
回调。
如果您正在实时渲染,那么调整大小的最佳方法是在每个渲染帧开始时将画布大小与容器或窗口大小进行比较。 如果尺寸不匹配,则调整画布的大小。
// no need for a resize event listener.
function renderLoop(){
// innerWidth / height or containor size
if(canvas.width !== innerWidth || canvas.height !== innerHeight){
canvas.width = innerWidth;
canvas.height = innerHeight;
}
// your code
requestAnimationFrame(renderLoop);
}
requestAnimationFrame(renderLoop);
如果您不经常渲染或根据需要进行渲染。 那么您最好将画布保持在屏幕外的标准分辨率,并在屏幕上使用可调整大小的画布来渲染屏幕外画布的视图。
在这种情况下,您保持主循环处于活动状态,它将检查指示需要更新视图的信号量。 任何更改画布的内容都会将标志设置为 true。
const mainCanvas = document.createElement("canvas");
const mCtx ...
const canvas = document.getElementById("displayCanvas");
const ctx ...
// when updating content
function renderContent(){
mCtx.drawStuff...
...
updateView = true; // flag the change
}
// the resize event only need flag that there is a change
window.addEventListener("resize",()=> updateView = true );
var updateView = true;
function renderLoop(){
if(updateView){
updateView = false; // clear the flag
// is there a need to change display canvas resolution.
if(canvas.width !== innerWidth || canvas.height !== innerHeight){
canvas.width = innerWidth;
canvas.height = innerHeight;
}
// draw the mainCanvas onto the display canvas.
ctx.drawImage(mainCanvas, viewOrigin.x, viewOrigin.y);
}
requestAnimationFrame(renderLoop);
}
requestAnimationFrame(renderLoop);
在您的情况下,使用上述方法(即使是实时的)可以让您更好地控制可以看到画布内容的哪一部分。
有些人认为 CSS 是唯一应该改变任何类型的视觉内容的地方。 画布的问题在于 CSS 无法设置画布分辨率,因此如果您使用 CSS,您仍然必须设置画布分辨率。
对于画布,我没有设置任何 CSS 大小,而是让画布分辨率属性设置显示大小canvas.width=1920; canvas.height=1080;
canvas.width=1920; canvas.height=1080;
我看不出在不需要时必须设置 CSS 宽度和高度的意义
注意:如果您不使用requestAnimationFrame
您将需要设置 CSS 大小,因为您无法保证在下一次刷新时及时设置画布分辨率,而自动 CSS 更新(例如canvas.style.width="100%"
) 将与显示设备同步变化。
它有效,您可以使用元素检查来检查它。 我在想你想改变画布的样式宽度/高度,而不是画布的宽度或高度,它们是完全不同的。 画布的宽度或高度只会影响您在画布上绘制的内容的比例。 并且 CSS 样式的宽度或高度可以改变画布的显示大小。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.