javascript 尝试在 html5 中创建五彩纸屑效果,如何为每个元素获得不同的填充颜色?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16322869/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 04:12:12  来源:igfitidea点击:

Trying to create a confetti effect in html5, how do I get a different fill color for each element?

javascripthtmlcanvashtml5-canvas

提问by Smeegs

EDIT:

编辑:

For anybody who is curious, here is the finished result.

对于任何好奇的人,这是最终结果。

http://jsfiddle.net/Javalsu/vxP5q/743/embedded/result/

http://jsfiddle.net/Javalsu/vxP5q/743/embedded/result/



I'm building off of the code I found in this link

我正在构建我在此链接中找到的代码

http://thecodeplayer.com/walkthrough/html5-canvas-snow-effect

http://thecodeplayer.com/walkthrough/html5-canvas-snow-effect

I want to make this more of a confetti falling effect than a snow effect, and I would need to make each element a different color. But it seems that the fill color is set for entire canvas at once.

我想让这更像是一种五彩纸屑掉落效果而不是雪效果,我需要让每个元素都变成不同的颜色。但似乎一次为整个画布设置了填充颜色。

Is there a way to specify a different fill color for each element or am I going about this the entirely wrong way?

有没有办法为每个元素指定不同的填充颜色,或者我是否以完全错误的方式解决这个问题?

Thanks

谢谢

Update: Here is the finished product if anybody has a need for confetti

更新:如果有人需要五彩纸屑,这里是成品

http://jsfiddle.net/mj3SM/6/

http://jsfiddle.net/mj3SM/6/

window.onload = function () {
//canvas init
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

//canvas dimensions
var W = window.innerWidth;
var H = window.innerHeight;
canvas.width = W;
canvas.height = H;

//snowflake particles
var mp = 200; //max particles
var particles = [];
for (var i = 0; i < mp; i++) {
    particles.push({
        x: Math.random() * W, //x-coordinate
        y: Math.random() * H, //y-coordinate
        r: Math.random() * 15 + 1, //radius
        d: Math.random() * mp, //density
        color: "rgba(" + Math.floor((Math.random() * 255)) + ", " + Math.floor((Math.random() * 255)) + ", " + Math.floor((Math.random() * 255)) + ", 0.8)",
        tilt: Math.floor(Math.random() * 5) - 5
    });
}

//Lets draw the flakes
function draw() {
    ctx.clearRect(0, 0, W, H);



    for (var i = 0; i < mp; i++) {
        var p = particles[i];
        ctx.beginPath();
        ctx.lineWidth = p.r;
        ctx.strokeStyle = p.color; // Green path
        ctx.moveTo(p.x, p.y);
        ctx.lineTo(p.x + p.tilt + p.r / 2, p.y + p.tilt);
        ctx.stroke(); // Draw it
    }

    update();
}

//Function to move the snowflakes
//angle will be an ongoing incremental flag. Sin and Cos functions will be applied to it to create vertical and horizontal movements of the flakes
var angle = 0;

function update() {
    angle += 0.01;
    for (var i = 0; i < mp; i++) {
        var p = particles[i];
        //Updating X and Y coordinates
        //We will add 1 to the cos function to prevent negative values which will lead flakes to move upwards
        //Every particle has its own density which can be used to make the downward movement different for each flake
        //Lets make it more random by adding in the radius
        p.y += Math.cos(angle + p.d) + 1 + p.r / 2;
        p.x += Math.sin(angle) * 2;

        //Sending flakes back from the top when it exits
        //Lets make it a bit more organic and let flakes enter from the left and right also.
        if (p.x > W + 5 || p.x < -5 || p.y > H) {
            if (i % 3 > 0) //66.67% of the flakes
            {
                particles[i] = {
                    x: Math.random() * W,
                    y: -10,
                    r: p.r,
                    d: p.d,
                    color: p.color,
                    tilt: p.tilt
                };
            } else {
                //If the flake is exitting from the right
                if (Math.sin(angle) > 0) {
                    //Enter from the left
                    particles[i] = {
                        x: -5,
                        y: Math.random() * H,
                        r: p.r,
                        d: p.d,
                        color: p.color,
                        tilt: p.tilt
                    };
                } else {
                    //Enter from the right
                    particles[i] = {
                        x: W + 5,
                        y: Math.random() * H,
                        r: p.r,
                        d: p.d,
                        color: p.color,
                        tilt: p.tilt
                    };
                }
            }
        }
    }
}

//animation loop
setInterval(draw, 20);

}

}

采纳答案by Niels

Try it like this: http://jsfiddle.net/vxP5q/

像这样尝试:http: //jsfiddle.net/vxP5q/

The JS:

JS:

