在javascript中旋转一个正方形 [英] rotating a square in javascript

查看:483
本文介绍了在javascript中旋转一个正方形的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在javascript中围绕它的中心旋转一个正方形。虽然在这种情况下,我使用画布来绘制正方形,我需要有一个旋转正方形的功能方法在其他地方使用,所以只是旋转画布是不能接受的。这是我到目前为止

  var thecanvas = this.myCanvas; 

var canvaswidth = thecanvas.width;
tlx =(0 - ((canvaswidth * 0.6)/ 2));
tly =(0 - ((canvaswidth * 0.6)/ 2));
trx =(0 +((canvaswidth * 0.6)/ 2));
tryy =(0 - ((canvaswidth * 0.6)/ 2));
blx =(0 - ((canvaswidth * 0.6)/ 2));
bly =(0 +((canvaswidth * 0.6)/ 2));
brx =(0 +((canvaswidth * 0.6)/ 2));
bry =(0 +((canvaswidth * 0.6)/ 2));

tlx =((tlx)*(this._cosD(orientation))) - ((tly)*(this._sinD(orientation))));
tly =((tlx)*(this._sinD(orientation))+(tly)*(this._cosD(orientation)))
trx =((trx)*(this._cosD(orientation))) - ((tryy)*(this._sinD(orientation))));
tryy =((trx)*(this._sinD(orientation))+(tryy)*(this._cosD(orientation)));
blx =((blx)*(this._cosD(orientation)) - (bly)*(this._sinD(orientation)));
bly =((blx)*(this._sinD(orientation))+(bly)*(this._cosD(orientation)))
brx =((brx)*(this._cosD(orientation)) - (bry)*(this._sinD(orientation)));
bry =((brx)*(this._sinD(orientation))+(bry)*(this._cosD(orientation)))


tlx =(tlx +(canvaswidth / 2));
tly =(tly +(canvaswidth / 2));
trx =(trx +(canvaswidth / 2));
tryy =(tryy +(canvaswidth / 2));
blx =(blx +(canvaswidth / 2));
bly =(bly +(canvaswidth / 2));
brx =(brx +(canvaswidth / 2));
bry =(bry +(canvaswidth / 2));


var c2 = thecanvas.getContext('2d');
c2.fillStyle ='#f00';
c2.beginPath();
c2.moveTo(tlx,tly);
c2.lineTo(trx,tryy);
c2.lineTo(brx,bry);
c2.lineTo(blx,bly);
c2.closePath();
c2.fill();`

orientation是从-90-90度。此代码开始旋转正方形,但正方形继续挤压,直到它完全消失90度。显然我的旋转公式抛弃了某个地方,但我不能弄清楚如何。

解决方案

您可以手动实现。



未来将给予我们 currentTransform 上下文(目前仅在Chrome中可用,Firefox遇到错误)会返回 SVGMatrix object ,你可以使用与上面的实现几乎相同的方式。


I am trying to rotate a square about its center in javascript. Although in this case I am using canvas to draw the square, I need to have a functional method of rotating the square for use elsewhere so just rotating the canvas is not acceptable. This is what I have so far

var thecanvas = this.myCanvas;      

  var canvaswidth = thecanvas.width;
  tlx = (0 - ((canvaswidth * 0.6) / 2));
  tly = (0 - ((canvaswidth * 0.6) / 2));
  trx = (0 + ((canvaswidth * 0.6) / 2));
  tryy = (0 - ((canvaswidth * 0.6) / 2));
  blx = (0 - ((canvaswidth * 0.6) / 2));
  bly = (0 + ((canvaswidth * 0.6) / 2));
  brx = (0 + ((canvaswidth * 0.6) / 2));
  bry = (0 + ((canvaswidth * 0.6) / 2));

  tlx = (((tlx) * (this._cosD(orientation))) - ((tly) * (this._sinD(orientation))));
  tly = ((tlx) * (this._sinD(orientation)) + (tly) * (this._cosD(orientation)));
  trx = (((trx) * (this._cosD(orientation))) - ((tryy) * (this._sinD(orientation))));
  tryy = ((trx) * (this._sinD(orientation)) + (tryy) * (this._cosD(orientation)));
  blx = ((blx) * (this._cosD(orientation)) - (bly) * (this._sinD(orientation)));
  bly = ((blx) * (this._sinD(orientation)) + (bly) * (this._cosD(orientation)));
  brx = ((brx) * (this._cosD(orientation)) - (bry) * (this._sinD(orientation)));
  bry = ((brx) * (this._sinD(orientation)) + (bry) * (this._cosD(orientation)));


  tlx = (tlx + (canvaswidth / 2));
  tly = (tly + (canvaswidth / 2));
  trx = (trx + (canvaswidth / 2));
  tryy = (tryy + (canvaswidth / 2));
  blx = (blx + (canvaswidth / 2));
  bly = (bly + (canvaswidth / 2));
  brx = (brx + (canvaswidth / 2));
  bry = (bry + (canvaswidth / 2));


  var c2 = thecanvas.getContext('2d');
  c2.fillStyle = '#f00';
  c2.beginPath();
  c2.moveTo(tlx, tly);
  c2.lineTo(trx, tryy);
  c2.lineTo(brx, bry);
  c2.lineTo(blx, bly);
  c2.closePath();
  c2.fill();`

