web-dev-qa-db-ja.com

html5で紙吹雪効果を作成しようとすると、各要素に異なる塗りつぶし色を取得するにはどうすればよいですか?

編集:

好奇心が強い人のために、ここに完成した結果があります。

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


私はこのリンクで見つけたコードから構築しています

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

これを雪の効果よりも紙吹雪の落下効果にしたいので、各要素を異なる色にする必要があります。しかし、塗りつぶし色はキャンバス全体に一度に設定されているようです。

各要素に異なる塗りつぶし色を指定する方法はありますか、それとも完全に間違った方法ですか?

ありがとう

更新:誰かが紙吹雪を必要とする場合の完成品はこちらです

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

}

21
Smeegs

次のように試してください: http://jsfiddle.net/vxP5q/

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

私がやったこと。ピクセルが生成される場所に、一意の(ランダムな)色を追加しました。更新がある場合は、色が変更されていることを確認し、その描画されている場所を変更して、紙吹雪アイテムごとにインクのないパスを作成します。

5
Niels

すばらしい質問です。サンプルの描画ループを考えてみます。

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

それはoneパスを作成し、多くの弧を追加し、それをone回埋めます。

変更するには、パーティクルごとに1回塗りつぶす必要があります。また、各パーティクルに一意の色を指定することもできます。

_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();
}
_

beginPath()fill()がループ内にどのように追加されたかに注意してください。各アークには独自のパスと塗りつぶしが必要なので、これは重要です。これは、すべてを1つのパスで作成するよりもはるかに低速ですが、異なる色のパーティクルが必要な場合に必要です。

その_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)"
})
_

これが実際の例です:

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

3
Simon Sarris

これはNielsによる投稿に基づいたバージョンです。呼び出して任意のページに追加できる再利用可能なオブジェクトが必要でした。

使用法:

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

コード:

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:

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