window.onload = function(){
//canvas init
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

//canvas dimensions
var W = window.innerWidth;
var H = window.innerHeight;
canvas.width = W;
canvas.height = H;

//snowflake particles
var mp = 25; //max particles
var particles = [];
for(var i = 0; i < mp; i++)
{
    particles.push({
        x: Math.random()*W, //x-coordinate
        y: Math.random()*H, //y-coordinate
        r: Math.random()*4+1, //radius
        d: Math.random()*mp, //density
        color: "rgba(" + Math.floor((Math.random() * 255)) +", " + Math.floor((Math.random() * 255)) +", " + Math.floor((Math.random() * 255)) + ", 0.8)"
    })
}

//Lets draw the flakes
function draw()
{
    ctx.clearRect(0, 0, W, H);



    for(var i = 0; i < mp; i++)
    { 
        var p = particles[i];
        ctx.beginPath();
        ctx.fillStyle = p.color;
        ctx.moveTo(p.x, p.y);
        ctx.arc(p.x, p.y, p.r, 0, Math.PI*2, true);
        ctx.fill();
    }

    update();
}

//Function to move the snowflakes
//angle will be an ongoing incremental flag. Sin and Cos functions will be applied to it to create vertical and horizontal movements of the flakes
var angle = 0;
function update()
{
    angle += 0.01;
    for(var i = 0; i < mp; i++)
    {
        var p = particles[i];
        //Updating X and Y coordinates
        //We will add 1 to the cos function to prevent negative values which will lead flakes to move upwards
        //Every particle has its own density which can be used to make the downward movement different for each flake
        //Lets make it more random by adding in the radius
        p.y += Math.cos(angle+p.d) + 1 + p.r/2;
        p.x += Math.sin(angle) * 2;

        //Sending flakes back from the top when it exits
        //Lets make it a bit more organic and let flakes enter from the left and right also.
        if(p.x > W+5 || p.x < -5 || p.y > H)
        {
            if(i%3 > 0) //66.67% of the flakes
            {
                particles[i] = {x: Math.random()*W, y: -10, r: p.r, d: p.d, color : p.color};
            }
            else
            {
                //If the flake is exitting from the right
                if(Math.sin(angle) > 0)
                {
                    //Enter from the left
                    particles[i] = {x: -5, y: Math.random()*H, r: p.r, d: p.d, color: p.color};
                }
                else
                {
                    //Enter from the right
                    particles[i] = {x: W+5, y: Math.random()*H, r: p.r, d: p.d, color : p.color};
                }
            }
        }
    }
}

//animation loop
setInterval(draw, 33);
}

What I've done. Where the pixels are generated I've added an unique (random) color. Where the update is, I'm making sure the colors are changed and where its drawn I've changed it so that it will create an inuque path for each confetti item.

我所做的。在生成像素的地方,我添加了一种独特的(随机)颜色。更新在哪里,我确保颜色被改变,它的绘制位置我已经改变了它,以便它为每个五彩纸屑项目创建一个不合适的路径。

回答by Simon Sarris

Great question. Consider the drawing loop for the sample:

很好的问题。考虑示例的绘图循环:

ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
ctx.beginPath();
for(var i = 0; i < mp; i++)
{
  var p = particles[i];
  ctx.moveTo(p.x, p.y);
  ctx.arc(p.x, p.y, p.r, 0, Math.PI*2, true);
}
ctx.fill();

It is making onepath, adding many arcs, and then filling it one time.

它正在制作一条路径,添加许多弧线,然后填充一次

To change it you will need to fill it once per particle instead. You'll also want to give each particle a unique color:

要更改它,您需要为每个粒子填充一次。您还需要为每个粒子赋予独特的颜色:

for (var i = 0; i < mp; i++) {
    var p = particles[i];
    ctx.fillStyle = p.color;
    ctx.beginPath();        
    ctx.moveTo(p.x, p.y);
    ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2, true);
    ctx.fill();
}

Note how beginPath()and fill()are now insidethe loop. This is important, because each arc needs its own path and fill. This is much slower than making them all with one path, but is necessary if you want different colored particles.

请注意 howbeginPath()fill()now循环内。这很重要,因为每个弧都需要自己的路径和填充。这比用一条路径制作它们要慢得多,但如果你想要不同颜色的粒子,这是必要的。

That p.color:

p.color

particles.push({
    x: Math.random() * W, //x-coordinate
    y: Math.random() * H, //y-coordinate
    r: Math.random() * 4 + 1, //radius
    d: Math.random() * mp, //density

    // I'm new!
    color: "rgba(" + Math.floor(Math.random()*255) +
            ", " + Math.floor(Math.random()*255) + ", 255, 0.8)"
})

Here's a working example:

这是一个工作示例:

http://jsfiddle.net/j4NZK/1/

http://jsfiddle.net/j4NZK/1/

回答by WeisserHund

