我正在尝试使用比例来设置canvas元素的动画。是否有可能只在不缩放坐标系的情况下缩放元素的大小(宽度和高度)?标准的ctx.scale(x,y)似乎正在影响两者。
如果您运行此代码段,您将看到该元素变得越来越大。但是,它也从一个位置移动到另一个位置。
var c = document.getElementById("c");
var ctx = c.getContext("2d");
var cH;
var cW;
cW = window.innerWidth;
cH = window.innerHeight;
c.width = cW * devicePixelRatio;
c.height = cH * devicePixelRatio;
ctx.scale(devicePixelRatio, devicePixelRatio);
var startX = 200;
var startY = 100;
var currentScale = 0.1
function animateCloud () {
// draw cloud shape
ctx.scale(currentScale, currentScale)
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.bezierCurveTo(startX - 40, startY + 10, startX - 20, startY + 180, startX + 60, startY + 70);
ctx.bezierCurveTo(startX + 100, startY + 100, startX + 150, startY + 100, startX + 150, startY + 70);
ctx.bezierCurveTo(startX + 280, startY + 70, startX + 230, startY + 40, startX + 210, startY + 20);
ctx.bezierCurveTo(startX + 360, startY - 40, startX + 210, startY - 50, startX + 160, startY - 30);
ctx.bezierCurveTo(startX + 150, startY - 75, startX + 80, startY - 60, startX + 70, startY - 30);
ctx.bezierCurveTo(startX + 30, startY - 75, startX - 10, startY - 60, startX, startY);
ctx.closePath();
ctx.lineWidth = 5;
ctx.strokeStyle = "#333";
ctx.stroke();
ctx.setTransform(1,0,0,1,0,0)
if (currentScale >= 1 ){
}else{
currentScale += 0.1
console.log(currentScale)
console.log('animations going')
requestAnimationFrame(animateCloud)
}
}
requestAnimationFrame(animateCloud)

canvas {
display: block;
width: 100vw;
height: 100vh;
cursor: pointer;
}

<canvas id="c"></canvas>
&#13;
我希望它保持相同的位置,但变得更大。缩放也影响坐标,这就是它在位置方面的移动原因。
我能想到的一个解决方案是遍历每个路径的坐标并将其除以比例变量。但直觉上看起来似乎是一个糟糕的解决方案。
答案 0 :(得分:2)
您需要使用translate
(以及rotate
和scale
)设置比例缩放的位置。事情总是围绕起源扩展。原点从左上角的0,0开始。如果你想从其他地方扩展,你需要移动那个原点,然后在原点附近绘制东西。
示例:
const ctx = document.querySelector("canvas").getContext("2d");
function render(time) {
time *= 0.001; // seconds
const width = ctx.canvas.width;
const height = ctx.canvas.height;
ctx.clearRect(0, 0, width, height);
// save all the canvas settings
ctx.save();
// move origin to center of canvas
ctx.translate(width / 2, height / 2);
const xScale = lerp(.5, 2, sinLerp(time * 1.1));
const yScale = lerp(.5, 2, sinLerp(time * 1.7));
ctx.scale(xScale, yScale);
// draw a rectangle around the origin
ctx.fillStyle = "red";
ctx.fillRect(-20, -10, 40, 20);
// restore all the canvas settings
ctx.restore();
requestAnimationFrame(render);
}
requestAnimationFrame(render);
// returns a number between 0 and 1
function sinLerp(t) {
return Math.sin(t) * .5 + .5;
}
// returns a number bewteen a and b
// assuming t is between 0 and 1 inclusive
function lerp(a, b, t) {
return a + (b - a) * t;
}
&#13;
canvas {
border: 1px solid black;
}
&#13;
<canvas></canvas>
&#13;
在您的情况下,首先将原点移动到您想要形状中心的位置,然后缩放,然后将原点从当前位置移动,这样当您绘制形状时,其中心将位于原点。在你的情况下你的云看起来是600x200大,所以为了使其中心在原点(0,0)绘制我们需要翻译-300,-100
var c = document.getElementById("c");
var ctx = c.getContext("2d");
var cH;
var cW;
cW = window.innerWidth;
cH = window.innerHeight;
c.width = cW * devicePixelRatio;
c.height = cH * devicePixelRatio;
ctx.scale(devicePixelRatio, devicePixelRatio);
var startX = 200;
var startY = 100;
var currentScale = 0.1
function animateCloud () {
// draw cloud shape
// move the origin to the center (or anywhere)
ctx.translate(c.width / 2, c.height / 2);
ctx.scale(currentScale, currentScale);
// move the origin from the center
// so that the center is in the
// center of your cloud
// PS: just guessed the center is at 300,100
// so you need to start drawing at -300,-100
// from the origin so your shape's center
// ends up at 0,0
ctx.translate(-300, -100);
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.bezierCurveTo(startX - 40, startY + 10, startX - 20, startY + 180, startX + 60, startY + 70);
ctx.bezierCurveTo(startX + 100, startY + 100, startX + 150, startY + 100, startX + 150, startY + 70);
ctx.bezierCurveTo(startX + 280, startY + 70, startX + 230, startY + 40, startX + 210, startY + 20);
ctx.bezierCurveTo(startX + 360, startY - 40, startX + 210, startY - 50, startX + 160, startY - 30);
ctx.bezierCurveTo(startX + 150, startY - 75, startX + 80, startY - 60, startX + 70, startY - 30);
ctx.bezierCurveTo(startX + 30, startY - 75, startX - 10, startY - 60, startX, startY);
ctx.closePath();
ctx.lineWidth = 5;
ctx.strokeStyle = "#333";
ctx.stroke();
ctx.setTransform(1,0,0,1,0,0)
if (currentScale >= 1 ){
}else{
currentScale += 0.1
console.log(currentScale)
console.log('animations going')
requestAnimationFrame(animateCloud)
}
}
requestAnimationFrame(animateCloud)
&#13;
body { margin: 0; }
canvas {
display: block;
width: 100vw;
height: 100vh;
cursor: pointer;
}
&#13;
<canvas id="c"></canvas>
&#13;