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

Javascript 如何围绕任意点旋转HTML5画布上的任何形状或点?,javascript,konvajs,Javascript,Konvajs,我见过一些关于如何围绕给定点旋转形状的问题,并决定自己问这个自答问题。那么-关于HTML5画布,或者事实上任何二维表面,我如何能够围绕任意x,y点旋转形状?结果是答案非常简单,但涉及一些数学问题,可能会让一些人感到不快。我使用的是Konvajs HTML5画布库,但是代码可以很容易地传输到您自己的库中。另外,这个例子被描述为旋转一个形状,但它实际上是旋转一个点——形状的原点——所以你可以将它用于任何围绕一个点旋转的情况 rotateAroundPoint()函数完成了这项工作——代码段中的其余代

我见过一些关于如何围绕给定点旋转形状的问题,并决定自己问这个自答问题。那么-关于HTML5画布,或者事实上任何二维表面,我如何能够围绕任意x,y点旋转形状?

结果是答案非常简单,但涉及一些数学问题,可能会让一些人感到不快。我使用的是Konvajs HTML5画布库,但是代码可以很容易地传输到您自己的库中。另外,这个例子被描述为旋转一个形状,但它实际上是旋转一个点——形状的原点——所以你可以将它用于任何围绕一个点旋转的情况

rotateAroundPoint()函数完成了这项工作——代码段中的其余代码将使其成为一个工作示例

将此函数提出来,我们可以看到输入是形状-尽管这可能是具有x、y和旋转属性的任何对象,以度为单位的旋转角度和旋转点-同样是具有x和y值的对象

当我们围绕点旋转时,我们执行的等效旋转是原地旋转,然后是平移(或移动)。必须按此顺序执行这些操作。此外,由于二维绘图的工作方式,我们必须计算出移动的新位置,这取决于形状的绘图原点

新x&y位置的计算需要使用正弦和余弦函数,这些函数需要弧度,而不是度。所以我们用π/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);

}
就这样!玩一玩代码片段-最好全屏观看。选择要旋转的形状,然后单击“旋转”按钮几次,以观察它围绕其原点旋转(如果只更改旋转角度而不更改其他内容,则为自然旋转点)。然后单击重置按钮,然后单击画布将蓝色目标移动到画布或形状上的其他位置,然后再旋转一些以查看效果

还有一个代码笔版本

//说明形状围绕任意给定点旋转的代码。这里的重要函数是rotateAroundPoint(),它进行旋转和运动数学!
让
角度=0,//角度显示值
startPos={x:80,y:45},
shapes=[],//形状重影/尾部数组
rotateBy=20,//每步旋转角度
shapeName=$('#shapeName').val(),//我们画的是什么形状
shape=null,
幽灵极限=10,
//搭台
舞台=新康瓦舞台({
容器:'容器',
宽度:window.innerWidth,
高度:window.innerHeight
}),
//添加要绘制的图层
层=新Konva.layer(),
//创建旋转目标点十字线标记
lineV=new Konva.Line({点:[0,-20,0,20],笔划:“青色”,笔划宽度:1}),
lineH=新的Konva.Line({points:[-20,0,20,0],stroke:'cyan',strokeWidth:1}),
圆=新的Konva.circle({x:0,y:0,半径:10,填充:“透明”,笔划:“青色”,笔划宽度:1}),
cross=new Konva.Group({draggable:true,x:startPos.x,y:startPos.y});
//将元素添加到交叉头发组
添加(线条V、线条H、圆圈);
层。添加(交叉);
//将层添加到舞台
阶段。添加(层);
$('#shapeName')。在('change',function()上{
shapeName=$('#shapeName').val();
shape.destroy();
shape=null;
重置();
})
//绘制用户选择的任何形状
函数drawShape(){
//添加要旋转的形状
如果(形状!==null){
shape.destroy();
}
开关(shapeName){
案例“矩形”:
shape=new Konva.Rect({x:startPos.x,y:startPos.y,宽度:120,高度:80,填充:“洋红色”,笔划:“黑色”,笔划宽度:4});
打破
案例“hexagon”:
形状=新的Konva.RegularPolygon({x:startPos.x,y:startPos.y,边:6,半径:40,填充:“洋红色”,笔划:“黑色”,笔划宽度:4});
打破
案例“椭圆”:
形状=新的Konva.Ellipse({x:startPos.x,y:startPos.y,半径x:40,半径y:20,填充:“洋红色”,笔划:“黑色”,笔划宽度:4});
打破
案例“圆圈”:
形状=新的Konva.Ellipse({x:startPos.x,y:startPos.y,radiusX:40,radiusY:40,填充:“洋红色”,笔划:“黑色”,笔划宽度:4});
打破
案例“star”:
形状=新的Konva.Star({x:startPos.x,y:startPos.y,numPoints:5,内半径:20,外半径:40,填充:“洋红色”,笔划:“黑色”,笔划宽度:4});
打破
};
层。添加(形状);
cross.moveToTop();
}
//重置形状位置等。
函数重置(){
drawShape();//绘制当前形状
//设置为起始位置等。
形状、位置(startPos)
交叉位置(startPos);
角度=0;
$('#angle').html(angle);
$('#position').html('('+shape.x()+','+shape.y()+'));
clearTails();//清除尾部形状
stage.draw();//刷新/绘制舞台。
}
//单击舞台以移动旋转点
舞台上('点击',功能(e){
交叉位置(stage.getPointerPosition());
stage.draw();
});
//围绕任意点旋转形状。
//形状是Konva形状
//angleRadians是旋转的角度,以弧度为单位
//点是一个对象{x:posX,y:posY}
函数rotateAroundPoint(形状、角度、度、点){
设angleRadians=angleDegrees*Math.PI/180;//正弦+余弦需要弧度
常数x=
第x点+
(shape.x()-point.x)*数学cos(角度弧度)-
(shape.y()-point.y)*数学sin(角度弧度);
常数=
点y+
(shape.x()-point.x)*数学sin(角度弧度)+
(shape.y()-point.y)*数学cos(角度弧度);
shape.rotation(shape.rotation()+angleDegrees);//将形状旋转到位
shape.x(x);//相对于旋转点移动旋转的形状。
形状y(y);
shape.moveToTop();//
}
$(“#旋转”)。在('click',function()上{
让newShape=shape.clo