【问题标题】:JavaScript: Rotating object in canvasJavaScript:画布中的旋转对象
【发布时间】:2019-01-30 19:18:41
【问题描述】:

过去三周我正在创建一个画布引擎,上周我试图解决一个在画布中旋转对象的问题。我尝试了很多解决方案,但都没有成功。在大多数情况下,代码是旋转画布的全部内容或者它什么都不显示(就像现在一样(但如果你删除 .save().restore(),一切都会旋转))。我希望这可以避免对代码进行重大更改,因为这是我编写的最大代码(而且我不想做很多更改)。代码 sn-p 在下面,感谢您的帮助。 (想看完整代码可以去here

//Functions.js File
function degToRad(int) {
    return int * Math.PI / 180;
}

//Init.js File
var fps = 0;
var objects = new Array();
var ctx_real = {
    context: undefined,
    width: 0,
    height: 0,
    init: function () {
        this.context = this.DOM.getContext("2d");
        this.width = this.DOM.width;
        this.height = this.DOM.height;
    },
    clear: function () {
        this.context.clearRect(0, 0, this.width, this.height);
    }
};
const proXy_ctx = {
    get: function (target, prop) {
        return target.hasOwnProperty(prop) ? target[prop] : ctx_real.context; //=> ctx.SomeAtributeThatNotExists = ctx.context
    }
};
const ctx = new Proxy(ctx_real, proXy_ctx);

function init() {
    ctx.DOM = document.getElementById("ctx");
    ctx.init();
    setLayout("Game");
    setLayout("Test2");
    setInterval(frameUpdate, 1);
}

//Script.js File
async function frameUpdate() {
    ctx.clear();
    clearObjects = false;
    for (var tmp0 = 0 in objects) {
        var object = objects[tmp0];
        var id = object[0];
        var type = object[1];
        var x = object[2];
        var y = object[3];
        var color = object[4];
        ctx.context.strokeStyle = color;
        ctx.context.fillStyle = color;
        var arg0 = object[5];
        var arg1 = object[6];
        var arg3 = object[8];
        var arg4 = object[9];
        switch (type) {
            case "Rct":
                var translateX = x + (arg0 / 2);
                var translateY = y + (arg1 / 2);
                if (typeof arg3 == "number" && arg3 != 0) {
                    ctx.context.save();
                    ctx.context.translate(translateX, translateY);
                    ctx.context.rotate(degToRad(arg3));
                }
                if (arg4) {
                    ctx.context.fillRect(x, y, arg0, arg1);
                } else {
                    ctx.context.strokeRect(x, y, arg0, arg1);
                }
                if (typeof arg3 == "number") {
                    ctx.context.restore();
                }
                break;
        }
    }
    if (clearObjects) {
        objects = objects.filter(Boolean);
    }
    fps++;
    setTimeout(function () { fps--; }, 1000);
    ctx.context.fillStyle = "black";
    ctx.context.font = "10px Verdana";
    ctx.context.fillText(fps, 10, 10);
}

function setLayout(layoutName) {
    switch (layoutName) {
        case "Game":
            createObject(["SomeId", "Rct", 0, ctx.height - 30, "green", ctx.width, 30, , , true]);
            createObject(["SomeId", "Rct", 0, ctx.height - 30, "#402a25", ctx.width, 3, , , true]);
            break;
        case "Test2":
            createObject(["SomeRotatedEl", "Rct", ctx.width / 2, ctx.height / 2, "red", 50, 50, , 90, true]);
            break;
    }
}

function createObject(object) {
    objects.push(object);
}
html,
body,
canvas {
  height: 100%;
  width: 100%;
  padding: 0;
  margin: 0;
  overflow-x: hidden;
  overflow-y: hidden;
}
<!DOCTYPE html>
<html>
<body onLoad="init()">
  <canvas id="ctx">You can simple download e.g. Chrome or what?!!!</canvas>
</body>
</html>

【问题讨论】:

标签: javascript canvas


【解决方案1】:

如果不“旋转”所有画布,就无法在画布上绘制旋转的对象。

不幸的是,画布就是这样工作的。这么想:

您只能在空间中的单个点{x:0,y:0} 进行绘制,而画布就在该点的正下方,就像一张物理纸。

然后,如果您想在{x:0,y:10} 绘制,则将所有画布向上移动 10 像素,所以如果从画布的顶部/左侧数起,现在您绘制的点变为 {x:0,y:10},但它是 {x:0,y:0}用于绘图。

// red rect at {x:0,y:40}
ctx.fillStyle = "rgba(255,0,0,0.3)";
ctx.translate(0, 40) // means that {x:0,y:10} "is new" {x:0,y:0}
ctx.fillRect(0, 0, 40, 20);

如果你想旋转,你旋转画布,这样你想画的东西就会在旋转时出现:

// reset all transformations
ctx.setTransform(1, 0, 0, 1, 0, 0);
// green rect at {x:0,y:0} rotated 45deg
ctx.fillStyle = "rgba(0,255,0,0.3)";
ctx.rotate(45 * Math.PI / 180);
ctx.fillRect(0, 0, 40, 20);

但它围绕其上/左角旋转。我猜那是你的问题?

要正确旋转对象(以中心为旋转轴),您需要放置画布,使对象的中心变为{x:0,y:0}。然后旋转并绘制对象,使其中心位于{x:0,y:0},对于大多数对象,这意味着您将它们绘制在{x:-width/2,y:-height/2}

例如,如果您希望 {x:50,y:50} 处的蓝色矩形与 {width:40,height:20} 旋转 45 度

// reset all transformations
ctx.setTransform(1, 0, 0, 1, 0, 0);

// blue rect at {x:50,y:50} rotated 45deg
var rectWidth = 40;
var rectHeight = 20;
ctx.fillStyle = "rgba(0,0,255,0.3)";
ctx.translate(50, 50);
ctx.rotate(45 * Math.PI / 180);
ctx.fillRect(-rectWidth/2, -rectHeight/2, rectWidth, rectHeight);

查看完整示例:https://codepen.io/anon/pen/QYGXzp?editors=0010

【讨论】:

  • 谢谢。我没有意识到,绘制坐标取决于平移移动。
  • 不幸的是,Canvas 的构建考虑了数学,而不是编程。如果您想了解有关其工作原理的更多信息,请查找“仿射变换”,我发现该答案中的图像很有帮助 - computergraphics.stackexchange.com/questions/391/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-10
  • 1970-01-01
  • 1970-01-01
  • 2013-02-23
  • 1970-01-01
相关资源
最近更新 更多