简体   繁体   English

如何连续旋转画布圆圈?

[英]How to rotate a canvas circle continuously?

https://codepen.io/saketkr7/pen/KKmzXOV I have a circle canvas in which n items are placed, I want to rotate all items placed? https://codepen.io/saketkr7/pen/KKmzXOV我有一个圆形画布,其中放置了 n 个项目,我想旋转放置的所有项目? How can I do that?我怎样才能做到这一点?

[![` [![`

 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 `] 1 ] 1

requestAnimationFrame请求动画帧

Use requestAnimationFrame(callback) (rAF) to render the animation.使用requestAnimationFrame(callback) (rAF) 来渲染动画。

The callback function is responsible for rendering each animation frame.回调函数负责渲染每个动画帧。 In this case it will clear the canvas and draw the circles.在这种情况下,它将清除画布并绘制圆圈。

The callback function gets the time in milliseconds (1/1000th seconds).回调函数以毫秒(1/1000 秒)为单位获取时间。 You can use that to set the rotation angle.您可以使用它来设置旋转角度。 The first example uses the time and the constant rate to define the number of rotations per second.第一个示例使用time和恒定rate来定义每秒的旋转次数。

In the callback function you need to request the new frame by calling rAF.在回调函数中,您需要通过调用 rAF 来请求新帧。

To start the animation request the first frame.开始动画请求第一帧。

Rendering渲染

Modify your code so that it is a function that can be called for each frame of the animation.修改您的代码,使其成为可以为动画的每一帧调用的函数。 In the example your modified code is in the function drawCircles(angle) where angle is the current rotation in radians.在示例中,您修改的代码位于函数drawCircles(angle) ,其中角度是以弧度为单位的当前旋转。

Pass it an argument that is the current rotation.向它传递一个当前旋转的参数。

Example例子

The snippet below does what is described above.下面的代码段执行上面描述的操作。

 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>

On many devices the frame rate will be very stable, you can use a fixed rate time to get a smoother animation.在许多设备上,帧速率会非常稳定,您可以使用固定速率时间来获得更流畅的动画。 As shown in next snippet.如下一个片段所示。 Be aware that time will drift if device drops frames.请注意,如果设备掉帧,时间会漂移。

 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>

Update更新

Re comments重新评论

The @MDN.API.CanvasRenderingContext2D@ is not best for 3D. @MDN.API.CanvasRenderingContext2D@ 不是 3D 的最佳选择。 The best option is to use WebGL However there is a steep learning curve for WebGL.最好的选择是使用 WebGL 但是 WebGL 有一个陡峭的学习曲线。

3D can be done on the 2D API but you need to implement all the 3D rendering code in JS which will be orders of magnitude slower than WebGl. 3D 可以在 2D API 上完成,但您需要在 JS 中实现所有 3D 渲染代码,这将比 WebGl 慢几个数量级。

3D via 2D API 3D 通过 2D API

The example below uses the 2D canvas to render a rotating ring of toon-shaded spheres rotating in 3D.下面的示例使用 2D 画布渲染以 3D 方式旋转的卡通阴影球体的旋转环。

It is the most basic example and will not support cameras, lights, textures, etc..这是最基本的示例,不支持相机、灯光、纹理等。

 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