Как да добавите ефект на избледняване само към определени елементи на 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)


Страхотен ресурс за canvas 2d е CanvasRenderingContext2D на MDN

Анимации с помощта на канава.

Ще ви е необходим цикъл за рендиране, ако искате да анимирате съдържание на платно.

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

Основният цикъл изчиства платното, след това рисува анимираното съдържание, след което изисква следващия кадър.

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