Matrix JS test

JavaScript performance comparison

Test case created by Joshua Smock

Info

Testing my implementation of CSS matrix performance by testing my old vs new code

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
Old (not general)
var cssMatrix = function(obj) {
  var multiply = function(_m) {
    // Go through each row against each current matrix's column
    _n = [
      [],
      [],
      []
    ];
    __m.forEach(function(ele, i) {
      _n[i][0] = ele[0] * _m[0][0] + ele[1] * _m[1][0] + ele[2] * _m[2][0];
      _n[i][1] = ele[0] * _m[0][1] + ele[1] * _m[1][1] + ele[2] * _m[2][1];
      _n[i][2] = ele[0] * _m[0][2] + ele[1] * _m[1][2] + ele[2] * _m[2][2];
    });
    __m = _n;
  };

  var makeMatrix = function(obj) {
    var i;
    var _m = [
      [1, 0, 0],
      [0, 1, 0],
      [0, 0, 1]
    ];
    for (var k in obj) {
      if (k >= 0 && k < 3) {
        i = 0;
      } else if (k >= 3 && k < 6) {
        i = 1;
      } else {
        i = 2;
      }
      _m[i][k % 3] = obj[k];
    }
    return _m;
  };

  var translateAngle = function(angle) {
    _t = !! (typeof angle == "number");
    if (_t || angle.match(/^[0-9]*(deg|turn|grad|rad)?$/)) {
      if (!_t)
        var _a = angle.match(/^[0-9]*/);
      else
        return angle * (Math.PI / 180);
      if (angle.match(/^[0-9]*deg$/))
        return _a * (Math.PI / 180);
      else if (angle.match(/^[0-9]*grad$/))
        return _a * (Math.PI / 200);
      else if (angle.match(/^[0-9]*rad$/))
        return _a;
      else if (angle.match(/^[0-9]*turn$/))
        return _a * 2 * Math.PI;
      else
        return 0;
    } else {
      return 0;
    }
  };

  var __m = makeMatrix({});
  for (var i in obj) {
    var _m = (function(i) {
      switch (i) {
        case 'translateX':
          return makeMatrix({
            2: obj[i]
          });
        case 'translateY':
          return makeMatrix({
            5: obj[i]
          });
        case 'scale':
          _p = obj[i].split(' ');
          return makeMatrix({
            0: _p[0],
            4: _p[1]
          });
        case 'scaleX':
          return makeMatrix({
            0: obj[i]
          });
        case 'scaleY':
          return makeMatrix({
            4: obj[i]
          });
        case 'skewX':
          return makeMatrix({
            1: Math.tan(translateAngle(obj[i]))
          });
        case 'skewY':
          return makeMatrix({
            4: Math.tan(translateAngle(obj[i]))
          });
        case 'rotate':
          _r = translateAngle(obj[i]);
          return makeMatrix({
            0: Math.cos(_r),
            1: -Math.sin(_r),
            3: Math.sin(_r),
            4: Math.cos(_r)
          });
        case 'squeeze':
          return makeMatrix({
            0: obj[i],
            4: 1 / obj[i]
          });
        case 'reflectX':
          return makeMatrix({
            0: 1 - obj[i],
            2: obj[i]
          });
      }
    })(i);
    multiply(_m);
  }
  return [__m[0][0], __m[1][0], __m[0][1], __m[1][1], __m[0][2], __m[1][2]];
}

cssMatrix({
  translateX: 25,
  squeeze: 2
});
pending…
New (general)
var Matrix = {
  add: function(_m1, _m2) {
    // Add each row to the other row
    _n = [];
    // _m1 num rows must equal _m2 num rows
    if (_m1.length !== _m2.length) {
      return false;
    }

    _m1.forEach(function(ele, i) {
      // Each row needs to be the same size
      // TODO: Case when row is length 1
      if (!(ele.length == _m2[i].length)) {
        if (ele.length > _m2[i].length) {
          _i = ele.length - _m2[i].length;
          for (var j = 0; j < _i; j++) {
            _m2[j].push(0);
          }
        } else {
          _i = _m2[i].length - ele.length;
          for (var j = 0; j < _i; j++) {
            ele.push(0);
          }
        }
      }

      // Add each row
      _k = [];
      for (var j = 0; j < ele.length; j++) {
        _k.push(ele[j] + _m2[i][j]);
      }
      _n.push(_k);
    });
    return _n;
  },

  multiply: function(_m1, _m2) {
    // _m1 is generally var matrix
    // _m2 is the matrix multiplying against matrix
    // _m1 row size must equal m2 column size (num elements)
    _n = [];

    if (_m1[0].length !== _m2.length) {
      return false;
    }

    _m1.forEach(function(ele, i) {
      _k = [];
      ele.forEach(function(_e, j) {
        sum = 0;
        for (var k = 0; k < ele.length; k++) {
          sum += ele[k] * _m2[k][j];
        }
        _k.push(sum);
      });
      _n.push(_k);
    });
    return _n;
  }
};

