【问题标题】:HTML5 canvas divide arc into 7 equal parts and rotateHTML5画布将圆弧分成7等份并旋转
【发布时间】:2018-04-09 13:55:35
【问题描述】:

我无法将一个圆圈分成 7 个部分。 目前我有一条线穿过圆心。 然后它在画布的墙壁上旋转和弹跳。 我似乎无法弄清楚要绘制 7 个相等的线段并让它们在圆圈内旋转。 到目前为止,请参阅 sn-p。 对此的任何帮助将不胜感激。

提前致谢。

    <!DOCTYPE html>
    
    <hmtl>
      <head>
        <meta charset="UTF-8">
        <title>Canvas</title>
    <!--change cnavas border color to black-->	
    		<style type="text/css">
    		
    		canvas{	
    		border: 1px solid black;
    		}
        </style>
    
      </head>
    
      <body>
    		<!-- Canvas one used as container for canvas-->
        <canvas id="canvasOne" ></canvas>
    		<script type="text/javascript">
    			var canvas = document.getElementById("canvasOne");
        	var me = canvas.getContext("2d");
    			canvas.width  = 500;
    			canvas.height = 500;
          var animation;
          var centerX = 125;
          var centerY =125;
          var radius = 100;
          var ballDx = 2;
          var ballDy = 2;
          var theta = 0;
          var thetaInc = 0.01;
          function drawBall(){
          	me.clearRect(0,0,canvas.width,canvas.height);
            centerX = centerX + ballDx;
            centerY = centerY + ballDy;
            me.beginPath();
            me.arc(centerX,centerY,radius,0,Math.PI*2,false);
            me.stroke();
            me.fillStyle = "orange";
            me.fill();
            theta += thetaInc;
    				me.moveTo(centerX - radius*Math.cos(theta),centerY - radius*Math.sin(theta));
            me.lineTo(centerX + radius*Math.cos(theta),centerY + radius*Math.sin(theta));
            me.lineWidth = "2";
            me.lineCap = "round";
            me.strokeStyle = "black";
            me.stroke();
            if(centerY > canvas.height - radius || centerY - radius <0){
            	ballDy = -1*ballDy;
            }
            if(centerX > canvas.width - radius || centerX - radius < 0){
            	ballDx = -1*ballDx;
            }
            }
    			function animate(){ 
        		clearInterval(animation);
        		setInterval(drawBall,25);
    			}
    			animate();
        </script>
    
      </body>
    
    </html>
        
           

