如何在 canvas 上为 Path2D 对象设置动画
How to animate Path2D objects on canvas
在我的 canvas 上,我有两种类型的圈子:
我直接根据上下文创建的那些 (= decorativeStars):
drawDecorativeStar = (decorativeStar) => {
this.ctx.beginPath();
this.ctx.arc(decorativeStar.x, decorativeStar.y, decorativeStar.radius, 0, 2 * Math.PI);
this.ctx.fillStyle = "rgba(254, 255, 242," + decorativeStar.alpha + ")";
this.ctx.fill();
this.ctx.closePath();
}
以及那些创建为 Path2D 的,因为我希望它们是可点击的(=planetPaths):
createPlanetPaths = (planets) => {
for (var i = 0; i < planets.length; i++) {
this.planetPaths[i] = {
ref: new Path2D(),
x: Math.random() * WIDTH_CANVAS,
y: Math.random() * HEIGHT_CANVAS,
radius: this.getPlanetRadius(planets[i]),
color: planets[i].color,
}
}
}
drawPlanets = (planetPaths) => {
for (let i = 0; i < planetPaths.length; i++) {
planetPaths[i].ref.arc(planetPaths[i].x, planetPaths[i].y, planetPaths[i].radius, 0, 2 * Math.PI);
planetPaths[i].ref.gradient = this.ctx.createLinearGradient((planetPaths[i].x - planetPaths[i].radius), (planetPaths[i].y - planetPaths[i].radius), 1.02 * (planetPaths[i].x + planetPaths[i].radius), 1.02 * (planetPaths[i].y + planetPaths[i].radius));
planetPaths[i].ref.gradient.addColorStop(0, planetPaths[i].color);
planetPaths[i].ref.gradient.addColorStop(1, 'red');
this.ctx.fillStyle = planetPaths[i].ref.gradient;
this.ctx.fill(planetPaths[i].ref);
}
};
现在我想使用 requestAnimationFrame 为这些圆圈制作动画。我的问题是 this.ctx.clearRect(0, 0, WIDTH_CANVAS, HEIGHT_CANVAS);
似乎对 Path2D 对象没有影响,但对其他对象有效。
还有其他方法可以清除 Path2D 对象吗?
编辑,这里是我的 updateCanvas 方法,用于生成动画:
updateCanvas() {
this.ctx.clearRect(0, 0, WIDTH_CANVAS, HEIGHT_CANVAS);
for (let i = 0; i < this.planetPaths.length; i++) {
var planetPath = this.planetPaths[i];
if (planetPath.x < WIDTH_CANVAS) {
planetPath.x += 1;
} else {
planetPath.x = 0;
}
}
for (let i = 0; i < this.decorativeStars.length; i++) {
var star = this.decorativeStars[i];
if (star.decreasing == true) {
star.alpha -= star.decreasingIncreasingRatio;
if (star.alpha < 0.10) { star.decreasing = false; }
}
else {
star.alpha += star.decreasingIncreasingRatio;
if (star.alpha > 0.95) { star.decreasing = true; }
}
// star.x+=0.01;
}
this.drawDecorativeStars(this.decorativeStars);
this.drawPlanets(this.planetPaths);
this.myReq = requestAnimationFrame(this.updateCanvas);
}
您使用的 Path2D 对象不正确。
在 drawPlanets
函数中,您每次调用 draw 时都会向路径添加子路径。
planetPaths[i].ref.arc(planetPaths[i].x, planetPaths[i].y, planetPaths[i].radius, 0, 2 * Math.PI);
因此,每次使用 this.ctx.fill(planetPaths[i].ref);
绘制路径时,您都会绘制到那时添加的所有子路径。
使用Path2D
修复
一次创建路径和所有不变的状态(初始化),然后多次渲染(每帧)
您的代码应该看起来更像...
createPlanetPaths = planets => {
for (const planet of planets) {
const path = new Path2D();
const x = Math.random() * WIDTH_CANVAS;
const y = Math.random() * HEIGHT_CANVAS;
const radius = this.getPlanetRadius(planet);
path.arc(x, y, radius, 0, 2 * Math.PI);
const gradient = this.ctx.createLinearGradient((px - radius), (y - radius), 1.02 * (x + radius), 1.02 * (y + radius));
gradient.addColorStop(0, planet.color);
gradient.addColorStop(1, 'red');
this.planetPaths[i] = {path, gradient};
}
}
drawPlanets = planetPaths => {
for (const planetPath of planetPaths) {
this.ctx.fillStyle = planetPath.gradient;
this.ctx.fill(planetPath.path);
}
}
在我的 canvas 上,我有两种类型的圈子:
我直接根据上下文创建的那些 (= decorativeStars):
drawDecorativeStar = (decorativeStar) => {
this.ctx.beginPath();
this.ctx.arc(decorativeStar.x, decorativeStar.y, decorativeStar.radius, 0, 2 * Math.PI);
this.ctx.fillStyle = "rgba(254, 255, 242," + decorativeStar.alpha + ")";
this.ctx.fill();
this.ctx.closePath();
}
以及那些创建为 Path2D 的,因为我希望它们是可点击的(=planetPaths):
createPlanetPaths = (planets) => {
for (var i = 0; i < planets.length; i++) {
this.planetPaths[i] = {
ref: new Path2D(),
x: Math.random() * WIDTH_CANVAS,
y: Math.random() * HEIGHT_CANVAS,
radius: this.getPlanetRadius(planets[i]),
color: planets[i].color,
}
}
}
drawPlanets = (planetPaths) => {
for (let i = 0; i < planetPaths.length; i++) {
planetPaths[i].ref.arc(planetPaths[i].x, planetPaths[i].y, planetPaths[i].radius, 0, 2 * Math.PI);
planetPaths[i].ref.gradient = this.ctx.createLinearGradient((planetPaths[i].x - planetPaths[i].radius), (planetPaths[i].y - planetPaths[i].radius), 1.02 * (planetPaths[i].x + planetPaths[i].radius), 1.02 * (planetPaths[i].y + planetPaths[i].radius));
planetPaths[i].ref.gradient.addColorStop(0, planetPaths[i].color);
planetPaths[i].ref.gradient.addColorStop(1, 'red');
this.ctx.fillStyle = planetPaths[i].ref.gradient;
this.ctx.fill(planetPaths[i].ref);
}
};
现在我想使用 requestAnimationFrame 为这些圆圈制作动画。我的问题是 this.ctx.clearRect(0, 0, WIDTH_CANVAS, HEIGHT_CANVAS);
似乎对 Path2D 对象没有影响,但对其他对象有效。
还有其他方法可以清除 Path2D 对象吗?
编辑,这里是我的 updateCanvas 方法,用于生成动画:
updateCanvas() {
this.ctx.clearRect(0, 0, WIDTH_CANVAS, HEIGHT_CANVAS);
for (let i = 0; i < this.planetPaths.length; i++) {
var planetPath = this.planetPaths[i];
if (planetPath.x < WIDTH_CANVAS) {
planetPath.x += 1;
} else {
planetPath.x = 0;
}
}
for (let i = 0; i < this.decorativeStars.length; i++) {
var star = this.decorativeStars[i];
if (star.decreasing == true) {
star.alpha -= star.decreasingIncreasingRatio;
if (star.alpha < 0.10) { star.decreasing = false; }
}
else {
star.alpha += star.decreasingIncreasingRatio;
if (star.alpha > 0.95) { star.decreasing = true; }
}
// star.x+=0.01;
}
this.drawDecorativeStars(this.decorativeStars);
this.drawPlanets(this.planetPaths);
this.myReq = requestAnimationFrame(this.updateCanvas);
}
您使用的 Path2D 对象不正确。
在 drawPlanets
函数中,您每次调用 draw 时都会向路径添加子路径。
planetPaths[i].ref.arc(planetPaths[i].x, planetPaths[i].y, planetPaths[i].radius, 0, 2 * Math.PI);
因此,每次使用 this.ctx.fill(planetPaths[i].ref);
绘制路径时,您都会绘制到那时添加的所有子路径。
使用Path2D
修复
一次创建路径和所有不变的状态(初始化),然后多次渲染(每帧)
您的代码应该看起来更像...
createPlanetPaths = planets => {
for (const planet of planets) {
const path = new Path2D();
const x = Math.random() * WIDTH_CANVAS;
const y = Math.random() * HEIGHT_CANVAS;
const radius = this.getPlanetRadius(planet);
path.arc(x, y, radius, 0, 2 * Math.PI);
const gradient = this.ctx.createLinearGradient((px - radius), (y - radius), 1.02 * (x + radius), 1.02 * (y + radius));
gradient.addColorStop(0, planet.color);
gradient.addColorStop(1, 'red');
this.planetPaths[i] = {path, gradient};
}
}
drawPlanets = planetPaths => {
for (const planetPath of planetPaths) {
this.ctx.fillStyle = planetPath.gradient;
this.ctx.fill(planetPath.path);
}
}