Как добавить эффект затухания только к определенным элементам на холсте html

У меня есть холст с несколькими кругами разных цветов, и я хочу добавить эффект затухания только к некоторым кругам. Эффект применим только к красным и зеленым.

Код выглядит следующим образом

function drawPiece(pieceX, pieceY, color) {

if (color === "rgba(0,0,0,1)" || color === "rgba(255,255,255,1)"){


    ctx.beginPath();
    ctx.fillStyle = color;
    ctx.arc(pieceX, pieceY, 50, 0, 2 * Math.PI, false);
    ctx.fill();
    ctx.lineWidth = "4";
    ctx.strokeStyle = "rgba(0,0,0,1)";
    ctx.stroke();
    ctx.closePath();
}
else {
    ctx.beginPath();
    ctx.fillStyle = color;
    ctx.arc(pieceX, pieceY, 10, 0, 2 * Math.PI, false);
    ctx.fill();
    ctx.lineWidth = "4";
    ctx.strokeStyle = "rgba(0,0,0,1)";
    ctx.stroke();
    ctx.closePath();
    setTimeout(function(){
        var fadeTarget = document.getElementById("canvasGame");
        var fadeEffect = setInterval(function () {
            if (!fadeTarget.style.opacity) {
                fadeTarget.style.opacity = 1;
            }
            if (fadeTarget.style.opacity > 0) {
                fadeTarget.style.opacity -= 0.02;
            } else {
                clearInterval(fadeEffect);
            }
        }, 20);
    },0.5);

}


}

Эффект затухания работает, но он затухает весь холст, а не отдельные круги.

Как я могу добиться этого, чтобы исчезли только некоторые элементы.

заранее спасибо


person nad34    schedule 31.12.2019    source источник


Ответы (2)


Отличным ресурсом по холсту 2D является CanvasRenderingContext2D MDN.

Анимации с использованием холста.

Вам понадобится цикл рендеринга, если вы хотите анимировать содержимое холста.

Цикл рендеринга вызывается 60 раз в секунду, если возможно, отрисовка слишком большая и скорость упадет ниже 60fps.

Основной цикл очищает холст, затем рисует анимированный контент, затем запрашивает следующий кадр.

requestAnimationFrame(mainLoop);  // request the first frame to start the animation
function mainLoop() {
    ctx.globalAlpha = 1; // default to 1 in case there is other content drawn
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);  // clear the canvas
    drawContent(); // render the content.
    requestAnimationFrame(mainLoop);  // request the next frame (in 1/60th second)
}

Функция для рисования круга. Вы можете удалить альфу из цвета и использовать globalAlpha установить прозрачность.

Math.TAU = Math.PI * 2;  // set up 2 PI
function drawCircle(x, y, radius, color, alpha = 1) {
    ctx.globalAlpha = alpha;
    ctx.fillStyle = color;
    ctx.strokeStyle = "#000"; 
    ctx.lineWidth = 4;
    ctx.beginPath();
    ctx.arc(x, y, radius, 0, Math.TAU);
    ctx.fill();
    ctx.stroke();
}

Создайте объект для хранения описания круга и массив для их размещения.

const circles = [];
function circle(x,y,r = 10, col = "#FFF", alpha = 1) {
    return {x, y, r, col, alpha, alphaTarget: alpha};
}

Затем в функции drawContent рисуйте круги по одному

function drawContent() {
    for (const circle of circles) {
        if(circle.alpha !== circle.alphaTarget) {
           const aStep = circle.alphaTarget - circle.alpha;
           const dir = Math.sign(aStep);
           circle.alpha += Math.min(Math.abs(aStep), dir * 0.02)) * dir;
        }  
        drawCircle(circle.x, circle.y, circle.r, circle.col, circle.alpha);
    }
 }

Демо

Демо рисует 100 кругов, каждый со своим цветом и альфой. Альфа выбирается случайным образом, чтобы исчезнуть, а затем снова появиться.

Вам понадобится цикл рендеринга, если вы хотите анимировать содержимое холста.

