用HTML5 Canvas(碰撞,图形)做一个简单的2d物理引擎。我想要一个带有标题导航栏的全屏画布。如何创建此布局并正确处理调整大小?
我尝试了几种解决方案:
任何人都可以帮我们带领圣杯吗?最重要的问题是你对画布调整最佳实践的看法(我们应该这样做吗?)。如果是这样,那么在调整画布像素和媒体查询之间的争论与flex /百分比和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是我制作的调整大小画布的示例。然而,在极度调整大小期间,它仍会在导航栏下退缩。
答案 0 :(得分:2)
这取决于你的呈现方式。
requestAnimationFrame
是最佳做法。通常,对DOM进行任何更改的最佳做法是使用requestAnimationFrame
来确保更改与显示硬件的刷新同步。 requestAnimationFrame
还确保只有在页面可见时才会进行更改。 ie(如果客户端将标签切换到另一个标签,则标签不会触发任何requestAnimationFrame
个事件)
最好保持画布分辨率尽可能低。将画布保持在高于显示的分辨率意味着您将在屏幕外的部分上进行大量不必要的渲染,或者如果您通过CSS缩放画布,则向下或上采样可能会导致各种不需要的伪像。 / p>
resize事件由各种源,可更改窗口大小的鼠标事件或来自Javascript的OS事件触发。这些事件都没有同步到显示器,并且一些调整大小事件可以以非常高的速率触发(鼠标驱动的调整大小可以每秒激发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;
我无法看到必须在不需要时设置CSS宽度和高度的重点
注意:如果您不使用requestAnimationFrame
,则需要设置CSS大小,因为无法保证在下次刷新时及时设置画布分辨率,而自动CSS更新(例如{{1} }})将与显示设备同步更改。
答案 1 :(得分:0)
它可以工作,你可以用元素检查来检查它。 我想你想要改变画布的宽度/高度,而不是画布的宽度或高度,它们是完全不同的。 画布的宽度或高度只会影响您在画布上绘制的内容的比例。 CSS样式的宽度或高度可能会改变画布的显示大小。