簡體   English   中英

如何在 html 畫布中為多個點設置動畫

[英]How to animate several dots moving here and there in html canvas

我需要在畫布內到處移動許多點。

因此,我創建了幾個具有不同半徑的弧並將它們放置在隨機位置。

 var context = document.getElementById('stage').getContext('2d'); var radian = Math.PI / 180; var x = 40; var y = 40; var r = 20; var colorPoints = []; var frames = 50; var currentFrame = 0; var toggle = false; var iconsLoaded = false; context.beginPath(); context.arc(x,y, r, 0 * radian, 360 * radian, false) context.fill(); var drawMultipleCurves = function(ctx){ if(!iconsLoaded){ for (let i = 0; i < 600; i++) { ctx.beginPath(); ctx.filter = 'blur(5px)'; ctx.fillStyle = '#B835FF'; colorPoints.push({x: Math.floor((Math.random() * 700) + 0), xMove: Math.floor((Math.random() * 2) + 0) , yMove: Math.floor((Math.random() * 2) + 0) , y: Math.floor((Math.random() * 700) + 0), radius: Math.floor((Math.random() * 20) + 5)}); ctx.arc(colorPoints[colorPoints.length - 1].x, colorPoints[colorPoints.length - 1].y, colorPoints[colorPoints.length - 1].radius, 0 * radian, 360 * radian, false); ctx.fill(); ctx.closePath(); iconsLoaded = true; } } else{ for(let i =0;i< colorPoints.length; i++){ if(frames === currentFrame ){ toggle = !toggle; currentFrame = 0; } if(!toggle){ colorPoints[i].xMove === 1 ? colorPoints[i].x = colorPoints[i].x + 5 : colorPoints[i].x = colorPoints[i].x - 5; colorPoints[i].yMove === 1 ? colorPoints[i].y = colorPoints[i].y + 5 : colorPoints[i].y = colorPoints[i].y - 5; } else{ colorPoints[i].xMove === 1 ? colorPoints[i].x = colorPoints[i].x - 5 : colorPoints[i].x = colorPoints[i].x + 5; colorPoints[i].yMove === 1 ? colorPoints[i].y = colorPoints[i].y - 5 : colorPoints[i].y = colorPoints[i].y + 5; } ctx.beginPath(); ctx.arc(colorPoints[i].x, colorPoints[i].y, colorPoints[i].radius, 0 * radian, 360 * radian, false); context.closePath( ); ctx.fill(); currentFrame = currentFrame + 1; } } } var animate = function(){ setTimeout(()=>{ context.clearRect(0,0,400,400); context.beginPath(); drawMultipleCurves(context); context.fill(); requestAnimationFrame(animate) }, 1000/30) } requestAnimationFrame(animate)
 <canvas id="stage" width="400" height="400"> <p>Your browser doesn't support canvas.</p> </canvas>

以上是我嘗試過的代碼。 我首先在隨機半徑的隨機位置創建並放置了幾個點。 當我創建它們時,我將所有這些隨機位置保存在數組“colorPoints”中

現在我循環進入這個數組並在每次調用“requestAnimation”時移動所有的點。

我能夠實現隨機移動點的動畫,但是由於我使用了 800 個點,然后將它們保存到數組中,然后再次循環它們以移動它們的位置,因此動畫看起來並不流暢。

它看起來像在移動和撞擊。 我怎樣才能順利實現這個動畫?

提前致謝 :)

每種樣式渲染一次“填充”

由於放置fill的位置,您的代碼速度變慢(如果使用stroke則相同)

當您有許多具有相同樣式的對象時,每個對象每幀只調用一次fill

你有類似的東西

  for (const c of circles) { 
      ctx.beginPath();
      ctx.arc(c.x, c.y, c.r, 0, TAU) 
      ctx.fill();
  }

激活過濾器后,填充命令會強制重置過濾器,這對於模糊來說很復雜。

而是添加所有弧然后填充。

   ctx.beginPath();
   for (const c of circles) { 
      ctx.moveTo(c.x + c.r, c.y);
      ctx.arc(c.x, c.y, c.r, 0, TAU) 
   }
   ctx.fill();

移動ctx.moveTo(cx + cr, cy); 用於關閉前一個弧。

您也可以使用ctx.closePath關閉弧,但是當路徑緩沖區中有許多弧時,這可能會慢很多。

   // slower than using moveTo
   ctx.beginPath();
   for (const c of circles) { 
      ctx.arc(c.x, c.y, c.r, 0, TAU) 
      ctx.closePath();
   }
   ctx.fill();

例子

示例使用模糊濾鏡繪制 600 條弧線,因為它每幀只調用一次fill 除了最低端的設備外,這應該可以在所有設備上順利運行。