Я перемещаю круг так, чтобы, если устройство будет медленно отображать контент, было бы легче увидеть низкую частоту кадров.

Math.TAU = Math.PI * 2;  // set up 2 PI
Math.rand = (val) => Math.random() * val;
Math.randI = (val) => Math.random() * val | 0;
requestAnimationFrame(mainLoop);  

const ctx = canvas.getContext("2d");
const W = canvas.width = innerWidth; // size canvas to page
const H = canvas.height = innerHeight; // size canvas to page
const circleCount = 100;
const circleFadeRate = 0.01; // per 60th second

const circles = [];
const circle = (x,y,r = 10, col = "#FFF", alpha = 1) => ({x, y, r, col, alpha, alphaTarget: alpha});
createCircles();
function createCircles() {
    var i = circleCount;
    while (i--) {
        circles.push(circle(Math.rand(W), Math.rand(H), Math.rand(10) + 10, "#" + Math.randI(0xFFF).toString(16).padStart(3,"0"), 1));
     }
     circles.sort((a,b) => a.r - b.r); // big drawn last
}
function mainLoop() {
    ctx.globalAlpha = 1;
    ctx.clearRect(0, 0, W, H);  
    drawContent(); 
    requestAnimationFrame(mainLoop); 
}
function drawCircle(x, y, radius, color, alpha = 1) {
    ctx.globalAlpha = alpha;
    ctx.fillStyle = color;
    ctx.strokeStyle = "#000";
    ctx.lineWidth = 2;
    ctx.beginPath();
    ctx.arc(x, y, radius, 0, Math.TAU);
    ctx.fill();
    ctx.stroke();
}
function drawContent() {
    for (const circle of circles) {
        if(circle.alpha !== circle.alphaTarget) {
           const aStep = circle.alphaTarget - circle.alpha;
           const dir = Math.sign(aStep);
           circle.alpha += Math.min(Math.abs(aStep), 0.02) * dir;
        } else if(Math.random() < 0.01) {
           circle.alphaTarget = circle.alpha < 0.7 ? 1 : Math.random() * 0.4;
        }
        circle.y += (circle.r - 10) / 5;
        circle.y = circle.y > H + circle.r + 2 ? -(circle.r + 2) : circle.y;
        drawCircle(circle.x, circle.y, circle.r, circle.col, circle.alpha);
    }
 }
body {
   padding: 0px;
}
canvas {
   position: absolute;
   top: 0px;
   left: 0px;
}
<canvas id="canvas"></canvas>

Для получения дополнительной информации об API 2D-холста см. ссылку в верхней части этого ответа.

person Blindman67    schedule 31.12.2019

Холст – это поверхность для рисования. Это означает, что вы не можете изменить его после того, как нарисуете. Его можно только очистить или закрасить. Как и в случае с настоящей картиной, вы не можете изменить цвет мазка, который вы уже нарисовали.

Таким образом, вы должны очистить холст, а затем перерисовать его. все, за исключением того, что на этот раз нарисуйте несколько кругов с разной непрозрачностью. Просто измените последнее число в этих значениях rgba, чтобы оно было между 0 и 1, чтобы изменить непрозрачность.

Сохраните непрозрачность в переменной где-нибудь:

var circleOpacity = 1;

Измените непрозрачность, а затем перерисуйте функцию интервала:

circleOpactiy -= 0.2;
drawMyCanvas();

Теперь нарисуйте несколько частей с помощью fillStyle что-то вроде:

ctx.fillStyle = shouldBeFaded ? `rgba(0,0,0,${circleOpacity})` : 'rgba(0,0,0,1)'

В качестве альтернативы вы можете расположить два холста так, чтобы они находились друг над другом, и вы можете затенить верхний, как вы уже делаете. Таким образом, вам не придется постоянно перерисовывать холст. Если единственное, что вы хотите сделать, это скрыть некоторые круги, это может быть проще. Но если вы хотите сделать что-то более сложное на этом холсте (например, визуализировать какую-то игру), вы все равно захотите перерисовывать холст каждый кадр анимации.

person Alex Wayne    schedule 31.12.2019