orientation is a value from -90-90 in degrees. This code starts to rotate the square but the square continues to "squish" until it is completely gone by 90 degrees. Obviously my formula for rotation is thrown off somewhere but I cant figure out how.

解决方案

You could manually implement a transformation matrix. This allows you to set up the matrix for both read and write, then apply it to the points returning absolute points with the new actual values without the need or hassle to make special code for each use-case.

The formula for the (2D affine) using a 3x3 matrix would be:

or simplified in JavaScript:

var newX = x * a + y * c + e,    // e (or tx) x 1 => e
    newY = x * b + y * d + f;    // f (or ty) x 1 => f

Now you would need to multiply the matrix with another to add rotation, translation, scale etc. The common way of doing this is this way - assume we have an object holding our values, you could do:

function Matrix() {
   this.a = 1;  // 1,0,0,1,0,0 = identity matrix (untransformed)
   this.b = 0;
   this.c = 0;
   this.d = 1;
   this.e = 0;
   this.f = 0;
}

Matrix.prototype = {

  // we need to be able to multiply matrices to accumulate values:
  transform: function(a2, b2, c2, d2, e2, f2) {

    var a1 = this.a,
        b1 = this.b,
        c1 = this.c,
        d1 = this.d,
        e1 = this.e,
        f1 = this.f;

    /* matrix order (canvas compatible):
    * ace
    * bdf
    * 001
    */
    this.a = a1 * a2 + c1 * b2;
    this.b = b1 * a2 + d1 * b2;
    this.c = a1 * c2 + c1 * d2;
    this.d = b1 * c2 + d1 * d2;
    this.e = a1 * e2 + c1 * f2 + e1;
    this.f = b1 * e2 + d1 * f2 + f1;
  }
}

With the core set up you can now add methods to do for example rotation:

rotate: function(angle) {
    var cos = Math.cos(angle),
        sin = Math.sin(angle);
    this.transform(cos, sin, -sin, cos, 0, 0);
}

scale:

scale: function(sx, sy) {
    this.transform(sx, 0, 0, sy, 0, 0);
}

translate:

translate: function(tx, ty) {
    this.transform(1, 0, 0, 1, tx, ty);
}

and so forth depending on your needs. Note that these will accumulate as with the ordinary canvas/SVG matrix. Reset to identity to remove all transforms.

All you need to do now is to feed your points after settings transformation to get the absolute points - lets say we have a box of 100x100 we want to rotate at center:

Adding this to the prototype:

applyToPoint: function(p) {
    return {
      x: p.x * this.a + p.y * this.c + this.e,
      y: p.x * this.b + p.y * this.d + this.f
    }
}

will allow us to do:

var m = new Matrix();
m.translate(50, 50);
m.rotate(0.3);
m.translate(-50, 50);

