HTML5画布将弧分成7个相等的部分并旋转

时间:2017-10-27 21:49:22

标签: javascript animation rotation html5-canvas

我遇到一个问题,即将一个圆圈分成7块。 此刻我有一条线穿过圆圈的中心。 然后旋转并从画布的墙壁反弹。 我似乎无法弄清楚绘制7个相等的段并让它们在圆圈内旋转。 请查看我到目前为止所拥有的代码片段。 任何有关这方面的帮助将不胜感激。

提前谢谢。

    <!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>
        
           

2 个答案:

答案 0 :(得分:1)

如果我理解正确,你几乎就在那里,但不是从圆上的一个点到一个完全相反的方向绘制一条线,而是从中心开始并以角度增量从theta开始绘制七个半径1/7圈。

因为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弧度的单独路径。

答案 1 :(得分:0)

创建动画实体。

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

实体AKA Object。

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

您应该将您绘制的每个项目视为一个独立的实体(例如球)并创建一个描述球的对象,包括其行为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();
}

现在您可以在任意位置渲染对象,并且位置,比例和旋转不会影响渲染代码。

在实践中。

该片段执行上述操作。我在球上添加了一个矩形,以说明旋转不需要额外的代码来向对象添加更多细节。还有一个第二个球(从原件复制)来说明一旦你设置了一个对象,制作它的副本很容易。

同样,当您制作动画时,不应使用setInterval,因为它与显示硬件不同步。使用代码段

中显示的requestAnimationFrame

&#13;
&#13;
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);
}
&#13;
canvas {
  border: 1px solid black;
}
&#13;
<canvas id="canvas"></canvas>
&#13;
&#13;
&#13;