2015-06-01 6 views
0

Я пытаюсь повернуть квадрат вокруг своего центра в 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();` 

Ориентация - значение от -90-90 градусов. Этот код начинает вращать квадрат, но квадрат продолжает «хлюпать», пока он полностью не исчезнет на 90 градусов. Очевидно, моя формула для вращения отбрасывается где-то, но я не могу понять, как это сделать.

+0

вы меняете 'tlx', затем используя измененное значение, чтобы выяснить' tly'. то же самое для всех других значений. во всех вычислениях вам необходимо использовать значения ORIGINAL. –

+0

Посмотрите на ответ здесь: http://stackoverflow.com/questions/5998924/how-can-i-rotate-a-shape-in-canvas-html5 Я думаю, что это будет проще и может быть сделано для нескольких фигур. Второй ответ с большим количеством голосов. –

+0

wow, nice catch, я разработал математику на бумаге, прежде чем делать это, и я даже не подумал, что обновляю x перед вычислением нового y. – DirkDefenderJr

ответ

3

Вы можете вручную ввести transformation matrix. Это позволяет вам настроить матрицу как для чтения, так и для записи, а затем применить ее к точкам, возвращающим абсолютные точки, с новыми фактическими значениями без необходимости или хлопот для создания специального кода для каждого случая использования.

Формула (2D аффинных) с использованием матрицы 3x3 будет:

3x3 affine matrix

или упрощены в 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 

Теперь вы должны умножить матрицу с другой добавить ротацию, перевод, масштаб и т. д. Общий способ сделать это - предположим, что у нас есть объект, содержащий наши значения, вы можете сделать:

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; 
    } 
} 

С ядром созданной теперь вы можете добавить методы, чтобы сделать, например, вращения:

rotation

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); 
} 

и т. д. в зависимости от ваших потребностей. Обратите внимание, что они будут накапливаться как с обычной матрицей canvas/SVG. Сбросьте идентификатор, чтобы удалить все преобразования.

Все, что вам нужно сделать сейчас, чтобы кормить свои очки после преобразования параметров, чтобы получить абсолютные точки - позволяет сказать, что мы имеем коробку 100x100, мы хотим, чтобы повернуть в центре:

Добавление этого к прототипу:

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 
    } 
} 

позволит нам сделать:

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

Красная коробка оригинальные координаты, синий преобразованные точки, которые мы получили доступ к:

snapshot

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>

Если вы не хотите, чтобы это реализовать себя, или хотите более обширное решение, не стесняйтесь проверить мой (бесплатно) matrix solution here.

future will give us currentTransform от контекста (в настоящее время доступны только в Chrome, Firefox борется с bug) возвращает SVGMatrix object, который вы можете использовать в значительной степени так же, как и выше реализации.

Смежные вопросы