javascript - 使用 JavaScript 在 HTML5 canvas 上绘制多个下降的圆圈

标签 javascript html canvas

//read where the click is made
$(document).click(function(e) { 
    var x = event.clientX;
    var y = event.clientY;
    drawCircle(x,y);
});


//array used for random colors of circles
var color = ["#E72B8E", "#238A9B", "#F05C3F"];  

//setting canvas and its size
var c = document.getElementById("canvas");

c.width  = window.innerWidth;
c.height = window.innerHeight;

var ctx = c.getContext("2d");

//function to draw circles
function drawCircle(x,y){

    //randomly chose color and size for circles
    var randC = color[Math.floor(Math.random() * color.length)];
    var randS = Math.floor(Math.random() * (80 - 30)) + 30;

    //draw circles
    ctx.beginPath();
    ctx.arc(x,y,randS,0,2*Math.PI);

    //make gradient for random color and fill
    var grd=ctx.createLinearGradient(0,0,170,0);
    grd.addColorStop(0,randC);
    grd.addColorStop(1,"transparent");

    ctx.fillStyle=grd;
    ctx.fill();
    ctx.closePath();
}

因此,我要做的是每次在 Canvas 上单击并使其落下时绘制一个圆圈。

我的第一个问题是我卡在如何让我的圈子留在 Canvas 上。每次点击,我都会画一个新的圆,但是之前画的圆没有了。因此,我尝试在 drawCircle 函数之外添加用于设置 Canvas 的行,因此它不会在函数调用时重置 Canvas 。现在点击根本不会画一个圆圈。将这些行放在函数之外会影响什么吗?

我的第二个问题是我想要渐变圆圈,从 100% 颜色到透明,但渐变似乎是相对于圆圈在 Canvas 中的位置。例如,如果我点击框架的左边缘,渐变会完全按照我想要的方式出现,但随着它变得更右,渐变的透明部分会变大,一旦我点击框架的中间框架,我根本看不到圆圈。渐变的透明部分对我来说似乎有点黑。我该怎么做才能修复它?

最后,一旦我完全弄清楚如何按照我想要的方式绘制多个圆圈,我最终会让它们像雪花一样落下。有没有可以促进它的功能?

非常感谢!

最佳答案

每次渲染一个可能很慢的圆时,您都可以创建一个新的渐变设置到圆的位置。或者您可以在位置 0,0 和固定半径处创建一个渐变,然后使用变换将渐变和圆移动到正确的位置。

要为许多对象设置动画,您需要创建一个对象数组,循环遍历每个项目以更新位置,然后进行绘制。您可以在同一个函数中执行更新和绘制,但是当事情变得更复杂时,最好将更新和绘制分开。

// get the 2D context
const ctx = canvas.getContext("2d");

// listen to click events adding ball for each click
canvas.addEventListener("click",(e)=>{ circles.add(e.pageX,e.pageY,20) });

// define a gradient for circles
const gradientRadius = 10;
const grad = ctx.createRadialGradient(0,0,0,0,0,gradientRadius); // gradient 10 pixels radius at 0,0
grad.addColorStop(1,"rgba(255,0,0,0)");
grad.addColorStop(0,"rgba(0,0,0,1)");

const gravity = 0.9; // gravity acceleration

// draws a circle using grad (above)
function drawCircle(x,y,radius){
    var scale = radius / gradientRadius;
    ctx.fillStyle = grad;
    ctx.setTransform(scale, 0, 0, scale, x, y);
    ctx.beginPath();
    ctx.arc(0, 0, radius / scale, 0, Math.PI * 2);
    ctx.fill();
}

// this object handles all circles. Circles are stored in the array circles.items
// the function update and draw both return the circles object so that they
// can be chained.
const circles = {
    items : [], // array of circles
    add(x,y,radius){
        var circle;
        circles.items.push(circle = {
            x,y,radius,
            dx : 0,  // delta x and y (movement per frame
            dy : 0, 
        });
        return circle;
    },
    update(){
        var i,c;
        for(i = 0; i < circles.items.length; i++){
            c = circles.items[i]; // get the circle
            c.dy += gravity;
            c.x += c.dx;
            c.y += c.dy;
            // simulate bounce.. This is the most basic, search SO for better methods
            if(c.y + c.radius > ctx.canvas.height){
                c.y = ctx.canvas.height - c.radius;
                c.dy = -Math.abs(c.dy);  // window resize may cause ball to be moving up when
                                         // it hits the bottom so need to ensure the bounce is
                                         // away from the bottom with Math.abs
            }
        }
        return circles;
    },
    draw(){
        var i,c;
        for(i = 0; i < circles.items.length; i++){
            c = circles.items[i]; // get the circle
            drawCircle(c.x,c.y,c.radius);
        }
        return circles;
    }
}

// main animation loop called once every 1/60th second (if possible)
// It checks if the widow size matches the canvas and will resize it
// if not.
// Then clears the canvas and updates and draws the circles.
// Then requests the next animation frame
function mainLoop(time){
    if(canvas.width !== innerWidth || canvas.height !== innerHeight){ // resize canvas if window size has changed
        canvas.width = innerWidth;
        canvas.height = innerHeight;
    }
    ctx.setTransform(1,0,0,1,0,0); // set default transform
    ctx.clearRect(0,0,canvas.width,canvas.height); // clear the canvas
    circles.update().draw();
    requestAnimationFrame(mainLoop);
}
requestAnimationFrame(mainLoop);
canvas {
   position : absolute;
   top : 0px;
   left : 0px;
}
Click to add circle.
<canvas id=canvas></canvas>

关于javascript - 使用 JavaScript 在 HTML5 canvas 上绘制多个下降的圆圈,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44223389/

相关文章:

javascript - 将简单的标记聚类器添加到谷歌地图

javascript - 如何在vue js中更改css背景?

CSS 导航选项卡显示在文本后面而不是前景中

asp.net - 是否可以在源代码中使用带有本地主机地址的 iframe?

javascript - 多个色标之间的平滑颜色过渡

javascript - 将文本框绑定(bind)到带有图像的响应式 Canvas

javascript - 抑制或解决 goog.base 中的编译器错误

javascript - 嵌套函数无法访问 requirejs 回调参数

html - Webfont位置渲染问题

python - tkinter( python ): assign class method to a key