[英]How to do a HTML5 Canvas scale animation
我正在开发一个画布白板工具。 现在我正在处理放大和缩小功能。
到目前为止这工作正常,但现在我喜欢为缩放制作平滑的动画。 但似乎它太快了,我看不到任何效果。 我单击 + 或 - 按钮并按比例缩放。
let scaleAmount = 1.00;
function scaleUpdate()
{
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.scale(scaleAmount, scaleAmount)
scaleSize.innerText = parseInt(parseFloat(scaleAmount.toFixed(2))*100)+"%";
stageUpdate();
}
function scale(direction)
{
let scaleSize = document.getElementById("scaleSize");
if(direction=="zoomIn")
{
for(let i = 0; i<10; i++)
{
scaleAmount += 0.01;
scaleAmount = parseFloat(scaleAmount.toFixed(2));
dx += scaleAmount;
dy += scaleAmount;
scaleUpdate();
}
}
if(direction=="zoomOut")
{
for(let i = 0; i<10; i++)
{
scaleAmount -=0.01;
scaleAmount = parseFloat(scaleAmount.toFixed(2));
dx -= scaleAmount;
dy -= scaleAmount;
scaleUpdate();
}
}
}
dx和dy是屏幕偏移量。
有人可以帮我解决这个问题吗?
提前感谢弗兰克
如果您在 for 循环中更新诸如比例尺之类的视觉属性,它实际上会发生一次——这不是真的,但比眼睛快得多。 屏幕不会随着 for 循环的每次迭代而更新。 这更像是在调用scale()
函数之前和完成之后(也不是真的,但你明白了)。
要使这些更改可见,您需要随着时间的推移进行操作。 例如,在开始时间 1.0 将比例设置为 1,在 1.1 将其设置为 1.01,在 1.2 将其设置为 1.02,依此类推,直到达到您的目标比例。 这可以通过使用setInterval()
或requestAnimationFrame()
函数来完成。 setInterval 有两个参数,要调用的函数和调用此函数的时间(以毫秒为单位)。 requestAnimationFrame 尝试以显示器的刷新率调用提供的函数 - 因此,如果它是 60hz 显示器,它将被调用接近每秒 60 次。
如果我们修改您的示例以利用 requestAnimationFrame 函数:
let canvas = document.getElementById("canvas"); let ctx = canvas.getContext("2d"); document.getElementById("scaleUp").onclick = () => { cancelAnimationFrame(animationID); scale("zoomIn"); } document.getElementById("scaleDown").onclick = () => { cancelAnimationFrame(animationID); scale("zoomOut"); } let scaleAmount = 1.0; let animationID; function scale(direction) { let animationReady = false; let targetScale; if (direction == "zoomIn") { scaleAmount += 0.01; targetScale = 2; animationReady = scaleAmount >= targetScale; } if (direction == "zoomOut") { scaleAmount -= 0.01; targetScale = 1; animationReady = scaleAmount <= targetScale; } if (animationReady) { scaleAmount = targetScale; } else { animationID = requestAnimationFrame(() => { scale(direction); }); } stageUpdate(); } function stageUpdate() { ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.translate(canvas.width / 2, canvas.height / 2); ctx.scale(scaleAmount, scaleAmount); ctx.beginPath(); ctx.arc(0, 0, 45, 0, 2 * Math.PI); ctx.closePath(); ctx.stroke(); } stageUpdate();
<button id="scaleUp" type="button">Scale +</button><button id="scaleDown" type="button">Scale -</button><br><canvas id="canvas" width="320" height="200"></canvas>
@obscure 你的回答真的很有帮助,谢谢。
我的最终代码如下所示:
let scaleAmount = 1.00;
let scaleAnimation;
let animationReady = false;
let scalePercent = parseInt(scaleSize.innerText.replace("%",""));
function scaleUpdate()
{
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.scale(scaleAmount, scaleAmount)
scaleSize.innerText = parseInt(parseFloat(scaleAmount.toFixed(1))*100)+"%";
stageUpdate();
}
function scale(direction)
{
let targetScale ;
if(direction=="zoomIn")
{
targetScale = scalePercent / 100 + 0.1;
scaleAmount += 0.01;
animationReady = scaleAmount > targetScale;
targetScale= parseFloat(targetScale.toFixed(3));
scaleAmount = parseFloat(scaleAmount.toFixed(3));
dx += scaleAmount;
dy += scaleAmount;
}
if(direction=="zoomOut")
{
targetScale = scalePercent / 100 - 0.1;
scaleAmount -= 0.01;
animationReady = scaleAmount < targetScale;
targetScale= parseFloat(targetScale.toFixed(3));
scaleAmount = parseFloat(scaleAmount.toFixed(3));
dx -= scaleAmount;
dy -= scaleAmount;
}
if (animationReady) {
scaleAmount = targetScale;
scalePercent = parseInt(scaleSize.innerText.replace("%",""));
} else {
scaleAnimation = requestAnimationFrame(() => {
scaleUpdate();
scale(direction);
});
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.