简体   繁体   English

使用JavaScript在HTML5画布上绘制多个落圆

[英]Draw multiples falling circles on HTML5 canvas using JavaScript

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

So, what I'm trying to do is to draw a circle every time I click on the canvas and make it fall down. 因此,我想做的是每次单击画布并使其掉落时都画一个圆。

My first problem is that I'm stuck on how to make my circles remained on the canvas. 我的第一个问题是我坚持如何使自己的圈子停留在画布上。 Everytime I click, I get to draw a new circle, but the circle drawn previously is gone. 每次单击时,我都会绘制一个新的圆,但是先前绘制的圆消失了。 So, I tried to have lines for setting canvas outside drawCircle function, so it doesn't reset canvas whenever the function called. 因此,我尝试在drawCircle函数外部设置用于设置画布的行,因此无论何时调用该函数都不会重置画布。 And now clicking doesn't draw a circle at all. 现在单击根本不会画一个圆。 Does having those lines outside the function affect something? 函数外的那些行会影响某些东西吗?

My second problem is that I want to have gradient circle, from 100% color to transparent, but it seems that the gradient is relative to the position of the circle in the canvas. 我的第二个问题是我想使用从100%颜色到透明的渐变圆,但是渐变似乎是相对于画布中圆的位置而言的。 For example, if I click on the left edge of the frame, the gradient comes out perfectly the way I want it, but as it gets more right, the the transparent part of the gradient gets bigger and once I click on the midst of the frame, I can't see the circle at all. 例如,如果我单击框架的左边缘,则渐变会以我想要的方式完美显示,但是随着渐变的增加,渐变的透明部分会变大,一旦我单击中间的框架,我根本看不到圆圈。 And the transparent part of the gradient seems little black to me. 渐变的透明部分对我来说似乎有点黑。 What can I do to fix it? 我该如何解决?

Lastly, once I'm all good with figuring out how to draw multiples circles in the way I want, I ultimately have them fall down like one of snowflake stuff. 最后,一旦我能很好地弄清楚如何以自己想要的方式绘制倍数圆,我最终会让它们像雪花一样落下。 Is there a function that could facilitate it? 有功能可以促进它吗?

Thank you very much! 非常感谢你!

You can create a new gradient set to the position of the circle each time you render a circle which can be slow. 每次渲染较慢的圆时,都可以为圆的位置创建一个新的渐变集。 Or you can create a gradient at position 0,0 and a fixed radius and then use transform to move the gradient and circle to the correct position. 或者,您可以在位置0,0和固定半径处创建渐变,然后使用transform将渐变和圆移到正确的位置。

To animate many objects you create an array of them, looping through each items to update the position, and then to draw. 要设置许多对象的动画,请创建它们的数组,遍历每个项目以更新位置,然后绘制。 You could do the update and draw in the same function but when things get more complex its best to separate the update and draw. 您可以执行更新并绘制相同的功能,但是当事情变得更复杂时,最好将更新和绘制分开。

 // 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; cx += c.dx; cy += c.dy; // simulate bounce.. This is the most basic, search SO for better methods if(cy + c.radius > ctx.canvas.height){ cy = 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(cx,cy,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> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM