繁体   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