微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何围绕任意点旋转HTML5画布上的任何形状或点?

如何解决如何围绕任意点旋转HTML5画布上的任何形状或点?

我已经看到一些问题,询问如何围绕给定点旋转形状,并决定自己问这个自我解答问题。那么-关于HTML5画布,或者实际上是任何二维表面,我如何围绕任意x,y点旋转形状?

解决方法

事实证明,答案很简单,但是涉及到一些数学运算,可能会使某些人失望。我正在使用Konvajs HTML5 canvas库,但是该代码很容易传输到您自己的lib中。另外,此示例被描述为旋转形状,但实际上是旋转一个点-形状的原点-因此,您可以将其用于任何围绕点旋转的情况。

rotateAroundPoint()函数可以完成工作-片段中的其余代码都可以作为工作示例。

将其移出,我们可以看到输入是形状-尽管它可以是具有x,y和旋转特性的任何对象,以度为单位的旋转角度和旋转点-还是具有x和y值的对象

当我们绕该点旋转时,我们将进行原位旋转,然后进行平移(或移动)。这些必须按此顺序进行。另外,由于2D绘图的工作方式,我们必须为移动确定新的位置,这取决于形状的绘图原点。

要计算新的x和y位置,需要使用需要弧度而不是度数的正弦和余弦函数。因此,我们将度数乘以PI / 180即可得到。

// Rotate a shape around any point.
// shape is a Konva shape
// angleDegrees is the angle to rotate by,in degrees
// point is an object {x: posX,y: posY}
function rotateAroundPoint(shape,angleDegrees,point) {
  let angleRadians = angleDegrees * Math.PI / 180; // sin + cos require radians
  
  const x =
    point.x +
    (shape.x() - point.x) * Math.cos(angleRadians) -
    (shape.y() - point.y) * Math.sin(angleRadians);
  const y =
    point.y +
    (shape.x() - point.x) * Math.sin(angleRadians) +
    (shape.y() - point.y) * Math.cos(angleRadians);
   
  shape.rotation(shape.rotation() + angleDegrees); // rotate the shape in place
  shape.x(x);  // move the rotated shape in relation to the rotation point.
  shape.y(y);

}

就是这样!播放片段-最佳全屏观看。选择要旋转的形状,然后单击几次旋转按钮以观看它围绕其原点旋转(如果我们只是更改旋转角度而没有其他操作,则为自然旋转点)。然后单击重置按钮,然后单击画布以将蓝色目标移动到画布或形状上的其他位置,然后再旋转一些以查看效果。

还有一个Codepen版本here

// Code to illustrate rotation of a shape around any given point. The important functions here is rotateAroundPoint() which does the rotation and movement math ! 