var points = [
      {x: 0, y: 0},      // upper-left
      {x: 100, y: 0},    // upper-right
      {x: 100, y: 100},  // bottom-right
      {x: 0, y: 100}     // bottom-left
    ],
    result = [],
    i = 0, p;

// transform points
while(p = points[i++]) result.push(m.applyToPoint(p));

Demo

Red box is original coordinates, blue is the transformed points which we now have access to:

function Matrix() {
  this.a = 1; // identity matrix
  this.b = 0;
  this.c = 0;
  this.d = 1;
  this.e = 0;
  this.f = 0;
}

Matrix.prototype = {

    applyToPoint: function(p) {
      return {
        x: p.x * this.a + p.y * this.c + this.e,
        y: p.x * this.b + p.y * this.d + this.f
      }
    },

    transform: function(a2, b2, c2, d2, e2, f2) {

      var a1 = this.a,
          b1 = this.b,
          c1 = this.c,
          d1 = this.d,
          e1 = this.e,
          f1 = this.f;

      /* matrix order (canvas compatible):
       * ace
       * bdf
       * 001
       */
      this.a = a1 * a2 + c1 * b2;
      this.b = b1 * a2 + d1 * b2;
      this.c = a1 * c2 + c1 * d2;
      this.d = b1 * c2 + d1 * d2;
      this.e = a1 * e2 + c1 * f2 + e1;
      this.f = b1 * e2 + d1 * f2 + f1;
    },

    rotate: function(angle) {
      var cos = Math.cos(angle),
          sin = Math.sin(angle);
      this.transform(cos, sin, -sin, cos, 0, 0);
    },

    scale: function(sx, sy) {
      this.transform(sx, 0, 0, sy, 0, 0);
    },

    translate: function(tx, ty) {
      this.transform(1, 0, 0, 1, tx, ty);
    }
};

// apply some transformation:
var m = new Matrix();     // our manual transformation-matrix
m.translate(50, 50);      // center of box
m.rotate(0.3);            // some angle in radians
m.translate(-50, -50);    // translate back

var points = [
      {x: 0, y: 0},       // upper-left
      {x: 100, y: 0},     // upper-right
      {x: 100, y: 100},   // bottom-right
      {x: 0, y: 100}      // bottom-left
    ],
    result = [], i = 0, p;

// transform points
while(p = points[i++]) result.push(m.applyToPoint(p));

// draw boxes to canvas:
var ctx = document.querySelector("canvas").getContext("2d");
ctx.translate(30, 30);    // give some room for rotation for this demo

drawPolygon(points, "red");
drawPolygon(result, "blue");
 
drawCoord(points[0]);     // plot old point
drawCoord(result[0]);     // plot resulting point

// Compare using ordinary canvas: -------------------

ctx.translate(150, 0);     // give some space
ctx.fillText("Regular canvas:", 0, -20);

drawPolygon(points, "red");

ctx.translate(50, 50);      // center of box
ctx.rotate(0.3);            // some angle in radians
ctx.translate(-50, -50);    // translate back

drawPolygon(points, "blue");


// plot result:
function drawPolygon(pts, color) {
  ctx.beginPath();
  ctx.strokeStyle = color;
  ctx.moveTo(pts[0].x, pts[0].y);
  for(var i = 1, p; p = pts[i++];) ctx.lineTo(p.x, p.y);
  ctx.closePath();
  ctx.stroke();
}

function drawCoord(p) {
  ctx.fillStyle = "#0c0"; ctx.fillRect(p.x - 2, p.y - 2, 4, 4);
  ctx.fillStyle = "#000";
  ctx.fillText(p.x.toFixed(1) + "," + p.y.toFixed(1), p.x, p.y - 2);
}

<canvas><canvas>

If you don't want to implement this yourselves, or want a more extensive solution, feel free to check out my (free) matrix solution here.

The future will give us currentTransform on the context (currently only available in Chrome, Firefox struggles with a bug) returning a SVGMatrix object which you can use in pretty much the same way as the above implementation.

这篇关于在javascript中旋转一个正方形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