Ad

Need to do 2d affine transformations, or rotate stuff in 3d for your toy canvas library? look no further, the solution is here! Or at least it will be if you help improve this thing by forking it.

var mat3 = (function(){

    function Mat3(a){
      if(!a) return mat3.identity();
      this.a = [];
      for(var i = 0; i < 9; i++) this.a[i] = a[i] || 0;
    };

    Mat3.prototype.add = function(mat){
      return mat3([
        this.a[0] + mat.a[0], this.a[1] + mat.a[1], this.arr[2] + mat.a[2],
        this.a[3] + mat.a[3], this.a[4] + mat.a[4], this.arr[5] + mat.a[5],
        this.a[6] + mat.a[6], this.a[7] + mat.a[7], this.arr[8] + mat.a[8]
      ]); 
    };
    
    Mat3.prototype.applyToCanvasContext = function(ctx){
      ctx.transform(this.a[0], this.a[3], this.a[1], this.a[4], this.a[2], this.a[5]);
    };
    
    Mat3.prototype.equals = function(mat){
      return this.a[0] === mat.a[0] && this.a[1] === mat.a[1] && this.a[2] === mat.a[2]
          && this.a[3] === mat.a[3] && this.a[4] === mat.a[4] && this.a[5] === mat.a[5]
          && this.a[6] === mat.a[6] && this.a[7] === mat.a[7] && this.a[8] === mat.a[8];
    };
    
    Mat3.prototype.toString = function(){
      return '[' + this.a.join(',') + ']';
    };
    
    // Matrix-Vector multiplication
    Mat3.prototype.transform3d = function(v){
      return [
        v[0] * this.a[0] + v[1] * this.a[1] + v[2] * this.a[2],
        v[0] * this.a[3] + v[1] * this.a[4] + v[2] * this.a[5],
        v[0] * this.a[6] + v[1] * this.a[7] + v[2] * this.a[8]
      ];
    };
    
    // 2d affine transformation
    Mat3.prototype.transform2d = function(v){
      var v2 = this.transform3d([v[0],v[1],1]);
      return [v2[0],v2[1]];
    };
    
    Mat3.prototype.inverse = function(){
      var f = this.a[0] * (this.a[4]*this.a[8] - this.a[5]*this.a[7])
            + this.a[1] * (this.a[5]*this.a[6] - this.a[3]*this.a[8])
            + this.a[2] * (this.a[3]*this.a[7] - this.a[4]*this.a[6]);
    
      return mat3([
        this.a[4]*this.a[8] - this.a[5]*this.a[7],
        this.a[2]*this.a[7] - this.a[1]*this.a[8],
        this.a[1]*this.a[5] - this.a[2]*this.a[4],
        
        this.a[5]*this.a[6] - this.a[3]*this.a[8],
        this.a[0]*this.a[8] - this.a[2]*this.a[6],
        this.a[2]*this.a[3] - this.a[0]*this.a[5],
        
        this.a[3]*this.a[7] - this.a[4]*this.a[6],
        this.a[1]*this.a[6] - this.a[0]*this.a[7],
        this.a[0]*this.a[4] - this.a[1]*this.a[3]
      ]).multiplyScalar(1/f);
    };
    
    Mat3.prototype.multiply = function(mat){
      return mat3([
        this.a[0] * mat.a[0] + this.a[1] * mat.a[3] + this.a[2] * mat.a[6],
        this.a[0] * mat.a[1] + this.a[1] * mat.a[4] + this.a[2] * mat.a[7],
        this.a[0] * mat.a[2] + this.a[1] * mat.a[5] + this.a[2] * mat.a[8],
    
        this.a[3] * mat.a[0] + this.a[4] * mat.a[3] + this.a[5] * mat.a[6],
        this.a[3] * mat.a[1] + this.a[4] * mat.a[4] + this.a[5] * mat.a[7],
        this.a[3] * mat.a[2] + this.a[4] * mat.a[5] + this.a[5] * mat.a[8],
    
        this.a[6] * mat.a[0] + this.a[7] * mat.a[3] + this.a[8] * mat.a[6],
        this.a[6] * mat.a[1] + this.a[7] * mat.a[4] + this.a[8] * mat.a[7],
        this.a[6] * mat.a[2] + this.a[7] * mat.a[5] + this.a[8] * mat.a[8]
      ]);
    };
    
    Mat3.prototype.multiplyScalar = function(s){
      return mat3([
        this.a[0] * s, this.a[1] * s, this.arr[2] * s,
        this.a[3] * s, this.a[4] * s, this.arr[5] * s,
        this.a[6] * s, this.a[7] * s, this.arr[8] * s
      ]);
    };
    
    Mat3.prototype.transpose = function(){
      return mat3([
        this.a[0], this.a[3], this.a[6],
        this.a[1], this.a[4], this.a[7],
        this.a[2], this.a[5], this.a[8]
      ]);
    };

    function mat3(a){
      return new Mat3(a);
    };
    
    mat3.identity = function(){
      return mat3([1,0,0,0,1,0,0,0,1]);
    };
    
    // 2d rotation
    mat3.rotate = function(phi){
      var s = Math.sin(phi), c = Math.cos(phi);
      return mat3([c,s,0,-s,c,0,0,0,1]);
    };
    
    // 3d rotations
    mat3.rotate.z = mat3.rotate;
    
    mat3.rotate.y = function(phi){
      var s = Math.sin(phi), c = Math.cos(phi);
      return mat3([c,0,s,0,1,0,-s,0,c]);
    };
    
    mat3.rotate.x = function(phi){
      var s = Math.sin(phi), c = Math.cos(phi);
      return mat3([1,0,0,0,c,-s,0,s,c]);
    };
    
    mat3.scale = function(x, y, z){
      return mat3([x,0,0,0,y,0,0,0,z||1]);
    };
    
    mat3.translate = function(x, y){
      return mat3([1,0,x,0,1,y,0,0,1]);
    };
    
    mat3.Mat3 = Mat3;

    return mat3;

})();