let 
    angle = 0,// display value of angle
    startPos = {x: 80,y: 45},shapes = [],// array of shape ghosts / tails
    rotateBy = 20,// per-step angle of rotation 
    shapeName = $('#shapeName').val(),// what shape are we drawing
    shape = null,ghostLimit = 10,// Set up a stage
    stage = new Konva.Stage({
        container: 'container',width: window.innerWidth,height: window.innerHeight
      }),// add a layer to draw on
    layer = new Konva.Layer(),// create the rotation target point cross-hair marker
    lineV = new Konva.Line({points: [0,-20,20],stroke: 'cyan',strokeWidth: 1}),lineH = new Konva.Line({points: [-20,20,0],circle = new Konva.Circle({x: 0,y: 0,radius: 10,fill: 'transparent',cross = new Konva.Group({draggable: true,x: startPos.x,y: startPos.y});

// Add the elements to the cross-hair group
cross.add(lineV,lineH,circle);
layer.add(cross);

// Add the layer to the stage
stage.add(layer);


$('#shapeName').on('change',function(){
  shapeName = $('#shapeName').val();
  shape.destroy();
  shape = null;
  reset();
})


// Draw whatever shape the user selected
function drawShape(){
  
    // Add a shape to rotate
    if (shape !== null){
      shape.destroy();
    }
   
    switch (shapeName){
      case "rectangle":
        shape = new Konva.Rect({x: startPos.x,y: startPos.y,width: 120,height: 80,fill: 'magenta',stroke: 'black',strokeWidth: 4});
        break;

      case "hexagon":
        shape = new Konva.RegularPolygon({x: startPos.x,sides: 6,radius: 40,strokeWidth: 4}); 
        break;
        
      case "ellipse":
        shape = new Konva.Ellipse({x: startPos.x,radiusX: 40,radiusY: 20,strokeWidth: 4});     
        break;
        
      case "circle":
        shape = new Konva.Ellipse({x: startPos.x,radiusY: 40,strokeWidth: 4});     
        break;

      case "star":
        shape = new Konva.Star({x: startPos.x,numPoints: 5,innerRadius: 20,outerRadius: 40,strokeWidth: 4});     
        break;        
    };
    layer.add(shape);
    
    cross.moveToTop();

  }



// Reset the shape position etc.
function reset(){

  drawShape();  // draw the current shape
  
  // Set to starting position,etc.
  shape.position(startPos)
  cross.position(startPos);
  angle = 0;
  $('#angle').html(angle);
  $('#position').html('(' + shape.x() + ',' + shape.y() + ')');
  
  clearTails(); // clear the tail shapes
  
  stage.draw();  // refresh / draw the stage.
}




// Click the stage to move the rotation point
stage.on('click',function (e) {
  cross.position(stage.getPointerPosition());
  stage.draw();
});

// Rotate a shape around any point.
// shape is a Konva shape
// angleRadians is the angle to rotate by,in radians
// point is an object {x: posX,point) {
  let angleRadians = angleDegrees * Math.PI / 180; // sin + cos require radians
  
  const x =
    point.x +
    (shape.x() - point.x) * Math.cos(angleRadians) -
    (shape.y() - point.y) * Math.sin(angleRadians);
  const y =
    point.y +
    (shape.x() - point.x) * Math.sin(angleRadians) +
    (shape.y() - point.y) * Math.cos(angleRadians);
   
  shape.rotation(shape.rotation() + angleDegrees); // rotate the shape in place
  shape.x(x);  // move the rotated shape in relation to the rotation point.
  shape.y(y);
  
  shape.moveToTop(); // 
}



$('#rotate').on('click',function(){
  
  let newShape = shape.clone();
  shapes.push(newShape);
  layer.add(newShape);
  
  // This ghost / tails stuff is just for fun.
  if (shapes.length >= ghostLimit){
    shapes[0].destroy();   
    shapes = shapes.slice(1);
  }
  for (var i = shapes.length - 1; i >= 0; i--){
    shapes[i].opacity((i + 1) * (1/(shapes.length + 2)))
  };

  // This is the important call ! Cross is the rotation point as illustrated by crosshairs.
  rotateAroundPoint(shape,rotateBy,{x: cross.x(),y: cross.y()});
  
  cross.moveToTop();
  
  stage.draw();
  
  angle = angle + 10;
  $('#angle').html(angle);
  $('#position').html('(' + Math.round(shape.x() * 10) / 10 + ',' + Math.round(shape.y() * 10) / 10 + ')');
})



// Function to clear the ghost / tail shapes
function clearTails(){

  for (var i = shapes.length - 1; i >= 0; i--){
    shapes[i].destroy();
  };
  shapes = [];
  
}

// User cicks the reset button.
$('#reset').on('click',function(){

  reset();

})

// Force first draw!
reset();
body {
  margin: 10;
  padding: 10;
  overflow: hidden;
  background-color: #f0f0f0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://unpkg.com/konva@^3/konva.min.js"></script>
<p>1. Click the rotate button to see what happens when rotating around shape origin.</p>
<p>2. Reset then click stage to move rotation point and click rotate button again - rinse & repeat</p>
<p>
<button id = 'rotate'>Rotate</button>
  <button id = 'reset'>Reset</button> 
  <select id='shapeName'>
    <option value='rectangle'>Rectangle</option>
    <option value='hexagon'>Polygon</option>
    <option value='ellipse' >Ellipse</option>
    <option value='circle' >Circle</option>
    <option value='star' selected='selected'>Star</option>    
    
  </select>
  Angle :    <span id='angle'>0</span>
Position :   <span id='position'></span>
</p>
<div id="container"></div>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。