以下图片可以更好地解释我的目标。请注意,枢轴点并不总是中心,否则我就可以将新范围和旧范围之间的差异减半。
因此,我知道原始对象的x、y、宽度、高度、旋转角度、新范围(rotatedWidth、rotatedHeight)和与原始对象相关联的枢轴X、Y。但我不知道如何获得新范围的x/y偏移量(以使其看起来像对象围绕枢轴点旋转)
提前致谢!
以下图片可以更好地解释我的目标。请注意,枢轴点并不总是中心,否则我就可以将新范围和旧范围之间的差异减半。
因此,我知道原始对象的x、y、宽度、高度、旋转角度、新范围(rotatedWidth、rotatedHeight)和与原始对象相关联的枢轴X、Y。但我不知道如何获得新范围的x/y偏移量(以使其看起来像对象围绕枢轴点旋转)
提前致谢!
上面的演示截图展示了从枢轴点到角落的直线。
当矩形通过移动旋转时,红色的点是通过计算得出的。
这里举了一个使用绝对角度的例子,但你也可以将其转换为例如旧角度和新角度之间的差异。出于简单起见,我保留了角度作为度数而非弧度。
演示首先使用画布的内部平移和旋转来旋转矩形。然后我们使用纯数学方法来达到与证明我们已经正确计算了角落的新x和y坐标点的相同点。
/// find distance from pivot to corner
diffX = rect[0] - mx; /// mx/my = center of rectangle (in demo of canvas)
diffY = rect[1] - my;
dist = Math.sqrt(diffX * diffX + diffY * diffY); /// Pythagoras
/// find angle from pivot to corner
ca = Math.atan2(diffY, diffX) * 180 / Math.PI; /// convert to degrees for demo
/// get new angle based on old + current delta angle
na = ((ca + angle) % 360) * Math.PI / 180; /// convert to radians for function
/// get new x and y and round it off to integer
x = (mx + dist * Math.cos(na) + 0.5)|0;
y = (my + dist * Math.sin(na) + 0.5)|0;
一开始,您可以通过查看打印的x和y值来验证它们是否与矩形(50,100)的初始角相同。
更新
我错过了“偏移量”这个词...很抱歉,但是您可以计算到每个角的距离,从而获得边界的外限,并且只需根据这些距离值混合和匹配角即可使用最小和最大值。
新部分包括一个函数,将为您提供角落的x和y:
///mx, my = pivot, cx, cy = corner, angle in degrees
function getPoint(mx, my, cx, cy, angle) {
var x, y, dist, diffX, diffY, ca, na;
/// get distance from center to point
diffX = cx - mx;
diffY = cy - my;
dist = Math.sqrt(diffX * diffX + diffY * diffY);
/// find angle from pivot to corner
ca = Math.atan2(diffY, diffX) * 180 / Math.PI;
/// get new angle based on old + current delta angle
na = ((ca + angle) % 360) * Math.PI / 180;
/// get new x and y and round it off to integer
x = (mx + dist * Math.cos(na) + 0.5)|0;
y = (my + dist * Math.sin(na) + 0.5)|0;
return {x:x, y:y};
}
/// offsets
c2 = getPoint(mx, my, rect[0], rect[1], angle);
c2 = getPoint(mx, my, rect[0] + rect[2], rect[1], angle);
c3 = getPoint(mx, my, rect[0] + rect[2], rect[1] + rect[3], angle);
c4 = getPoint(mx, my, rect[0], rect[1] + rect[3], angle);
/// bounds
bx1 = Math.min(c1.x, c2.x, c3.x, c4.x);
by1 = Math.min(c1.y, c2.y, c3.y, c4.y);
bx2 = Math.max(c1.x, c2.x, c3.x, c4.x);
by2 = Math.max(c1.y, c2.y, c3.y, c4.y);
Here is the way that worked best for me. First I calculate what is the new width and height of that image, then I translate it by half of that amount, then I apply the rotation and finally I go back by the original width and height amount to re center the image.
var canvas = document.getElementById("canvas")
const ctx = canvas.getContext('2d')
drawRectangle(30,30,40,40,30,"black")
function drawRectangle(x,y,width,height, angle,color) {
drawRotated(x,y,width,height,angle,ctx =>{
ctx.fillStyle = color
ctx.fillRect(0,0,width,height)
})
}
function drawRotated(x,y,width,height, angle,callback)
{
angle = angle * Math.PI / 180
const newWidth = Math.abs(width * Math.cos(angle)) + Math.abs(height * Math.sin(angle));
const newHeight = Math.abs(width * Math.sin(angle)) + Math.abs(height * Math.cos(angle));
var surface = document.createElement('canvas')
var sctx = surface.getContext('2d')
surface.width = newWidth
surface.height = newHeight
// START debug magenta square
sctx.fillStyle = "magenta"
sctx.fillRect(0,0,newWidth,newHeight)
// END
sctx.translate(newWidth/2,newHeight/2)
sctx.rotate(angle)
sctx.translate(-width/2,-height/2)
callback(sctx)
ctx.drawImage(surface,x-newWidth/2,y-newHeight/2)
}
#canvas{
border:1px solid black
}
<canvas id="canvas">
</canvas>
要围绕画布中心点旋转,您可以使用此函数:
function rotate(context, rotation, canvasWidth, canvasHeight) {
// Move registration point to the center of the canvas
context.translate(canvasWidth / 2, canvasHeight/ 2);
// Rotate 1 degree
context.rotate((rotation * Math.PI) / 180);
// Move registration point back to the top left corner of canvas
context.translate(-canvasWidth / 2, -canvasHeight/ 2);
}