【问题讨论】:

    标签: javascript animation rotation html5-canvas


    【解决方案1】:

    如果我理解正确,您就快到了,但不是从圆上的一点画一条直线到直径相对的另一边,而是从中心开始,以角度theta 开始绘制七个半径,角度增量为 1 /第七圈。

    因为moveTo在画布上开始了一个新的子路径,所以你只需要在绘制完所有的半径后对它们进行描边。作为实现结果的简单修改示例:

        <!DOCTYPE html>
        
        <hmtl>
          <head>
            <meta charset="UTF-8">
            <title>Canvas</title>
        <!--change cnavas border color to black-->	
        		<style type="text/css">
        		
        		canvas{	
        		border: 1px solid black;
        		}
            </style>
        
          </head>
        
          <body>
        		<!-- Canvas one used as container for canvas-->
            <canvas id="canvasOne" ></canvas>
        		<script type="text/javascript">
        			var canvas = document.getElementById("canvasOne");
            	var me = canvas.getContext("2d");
        			canvas.width  = 500;
        			canvas.height = 500;
              var animation;
              var centerX = 125;
              var centerY =125;
              var radius = 100;
              var ballDx = 2;
              var ballDy = 2;
              var theta = 0;
              var thetaInc = 0.01;
              var seventh = (Math.PI*2)/7;     // add
              var theta2 = 0;                  // add
              function drawBall(){
              	me.clearRect(0,0,canvas.width,canvas.height);
                centerX = centerX + ballDx;
                centerY = centerY + ballDy;
                me.beginPath();
                me.arc(centerX,centerY,radius,0,Math.PI*2,false);
                me.stroke();
                me.fillStyle = "orange";
                me.fill();
                theta += thetaInc;
    
    /* removed:
        				me.moveTo(centerX - radius*Math.cos(theta),centerY - radius*Math.sin(theta));
                me.lineTo(centerX + radius*Math.cos(theta),centerY + radius*Math.sin(theta));
    */
                for( var n = 0; n < 7; ++n) {  // add loop to draw radii
                   theta2 = theta + n * seventh;
                   me.moveTo( centerX, centerY);
                   me.lineTo( centerX + radius*Math.cos(theta2), centerY + radius*Math.sin(theta2));
                }
                me.lineWidth = "2";
                me.lineCap = "round";
                me.strokeStyle = "black";
                me.stroke();
                if(centerY > canvas.height - radius || centerY - radius <0){
                	ballDy = -1*ballDy;
                }
                if(centerX > canvas.width - radius || centerX - radius < 0){
                	ballDx = -1*ballDx;
                }
                }
        			function animate(){ 
            		clearInterval(animation);
            		setInterval(drawBall,25);
        			}
        			animate();
            </script>
        
          </body>
        
        </html>
            
               

    但是,如果您需要单独为线段着色,则需要在描边或填充之前将每个线段绘制为具有两个半径和 2π/7 弧度的弧的单独路径。

    【讨论】:

    • 谢谢!!这正是我想要的
    【解决方案2】:

    创建动画实体。

    认为给定的答案有效,但这不是解决问题的最佳方法。

    实体 AKA 对象。

    如果您想添加一些旋转的文本、图像或与球相关的任何其他图形内容,该怎么办。如果你想让球在撞到墙壁时稍微压扁怎么办。如果将方向和位置作为渲染代码的一部分,这些事情都会变得很困难。

    您应该将您绘制的每个项目视为一个独立的实体(例如球)并创建一个描述球的对象,包括它的行为update 函数、样式和渲染函数draw

    该实体有自己的局部坐标系,并围绕自己的中心 (0,0) 绘制。

    const ballStyle = {
        fillStyle : "orange",
        lineWidth : "2",
        lineCap : "round",
        strokeStyle : "black",
    };
    const ball = {
      x : 125,
      y : 125,
      radius : 100,
      scale : 1,
      dx : 2,
      dy : 2,
      rot : 0,
      dRot : 0.1,
      segments : 7,
      style : ballStyle,
      draw : drawBall,
    }
    function drawBall(){
        var i;
        const step = Math.PI * 2 / this.segments;
        Object.assign(ctx,this.style);
        ctx.beginPath();
        ctx.arc(0, 0, this.radius, 0, Math.PI * 2);
        ctx.fill();
        for(i = 0; i < this.segments; i ++){
            ctx.moveTo(0,0);
            ctx.lineTo(Math.cos(i * step) * this.radius, Math.sin(i * step) * this.radius);
        }
        ctx.stroke();
    
    }
    

    因此,如果您调用函数ball.draw(),球将在画布的左上角以其自己的坐标系绘制。这不是你想要的。

    使用画布变换。

    这是您使用画布变换来定位和旋转对象的地方。

    因此,请创建一个通用函数来设置您要绘制的对象的位置、比例和旋转。

    function drawObject(ball) {
        ctx.setTransform(ball.scale, 0, 0, ball.scale, ball.x, ball.y); // set position and scale
        ctx.rotate(ball.rotation);
        ball.draw();
    }
    

    现在您可以将对象渲染到您想要的位置,并且位置、缩放和旋转不会影响渲染代码。

    在实践中。

    sn-p 执行上述操作。我在球上添加了一个矩形只是为了说明旋转不需要额外的代码来为对象添加更多细节。还有第二个球(从原件复制)说明一旦您设置了一个对象,复制它就很容易。

    此外,当您制作动画时,您永远不应该使用setInterval,因为它与显示硬件不同步。使用requestAnimationFrame如sn-p所示

    requestAnimationFrame(mainLoop); // start the animation at the next frame
    const ctx = canvas.getContext("2d");
    
    canvas.width = 500;
    canvas.height = 500;
    
    const ballStyle = {
      fillStyle: "orange",
      lineWidth: "2",
      lineCap: "round",
      strokeStyle: "black",
    };
    const ball = {
      x: 125,
      y: 155,
      radius: 100,
      scale: 1,
      dx: 2,
      dy: 2.5,
      rotation: 0,
      dRot: 0.02,
      segments: 7,
      style: ballStyle,
      draw: drawBall,
      update: updateBall,
    }
    
    function updateBall() {
      this.x += this.dx;
      this.y += this.dy;
      this.rotation += this.dRot;
      var r = this.radius * this.scale;
      if (this.x - r < 0) {
        this.dx = Math.abs(this.dx);
        this.x = r;
      } else if (this.x + r > ctx.canvas.width) {
        this.dx = -Math.abs(this.dx);
        this.x = ctx.canvas.width - r;
      }
      if (this.y - r < 0) {
        this.dy = Math.abs(this.dy);
        this.y = r;
      } else if (this.y + r > ctx.canvas.height) {
        this.dy = -Math.abs(this.dy);
        this.y = ctx.canvas.height - r;
      }
    }
    
    function drawBall() {
      var i;
      const step = Math.PI * 2 / this.segments;
      Object.assign(ctx, this.style);
      ctx.beginPath();
      ctx.arc(0, 0, this.radius, 0, Math.PI * 2);
      ctx.rect(this.radius - 22, -5, 20, 10);
      ctx.fill();
      for (i = 0; i < this.segments; i++) {
        ctx.moveTo(0, 0);
        ctx.lineTo(Math.cos(i * step) * this.radius, Math.sin(i * step) * this.radius);
      }
      ctx.stroke();
    }
    
    // will draw any object that has the properties x,y,scale and rotation and the function draw.
    function drawObject(ball) {
      ctx.setTransform(ball.scale, 0, 0, ball.scale, ball.x, ball.y); // set position and scale
      ctx.rotate(ball.rotation);
      ball.draw();
    }
    
    // create a copy of the ball.
    const ball1 = Object.assign(
      {},
      ball,
      {
        scale : 0.5, 
        segments : 9, 
        dx : -2,
        dRot : - 0.02,
        style : Object.assign(
          {}, 
          ballStyle, 
          {
            lineWidth : 4, 
            fillStyle : "yellow"
          }
        ),
      }
    );
    
    
    function mainLoop() {
      ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default transform
      ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
      ball.update();
      ball1.update();
      drawObject(ball);
      drawObject(ball1);
      requestAnimationFrame(mainLoop);
    }
    canvas {
      border: 1px solid black;
    }
    &lt;canvas id="canvas"&gt;&lt;/canvas&gt;

    【讨论】:

      猜你喜欢
      • 2013-11-25
      • 1970-01-01
      • 2011-04-03
      • 2014-09-21
      • 1970-01-01
      • 1970-01-01
      • 2015-05-25
      • 2011-09-04
      • 2012-09-17
      相关资源
      最近更新 更多