Как анимировать объекты Path2D на холсте - PullRequest
0 голосов
/ 13 января 2020

На холсте у меня есть 2 типа кругов:

те, которые я создал непосредственно из контекста (= декоративная звезда):

 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?

EDIT, здесь мой метод 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);

    }

1 Ответ

1 голос
/ 13 января 2020

Вы неправильно используете объект 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

  • Вы не можете очистить объект Path2D.
  • Вы только один раз добавляете путь, который хотите визуализировать.
  • Чтобы изменить путь, вам нужно создать новый Path2D или преобразовать путь при его рендеринге. .

Исправление

Создайте путь и все неизменяемые состояния один раз (init), затем многократно визуализируйте (каждый кадр)

Ваш код должен выглядеть более похоже. ..

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);
    }
}
...