Here is a version based on the post by Niels, I wanted a reusable object that I can call and add to any page.

这是一个基于 Niels 帖子的版本,我想要一个可以调用并添加到任何页面的可重用对象。

Usage:

用法:

confetti.Init(#IdofContainer(div)#, 50,25,100)

Code:

代码:

var confetti = {
angle: 0,
ctx: 0,
H: 0,
W: 0,
mp: 0,
particles: [],
endFunction: '',
Init: function (parent, maxParticles, iCount, speed, endFunct) {
    confetti.stopped = false;
    confetti.runner = null;
    confetti.endFunction = endFunct;
    var canvas = document.getElementById("confettiCanvasId");
    if (canvas) {
        canvas.parentNode.removeChild(canvas);
    }
    canvas = document.createElement('canvas');
    canvas.className = 'confettiCanvas';
    canvas.id = 'confettiCanvasId'
    $id(parent).appendChild(canvas);
    var ctx = canvas.getContext("2d");
    var W = $id(parent).clientHeight;
    var H = $id(parent).clientWidth;
    canvas.width = W;
    canvas.height = H;
    confetti.particles = [];
    for (var i = 0; i < maxParticles; i++) {
        confetti.particles.push({
            x: Math.random() * W,
            y: Math.random() * H,
            r: Math.random() * 4 + 1, //radius
            d: Math.random() * maxParticles, //density
            color: "rgba(" + Math.floor((Math.random() * 255)) + ", " + Math.floor((Math.random() * 255)) + ", " + Math.floor((Math.random() * 255)) + ", 0.8)"
        });
    }
    myCounter = new confetti.Counter({
        seconds: iCount,
        speed: speed,
        onUpdateStatus: function (sec) {
            $l(Math.random() * 255)
            ctx.clearRect(0, 0, W, H);
            for (var i = 0; i < maxParticles; i++) {
                var p = confetti.particles[i];
                ctx.beginPath();
                ctx.fillStyle = p.color;
                ctx.moveTo(p.x, p.y);
                ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2, true);
                ctx.fill();
            }

            confetti.angle += 0.01;
            for (var i = 0; i < maxParticles; i++) {
                var p = confetti.particles[i];
                p.y += Math.cos(confetti.angle + p.d) + 1 + p.r / 2;
                p.x += Math.sin(confetti.angle) * 2;
                if (p.x > W + 5 || p.x < -5 || p.y > H) {
                    if (i % 3 > 0) //66.67% of the flakes
                    {
                        confetti.particles[i] = {x: Math.random() * W, y: -10, r: p.r, d: p.d, color: p.color};
                    }
                    else {
                        if (Math.sin(confetti.angle) > 0) {
                            confetti.particles[i] = {x: -5, y: Math.random() * H, r: p.r, d: p.d, color: p.color};
                        }
                        else {
                            confetti.particles[i] = {x: W + 5, y: Math.random() * H, r: p.r, d: p.d, color: p.color};
                        }
                    }
                }
            }
        },
        onCounterEnd: function () {
            stopTimer();
            myCounter.stop();
            confetti.Stop();
        }});
    myCounter.start();
},
FadeOut:function fadeOut() {
    var alpha = 1.0;   // full opacity
    for (var i = 0; i < confetti.particles.length; i++) {
        var p = confetti.particles[i];
        interval = setInterval(function () {
            //confetti.canvas.width = confetti.canvas.width; // Clears the canvas
            p.color = "rgba(255, 0, 0, " + alpha + ")";
            alpha = alpha - 0.05; // decrease opacity (fade out)
            if (alpha < 0) {
                //confetti.canvas.width = confetti.canvas.width;
                clearInterval(interval);
            }
        }, 50);


    }
        },
Counter: function Countdown(options) {
    var timer,
        instance = this,
        seconds = options.seconds || 10,
        updateStatus = options.onUpdateStatus || function () {
        },
        counterEnd = options.onCounterEnd || function () {
        };

    function decrementCounter() {
        updateStatus(seconds);
        if (seconds === 0) {
            counterEnd();
            instance.stop();
        }
        seconds--;
    }

    this.start = function () {
        clearInterval(timer);
        timer = 0;
        seconds = options.seconds;
        timer = setInterval(decrementCounter, options.speed);
    };

    this.stop = function () {
        clearInterval(timer);
    };
},
Stop: function stop() {
    $('#confettiCanvasId').fadeOut();
    setTimeout(function(){
        var canvas = document.getElementById("confettiCanvasId");
        if (canvas) {
            canvas.parentNode.removeChild(canvas);
        }
        if (confetti.endFunction) {
            confetti.endFunction();
        }
    },1000);

}
};

CSS:

CSS:

.confettiCanvas{
overflow: hidden;
position: absolute;
height: 100%;
width: 100%;
top: 0;
left: 0;
}