【问题标题】:How to add a fade effect to only certain elements on a html canvas如何仅向 html 画布上的某些元素添加淡入淡出效果
【发布时间】:2020-04-20 04:39:31
【问题描述】:

我有一个带有多个不同颜色的圆圈的画布,我只想为某些圆圈添加淡出效果。该效果只适用于红色和绿色。

代码如下

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

}


}

淡入淡出效果有效,但它会淡出整个画布而不是单个圆圈。

我怎样才能做到这一点,只有一些元素淡出。

提前致谢

【问题讨论】:

    标签: javascript html canvas html5-canvas


    【解决方案1】:

    MDN 的 CanvasRenderingContext2D 是一个很棒的 canvas 2d 资源

    使用画布的动画。

    如果您想为画布内容设置动画,则需要一个渲染循环。

    渲染循环每秒调用 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)
    }
    

    绘制圆的函数。您可以从颜色中移除 alpha 并使用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 个圆圈,每个圆圈都有自己的颜色和 alpha。 alpha 被随机选择淡出然后重新加入。

    如果您想为画布内容设置动画,则需要一个渲染循环。

    我移动了圆圈,这样如果设备渲染内容的速度很慢,那么低帧率会更容易看到。

    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;
    }
    &lt;canvas id="canvas"&gt;&lt;/canvas&gt;

    有关 2D 画布 API 的更多信息,请参阅此答案顶部的链接。

    【讨论】:

      【解决方案2】:

      画布是一个绘画表面。这意味着你不能在之后改变它。您只能清除它,或在其上涂漆。就像一幅真正的画,你不能改变你已经画的笔触的颜色。

      所以你必须clear 画布然后重新绘制它,除了这次绘制一些不透明度不同的圆圈。只需将这些 rgba 值的最后一个数字更改为介于 0 和 1 之间即可更改不透明度。

      将不透明度存储在某个变量中:

      var circleOpacity = 1;
      

      更改不透明度,然后在区间函数中重绘:

      circleOpactiy -= 0.2;
      drawMyCanvas();
      

      现在用fillStyle 画一些类似的东西:

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

      或者,您可以绝对放置两个画布,使它们彼此重叠,并且您可以像已经在做的那样淡化顶部的画布。这样您就不必不断地重新渲染画布。如果您只想淡化一些圆圈,这可能会更容易。但是,如果您想在该画布上进行更复杂的操作(例如渲染某种游戏),则无论如何您都需要在动画的每一帧中重新绘制画布。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-07
        相关资源
        最近更新 更多