Проблема с globalCompositeOperation и setTimeout - PullRequest
0 голосов
/ 10 ноября 2011

Я пытаюсь создать анимацию, которая очищает (как ластик) прямоугольную заливку поверх изображения. Когда кружок оживляет, он очищает всю область, которую он покрыл.

Я могу сделать это с помощью globalCompositeOperation, однако, когда я пытаюсь замедлить анимацию, она не работает. Я пытаюсь установить функцию setTimeout. Есть идеи, почему анимация не тормозит? Я перепробовал все, что знаю, любая помощь или альтернативы будут с благодарностью.

Также, когда я пытаюсь использовать функцию setTimeout (func (), время в мс), она также удаляет изображение.

function compose()
//adds the purple fill rectangle, adds the image and then animates the circle
{
context.globalCompositeOperation = 'destination-atop';
fillRectangle(100, 100, 900, 500);
context.globalCompositeOperation = 'destination-atop';
context.drawImage(img, destX, destY);
for (var a = 0; a < 1000; a++) {

    if (x + dx + radius > width || x + dx < radius) {
        dx = -dx;
    }
    if (y + dy + radius > height || y + dy < radius) {
        dy = -dy;
    }
    x = x + dx;
    y = y + dy;
    //setTimeout("circle(x,y)", 1);
    circle(x, y);
    }
context.globalCompositeOperation = 'destination-atop';
context.drawImage(img, destX, destY
}
function circle(x, y)
{// this simply animates the circle over the purple fill
context.globalCompositeOperation = 'destination-out';
context.fillStyle = "#444444";
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, true);
context.closePath();
context.fill(); //setTimeout("context.fill();",3);
context.globalCompositeOperation = 'destination-atop';
}

Полный код:

Canvas Test

        var t;
        //holds the drawing context of the canvas element
        var context;

        //size of canvas
        var width = 600;
        var height = 300;

        //position of the ball
        var x = 150;
        var y = 150;

        //speed of the ball
        var dx = 2;
        var dy = 2;

        //ball radius
        var radius = 10;
        var compositeType = ['xor'];
        var destX = 0;
        var destY = 0;
        var img = new Image();
        img.src = 'nexus.jpg';
        function init() {
            context = document.getElementById("canvas").getContext("2d");

            compose();

        }
        function compose()
        //adds the purple fill rectangle, adds the image and then animates the circle
        {
            context.globalCompositeOperation = 'destination-atop';
            fillRectangle(0, 0, 900, 600);
            context.globalCompositeOperation = 'destination-atop';
            context.drawImage(img, destX, destY);
            var cnt = 0;

            function runIteration() {
                if (x + dx + radius > width || x + dx < radius) {
                    dx = -dx;
                }
                if (y + dy + radius > height || y + dy < radius) {
                    dy = -dy;
                }
                x = x + dx;
                y = y + dy;
                circle(x, y);
                cnt++;
                if (cnt < 10000) {
                    context.globalCompositeOperation = 'destination-atop';
                    context.drawImage(img, destX, destY);
                    setTimeout(runIteration, 10);

                }
            }
            runIteration();

        }

        function fillRectangle(x, y, w, h)
        {
            context.fillStyle = "#550055";
            context.fillRect(x, y, w, h);
        }
        //draws the circle with center location at x,y
        function circle(x, y) {
            // context.globalAlpha=0.1;
            context.globalCompositeOperation = 'destination-out';

            context.fillStyle = "#444444";
            context.beginPath();
            context.arc(x, y, radius, 0, 2 * Math.PI, true);
            context.closePath();
            context.fill(); //setTimeout("context.fill();",3);

            context.globalCompositeOperation = 'destination-atop';
        }

        //draws a rectangle with width(w) & height(h) with top left corner at (x,y)
        function rectangle(x, y, w, h) {
            context.fillStyle = "#000000";
            context.strokeRect(x, y, w, h);
        }
        //clears the whole canvas
        function clear() {
            context.clearRect(0, 0, 800, 300);
        }
        window.addEventListener("load", init, true);
    </script>

1 Ответ

0 голосов
/ 10 ноября 2011

Ваше использование setTimeout() не является правильным способом сделать что-то. setTimeout() - асинхронная функция. Он немедленно возвращается и планирует свою работу на потом.

Когда ваш код написан, весь цикл for будет запущен немедленно, установив 1000 setTimeout таймеров. Это не замедлит анимацию, только немного задержит ее запуск.

Чтобы замедлить анимацию, вам придется реструктурировать свой код так, чтобы вы выполняли каждую итерацию цикла for в setTimeout(), а когда этот тайм-аут заканчивается и выполняется, вы затем планируете следующий setTimeout() со следующим итерация цикла. Было бы что-то вроде этого:

function compose()
//adds the purple fill rectangle, adds the image and then animates the circle
{
    context.globalCompositeOperation = 'destination-atop';
    fillRectangle(100, 100, 900, 500);
    context.globalCompositeOperation = 'destination-atop';
    context.drawImage(img, destX, destY);
    var cnt = 0;

    function runIteration() {
        if (x + dx + radius > width || x + dx < radius) {
            dx = -dx;
        }
        if (y + dy + radius > height || y + dy < radius) {
            dy = -dy;
        }
        x = x + dx;
        y = y + dy;
        circle(x, y);
        cnt++;
        if (cnt < 1000) {
            setTimeout(runIteration, 10);
        }
    }
    runIteration();
}
...