Javascript Html画布-在中心轴上旋转各个形状

Javascript Html画布-在中心轴上旋转各个形状,javascript,html,canvas,Javascript,Html,Canvas,正如您在演示中看到的,L形从屏幕顶部被裁剪掉,应该旋转180度并与左上角齐平。我注意到有两件事情并没有像预期的那样起作用,第一件是当我将ctx.translate(x,y)更改为ctx.moveTo(x,y)并将形状位置增加到100100时,它会随着translate移动超过100px,其中moveTo似乎是准确的。第二个是在ctx.stroke()之后使用负平移对形状位置没有影响 var-shape={}; 函数图(形状){ var canvas=document.getElementByI

正如您在演示中看到的,L形从屏幕顶部被裁剪掉,应该旋转180度并与左上角齐平。我注意到有两件事情并没有像预期的那样起作用,第一件是当我将
ctx.translate(x,y)
更改为
ctx.moveTo(x,y)
并将形状位置增加到
100100
时,它会随着translate移动超过100px,其中moveTo似乎是准确的。第二个是在
ctx.stroke()
之后使用负平移对形状位置没有影响

var-shape={};
函数图(形状){
var canvas=document.getElementById('canvas');
if(canvas.getContext){
var ctx=canvas.getContext('2d');
clearRect(0,0,canvas.width,canvas.height);
ctx.save();
var x=形状位置x+0.5;
变量y=形状位置y+0.5;
ctx.translate(x,y);
ctx.translate(shape.width*shape.scale/2,shape.height*shape.scale/2);
ctx.旋转(形状方向*数学PI/180);
ctx.beginPath();
对于(变量i=0;i
#画布{
背景:#272B34;}

进行二维变换的最简单方法是使用setTransform函数,该函数包含6个数字、2个代表X轴和y轴方向和比例的向量,以及一个代表新原点的坐标

与依赖于当前状态的其他变换函数不同,setTransform在调用之前不受任何变换的影响

为具有方形纵横比(x和y比例相同)且y轴与x成90度角(无倾斜)且旋转的矩阵设置变换,如下所示

// x,y the position of the orign
function setMatrix(x,y,scale,rotate){ 
    var xAx = Math.cos(rotate) * scale;  // the x axis x
    var xAy = Math.sin(rotate) * scale;  // the x axis y
    ctx.setTransform(xAx, xAy, -xAy, xAx, x, y);
}

//use
setMatrix(100,100,20,Math.PI / 4);
ctx.strokeRect(-2,-2,4,4); // draw a square centered at 100,100 
                           // scaled 20 times
                           // and rotate clockwise 45 deg
更新 回答评论中的问题

为什么是罪恶和罪恶? 你能解释一下为什么你用cos和sin作为轴心吗

我使用
Math.sin
Math.cos
来计算X轴,从而计算Y轴(因为Y与X成90度角),因为它比将旋转作为单独的变换添加稍微快

当您使用除
setTransform
之外的任何变换函数时,您正在进行矩阵乘法。下一个代码片段是使用
ctx.rotate
ctx.scale
ctx.translate
ctx.transform
时所做的JS等效最小计算

// mA represent the 2D context current transform
mA = [1,0,0,1,0,0];  // default transform
// mB represents the transform to apply
mB = [0,1,-1,0,0,0];  // Rotate 90 degree clockwise
// m is the resulting matrix
m[0] = mA[0] * mB[0] + mA[2] * mB[1];
m[1] = mA[1] * mB[0] + mA[3] * mB[1];
m[2] = mA[0] * mB[2] + mA[2] * mB[3];
m[3] = mA[1] * mB[2] + mA[3] * mB[3];
m[4] = mA[0] * mB[0] + mA[2] * mB[1] + mA[4];
m[5] = mA[1] * mB[0] + mA[3] * mB[1] + mA[5];
如您所见,有12次乘法和6次加法,加上需要内存来保存中间值,如果调用的是
ctx。旋转
角度的正弦波和余弦波也将完成。这一切都是在JavaScript引擎中的本机代码中完成的,因此比在JS中完成要快,但是在JavaScript中通过计算轴来避免矩阵乘法会导致更少的工作。使用
setTransform
仅替换当前矩阵,不需要执行矩阵乘法

答案的
setMatrix
功能的替代方法可以是

function setMatrix(x,y,scale,rotate){ 
    ctx.setTransform(scale,0,0,scale, x, y); // set current matrix
    ctx.rotate(rotate);  // multiply current matrix with rotation matrix
}
这也一样,而且看起来更干净,但是速度较慢,当你想做性能非常重要的游戏时,通常称为函数应该尽可能快

使用
setMatrix
功能 那么,我将如何使用这个自定义形状,如我的演示中的L

替换绘图功能。顺便说一句,你应该得到任何绘图函数之外的上下文

// assumes ctx is the 2D context in scope for this function.
function draw(shape) { 
    var i = 0;
    setMatrix(shape.position.x, shape.position.y, shape.scale, shape.orientation); // orientation is in radians
    ctx.strokeStyle = '#fff';

    ctx.beginPath();
    ctx.moveTo(shape.points[i].x, shape.points[i++].y)
    while (i < shape.points.length) {
      ctx.lineTo(shape.points[i].x, shape.points[i++].y);
    }
    ctx.closePath(); // draw line from end to start
    ctx.stroke();
}
//假定ctx是此函数作用域中的2D上下文。
函数绘制(形状){
var i=0;
setMatrix(shape.position.x,shape.position.y,shape.scale,shape.orientation);//方向以弧度为单位
ctx.strokeStyle='#fff';
ctx.beginPath();
ctx.moveTo(shape.points[i].x,shape.points[i++].y)
而(i
在代码中,存储的行的原点(0,0)位于左上角。定义形状时,应根据其局部坐标进行定义。这将定义旋转和缩放点,并表示将位于变换原点(位置x,y)的坐标

因此,您应该在其原点定义形状

function createShape(originX, originY, points){
    var i;
    const shape = [];
    for(i = 0; i < points.length; i++){
        shape.push({
            x : points[i][0] - originX,
            y : points[i][1] - originY,
        });
    }
    return shape;
}
const shape = {};
shape.points = createShape(
     1,1.5,  // the local origin relative to the coords on next line
     [[0,0],[0,3],[2,3],[2,2],[1,2],[1,0]]  // shape coords
);
函数createShape(原点、原点、点){
var i;
常量形状=[];
对于(i=0;i
感谢@Blindman67迄今为止的所有帮助!那么,我将如何使用这个自定义形状,如我的演示中的L?你能解释一下你为什么用cos和sin作为轴心吗?@PaulMason我已经更新了答案来回答你的其他问题。嘿@Blindman67我试了一下,就快到了,真的很感谢你的帮助!我做了一个密码笔来指出最后一件事,看看它是如何不成比例的,伸出的部分应该和茎一样宽:@PaulMason那是因为你是usi