參見函數drawCircles

 requestAnimationFrame(animate); const ctx = canvas.getContext('2d'); const W = canvas.width; const BLUR = 5; const CIRCLE_COUNT = 600; const MIN_RADIUS = BLUR; const MAX_RADIUS = 30; const MAX_DELTA = 1; const MAX_CIR_R = MAX_RADIUS + BLUR; const MOVE_SIZE = MAX_CIR_R * 2 + W; const TAU = 2 * Math.PI; const setOf = (c, cb, i = 0, a = []) => { while(i < c) { a.push(cb(i++)) } return a }; const rnd = (m, M) => Math.random() * (M - m) + m; const style = { filter: "blur(" + BLUR + "px)", fillStyle: '#B835FF', }; var currentStyle; function setStyle(ctx, style) { if (currentStyle !== style) { Object.assign(ctx, style); currentStyle = style; } } const circle = { get x() { return rnd(-MAX_CIR_R, W + MAX_CIR_R) }, get y() { return rnd(-MAX_CIR_R, W + MAX_CIR_R) }, get dx() { return rnd(-MAX_DELTA, MAX_DELTA) }, get dy() { return rnd(-MAX_DELTA, MAX_DELTA) }, get r() { return rnd(MIN_RADIUS, MAX_RADIUS) }, move() { var x = this.x + this.dx + MOVE_SIZE + MAX_CIR_R; var y = this.y + this.dy + MOVE_SIZE + MAX_CIR_R; this.x = x % MOVE_SIZE - MAX_CIR_R; this.y = y % MOVE_SIZE - MAX_CIR_R; } }; const circles = setOf(CIRCLE_COUNT, () => Object.assign({}, circle)); function drawCircles(circles, ctx, style) { setStyle(ctx, style); ctx.beginPath(); for (const c of circles) { ctx.moveTo(cx + cr, cy); ctx.arc(cx, cy, cr, 0, TAU); } ctx.fill(); } function updateCircles(circles) { for (const c of circles) { c.move(); } } function animate() { ctx.clearRect(0,0,W, W); updateCircles(circles); drawCircles(circles, ctx, style); requestAnimationFrame(animate); }
 <canvas id="canvas" width="600" height="600"> </canvas>

如果您有多種顏色,請將所有相同的顏色分組,這樣您就可以將填充調用的數量保持在盡可能低的水平。

有很多方法可以通過多種顏色獲得相同的效果(每個圓圈都有不同的顏色),但需要更多設置代碼。

CanvasRenderingContext2D模糊濾鏡非常重 - 特別是如果您在由 600 個圓圈組成的畫布上使用它。 這意味着在每次屏幕更新時,它必須重新繪制 600 個圓圈並在之后應用模糊濾鏡。

通常的方法有點不同。 最初,您創建一個帶有模糊圓圈的主紋理。 然后可以使用drawImage()方法重新使用此紋理並將其繪制到畫布上。 為了改變圓的大小,不再有radius了。 我們可以通過使用scale來獲得相同的效果。

這是一個例子:

 var context = document.getElementById('stage').getContext('2d'); var radian = Math.PI / 180; var x = 40; var y = 40; var r = 20; var colorPoints = []; var frames = 50; var currentFrame = 0; var toggle = false; var iconsLoaded = false; var texture = document.createElement("canvas"); var textureContext = texture.getContext("2d"); texture.width = 80; texture.height = 80; textureContext.filter = 'blur(5px)'; textureContext.fillStyle = '#B835FF'; textureContext.arc(texture.width / 2, texture.height / 2, 25, 0 * radian, 360 * radian, false); textureContext.fill(); textureContext.closePath(); var drawMultipleCurves = function(ctx) { if (!iconsLoaded) { for (let i = 0; i < 600; i++) { colorPoints.push({ x: Math.floor((Math.random() * 700) + 0), xMove: Math.floor((Math.random() * 2) + 0), yMove: Math.floor((Math.random() * 2) + 0), y: Math.floor((Math.random() * 700) + 0), scale: 0.2 + Math.random() * 0.8 }); iconsLoaded = true; } } else { for (let i = 0; i < colorPoints.length; i++) { if (frames === currentFrame) { toggle = !toggle; currentFrame = 0; } if (!toggle) { colorPoints[i].xMove === 1 ? colorPoints[i].x = colorPoints[i].x + 5 : colorPoints[i].x = colorPoints[i].x - 5; colorPoints[i].yMove === 1 ? colorPoints[i].y = colorPoints[i].y + 5 : colorPoints[i].y = colorPoints[i].y - 5; } else { colorPoints[i].xMove === 1 ? colorPoints[i].x = colorPoints[i].x - 5 : colorPoints[i].x = colorPoints[i].x + 5; colorPoints[i].yMove === 1 ? colorPoints[i].y = colorPoints[i].y - 5 : colorPoints[i].y = colorPoints[i].y + 5; } ctx.drawImage(texture, colorPoints[i].x, colorPoints[i].y, texture.width * colorPoints[i].scale, texture.height * colorPoints[i].scale); currentFrame = currentFrame + 1; } } } var animate = function() { setTimeout(() => { context.clearRect(0, 0, 400, 400); context.beginPath(); drawMultipleCurves(context); context.fill(); requestAnimationFrame(animate) }) } requestAnimationFrame(animate)
 <canvas id="stage" width="400" height="400"> <p>Your browser doesn't support canvas.</p> </canvas>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM