簡體   English   中英

如何連續旋轉畫布圓圈?

[英]How to rotate a canvas circle continuously?

https://codepen.io/saketkr7/pen/KKmzXOV我有一個圓形畫布,其中放置了 n 個項目,我想旋轉放置的所有項目? 我怎樣才能做到這一點?

[![`

 const canvas = document.getElementById('myCanvas'); var items = ['a', 'b' , 'c', 'd', 'e', 'g']; const ctx = canvas.getContext('2d'); var n = 6; var numElements = 8; var angle = 0; var step = (2*Math.PI) / numElements; var rotateAngle = 36 * Math.PI / 180; for(var i = 0; i < numElements; i++) { var x = 500/2 + 100 * Math.cos(angle); var y = 500/2 + 100 * Math.sin(angle); console.log(x, y); ctx.beginPath(); ctx.arc(x, y, 10, 0, 2 * Math.PI); ctx.stroke(); angle += step; }
 <!DOCTYPE html> <html> <body> <canvas id="myCanvas" width="500" height="500"> Your browser does not support the HTML canvas tag. </canvas> </body> </html>

`] 1 ] 1

請求動畫幀

使用requestAnimationFrame(callback) (rAF) 來渲染動畫。

回調函數負責渲染每個動畫幀。 在這種情況下,它將清除畫布並繪制圓圈。

回調函數以毫秒(1/1000 秒)為單位獲取時間。 您可以使用它來設置旋轉角度。 第一個示例使用time和恆定rate來定義每秒的旋轉次數。

在回調函數中,您需要通過調用 rAF 來請求新幀。

開始動畫請求第一幀。

渲染

修改您的代碼,使其成為可以為動畫的每一幀調用的函數。 在示例中,您修改的代碼位於函數drawCircles(angle) ,其中角度是以弧度為單位的當前旋轉。

向它傳遞一個當前旋轉的參數。

例子

下面的代碼段執行上面描述的操作。

 const ctx = canvas.getContext('2d'); const rate = 0.2; // Number of rotations per second function drawCircles(angle) { var i = 0; const numElements = 8; const step = (2 * Math.PI) / numElements; ctx.beginPath(); while (i < numElements) { const x = ctx.canvas.width / 2 + 100 * Math.cos(angle + i * step); const y = ctx.canvas.height / 2 + 100 * Math.sin(angle + i * step); ctx.moveTo(x + 10, y); ctx.arc(x, y, 10, 0, 2 * Math.PI); i++; } ctx.stroke(); } requestAnimationFrame(renderLoop); // rAF to start animation function renderLoop(time) { // rAF callback ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); drawCircles(((time * Math.PI * 2) / 1000) * rate); requestAnimationFrame(renderLoop); // request next frame }
 <canvas id = "canvas" width="220" height="220"></canvas>

在許多設備上,幀速率會非常穩定,您可以使用固定速率時間來獲得更流暢的動畫。 如下一個片段所示。 請注意,如果設備掉幀,時間會漂移。

 const ctx = canvas.getContext('2d'); const rate = 0.2; // APPROX Number of rotations per second var frame = 0; // counts frames function drawCircles(angle) { var i = 0; const numElements = 8; const step = (2 * Math.PI) / numElements; ctx.beginPath(); while (i < numElements) { const x = ctx.canvas.width / 2 + 100 * Math.cos(angle + i * step); const y = ctx.canvas.height / 2 + 100 * Math.sin(angle + i * step); ctx.moveTo(x + 10, y); ctx.arc(x, y, 10, 0, 2 * Math.PI); i++; } ctx.stroke(); } requestAnimationFrame(renderLoop); // rAF to start animation function renderLoop() { // rAF callback ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); time = frame++ * (1000 / 60); // Assumes 60 fps drawCircles(((time * Math.PI * 2) / 1000) * rate); requestAnimationFrame(renderLoop); // request next frame }
 <canvas id = "canvas" width="220" height="220"></canvas>

更新

重新評論

@MDN.API.CanvasRenderingContext2D@ 不是 3D 的最佳選擇。 最好的選擇是使用 WebGL 但是 WebGL 有一個陡峭的學習曲線。

3D 可以在 2D API 上完成,但您需要在 JS 中實現所有 3D 渲染代碼,這將比 WebGl 慢幾個數量級。

3D 通過 2D API

下面的示例使用 2D 畫布渲染以 3D 方式旋轉的卡通陰影球體的旋轉環。

這是最基本的示例,不支持相機、燈光、紋理等。

 const ctx = canvas.getContext('2d'); const rate = 0.2; // APPROX Number of rotations per second const numCircles = 18; const perspectiveRange = 300; // dist between front and back planes const ringRadius = 60; // in pixels const circleRadius = 10; // in pixels. Radius of circle at z === 0 const colors = [["#B11", "#F22"], ["#DB0", "#FF0"]]; var frame = 0; // counts frames function drawCircles(angle, rotY) { // rotZ rotates around Y axis (in and out of screen) var i = 0; ctx.fillStyle = "#FF0"; const step = (2 * Math.PI) / numCircles; const circles = []; // The transform for y rotation const dx = Math.cos(rotY); const dy = Math.sin(rotY); // get 3D location of each circle while (i < numCircles) { const x = ringRadius * Math.cos(angle + i * step); const y = ringRadius * Math.sin(angle + i * step); circles.push({x: x * dx, y, z: x * dy, colIdx: i % 2}); i++; } // sort circles from back to front circles.sort((a, b) => bz - az); // center on canvas ctx.setTransform(1,0,0,1, ctx.canvas.width / 2, ctx.canvas.height / 2); // draw 3D circles with perspective for (const c of circles) { const col = colors[c.colIdx]; // Calculate perspective scale. The further from the front the // smaller the perspective scale const p = (perspectiveRange - cz) / perspectiveRange; // Scale radius, x, y pos and line with by perspective scale const r = Math.abs(p * circleRadius); const x = p * cx; const y = p * cy; ctx.lineWidth = 1.5 * p; // shaded color ctx.fillStyle = col[0]; ctx.beginPath(); ctx.arc(x, y, r, 0, 2 * Math.PI); ctx.fill(); ctx.stroke(); // highlight color ctx.fillStyle = col[1]; ctx.beginPath(); ctx.arc(x - r * 0.1, y - r * 0.1, r * 0.8, 0, 2 * Math.PI); ctx.fill(); ctx.fillStyle = "#FFFA"; ctx.beginPath(); ctx.arc(x - r * 0.3, y - r * 0.3, r * 0.3, 0, 2 * Math.PI); ctx.fill(); } // reset canvas transform ctx.setTransform(1,0,0,1,0, 0); } requestAnimationFrame(renderLoop); // rAF to start animation function renderLoop() { // rAF callback ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); time = frame++ * (1000 / 60); // Assumes 60 fps const ang = ((time * Math.PI * 2) / 1000) * rate drawCircles(ang, ang / 2); requestAnimationFrame(renderLoop); // request next frame }
 <canvas id = "canvas" width="180" height="180"></canvas>

暫無
暫無

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

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