[英]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.