【问题标题】:How to rotate a canvas circle continuously?如何连续旋转画布圈?
【发布时间】:2023-03-11 16:45:01
【问题描述】:

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

【问题讨论】:

    标签: javascript html html5-canvas


    【解决方案1】:

    requestAnimationFrame

    使用requestAnimationFrame(callback) (rAF) 来渲染动画。

    回调函数负责渲染每个动画帧。在这种情况下,它将清除画布并绘制圆圈。

    回调函数以毫秒(1/1000 秒)为单位获取时间。您可以使用它来设置旋转角度。第一个示例使用time 和常量rate 来定义每秒的旋转次数。

    在回调函数中需要通过调用 rAF 来请求新的帧。

    开始动画请求第一帧。

    渲染

    修改您的代码,使其成为可以为动画的每一帧调用的函数。在示例中,您修改后的代码位于函数 drawCircles(angle) 中,其中角度是当前旋转的弧度。

    向它传递一个当前旋转的参数。

    示例

    下面的 sn-p 做了上面描述的事情。

    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
    }
    &lt;canvas id = "canvas" width="220" height="220"&gt;&lt;/canvas&gt;

    在许多设备上,帧速率会非常稳定,您可以使用固定速率时间来获得更流畅的动画。如接下来的sn-p所示。请注意,如果设备丢帧,时间会漂移。

    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
    }
    &lt;canvas id = "canvas" width="220" height="220"&gt;&lt;/canvas&gt;

    更新

    重新计算

    @MDN.API.CanvasRenderingContext2D@ 不适合 3D。最好的选择是使用 WebGL,但是 WebGL 的学习曲线很陡峭。

    3D 可以在 2D API 上完成,但您需要在 JS 中实现所有 3D 渲染代码,这将比 WebGl 慢几个数量级。

    通过 2D API 实现 3D

    下面的示例使用 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) => b.z - a.z);
    
    // 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 - c.z) / perspectiveRange;
    
         // Scale radius, x, y pos and line with by perspective scale
         const r = Math.abs(p * circleRadius);
         const x = p * c.x;
         const y = p * c.y;
         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
    }
    &lt;canvas id = "canvas" width="180" height="180"&gt;&lt;/canvas&gt;

    【讨论】:

    • 它很有帮助,我也想在它的轴上旋转它我的意思是z轴,这怎么可能?
    • 您好,请帮助我如何像 3D(Z 轴)一样旋转此画布。
    • @SaketKumar 画布上下文CanvasRenderingContext2D 顾名思义,并不是为渲染3D 而设计的。这并不意味着它不能完成。有关更多信息,请参阅答案中的更新。
    猜你喜欢
    • 2013-09-06
    • 2019-03-03
    • 1970-01-01
    • 2018-12-16
    • 1970-01-01
    • 2015-10-22
    • 1970-01-01
    • 1970-01-01
    • 2013-03-08
    相关资源
    最近更新 更多