var cssMatrix2D = function(obj) {
  // CSS 2d matrix transformations
  var _matrix = [
    [1, 0, 0],
    [0, 1, 0],
    [0, 0, 1]
  ];

  // Translates a CSS angle into radians
  // Returns 0 if unable to parse (is this desired, or should it return an error?)
  var translateAngle = function(angle) {
    if (typeof angle == "number") {
      // Assume that the value is a degree
      return angle * (Math.PI / 180);
    } else if (typeof angle == "string") {
      _a = angle.match(/^[0-9]*/);
      if (angle.match(/^[0-9]*deg$/)) {
        return _a * (Math.PI / 180);
      } else if (angle.match(/^[0-9]*grad$/)) {
        return _a * (Math.PI / 200);
      } else if (angle.match(/^[0-9]*rad$/)) {
        return _a;
      } else if (angle.match(/^[0-9]*turn$/)) {
        return _a * 2 * Math.PI;
      } else {
        return 0;
      }
    } else {
      return 0;
    }
  };

  var translateX = function(val) {
    var _m = [
      [0, 0, val],
      [0, 0, 0],
      [0, 0, 1]
    ];
    _matrix = Matrix.add(_matrix, _m);
  };

  var translateY = function(val) {
    var _m = [
      [0, 0, 0],
      [0, 0, val],
      [0, 0, 1]
    ];
    _matrix = Matrix.add(_matrix, _m);
  };

  var scale = function(x, y) {
    var _m = [
      [x, 0, 0],
      [0, y, 0],
      [0, 0, 1]
    ];
    _matrix = Matrix.multiply(_matrix, _m);
  };

  var scaleX = function(val) {
    var _m = [
      [val],
      [0],
      [0]
    ];
    _matrix = Matrix.multiply(_matrix, _m);
  };

  var scaleY = function(val) {
    var _m = [
      [1, 0, 0],
      [0, val, 0],
      [0, 0, 1]
    ];
    _matrix = Matrix.multiply(_matrix, _m);
  };

  var skew = function(x, y) {
    var _m = [
      [1, Math.tan(translateAngle(x)), 0],
      [Math.tan(translateAngle(y)), 1, 0],
      [0, 0, 1]
    ];
    _matrix = Matrix.multiply(_matrix, _m);
  };

  var skewX = function(val) {
    var _m = [
      [1, Math.tan(translateAngle(val)), 0],
      [0, 1, 0],
      [0, 0, 1]
    ];
    _matrix = Matrix.multiply(_matrix, _m);
  };

  var skewY = function(val) {
    var _m = [
      [1, 0, 0],
      [Math.tan(translateAngle(val)), 1, 0],
      [0, 0, 1]
    ];
    _matrix = Matrix.multiply(_matrix, _m);
  };

  var rotate = function(val) {
    var _m = [
      [Math.cos(translateAngle(val)), -Math.sin(translateAngle(val)), 0],
      [Math.sin(translateAngle(val)), Math.cos(translateAngle(val)), 0],
      [0, 0, 1]
    ];
    _matrix = Matrix.multiply(_matrix, _m);
  };

  var squeeze = function(val) {
    _m = [
      [val, 0, 0],
      [0, 1 / val, 0],
      [0, 0, 1]
    ];
    _matrix = Matrix.multiply(_matrix, _m);
  };

  var reflectX = function(val) {
    _m = [
      [1 - val, 0, val],
      [0, 1, 0],
      [0, 0, 1]
    ];
    _matrix = Matrix.multiply(_matrix, _m);
  };

  for (var i in obj) {
    switch (i) {
      case 'translateX':
        translateX(obj[i]);
        break;
      case 'translateY':
        translateY(obj[i]);
        break;
      case 'scale':
        scale(obj[i][0], obj[i][1]);
        break;
      case 'scaleX':
        scaleX(obj[i]);
        break;
      case 'scaleY':
        scaleY(obj[i]);
        break;
      case 'skew':
        skew(obj[i][0], obj[i][1]);
        break;
      case 'skewX':
        skewX(obj[i]);
        break;
      case 'skewY':
        skewY(obj[i]);
        break;
      case 'rotate':
        rotate(obj[i]);
        break;
      case 'squeeze':
        squeeze(obj[i]);
        break;
      case 'reflectX':
        reflectX(obj[i]);
        break;
    }
  }

  return [_matrix[0][0], _matrix[1][0], _matrix[0][1], _matrix[1][1], _matrix[0][2], _matrix[1][2]];
};

cssMatrix2D({
  translateX: 25,
  squeeze: 2
});
pending…

You can edit these tests or add even more tests to this page by appending /edit to the URL.

Compare results of other browsers

0 comments

Add a comment