Starts work on transform stack.
authordsc <david.schoonover@gmail.com>
Thu, 4 Nov 2010 05:46:26 +0000 (22:46 -0700)
committerdsc <david.schoonover@gmail.com>
Thu, 4 Nov 2010 05:46:26 +0000 (22:46 -0700)
35 files changed:
css/lttl.css
index.php
notes.md
src/Y/core.js
src/Y/modules/y.control.js [new file with mode: 0644]
src/Y/modules/y.event.js
src/Y/modules/y.op.js [deleted file]
src/Y/y-class.js
src/Y/y-core.js
src/Y/y-function.js
src/Y/y-number.js
src/Y/y-string.js
src/lessly/bitgrid.js
src/lessly/draw.js
src/lessly/log.js
src/lessly/viewport.js
src/portal/layer.js
src/portal/shape.js
src/portal/transform.js [new file with mode: 0644]
src/portal/util/eventloop.js
src/portal/util/fps.js
src/portal/util/loc.js
src/portal/util/pointquadtree.js
src/portal/util/quadtree.js
src/portal/util/rbtree.js
src/tanks/game/game.js
src/tanks/game/map.js
src/tanks/game/player.js
src/tanks/globals.js [new file with mode: 0644]
src/tanks/ui.js
src/tanks/unit/tank.js
src/tanks/unit/thing.js
src/tanks/util/calc.js [new file with mode: 0644]
src/tanks/util/grid.js
src/tanks/util/pathmap.js

index 0bd2596..5b26d43 100644 (file)
@@ -6,8 +6,8 @@ ul, ol, li { list-style: none ! important; margin:0; padding:0; }
 
 .rounded { border-radius:1em; -moz-border-radius:1em; -webkit-border-radius:1em; }
 
-#viewport { position:relative; top:1em; width:500px; height:500px; margin:0 auto;
-    /* outline:1px solid #ccc; */ }
+#viewport { position:relative; top:1em; width:500px; height:500px; margin:0 auto; overflow:hidden;
+    /* outline:1px solid #aaa; */ }
 
 #howto { position:fixed; top:3em; right:1em; color:#BFBFBF; }
 
index e2b5d7a..f22a776 100644 (file)
--- a/index.php
+++ b/index.php
@@ -50,17 +50,15 @@ $scripts = array(
     "src/portal/util/cooldown.js",
     "src/portal/util/loc.js",
     
+    "src/tanks/globals.js",
+    "src/tanks/util/calc.js",
     "src/tanks/util/pathmap.js",
     "src/tanks/util/grid.js",
-    
     "src/tanks/game/game.js",
     "src/tanks/game/map.js",
-    
     "src/tanks/unit/thing.js",
     "src/tanks/unit/tank.js",
-    
     "src/tanks/game/player.js",
-    
     "src/tanks/lttl.js",
     "src/tanks/ui.js"
     
index 1d5c4a2..dc5d10b 100644 (file)
--- a/notes.md
+++ b/notes.md
@@ -1 +1,2 @@
-- Clipping is going to suck
\ No newline at end of file
+- Clipping is going to suck
+- TODO Replace *2 and /2 with shifts at compile-time
\ No newline at end of file
index bc22ed7..4536fb6 100644 (file)
@@ -20,6 +20,16 @@ function reduce(o, fn, acc, cxt){
     return acc;
 }
 
+function set(o, key, value, def){
+    if ( o && notSelfOrWrapped(o.set) )
+        return o.set.apply(o, slice.call(arguments,1));
+    
+    if ( o && key !== undefined )
+        o[key] = (value !== undefined ? value : def);
+    
+    return o;
+}
+
 function attr(o, key, value, def){
     if ( o && notSelfOrWrapped(o.attr) )
         return o.attr.apply(o, slice.call(arguments,1));
@@ -30,8 +40,7 @@ function attr(o, key, value, def){
         return extend(o, key);
     
     if ( value !== undefined || def !== undefined ){
-        o[key] = (value !== undefined ? value : def);
-        return o;
+        return set(o, key, value, def);
     } else
         return o[key];
 }
diff --git a/src/Y/modules/y.control.js b/src/Y/modules/y.control.js
new file mode 100644 (file)
index 0000000..84631ef
--- /dev/null
@@ -0,0 +1,48 @@
+(function(Y, undefined){ if (!Y) return;
+
+/* Functional Control "Statements" */
+Y.extend(Y.op, { 
+    
+    // flow
+    either: function( test, t, f ){ return function(v){ return test(v) ? t : f; }; },
+    dowhile: function( test, action ){
+        return function(v){
+            var acc = v;
+            while( test(acc) ){ acc = action(acc); }
+            return acc;
+        };
+    },
+    dountil: function( test, action ){ 
+        return Y.ops.dowhile( function(v){ return !test(v); }, action ); 
+    },
+    forloop: function( test, action, pretest, posttest ){
+        pretest = pretest || Y.ops.I;
+        posttest = posttest || Y.ops.I;
+        return function(v){
+            for(var acc = pretest(v); test(acc); acc = posttest(acc) ){
+                acc = action(acc);
+            }
+            return acc;
+        };
+    },
+    repeat: function( action, n ){
+        return function(v){
+            for( var acc = v, i = 0; i < n; ++i ){ acc = action(acc); }
+            return acc;
+        };
+    },
+    maybe: function( pitcher, catcher ){
+        return function(){
+            var args = Y(arguments);
+            try { 
+                return pitcher.apply( this, args );
+            } catch(e) {
+                args.unshift(e);
+                return catcher.apply( this, args );
+            }
+        };
+    }
+});
+
+
+})(this.Y);
index 8b8cdce..7e085cf 100644 (file)
@@ -11,7 +11,7 @@ ns = Y.event = {}
  */
 , YEvent = ns.YEvent = 
 Y.YObject.subclass('YEvent', {
-    init : function( type, target, trigger, data ){
+    init : function init( type, target, trigger, data ){
         data = data || {};
         for (var k in data) this[k] = data[k];
         this.data = this._o = data;
@@ -28,23 +28,23 @@ Y.YObject.subclass('YEvent', {
  * A simple multicaster.
  */
 , methods = {
-    getQueue : function(evt){
+    getQueue : function getQueue(evt){
         var Qs = this.queues;
         if ( !Qs[evt] )
             Qs[evt] = Y([]);
         return Qs[evt];
     },
     
-    addEventListener : function(evt, fn){
+    addEventListener : function addEventListener(evt, fn){
         this.getQueue(evt).push(fn);
         return this.target;
     },
     
-    removeEventListener : function(evt, fn){
+    removeEventListener : function removeEventListener(evt, fn){
         this.getQueue(evt).remove(fn);
     },
     
-    fire : function(evtname, trigger, data, async){
+    fire : function fire(evtname, trigger, data, async){
         var evt = new YEvent(evtname, this.target, trigger, data);
         if (async)
             setTimeout(this.dispatchEvent.bind(this, evt), 10);
@@ -54,7 +54,7 @@ Y.YObject.subclass('YEvent', {
     },
     
     // XXX: does not handle degenerate or recursive event dispatch
-    dispatchEvent : function(evt){
+    dispatchEvent : function dispatchEvent(evt){
         this.getQueue(evt.type).invoke('call', evt.target, evt);
         if (this.parent) this.parent.fire(evt.type, evt.trigger, evt.data);
         return evt;
@@ -63,7 +63,7 @@ Y.YObject.subclass('YEvent', {
     /**
      * Decorates object with bound methods to act as a delegate of this hub.
      */
-    decorate : function(delegate){
+    decorate : function decorate(delegate){
         if (!delegate) return;
         for (var k in methods)
             delegate[k] = methods[k].bind(this);
diff --git a/src/Y/modules/y.op.js b/src/Y/modules/y.op.js
deleted file mode 100644 (file)
index d8260a4..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-(function(Y, undefined){ if (!Y) return;
-
-/* Functional Operators (Taste Great with Curry!) */
-Y.op = { 
-    
-    // comparison
-    cmp:    function(x,y){  return x == y ? 0 : (x > y ? 1 : -1); },
-    eq:     function(x,y){  return x == y; },
-    ne:     function(x,y){  return x != y; },
-    gt:     function(x,y){  return x  > y; },
-    ge:     function(x,y){  return x >= y; },
-    lt:     function(x,y){  return x  < y; },
-    le:     function(x,y){  return x <= y; },
-    
-    // math
-    add:    function(x,y){  return x  + y; },
-    sub:    function(x,y){  return x  - y; },
-    mul:    function(x,y){  return x  * y; },
-    div:    function(x,y){  return x  / y; },
-    flrdiv: function(x,y){  return Math.floor(x / y); },
-    mod:    function(x,y){  return x  % y; },
-    
-    // logic
-    and:    function(x,y){  return x && y; },
-    or:     function(x,y){  return x || y; },
-    xor:    function(x,y){  return x != y; },
-    not:    function(x){    return !x; },
-    neg:    function(x){    return -x; },
-    
-    // bitwise
-    bitnot: function(x){    return ~x; },
-    bitand: function(x,y){  return x  & y; },
-    bitor:  function(x,y){  return x  | y; },
-    bitxor: function(x,y){  return x  ^ y; },
-    lshift: function(x,y){  return x << y; },
-    rshift: function(x,y){  return x >> y; },
-    zrshift: function(x,y){ return x >>> y; },
-    
-    // typecast
-    bool:   function(x){    return !!x; },
-    number: function(x){    return Number(x); },
-    int:    function(x){    return parseInt(x); },
-    float:  function(x){    return parseFloat(x); },
-    str:    function(x){    return String(x); },
-    
-    // functional
-    I:      function(x){    return x; },
-    K:      function(k){    return function(){ return k; }; },
-    nop:    function(){},
-    
-    // accessors
-    isset:  function(o,def){ return o !== undefined ? o : def; },
-    has:    function(x,y){  return y in x; },
-    getkey: function(k,o){  return o[k] },
-    getdef: function(o,k,def){ return (k in o ? o[k] : def); },
-    set:    function(o,k,v){ if (o) o[k] = v; return o; },
-    
-    
-    // flow
-    either: function( test, t, f ){ return function(v){ return test(v) ? t : f; }; },
-    dowhile: function( test, action ){
-        return function(v){
-            var acc = v;
-            while( test(acc) ){ acc = action(acc); }
-            return acc;
-        };
-    },
-    dountil: function( test, action ){ 
-        return Y.ops.dowhile( function(v){ return !test(v); }, action ); 
-    },
-    forloop: function( test, action, pretest, posttest ){
-        pretest = pretest || Y.ops.I;
-        posttest = posttest || Y.ops.I;
-        return function(v){
-            for(var acc = pretest(v); test(acc); acc = posttest(acc) ){
-                acc = action(acc);
-            }
-            return acc;
-        };
-    },
-    repeat: function( action, n ){
-        return function(v){
-            for( var acc = v, i = 0; i < n; ++i ){ acc = action(acc); }
-            return acc;
-        };
-    },
-    maybe: function( pitcher, catcher ){
-        return function(){
-            var args = Y(arguments);
-            try { 
-                return pitcher.apply( this, args );
-            } catch(e) {
-                args.unshift(e);
-                return catcher.apply( this, args );
-            }
-        };
-    }
-};
-
-
-})(this.Y);
index d297e05..ee07b8c 100644 (file)
@@ -118,9 +118,10 @@ Y.subclass = Class;
 Class.instantiate = 
     function(){
         var instance = this.fabricate();
-        if ( instance.init )
-            return instance.init.apply(instance, arguments);
-        else
+        if ( instance.init ) {
+            var r = instance.init.apply(instance, arguments);
+            return (r !== undefined ? r : instance);
+        } else
             return instance;
     };
     
index 10a9b26..995751b 100644 (file)
@@ -1,5 +1,6 @@
 
 Y.reduce = reduce;
+Y.set    = set;
 Y.attr   = attr;
 Y.extend = extend;
 
index ef502f9..01edb5a 100644 (file)
@@ -18,7 +18,7 @@ Y.extend(YFunction.prototype, {
     init   : YFunction,
     reduce : methodize(Y.reduce),
     extend : methodize(Y.extend),
-    end : function(){ return this; }
+    end : function end(){ return this; }
 });
 YFunction.prototype.attr   = methodize(Y.attr);
 // YFunction.prototype.extend = methodize(Y.extend);
@@ -185,28 +185,40 @@ function genericize( fn ) {
 // XXX: hashCode()
 Y.memoize = memoize;
 YFunction.prototype.memoize = methodize(memoize);
-function memoize(fn){
+
+/**
+ * @param {Function} fn Function to memorize.
+ * @param {Array -> String} [keyfn] Serializes an array of arguments to a string. By default, joins with three nulls.
+ * @param {Object} [cacher] Object on which to store the memorization cache for lookups. Useful for meta-caches. Defaults to the memorized function.
+ * @param {String} [cacheName="cache"] Property this cache will be stored under.
+ */
+function memoize(fn, keyfn, cacher, cacheName){
     if (fn.__memoized__) return fn.__memoized__;
-    var cache;
     
-    fn.__memoized__ = memorizer;
-    function memorizer(){
-        // I'd like to use toJSON here, but that won't work cross-browser.
-        var key = Y(arguments).join('\0');
-        if ( !(key in cache) )
-            cache[key] = fn.apply(this, arguments);
-        return cache[key];
-    }
+    var m =
+    fn.__memoized__ =
+        function memorizer(){
+            var key = keyfn(Y(arguments))
+            ,   cache = cacher[cacheName] ;
+            if ( !(key in cache) )
+                cache[key] = fn.apply(this, arguments);
+            return cache[key];
+        };
     
-    memorizer.purge = purge;
-    function purge(){
-        memorizer.cache = cache = {};
-    }
+    // toJSON would be a better alternative, but that won't work cross-browser
+    keyfn     = keyfn  || function keyfn(args){ return args.join('\0\0\0'); };
+    cacher    = cacher || m;
+    cacheName = cacheName || 'cache';
     
-    purge();
-    memorizer.__wraps__ = fn;
+    m.__wraps__ = fn;
+    m.purge = function purge(){
+        var cache = cacher[cacheName];
+        cacher[cacheName] = {};
+        return cache;
+    };
     
-    return memorizer;
+    m.purge();
+    return m;
 }
 
 // Memorized to reduce eval costs
@@ -214,28 +226,52 @@ var
 _ofArityWrapper =
 YFunction._ofArityWrapper =
     memoize(function(n, limit){
-        return eval('(function(fn){ '+
+        return eval('(function '+(limit ? 'limited' : 'artized')+'(fn){ '+
             'return function('+Y.range(n).map( Y.op.add('$') ).join(',')+'){ '+
                 'return fn.apply(this,' + (limit ? 'Y(arguments).slice(0,'+n+')' : 'arguments')+ 
             '); }; })');
     });
 
-YFunction.prototype.aritize = function(n){
-    return _ofArityWrapper(n, false)(this);
+YFunction.prototype.aritize = 
+function aritize(n){
+    var fn = this
+    ,   cache = fn.__aritized__ ;
+    
+    if (fn.length === n)
+        return fn;
+    
+    if ( !cache )
+        cache = fn.__aritized__ = {};
+    else if ( cache[n] )
+        return cache[n];
+    
+    return ( cache[n] = _ofArityWrapper(n, false)(fn) );
 };
 
-YFunction.prototype.limit = function(n){
-    return _ofArityWrapper(n, true)(this);
+YFunction.prototype.limit = 
+function limit(fn, n){
+    var fn = this
+    ,   cache = fn.__limited__ ;
+    
+    if (fn.length === n)
+        return fn;
+    
+    if ( !cache )
+        cache = fn.__limited__ = {};
+    else if ( cache[n] )
+        return cache[n];
+    
+    return ( cache[n] = _ofArityWrapper(n, true)(fn) );
 };
 
 
 /**
  * Filter the arguments passed to the wrapper function
  */
-YFunction.prototype.mask = mask;
-function mask(){
-    
-}
+// YFunction.prototype.mask = mask;
+// function mask(){
+//     
+// }
 
 
 
@@ -270,6 +306,7 @@ function mixinNames(o, Donor, names, override, yWrap){
 
 YFunction(Y);
 Y(Y.reduce);
+Y(Y.set);
 Y(Y.attr);
 Y(Y.extend);
 Y.reduce(YFunction.prototype, function(_,fn,name){
index c390bb5..dba6137 100644 (file)
@@ -8,13 +8,13 @@ YCollection.subclass('YNumber', {
         YCollection.init.call(this, o);
     },
     
-    compare : function(n){
+    compare : function compare(n){
         var m = this._o;
         return (m > n ?  1 :
                (m < n ? -1 : 0 ));
     },
     
-    toString : function(){
+    toString : function toString(){
         return this.end()+'';
     }
 });
index 57d2ddc..572d443 100644 (file)
@@ -40,7 +40,7 @@ var
 YString =
 Y.YString =
 YCollection.subclass('YString', {
-    init : function(o){
+    init : function init(o){
         if (!o) o = "";
         this._o = o;
         YCollection.init.call(this, o);
@@ -52,7 +52,7 @@ YCollection.subclass('YString', {
     startsWith: startsWith,
     endsWith: endsWith,
     
-    compare : function(n){
+    compare : function compare(n){
         var m = this._o;
         return (m > n ?  1 :
                (m < n ? -1 : 0 ));
index 37efb7b..815b3b5 100644 (file)
@@ -21,7 +21,7 @@ function toY(y){ return Math.floor(y/CELL_Y); }
  * TODO: Optimize set operations
  */
 BitGrid = new Y.Class('BitGrid', {
-    init : function(w, h){
+    init : function init(w, h){
         this.width = w;
         this.height = h;
         
@@ -37,7 +37,7 @@ BitGrid = new Y.Class('BitGrid', {
         // }
     },
     
-    _getCol : function(x){
+    _getCol : function _getCol(x){
         var xi    = toX(x)
         ,   cells = this.cells
         ,   xcell = cells[xi]
@@ -45,7 +45,7 @@ BitGrid = new Y.Class('BitGrid', {
         return xcell || (cells[xi] = []);
     },
     
-    _getCell : function(x,y){
+    _getCell : function _getCell(x,y){
         var xi    = toX(x)
         ,   cells = this.cells
         ,   xcell = cells[xi]
@@ -53,7 +53,7 @@ BitGrid = new Y.Class('BitGrid', {
         return (xcell ? xcell[ toY(y) ] || 0 : 0);
     },
     
-    _setCell : function(x,y, b){
+    _setCell : function _setCell(x,y, b){
         this._getCol(x)[ toY(y) ] = b;
     },
     
@@ -64,7 +64,7 @@ BitGrid = new Y.Class('BitGrid', {
      *      function iter(acc, cell, x, y) -> new acc
      * Returns the final accumulated value.
      */
-    reduce : function(iter, acc, context){
+    reduce : function reduce(iter, acc, context){
         context = context || this;
         var cells = this.cells
         ,   xi_max = toX(this.width)
@@ -85,7 +85,7 @@ BitGrid = new Y.Class('BitGrid', {
      * iter has sig:
      *      function iter(cell, x, y) -> new value
      */
-    map : function(iter, context){
+    map : function map(iter, context){
         context = context || this;
         var col, cell
         ,   cells = this.cells
@@ -109,7 +109,7 @@ BitGrid = new Y.Class('BitGrid', {
      * iter has sig:
      *      function iter(cell, x, y) -> void
      */
-    each : function(iter, context){
+    each : function each(iter, context){
         context = context || this;
         var col
         ,   cells = this.cells
@@ -125,18 +125,18 @@ BitGrid = new Y.Class('BitGrid', {
         return this;
     },
     
-    isSet : function(x,y){
+    isSet : function isSet(x,y){
         return this._getCell(x,y) & toBits(x,y);
     },
     
-    addPoint : function(x,y){
+    addPoint : function addPoint(x,y){
         // if (x < 0 || x > this.width || y < 0 || y > this.height)
         //     return undefined;
         this._getCol(x)[ toY(y) ] |= toBits(x,y);
         return this;
     },
     
-    addRect : function(x1,y1, x2,y2){
+    addRect : function addRect(x1,y1, x2,y2){
         var cells = this.cells
         ,   x_min = toX(x1), x_max = toX(x2)
         ,   y_min = toY(y1), y_max = toY(y2)
@@ -168,7 +168,7 @@ BitGrid = new Y.Class('BitGrid', {
         return this;
     },
     
-    addGrid : function(other){
+    addGrid : function addGrid(other){
         var cells = this.cells
         ,   o_cells = other.cells
         ,   x_len = o_cells.length
@@ -188,7 +188,7 @@ BitGrid = new Y.Class('BitGrid', {
         return this;
     },
     
-    add : function(x1,y1, x2,y2){
+    add : function add(x1,y1, x2,y2){
         var L = arguments.length;
         if (L == 4) {
             this.addRect(x1,y1, x2,y2);
@@ -202,11 +202,11 @@ BitGrid = new Y.Class('BitGrid', {
         return this;
     },
     
-    subtractPoint : function(x,y){
+    subtractPoint : function subtractPoint(x,y){
         this._getCol(x)[ toY(y) ] &= CELL_MASK ^ toBits(x,y);
     },
     
-    subtractRect : function(x1,y1, x2,y2){
+    subtractRect : function subtractRect(x1,y1, x2,y2){
         var cells = this.cells
         ,   x_min = toX(x1), x_max = toX(x2)
         ,   y_min = toY(y1), y_max = toY(y2)
@@ -238,7 +238,7 @@ BitGrid = new Y.Class('BitGrid', {
         return this;
     },
     
-    subtractGrid : function(other){
+    subtractGrid : function subtractGrid(other){
         var cells = this.cells
         ,   o_cells = other.cells
         ,   x_len = o_cells.length
@@ -260,7 +260,7 @@ BitGrid = new Y.Class('BitGrid', {
         return this;
     },
     
-    subtract : function(x1,y1, x2,y2){
+    subtract : function subtract(x1,y1, x2,y2){
         var L = arguments.length;
         if (L == 4) {
             this.subtractRect(x1,y1, x2,y2);
@@ -274,32 +274,32 @@ BitGrid = new Y.Class('BitGrid', {
         return this;
     },
     
-    intersection : function(other){
+    intersection : function intersection(other){
         return this.reduce(function(g, cell, x, y){
             g._setCell(x,y, cell & other._getCell(x,y));
             return g;
         }, new Grid(this.width, this.height));
     },
     
-    union : function(other){
+    union : function union(other){
         return this.reduce(function(g, cell, x, y){
             g._setCell(x,y, cell | other._getCell(x,y));
             return g;
         }, new Grid(this.width, this.height));
     },
     
-    difference : function(other){
+    difference : function difference(other){
         return this.reduce(function(g, cell, x, y){
             g._setCell(x,y, cell & (CELL_MASK ^ other._getCell(x,y)));
             return g;
         }, new Grid(this.width, this.height));
     },
     
-    symmetricDifference : function(grid){
+    symmetricDifference : function symmetricDifference(grid){
         return this.difference(grid).addGrid( grid.difference(this) );
     },
     
-    toDiagram : function(label, selector){
+    toDiagram : function toDiagram(label, selector){
         var 
         self = this,
         el = $('<div class="grid diagram"><div class="close">&otimes;</div><canvas/><label/></div>'),
@@ -371,7 +371,7 @@ BitGrid = new Y.Class('BitGrid', {
         });
     },
     
-    toString : function(){
+    toString : function toString(){
         return 'Grid['+this.width+','+this.height+']()';
     }
 });
index b23b5b0..2024499 100644 (file)
@@ -31,7 +31,7 @@ function YProcessing(P){
 }
 var methods = {
     init : YProcessing,
-    rectXY : function(x1,y1, x2,y2){
+    rectXY : function rectXY(x1,y1, x2,y2){
         return this.rect( x1,y2, x2-x1,y2-y1 );
     }
     
index 7125be6..b1d85bb 100644 (file)
@@ -5,7 +5,7 @@ Log = new Y.Class('Log', {
         prefix : ''
     },
     
-    init : function(el, options){
+    init : function init(el, options){
         this.el = el;
         var o = Y({}, this.DEFAULT_OPTIONS, options || {});
         this.options = o.end();
@@ -25,7 +25,7 @@ Log = new Y.Class('Log', {
         return Logger;
     },
     
-    ready : function(evt){
+    ready : function ready(evt){
         var self = this
         ,   el = self.el = $(self.el)
         ,   n = this.id
@@ -52,13 +52,13 @@ Log = new Y.Class('Log', {
         });
     },
     
-    log : function(){
+    log : function log(){
         var msgs = this.msgs;
         msgs.append('<div class="log_item">'+this.prefix+Y(arguments).join(' ')+'</div>');
         if (this.options.autoScroll) msgs.scrollTop(msgs.attr('scrollHeight'));
     },
     
-    clear : function(){ 
+    clear : function clear(){ 
         this.msgs.empty().append(this.meta_spacer);
     }
 });
index 9a82530..b6de63e 100644 (file)
@@ -13,7 +13,7 @@ Y.subclass(Viewport, Y.event.Emitter, {
      * Creates Processing instance and begins dispatch. 
      * Clients must listen for `setup` prior to init().
      */
-    init : function(){
+    init : function init(){
         var self = this;
         self.processing = new Processing(
             self.canvas, 
@@ -34,7 +34,7 @@ Y.subclass(Viewport, Y.event.Emitter, {
             });
     },
     
-    dispatchEvent : function(evt){
+    dispatchEvent : function dispatchEvent(evt){
         // log.debug('dispatchEvent('+evt.type+')', this);
         this.getQueue(evt.type).each(function(fn){
             fn.call(evt.target, evt, evt.data.api, evt.data.constants);
index 31ac03d..244a684 100644 (file)
@@ -1,28 +1,5 @@
 (function($, undefined){
 
-// Install CSS styles
-$(function(){
-    $('<style />')
-        .text([
-            '.portal.layer { position:absolute; z-index:1; overflow:hidden; top:0; left:0; }',
-            '.portal.layer canvas { z-index:0; }'
-        ].join('\n'))
-        .appendTo('head');
-});
-
-function makeDelegate(name, dirties, prop){
-    prop = prop || 'layer';
-    return function(){
-        if (dirties && arguments.length)
-            this.dirty = true;
-        
-        var target = this[prop]
-        ,   result = target[name].apply(target, arguments);
-        
-        return (result !== target ? result : this);
-    };
-}
-
 Layer = new Y.Class('Layer', {
     _cssClasses : 'portal layer',
     
@@ -34,12 +11,37 @@ Layer = new Y.Class('Layer', {
     ctx      : null,
     dirty    : true,
     
+    canvasWidth  : 0,   layerWidth  : 0,
+    canvasHeight : 0,   layerHeight : 0,
+    
+    x0: 0, y0: 0,
+    
+    // Rotational origin of the layer (or shape)
+    _origin : null, // loc
+    
+    // Bleeds are marks outside the declared layer-size
+    negBleed : null, // loc
+    posBleed : null, // loc
+    
+    // Transforms
+    transforms : null, // YArray
+    
+    
     
     /// Setup ///
     
-    init : function(){
+    init : function init(){
+        this._loc    = new Loc(0,0);
+        this._origin = new Loc(0,0);
+        this._offset = new Loc(0,0);
+        
         this.children = new Y.YArray();
         
+        var transforms = this.transforms = new Y.YArray();
+        transforms.rotation  = 0;
+        transforms.scale     = new Loc(1.0,1.0);
+        transforms.translate = new Loc(0,0);
+        
         this.canvas = jQuery('<canvas />');
         this.ctx = this.canvas[0].getContext('2d');
         
@@ -53,14 +55,14 @@ Layer = new Y.Class('Layer', {
     /// Scene Graph Heirarchy ///
     
     /** @param {Layer} child */
-    append : function(child){
+    append : function append(child){
         new Y(arguments).invoke('appendTo', this);
         // if (child) child.appendTo(this);
         return this;
     },
     
     /** @param {Layer} parent */
-    appendTo : function(parent){
+    appendTo : function appendTo(parent){
         if (!parent) return this;
         
         // Always ensure we detach from the DOM and redraw this node
@@ -83,44 +85,144 @@ Layer = new Y.Class('Layer', {
     /**
      * Removes this layer from its parent and the DOM.
      */
-    remove : function(){
+    remove : function remove(){
         if (this.parent)
             this.parent.children.remove(this);
         this.parent = null;
         this.layer.remove();
     },
     
+    /**
+     * Clears this layer and destroys all children.
+     */
+    empty : function empty(ctx){
+        this.children.invoke('remove');
+        this.clear();
+        return this;
+    },
+    
+    /**
+     * @returns The root of the scene graph.
+     */
+    root : function root(){
+        if (this.parent)
+            return this.parent.root();
+        else
+            return this;
+    },
+    
     
     
     
     
     /// Attributes ///
     
-    width : function(w){
+    /**
+     * Changes the layer's width and then updates the canvas.
+     */
+    width : function width(w){
         if (w === undefined)
             return this.layer.width();
         
-        this.layer.add(this.canvas)
-            .attr({ width : w      })
-            .css( { width : w+'px' });
-        this.canvas[0].width = w;
+        this.layerWidth = w;
+        this.layer.width(w);
+        
+        // We want a canvas larger than our viewport so rotation doesn't require a
+        // bunch of math. We only really need v*sqrt(2), but whatever, this is faster.
+        var off = this._offset.x
+        ,   w2  = this.canvasWidth = w*2 + off;
+        this.canvas.css({
+            'width' : w2+'px',
+            'margin-left' : (-1 * w/2 + off)+'px'
+        });
+        this.canvas[0].width = w2;
         
         return this;
     },
     
-    height : function(h){
+    height : function height(h){
         if (h === undefined)
             return this.layer.height();
         
-        this.layer.add(this.canvas)
-            .css( { height : h+'px' });
-        this.canvas[0].height = h;
+        this._height = h;
+        this.layer.height(h);
+        
+        var h2 = h*2;
+        this.canvas.css({
+            'height' : h2+'px',
+            'margin-top': (-h/2)+'px'
+        });
+        this.canvas[0].height = h2;
+        
+        return this;
+    },
+    
+    origin : function origin(x,y){
+        var o = this._origin;
+        if (arguments.length === 0)
+            return o.clone();
+        
+        o.x = x;
+        o.y = y;
+        return this;
+    },
+    
+    /**
+     * Rotates this layer by theta radians, and then applies rotation relatively
+     * to all sublayers (preserving knowledge of their individual rotations).
+     */
+    rotate : function rotate(rotation){
+        if (rotation === undefined)
+            return this.transforms.rotation;
         
+        // Record my relative rotation...
+        this.transforms.rotation = rotation;
+        
+        // Propogate...
+        var p = this.parent;
+        return this._rotate(p ? p.rotation : 0);
+    },
+    
+    _rotate : function _rotate(cumRotation){
+        this.dirty = true;
+        var absR = this.absRotation = this.rotation+cumRotation;
+        this.children.invoke('_rotate', absR);
         return this;
     },
     
-    viewportWidth  : makeDelegate('width' , true, 'canvas'),
-    viewportHeight : makeDelegate('height', true, 'canvas'),
+    
+    /**
+     * Scales this layer by (sx,sy), and then applies scaling relatively
+     * to all sublayers (preserving knowledge of their individual scaling).
+     */
+    scale : function scale(sx,sy){
+        if (arguments.length === 0)
+            return { 'x': this.absScaleX, 'y': this.absScaleY };
+        
+        // Record my relative scaling...
+        this.dirty = true;
+        this.scaleX = sx;
+        this.scaleY = sy;
+        
+        // Propogate...
+        var p = this.parent
+        ,   ps = (p ? p.scale() : { x:1.0, y:1.0 }) ;
+        return this._scale(ps.x, ps.y);
+    },
+    
+    _scale : function _scale(parentScaleX, parentScaleY){
+        var absX = this.absScaleX = this.scaleX * parentScaleX
+        ,   absY = this.absScaleY = this.scaleY * parentScaleY
+        ;
+        
+        // Apply absolute scaling...
+        this.ctx.scale(absX, absY);
+        
+        // And propogate down the line
+        this.children.invoke('_scale', absX, absY);
+        
+        return this;
+    },
     
     hide : makeDelegate('hide'),
     show : makeDelegate('show'),
@@ -143,7 +245,7 @@ Layer = new Y.Class('Layer', {
      * Sets the position of this node, and then returns it.
      * @param {Object} pos An object with "top" and/or "left" properties as in `position(top, left)`.
      */
-    position : function(left, top){
+    position : function position(left, top){
         if (top === undefined && left === undefined)
             return this.layer.position();
         
@@ -152,6 +254,9 @@ Layer = new Y.Class('Layer', {
         else
             var pos = { 'top': top, 'left':left };
         
+        // if (pos.left !== undefined)  pos.left -= this.offsetX;
+        // if (pos.top  !== undefined)  pos.top  -= this.offsetY;
+        
         this.css(pos);
         return this;
     },
@@ -163,83 +268,164 @@ Layer = new Y.Class('Layer', {
     
     /// Drawing Functions ///
     
-    /**
-     * To be implemented by subclasses.
-     */
-    drawShape : function(ctx){ return this; },
-    
+    // for debugging
+    point : function point(x,y, color, noTransforms){
+        var ctx = this.ctx;
+        this._openPath(ctx);
+        if (!noTransforms) this._applyTransforms(ctx);
+        
+        var r = 2;
+        ctx.arc(x+r,y+r, r, 0, Math.PI*2, false);
+        ctx.fillStyle = color || '#FFFFFF';
+        ctx.fill();
+        
+        this._closePath(ctx);
+        return this;
+    },
     /**
      * @param {CanvasDrawingContext2D} [ctx=this.ctx] Forces context to use rather than the layer's own.
      * @param {Boolean} [force=false] Forces redraw.
      */
-    draw : function(ctx, force){
-        if ( !(this.dirty || force) )
-            return this;
-        
-        var _ctx = ctx || this.ctx;
-        this._openPath(_ctx);
-        this.drawShape(_ctx);
-        this._closePath(_ctx);
+    draw : function draw(ctx, force){
+        if ( this.dirty || force ){
+            var _ctx = ctx || this.ctx;
+            this._openPath(_ctx);
+            this.drawShape(_ctx);
+            this._closePath(_ctx);
+        }
         
         this.dirty = false;
-        this.children.invoke('draw', ctx);
+        this.children.invoke('draw', ctx, force);
         return this;
     },
     
-    _openPath : function(ctx){
+    _openPath : function _openPath(ctx){
+        var w = this.canvas.width()
+        ,   h = this.canvas.height();
+        
         ctx.beginPath();
-        // ctx.lineWidth = 0;
-        // ctx.fillStyle = "transparent";
+        ctx.setTransform(1,0,0,1,0,0);
+        ctx.clearRect(-w,-h, 2*w,2*h);
+        
+        ctx.translate(w/4 + this.originX, h/4 + this.originY);
+        ctx.rotate(this.absRotation);
+        ctx.translate(-this.originX, -this.originY);
+        
+        ctx.scale(this.absScaleX, this.absScaleY);
+        
         return this;
     },
     
-    _closePath : function(ctx){
+    _applyTransforms : function _applyTransforms(){
+        
+    },
+    
+    /**
+     * To be implemented by subclasses.
+     */
+    drawShape : function drawShape(ctx){ return this; },
+    
+    _closePath : function _closePath(ctx){
         ctx.closePath();
         return this;
     },
     
-    clear : function(ctx){
+    /**
+     * Clears this layer and all children.
+     */
+    clear : function clear(ctx){
+        var w = this.canvas.width()
+        ,   h = this.canvas.height();
         ctx = ctx || this.ctx;
         ctx.beginPath();
-        ctx.clearRect(0,0, this.canvas.width(),this.canvas.height());
+        ctx.setTransform(1,0,0,1,0,0);
+        ctx.clearRect(-w,-h, 2*w,2*h);
         ctx.closePath();
+        this.children.invoke('clear');
         return this;
     },
     
     
     
+    
+    
+    
     /// Iterators ///
     
+    invoke : function invoke(name){
+        var args = Y(arguments,1);
+        
+        this[name].apply(this, args);
+        this.children.invoke.apply(this.children, ['invoke', name].concat(args));
+        return this;
+    },
+    
+    setAll : function setAll(k,v){
+        this[k] = v;
+        this.children.invoke('setAll', k,v);
+        return this;
+    },
+    
     /**
-     * fold across this and parents, inner to outer:
+     * Reduce "up", across this and parents, inner to outer:
      *      acc = fn.call(context || node, acc, node)
      */
-    foldParents : function(acc, fn, context){
+    reduceup : function reduceup(acc, fn, context){
         // if ( Y.isFunction(fn) )
         //     acc = fn.call(context || this, acc, this);
         // else
         //     acc = this[fn].call(context || this, acc, this);
         acc = fn.call(context || this, acc, this);
-        return ( this.parent ? this.parent.foldParents(acc, fn, context) : acc );
+        return ( this.parent ? this.parent.reduceup(acc, fn, context) : acc );
     },
     
     /**
-     * fold across this and children, depth-first:
+     * Reduce "down", across this and children, depth-first:
      *      acc = fn.call(context || node, acc, node)
      */
-    foldChildren : function(acc, fn, context){
+    reduce : function reduce(acc, fn, context){
         acc = fn.call(context || this, acc, this);
-        return this.children.foldChildren(acc, fn, context);
+        return this.children.reduce(acc, fn, context);
     },
     
     
     
     /// Misc ///
     
-    toString : function(){
+    toString : function toString(){
         var pos = (this.layer ? this.position() : {top:NaN, left:NaN});
         return this.className+'['+pos.left+','+pos.top+']( children='+this.children.size()+' )';
     }
 });
 
+
+// Helpers for building the class
+
+function makeDelegate(name, dirties, prop){
+    prop = prop || 'layer';
+    return function(){
+        if (dirties && arguments.length)
+            this.dirty = true;
+        
+        var target = this[prop]
+        ,   result = target[name].apply(target, arguments);
+        
+        return (result !== target ? result : this);
+    };
+}
+
+// Install CSS styles
+$(function(){
+    $('<style />')
+        .text([
+            '.portal.layer { position:absolute; z-index:1; top:0; left:0; }',
+            '.portal.layer canvas { z-index:0; }'
+        ].join('\n'))
+        .appendTo('head');
+});
+
+
+
+
+
 })(jQuery);
index 364263a..b36a333 100644 (file)
@@ -8,13 +8,7 @@ CONTEXT_ATTRS = Y([
 Shape = new Y.Class('Shape', Layer, {
     _cssClasses : 'portal layer shape',
     
-    x0: 0, y0: 0,
-    
-    _offsetX : 0, // We need our shape to be in the first quadrant
-    _offsetY : 0, // so we'll have to offset any negative shapes at the position call
-    
-    
-    attr : function(key, value, def){
+    attr : function attr(key, value, def){
         if (!key) return this;
         
         if ( Y.isPlainObject(key) ) {
@@ -36,56 +30,31 @@ Shape = new Y.Class('Shape', Layer, {
             return Y.attr(this, key, value, def);
     },
     
-    _calcOffset : function(which, values){
+    _calcDimension : function _calcDimension(which, values){
         values.unshift(0);
         var self = this
         ,   off = -1 * Math.min.apply(Math, values);
         
-        self['_offset'+which.toUpperCase()] = off;
-        self[which+'s'] = values = values.map(function(v, i){
-                // v += (i === 0 ? 0 : off);
-                return (self[which+i] = v + off);
+        self._offset.attr(which, off);
+        return values.map(function(v, i){
+                return (self[which+i] = v);
             });
-        return values;
-    },
-    
-    position : function(left, top){
-        if (top === undefined && left === undefined)
-            return this.layer.position();
-        
-        if (top && Y.isPlainObject(top))
-            var pos = top;
-        else
-            var pos = { 'top':top, 'left':left };
-        
-        if (pos.top  !== undefined)  pos.top  -= this._offsetY;
-        if (pos.left !== undefined)  pos.left -= this._offsetX;
-        
-        this.css(pos);
-        return this;
     }
     
-    
 });
 
 Rect = new Y.Class('Rect', Shape, {
     _cssClasses : 'portal layer shape rect',
     
-    _width  : 0,
-    _height : 0,
-    
-    
-    init : function(w, h){
+    init : function init(w, h){
         Layer.init.call(this);
         
-        this._width = w;
-        this.width(w);
-        
-        this._height = h;
-        this.height(h);
+        this.width(w)
+            .height(h)
+            .origin(w/2, h/2);
     },
     
-    drawShape : function(ctx){
+    drawShape : function drawShape(ctx){
         ctx.rect(0,0, this._width,this._height);
         ctx.fill();
     }
@@ -100,21 +69,24 @@ Polygon = new Y.Class('Polygon', Shape, {
      * together to make the numbered coordinates.
      * x0 and y0 will always be 0.
      */
-    init : function(xs, ys){
+    init : function init(xs, ys){
         Layer.init.call(this);
         
-        var xs = this._calcOffset('x', xs)
-        ,   ys = this._calcOffset('y', ys) ;
+        var xs = this._calcDimension('x', xs)
+        ,   ys = this._calcDimension('y', ys)
+        ,   w  = Math.max.apply(Math, xs)
+        ,   h  = Math.max.apply(Math, ys)
+        ;
         
-        this.points = Y(xs).zip(ys);
-        
-        this.width(  Math.max.apply(Math, xs) );
-        this.height( Math.max.apply(Math, ys) );
+        this.points = Y(xs).zip(ys).map(Loc.instantiate, Loc);
+        this.width(w)
+            .height(h)
+            .origin(w/2, h/2);
     },
     
-    drawShape : function(ctx){
-        this.points.forEach(function(pair, i){
-            ctx.lineTo.apply(ctx, pair);
+    drawShape : function drawShape(ctx){
+        this.points.forEach(function(loc, i){
+            ctx.lineTo(loc.x, loc.y);
         });
         ctx.fill();
     }
@@ -123,15 +95,29 @@ Polygon = new Y.Class('Polygon', Shape, {
 Triangle = new Y.Class('Triangle', Polygon, {
     _cssClasses : 'portal layer shape polygon triangle',
     
-    init : function(x1,y1, x2,y2){
+    init : function init(x1,y1, x2,y2){
         Polygon.init.call(this, [x1,x2], [y1,y2]);
-    }
+    },
+    
+    circumcenter : function circumcenter(){
+        var offX = this.offsetX, offY = this.offsetY
+        ,   x1 = this.x1 - offX, y1 = -1 * (this.y1 - offY) // remember, DOM is Y-inverted
+        ,   x2 = this.x2 - offX, y2 = -1 * (this.y2 - offY) // which affects the signs
+        
+        ,   D = 2 * (x1*y2 - y1*x2)
+        ,   B = Math.pow(x1,2) + Math.pow(y1,2)
+        ,   C = Math.pow(x2,2) + Math.pow(y2,2)
+        ;
+        return { 'x' : offX + (y2*B - y1*C)/D
+               , 'y' : offY + (x1*C - x2*B)/D * -1 // fix inverted Y-axis
+               };
+    },
 });
 
 Quad = new Y.Class('Quad', Polygon, {
     _cssClasses : 'portal layer shape polygon quad',
     
-    init : function(x1,y1, x2,y2, x3,y3){
+    init : function init(x1,y1, x2,y2, x3,y3){
         Polygon.init.call(this, [x1,x2,x3], [y1,y2,y3]);
     }
 });
@@ -139,16 +125,21 @@ Quad = new Y.Class('Quad', Polygon, {
 Circle = new Y.Class('Circle', Shape, {
     _cssClasses : 'portal layer shape circle',
     
-    init : function(radius){
+    init : function init(radius){
         Layer.init.call(this);
         
         var d = radius * 2;
-        this.width(d).height(d);
         this.radius = radius;
+        this.width(d)
+            .height(d)
+            .center(r,r);
     },
     
-    drawShape : function(ctx){
-        var r = this.radius;
+    drawShape : function drawShape(ctx){
+        var r  = this.radius
+        // ,   cx = -this.originX
+        // ,   cy = -this.originY ;
+        // ctx.arc(cx,cy, r, 0, Math.PI*2, false);
         ctx.arc(r,r, r, 0, Math.PI*2, false);
         ctx.fill();
     }
diff --git a/src/portal/transform.js b/src/portal/transform.js
new file mode 100644 (file)
index 0000000..6e829f6
--- /dev/null
@@ -0,0 +1,61 @@
+Transform = new Y.Class('Transform', {
+    
+    scale : function scale(x,y, layer, ctx){
+        
+    },
+    
+    translate : function translate(x,y, layer, ctx){
+        
+    },
+    
+    crop : function crop(){
+        
+    }
+    
+});
+
+Transform.Rotation = new Y.Class('Rotation', Transform, {
+    
+    init : function initRotation(theta, x,y){
+        this.theta = theta;
+        this.x = x;
+        this.y = y;
+    },
+    
+    apply : function applyRotation(layer, ctx){
+        ctx = ctx || layer.ctx;
+        ctx.translate(this.x, this.y);
+        ctx.rotate(this.theta);
+        ctx.translate(-this.x, -this.y);
+    }
+    
+});
+
+Transform.Scale = new Y.Class('Scale', Transform, {
+    
+    init : function initScale(x,y){
+        this.x = x;
+        this.y = y;
+    },
+    
+    apply : function apply(layer, ctx){
+        ctx = ctx || layer.ctx;
+        ctx.scale(this.x, this.y);
+    }
+    
+});
+
+Transform.Translate = new Y.Class('Translate', Transform, {
+    
+    init : function init(x,y){
+        this.x = x;
+        this.y = y;
+    },
+    
+    apply : function apply(layer, ctx){
+        ctx = ctx || layer.ctx;
+        ctx.translate(this.x, this.y);
+    }
+    
+});
+
index 9a8bd27..815ab89 100644 (file)
@@ -29,7 +29,7 @@ methods = {
     // times     : null, // Last `samples` frame durations
     
     
-    init : function(target, framerate, samples){
+    init : function init(target, framerate, samples){
         Y.event.Emitter.init.call(this, target);
         decorate.call(this, target);
         this.tick = this.tick.bind(this);
@@ -42,7 +42,7 @@ methods = {
         this.reset();
     },
     
-    reset : function(){
+    reset : function reset(){
         this.stop();
         this.elapsedAtStop = 0;
         this.ticks = 0;
@@ -50,7 +50,7 @@ methods = {
         this.realtimes = [];
     },
     
-    start : function(){
+    start : function start(){
         if (this.running) return;
         
         this.running = true;
@@ -64,7 +64,7 @@ methods = {
         this.elapsedAtStop = 0;
     },
     
-    stop : function(){
+    stop : function stop(){
         if (!this.running) return;
         
         clearTimeout(this.timer);
@@ -74,14 +74,14 @@ methods = {
         this.fire('stop');
     },
     
-    sleepMinus : function(tFrame){
+    sleepMinus : function sleepMinus(tFrame){
         if (this.timer !== null) return;
         
         var tickInt = Math.max(MIN_TICK_INTERVAL, this.targetTime - tFrame);
         this.timer = setTimeout(this.tick, tickInt);
     },
     
-    tick : function(lastTick){
+    tick : function tick(lastTick){
         lastTick     = lastTick || this.now;
         this.now     = new Date().getTime();
         this.elapsed = this.now - lastTick;
@@ -106,11 +106,11 @@ methods = {
         }
     },
     
-    fps : function(){
+    fps : function fps(){
         return 1000 / (this.times.reduce(Y.op.add,0) / this.times.length);
     },
     
-    frametime : function(){
+    frametime : function frametime(){
         return (this.realtimes.reduce(Y.op.add,0) / this.realtimes.length);
     }
     
index c66cc33..947c7c0 100644 (file)
@@ -1,6 +1,6 @@
 FpsSparkline = new Y.Class('FpsSparkline', {
     
-    init : function(loop, el, w,h, maxBuffer, interval){
+    init : function init(loop, el, w,h, maxBuffer, interval){
         this.buffer    = [];
         
         this.el        = el;
@@ -22,7 +22,7 @@ FpsSparkline = new Y.Class('FpsSparkline', {
         $(this.setup.bind(this));
     },
     
-    setup : function(){
+    setup : function setup(){
         this.el = $(this.el);
         
         var w = this.el.parent().width();
@@ -34,7 +34,7 @@ FpsSparkline = new Y.Class('FpsSparkline', {
             this.maxBuffer = Math.floor(w / 3);
     },
     
-    tickTime : function(lastTick){
+    tickTime : function tickTime(lastTick){
         var loop = this.loop
         ,   buf  = this.buffer
         ;
@@ -53,7 +53,7 @@ FpsSparkline = new Y.Class('FpsSparkline', {
     /**
      * Draws average render time across interval frames
      */
-    drawTimes : function(){
+    drawTimes : function drawTimes(){
         var buf = this.buffer
         ,   max = this.maxBuffer
         ,   diff = max - buf.length
@@ -73,8 +73,8 @@ FpsSparkline = new Y.Class('FpsSparkline', {
                 , width            : this.width
                 , height           : this.height
                 
-                , lineColor        : '#333333'
-                , fillColor        : '#333333'
+                , lineColor        : '#2F2F2F'
+                , fillColor        : '#2F2F2F'
                 , spotColor        : false
                 , minSpotColor     : '#83BB32'
                 , maxSpotColor     : '#AF2A31'
@@ -90,7 +90,7 @@ FpsSparkline = new Y.Class('FpsSparkline', {
     /**
      * Draws average FPS over interval.
      */
-    drawFps : function(){
+    drawFps : function drawFps(){
         
     }
     
index 88f66e2..7228012 100644 (file)
@@ -1,31 +1,58 @@
-Loc = new Y.Class('Loc', {
-    init : function(x, y){
-        this.x = Math.max(x,0);
-        this.y = Math.max(y,0);
+// [x,y]
+Loc = new Y.Class('Loc', [], {
+    
+    init : function init(x, y){
+        if ( Array.isArray(x) ) {
+            y = x[1];
+            x = x[0];
+        }
+        
+        this.length = 2;
+        this.x = this[0] = x;
+        this.y = this[1] = y;
     },
     
-    moveBy : function(dir, amount){
-        var mod = 1;
-        switch (dir) {
-            case Loc.LEFT: mod = -1;
-            case Loc.RIGHT:
-                return new Loc(this.x+amount*mod, this.y);
-            
-            case Loc.UP: mod = -1;
-            case Loc.DOWN:
-                return new Loc(this.x, this.y+amount*mod);
+    set : function set(k, v, def){
+        v = (v !== undefined ? v : def);
+        switch (k) {
+            case 'x': case 0:
+                this.x = this[0] = v; break;
+            case 'y': case 1:
+                this.y = this[1] = v; break;
+            default:
+                this[k] = v;
         }
+        return this;
+    },
+    attr : Y.attr.methodize(),
+    
+    equals : function equals(loc){
+        return (this.x === loc.x) && (this.y === loc.y);
     },
     
-    clone : function(){
+    clone : function clone(){
         return new Loc(this.x, this.y);
     },
     
-    toSquare : function(){
+    moveBy : function moveBy(x,y){
+        return new Loc(this.x+x, this.y+y);
+    },
+    
+    moveByAngle : function moveByAngle(theta, v){
+        var x = this.x + v*Math.sin(theta)
+        ,   y = this.y + v*Math.cos(theta);
+        return new Loc(x,y);
+    },
+    
+    moveByDir : function moveByDir(dir, v){
+        return this.moveByAngle(Loc.dirToAngle(dir), v);
+    },
+    
+    toSquare : function toSquare(){
         return Loc.Square.fromLoc(this.x, this.y);
     },
     
-    toString : function(){
+    toString : function toString(){
         return '('+Math.round(this.x, 2)+','+Math.round(this.y, 2)+')';
     }
     
@@ -34,21 +61,34 @@ Y(Loc).extend({
     UP    : 'up',    DOWN : 'down',
     RIGHT : 'right', LEFT : 'left',
     
-    fromSquare : function(col, row){
+    dirToAngle : function dirToAngle(dir){
+        switch (dir) {
+            case Loc.RIGHT: return 0;
+            case Loc.UP:    return HALF_PI;
+            case Loc.LEFT:  return PI;
+            case Loc.DOWN:  return PI_AND_HALF;
+            
+            default: throw new Error("wtf direction is "+dir+"??");
+        }
+    },
+    
+    fromSquare : function fromSquare(col, row){
         return new Loc(
             col * REF_SIZE,
             row * REF_SIZE );
     },
     
-    centerInSquare : function(v){
+    // XXX: Probably wrong for negative locations
+    centerInSquare : function centerInSquare(v){
         return Math.floor(v/REF_SIZE)*REF_SIZE + REF_SIZE/2;
     }
     
 });
 
 
-Loc.Rect = new Y.Class('Rect', {
-    init : function(x1,y1, x2,y2){
+// [x1,y1, x2,y2]
+Loc.Rect = new Y.Class('Rect', [], {
+    init : function init(x1,y1, x2,y2){
         if (x1 instanceof Loc && y1 instanceof Loc) {
             var top    = x1,
                 bottom = y1;
@@ -58,68 +98,102 @@ Loc.Rect = new Y.Class('Rect', {
         }
         this.left  = this.top    = top;
         this.right = this.bottom = bottom;
-        this.x1 = top.x; this.x2 = bottom.x;
-        this.y1 = top.y; this.y2 = bottom.y;
+        
+        this.length = 4;
+        x1 = this.x1 = this[0] = this.x = top.x;
+        y1 = this.y1 = this[1] = this.y = top.y;
+        x2 = this.x2 = this[2] = bottom.x;
+        y2 = this.y2 = this[3] = bottom.y;
+        
+        this.width  = x2 - x1;
+        this.height = y2 - y1;
+    },
+    
+    set : function set(k, v, def){
+        v = (v !== undefined ? v : def);
+        switch (k) {
+            case 'x1': case 0: case 'x':
+                this.x1 = this[0] = this.x = this.top.x = this.left.x = v;
+                break;
+            case 'y1': case 1: case 'y':
+                this.y1 = this[1] = this.y = this.top.y = this.left.y = v;
+                break;
+            case 'x2': case 2:
+                this.x2 = this[2] = this.bottom.x = this.right.x = v;
+                break;
+            case 'y1': case 3:
+                this.y2 = this[3] = this.bottom.y = this.right.y = v;
+                break;
+            default:
+                this[k] = v;
+        }
+        return this;
     },
     
+    attr : Y.attr.methodize(),
+    
+    // XXX: This would slow performance, but prevent state duplication and out of sync errors
+    
     // top    : function(){ return new Loc(this.x1, this.y1); },
-    // bottom : function(){ return new Loc(this.x2, this.y2); },
+    // bottom : function bottom(){ return new Loc(this.x2, this.y2); },
     // 
     // left   : function(){ return new Loc(this.x1, this.y1); },
     // right  : function(){ return new Loc(this.x2, this.y2); },
     
-    midpoint : function(){
-        var t = this.top,
-            b = this.bottom;
+    moveTo : function moveTo(x,y){
+        return new Loc.Rect(x,y, x+this.width,y+this.height);
+    },
+    
+    midpoint : function midpoint(){
         return new Loc(
-            t.x + (b.x-t.x)/2,
-            t.y + (b.y-t.y)/2 );
+            this.x1 + this.width /2,
+            this.y1 + this.height/2 );
     },
     
-    clone : function(){
+    clone : function clone(){
         return new Loc.Rect(
             this.top.clone(),
             this.bottom.clone() );
     },
     
-    contains : function(x,y){
-        var t = this.top, b = this.bottom;
-        return ( x >= t.x && x <= b.x  &&
-                 y >= t.y && y <= b.y  );
+    contains : function contains(x,y){
+        return ( x >= this.x1 && x <= this.x2  &&
+                 y >= this.y1 && y <= this.y2  );
     },
     
-    toString : function(){
+    toString : function toString(){
         return '['+this.top+' '+this.bottom+']';
     }
     
 });
 
-Loc.Square = new Y.Class('Square', Rect, {
-    init : function(col, row){
-        col = this.col = Math.max(col,0);
-        row = this.row = Math.max(row,0);
+Loc.Square = new Y.Class('Square', Loc.Rect, {
+    init : function init(col, row){
+        this.col = col;
+        this.row = row;
         
-        var x1 = this.x = col * REF_SIZE
-        ,   y1 = this.y = row * REF_SIZE
-        ,   x2 = x1 + REF_SIZE
-        ,   y2 = y1 + REF_SIZE;
+        var x1 = col * REF_SIZE,   y1 = row * REF_SIZE
+        ,   x2 = x1  + REF_SIZE,   y2 = y1  + REF_SIZE
+        ;
         
         Loc.Rect.init.call(this, x1,y1, x2,y2);
     },
     
-    clone : function(){
+    clone : function clone(){
         return new Square(this.col, this.row);
     },
     
-    toLoc : function(){
+    toLoc : function toLoc(){
         return Loc.fromSquare(this.col, this.row);
     },
     
-    toString : function(){
+    toString : function toString(){
         return this.col+'_'+this.row;
     }
     
 });
+
+// XXX: Negative grid positions don't round correctly
 Loc.Square.fromLoc = function(x, y){
     return new Loc.Square(
         Math.floor(x / REF_SIZE),
index e2bc43b..28d2e16 100644 (file)
@@ -6,7 +6,7 @@ NodeType = {
     EMPTY    : 0,
     LEAF     : 1,
     POINTER  : 2,
-    toString : function(type){
+    toString : function toString(type){
         switch (type) {
             case NodeType.EMPTY:    return "Empty";
             case NodeType.LEAF:     return "Leaf";
@@ -27,7 +27,7 @@ LeafType = {
     RANGE_TR : 1 | RangeCellType.TOP    | RangeCellType.RIGHT,
     RANGE_BL : 1 | RangeCellType.BOTTOM | RangeCellType.LEFT,
     RANGE_BR : 1 | RangeCellType.BOTTOM | RangeCellType.RIGHT,
-    toString : function(type){
+    toString : function toString(type){
         switch (type) {
             case LeafType.POINT:    return "Point";
             case LeafType.RANGE:    return "Range";
@@ -56,7 +56,7 @@ Node = new Y.Class('Node', {
     se    : null,
     value : null,
     
-    reduce : function(fn, acc, context){
+    reduce : function reduce(fn, acc, context){
         context = context || this;
         if (this.nw) acc = fn.call(context, acc, this.nw, 'nw', this);
         if (this.ne) acc = fn.call(context, acc, this.ne, 'ne', this);
@@ -65,7 +65,7 @@ Node = new Y.Class('Node', {
         return acc;
     },
     
-    toString : function(){
+    toString : function toString(){
         return (NodeType.toString(this.type)+'( '+
             'x='+this.x+',y='+this.y+', '+
             'w='+this.w+',h='+this.h+
@@ -74,7 +74,7 @@ Node = new Y.Class('Node', {
 }),
 
 Range = new Y.Class('Range', Y.YCollection, {
-    init : function(tree, x1,y1, x2,y2, value){
+    init : function init(tree, x1,y1, x2,y2, value){
         this.x1 = this.x = x1;
         this.y1 = this.y = y1;
         this.x2 = x2;
@@ -88,29 +88,29 @@ Range = new Y.Class('Range', Y.YCollection, {
         tree._ranges.push(this);
     },
     
-    contains : function(x,y){
+    contains : function contains(x,y){
         return (this.x1 <= x && x <= this.x2)
             && (this.y1 <= y && y <= this.y2);
     },
     
-    containsRange : function(x1,y1, x2,y2){
+    containsRange : function containsRange(x1,y1, x2,y2){
         var sm_x = Math.min(x1,x2), lg_x = Math.max(x1,x2)
         ,   sm_y = Math.min(y1,y2), lg_y = Math.max(y1,y2);
         return !( sm_x > this.x2 || sm_y > this.y2
                || lg_x < this.x1 || lg_y < this.y1 );
     },
     
-    getCell : function(x1,y1, x2,y2){
+    getCell : function getCell(x1,y1, x2,y2){
         var cell =  new RangeCell(cellId++, x1,y1, x2,y2, this);
         this.cells[cell.id] = cell;
         return cell;
     },
     
-    removeCell : function(cell){
+    removeCell : function removeCell(cell){
         delete this.cells[cell.id];
     },
     
-    removeAll : function(){
+    removeAll : function removeAll(){
         var tree = this.tree;
         this.forEach(function(cell){
             this.removeCell(cell);
@@ -120,18 +120,18 @@ Range = new Y.Class('Range', Y.YCollection, {
         tree._ranges.remove(this);
     },
     
-    reduce : function(fn, acc, context){
+    reduce : function reduce(fn, acc, context){
         context = context || this;
         return Y(this.cells).clone().reduce(fn, acc, context);
     },
     
-    toString : function(){
+    toString : function toString(){
         return 'Range('+this.x1+','+this.y1+', '+this.x2+','+this.y2+', value='+this.value+')'
     }
 }),
 
 Leaf = new Y.Class('Leaf', {
-    toString : function(){
+    toString : function toString(){
         return LeafType.toString(this.type)+'('+this.x+','+this.y+', value='+this.value+')';
     }
 }),
@@ -144,7 +144,7 @@ Point = new Y.Class('Point', Leaf, {
     }
 }),
 RangeCell = new Y.Class('RangeCell', Leaf, {
-    init : function(id, x1,y1, x2,y2, owner) {
+    init : function init(id, x1,y1, x2,y2, owner) {
         this.id = id;
         this.x1 = this.x = x1;
         this.y1 = this.y = y1;
@@ -157,14 +157,14 @@ RangeCell = new Y.Class('RangeCell', Leaf, {
         this.value = owner.value;
     },
     
-    containsRange : function(x1,y1, x2,y2){
+    containsRange : function containsRange(x1,y1, x2,y2){
         var sm_x = Math.min(x1,x2), lg_x = Math.max(x1,x2)
         ,   sm_y = Math.min(y1,y2), lg_y = Math.max(y1,y2);
         return !( sm_x > this.x2 || sm_y > this.y2
                || lg_x < this.x1 || lg_y < this.y1 );
     },
     
-    calc : function(node){
+    calc : function calc(node){
         var r = this, t = LeafType.RANGE;
         
         if (node.x2 > r.x2)
@@ -186,7 +186,7 @@ RangeCell = new Y.Class('RangeCell', Leaf, {
         this.type = t;
     },
     
-    removeRange : function(){
+    removeRange : function removeRange(){
         this.owner.removeAll();
     }
 }),
@@ -205,12 +205,12 @@ PointQuadTree = new Y.Class('PointQuadTree', {
     count : 0,
     _ranges : null,
     
-    inBounds : function(x,y){
+    inBounds : function inBounds(x,y){
         var root = this._root;
         return !( x<root.x1 || y<root.y1 || x>root.x2 || y>root.y2 );
     },
     
-    _inSubrange : function(x1,y1, x2,y2){
+    _inSubrange : function _inSubrange(x1,y1, x2,y2){
         if (arguments.length === 4)
             return this._ranges.invoke('containsRange', x1,y1, x2,y2).any();
         else
@@ -218,24 +218,24 @@ PointQuadTree = new Y.Class('PointQuadTree', {
     },
     
     // XXX: Hm. Should this be contains ALL or contains ANY for the range query?
-    contains : function(x1,y1, x2,y2){
+    contains : function contains(x1,y1, x2,y2){
         if (arguments.length === 4)
             return this._inSubrange(x1,y1, x2,y2);
         else
             return this._inSubrange(x1,y1) || this.get(x1,y1) !== null;
     },
     
-    isEmpty : function(){
+    isEmpty : function isEmpty(){
         return this._root.type == NodeType.EMPTY;
     },
     
-    clear : function(){
+    clear : function clear(){
         this._root = new Node(this.x1,this.y1, this.width,this.height);
         this._ranges = Y([]);
         this.count = 0;
     },
     
-    get : function(x,y, def){
+    get : function get(x,y, def){
         var node = this.closest(x,y);
         if (node && node.value.x === x && node.value.y === y)
             return node.value.value;
@@ -243,7 +243,7 @@ PointQuadTree = new Y.Class('PointQuadTree', {
             return def;
     },
     
-    set : function(x,y, value){
+    set : function set(x,y, value){
         if ( !this.inBounds(x,y) )
             throw new Error('Out of bounds: ('+x+', '+y+')');
         if ( this._inSubrange(x,y) )
@@ -252,7 +252,7 @@ PointQuadTree = new Y.Class('PointQuadTree', {
         this._insert(this._root, new Point(x,y, value), 1);
     },
     
-    addRange : function(x1,y1, x2,y2, value){
+    addRange : function addRange(x1,y1, x2,y2, value){
         if ( !this.inBounds(x1,y1) )
             throw new Error('Out of bounds: ('+x1+', '+y1+')');
         if ( !this.inBounds(x2,y2) )
@@ -269,13 +269,13 @@ PointQuadTree = new Y.Class('PointQuadTree', {
         return this._addRangeUnsafe(sm_x,sm_y, lg_x,lg_y, value)
     },
     
-    _addRangeUnsafe : function(x1,y1, x2,y2, value){
+    _addRangeUnsafe : function _addRangeUnsafe(x1,y1, x2,y2, value){
         var range = new Range(this, x1,y1, x2,y2, value);
         this._addRange(x1,y1, x2,y2, range);
         return range;
     },
     
-    _addRange : function(x1,y1, x2,y2, range){
+    _addRange : function _addRange(x1,y1, x2,y2, range){
         if (x1 === x2 || y1 === y2) return;
         
         var r = range.getCell(x1,y1, x2,y2)
@@ -295,7 +295,7 @@ PointQuadTree = new Y.Class('PointQuadTree', {
         return n;
     },
     
-    remove : function(x,y){
+    remove : function remove(x,y){
         var self = this
         ,   node = this.closest(x,y)
         ,   leaf = node && node.value;
@@ -305,7 +305,7 @@ PointQuadTree = new Y.Class('PointQuadTree', {
             return null;
     },
     
-    _removeClosest : function(x,y){
+    _removeClosest : function _removeClosest(x,y){
         var node = this.closest(x,y);
         if (node && node.type === NodeType.LEAF)
             return this._remove(node);
@@ -313,7 +313,7 @@ PointQuadTree = new Y.Class('PointQuadTree', {
             return null;
     },
     
-    _remove : function(node, range){
+    _remove : function _remove(node, range){
         var leaf = node.value;
         node.value = null;
         node.type = NodeType.EMPTY;
@@ -326,7 +326,7 @@ PointQuadTree = new Y.Class('PointQuadTree', {
         return leaf ? leaf.value : leaf;
     },
     
-    find : function(x1,y1, x2,y2, fn, acc, context){
+    find : function find(x1,y1, x2,y2, fn, acc, context){
         var self = this
         ,   cxt  = context || self
         ,   sm_x = Math.min(x1,x2), lg_x = Math.max(x1,x2)
@@ -359,13 +359,13 @@ PointQuadTree = new Y.Class('PointQuadTree', {
         return collect(acc, this._root);
     },
     
-    closest : function(x,y){
+    closest : function closest(x,y){
         if ( !this.inBounds(x,y) )
             return null;
         return this._closest(x,y, this._root);
     },
     
-    _closest : function(x,y, node){
+    _closest : function _closest(x,y, node){
         if ( !(node && this.inBounds(x,y)) )
             return null;
         
@@ -384,7 +384,7 @@ PointQuadTree = new Y.Class('PointQuadTree', {
         }
     },
     
-    _getQuadrantForPoint : function(parent, x,y){
+    _getQuadrantForPoint : function _getQuadrantForPoint(parent, x,y){
         var mx = parent.x + parent.w/2;
         var my = parent.y + parent.h/2;
         if (x < mx) {
@@ -394,7 +394,7 @@ PointQuadTree = new Y.Class('PointQuadTree', {
         }
     },
     
-    _insert : function(parent, value, isNew){
+    _insert : function _insert(parent, value, isNew){
         switch (parent.type) {
             case NodeType.EMPTY:
                 this._setPointForNode(parent, value);
@@ -419,14 +419,14 @@ PointQuadTree = new Y.Class('PointQuadTree', {
         }
     },
     
-    _setPointForNode : function(node, value){
+    _setPointForNode : function _setPointForNode(node, value){
         if (node.type == NodeType.POINTER)
             throw new Error('Can not set value for node of type POINTER');
         node.type = NodeType.LEAF;
         node.value = value;
     },
     
-    _split : function(node){
+    _split : function _split(node){
         var v = node.value;
         node.value = null;
         node.type = NodeType.POINTER;
@@ -449,7 +449,7 @@ PointQuadTree = new Y.Class('PointQuadTree', {
     },
     
     // TODO: beautify
-    _balance : function(node){
+    _balance : function _balance(node){
         switch (node.type) {
             case NodeType.EMPTY:
             case NodeType.LEAF:
@@ -511,7 +511,7 @@ PointQuadTree = new Y.Class('PointQuadTree', {
         }
     },
     
-    getKeys : function(){
+    getKeys : function getKeys(){
         var arr = [];
         this._traverse(this._root, function(node) {
             arr.push({ 'x':node.value.x, 'y':node.value.y });
@@ -519,7 +519,7 @@ PointQuadTree = new Y.Class('PointQuadTree', {
         return arr;
     },
     
-    getValues : function(){
+    getValues : function getValues(){
         var arr = [];
         this._traverse(this._root, function(node) {
             // Must have a value because it's a leaf.
@@ -528,14 +528,14 @@ PointQuadTree = new Y.Class('PointQuadTree', {
         return arr;
     },
     
-    forEach : function(fn, context){
+    forEach : function forEach(fn, context){
         this._traverse(this._root, function(node) {
             var coord = { 'x':node.value.x, 'y':node.value.y };
             fn.call(context || this, node.value.value, coord, this);
         });
     },
     
-    clone : function(){
+    clone : function clone(){
         var x1 = this._root.x;
         var y1 = this._root.y;
         var x2 = x1 + this._root.w;
@@ -550,7 +550,7 @@ PointQuadTree = new Y.Class('PointQuadTree', {
         return clone;
     },
     
-    _traverse : function(node, fn){
+    _traverse : function _traverse(node, fn){
         switch (node.type) {
             case NodeType.LEAF:
                 fn.call(this, node);
index 5a7cfc5..47b9fa7 100644 (file)
@@ -16,19 +16,19 @@ CAPACITY  = 8,
 REGION_ID = 0,
 
 Region = new Y.Class('Region', {
-    init : function(x1,y1, x2,y2, value){
+    init : function init(x1,y1, x2,y2, value){
         Rect.call(this, x1,y1, x2,y2);
         this.id = REGION_ID++;
         this.value = value;
     },
     
     // Expects caller will have ordered x1 < x2, y1 < y2
-    overlaps : function(x1,y1, x2,y2){
+    overlaps : function overlaps(x1,y1, x2,y2){
         return !( x1 > this.x2 || y1 > this.y2
                || x2 < this.x1 || y2 < this.y1 );
     },
     
-    toString : function(){
+    toString : function toString(){
         return this.className+'(id='+this.id+', value='+this.value+')';
     }
 }),
@@ -44,7 +44,7 @@ QuadTree = new Y.Class('QuadTree', {
     sw : null, se : null,
     
     
-    init : function(x1,y1, x2,y2, capacity, parent) {
+    init : function init(x1,y1, x2,y2, capacity, parent) {
         Rect.call(this, x1,y1, x2,y2);
         this.capacity = capacity || CAPACITY;
         this.parent   = parent   || null;
@@ -53,17 +53,17 @@ QuadTree = new Y.Class('QuadTree', {
     },
     
     // Expects caller will have ordered x1 < x2, y1 < y2
-    overlaps : function(x1,y1, x2,y2){
+    overlaps : function overlaps(x1,y1, x2,y2){
         return !( x1 > this.x2 || y1 > this.y2
                || x2 < this.x1 || y2 < this.y1 );
     },
     
     
-    get : function(x1,y1, x2,y2){
+    get : function get(x1,y1, x2,y2){
         return this.collect(x1,y1, x2,y2, this._get, { vals:Y([]) }, this).vals;
     },
     
-    _get : function(acc, value, region){
+    _get : function _get(acc, value, region){
         if ( !acc[region.id] ) {
             acc[region.id] = region;
             acc.vals.push(value);
@@ -71,11 +71,11 @@ QuadTree = new Y.Class('QuadTree', {
         return acc;
     },
     
-    set : function(x1,y1, x2,y2, value){
+    set : function set(x1,y1, x2,y2, value){
         return this._set(new Region(x1,y1, x2,y2, value));
     },
     
-    _set : function(r){
+    _set : function _set(r){
         return this.leaves(r.x1,r.y1, r.x2,r.y2, function(acc, regions, tree){
             if ( regions.length < tree.capacity || tree.overflow )
                 regions.push(r);
@@ -87,7 +87,7 @@ QuadTree = new Y.Class('QuadTree', {
         });
     },
     
-    remove : function(region){
+    remove : function remove(region){
         var trees =
             this.leaves(
                 region.x1,region.y1, region.x2,region.y2,
@@ -106,13 +106,13 @@ QuadTree = new Y.Class('QuadTree', {
         return region;
     },
     
-    removeAll : function(x1,y1, x2,y2){
+    removeAll : function removeAll(x1,y1, x2,y2){
         this.leaves(x1,y1, x2,y2, function(_, regions, tree){
             tree.clear();
         });
     },
     
-    leaves : function(x1,y1, x2,y2, fn, acc, context){
+    leaves : function leaves(x1,y1, x2,y2, fn, acc, context){
         var self = this
         ,   cxt = context || self
         ,   _x1 = Math.min(x1,x2), _x2 = Math.max(x1,x2)
@@ -134,7 +134,7 @@ QuadTree = new Y.Class('QuadTree', {
         return acc;
     },
     
-    collect : function(x1,y1, x2,y2, fn, acc, context){ // XXX: unique=false, limit=Infinity, depth=Infinity
+    collect : function collect(x1,y1, x2,y2, fn, acc, context){ // XXX: unique=false, limit=Infinity, depth=Infinity
         var _x1 = Math.min(x1,x2), _x2 = Math.max(x1,x2)
         ,   _y1 = Math.min(y1,y2), _y2 = Math.max(y1,y2);
         return this.leaves(
@@ -149,18 +149,18 @@ QuadTree = new Y.Class('QuadTree', {
             context );
     },
     
-    reduce : function(fn, acc, context){
+    reduce : function reduce(fn, acc, context){
         return this.collect(this.x1,this.y1, this.x2,this.y2, fn, acc, context);
     },
     
-    clear : function(){
+    clear : function clear(){
         this.overflow = false;
         this.regions  = [];
         this.children = null;
         this.nw = this.ne = this.sw = this.se = null;
     },
     
-    _split : function(){
+    _split : function _split(){
         if (this.overflow) return;
         
         var regions = this.regions
@@ -187,11 +187,11 @@ QuadTree = new Y.Class('QuadTree', {
         }
     },
     
-    _balance : function(){
+    _balance : function _balance(){
         
     },
     
-    toString : function(){
+    toString : function toString(){
         var indent = '', d = this.depth+1;
         while ( d-- > 0 ) indent += '\t';
         return this.className+'('+this.x1+','+this.y1+', '+this.x2+','+this.y2+(this.regions ? ', regions='+this.regions.length : 0)+') '+
index b3d4b7d..1c71b2f 100644 (file)
@@ -27,7 +27,7 @@ Node.prototype.toString = function(){
 
 var
 RedBlackTree = new Y.Class('RedBlackTree', {
-    init : function(key, value){
+    init : function init(key, value){
         if (this.key !== undefined)
             this.setKey(key, value);
     },
@@ -56,7 +56,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
     },
 
     // value associated with the given key in subtree rooted at x; null if no such key
-    _getKey : function(x, key) {
+    _getKey : function _getKey(x, key) {
         while (x !== null) {
             if      (key < x.key) x = x.left;
             else if (key > x.key) x = x.right;
@@ -71,7 +71,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
     },
 
     // is there a key-value pair with the given key in the subtree rooted at x?
-    _contains : function(x, Key) {
+    _contains : function _contains(x, Key) {
         return (this._getKey(x, key) !== null);
     },
 
@@ -89,7 +89,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
     },
 
     // insert the key-value pair in the subtree rooted at h
-    _setKey : function(h, key, val) {
+    _setKey : function _setKey(h, key, val) {
         if (h === null) return new Node(key, val, RED, 1);
         
         if      (key < h.key) h.left  = this._setKey(h.left,  key, val);
@@ -116,7 +116,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
     },
 
     // remove the key-value pair with the given key rooted at h
-    _remove : function(h, key) {
+    _remove : function _remove(h, key) {
         // assert this.contains(h, key);
 
         if (key < h.key)  {
@@ -141,7 +141,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
     },
     
     // remove the key-value pair with the minimum key
-    _removeMin : function(h) {
+    _removeMin : function _removeMin(h) {
         if (h) {
             if (h.left === null)
                 return null;
@@ -166,7 +166,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
     },
 
     // remove the key-value pair with the maximum key
-    _removeMax : function(h){
+    _removeMax : function _removeMax(h){
         if (h) {
             if (isRed(h.left))
                 h = this._rotateRight(h);
@@ -199,7 +199,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
     *************************************************************************/
 
     // make a left-leaning link lean to the right
-    _rotateRight : function(h) {
+    _rotateRight : function _rotateRight(h) {
         // assert (h !== null) && isRed(h.left);
         var x = h.left;
         h.left = x.right;
@@ -212,7 +212,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
     },
 
     // make a right-leaning link lean to the left
-    _rotateLeft : function(h) {
+    _rotateLeft : function _rotateLeft(h) {
         // assert (h !== null) && isRed(h.right);
         var x = h.right;
         h.right = x.left;
@@ -225,7 +225,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
     },
 
     // flip the colors of a node and its two children
-    _flipColors : function(h) {
+    _flipColors : function _flipColors(h) {
         // h must have opposite color of its two children
         // assert (h !== null) && (h.left !== null) && (h.right !== null);
         // assert (!isRed(h) &&  isRed(h.left) &&  isRed(h.right)) ||
@@ -237,7 +237,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
 
     // Assuming that h is red and both h.left and h.left.left
     // are black, make h.left or one of its children red.
-    _moveRedLeft : function(h) {
+    _moveRedLeft : function _moveRedLeft(h) {
         // assert (h !== null);
         // assert isRed(h) && !isRed(h.left) && !isRed(h.left.left);
 
@@ -252,7 +252,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
 
     // Assuming that h is red and both h.right and h.right.left
     // are black, make h.right or one of its children red.
-    _moveRedRight : function(h) {
+    _moveRedRight : function _moveRedRight(h) {
         // assert (h !== null);
         // assert isRed(h) && !isRed(h.right) && !isRed(h.right.left);
         this._flipColors(h);
@@ -264,7 +264,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
     },
 
     // restore red-black tree invariant
-    _balance : function(h) {
+    _balance : function _balance(h) {
         // assert (h !== null);
         if (h === null)
             throw new Exception("wtf balance a null node?");
@@ -284,7 +284,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
 
     // height of tree; 0 if empty
     'height' : function() { return this._height(this._root); },
-    _height : function(x) {
+    _height : function _height(x) {
         if (x === null) return 0;
         return 1 + Math.max(this._height(x.left), this._height(x.right));
     },
@@ -300,7 +300,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
     },
 
     // the smallest key in subtree rooted at x; null if no such key
-    _min : function(x) {
+    _min : function _min(x) {
         // assert x !== null;
         if (x.left === null) return x;
         else                 return this._min(x.left);
@@ -313,7 +313,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
     },
 
     // the largest key in the subtree rooted at x; null if no such key
-    _max : function(x) {
+    _max : function _max(x) {
         // assert x !== null;
         if (x.right === null) return x;
         else                  return this._max(x.right);
@@ -327,7 +327,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
     },
 
     // the largest key in the subtree rooted at x less than or equal to the given key
-    _floor : function(x, key) {
+    _floor : function _floor(x, key) {
         if (x === null)    return null;
         if (key === x.key) return x;
         if (key < x.key)   return this._floor(x.left, key);
@@ -344,7 +344,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
     },
 
     // the smallest key in the subtree rooted at x greater than or equal to the given key
-    _ceiling : function(x, key) {
+    _ceiling : function _ceiling(x, key) {
         if (x === null)    return null;
         if (key === x.key) return x;
         if (key > x.key)   return this._ceiling(x.right, key);
@@ -363,7 +363,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
     },
 
     // the key of rank i in the subtree rooted at x
-    _iRank : function(x, i) {
+    _iRank : function _iRank(x, i) {
         // assert x !== null;
         // assert i >= 0 && i < size(x);
         var t = size(x.left);
@@ -378,7 +378,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
     },
 
     // number of keys less than key in the subtree rooted at x
-    _rank : function(key, x) {
+    _rank : function _rank(key, x) {
         if (x === null) return 0;
         if      (key < x.key) return this._rank(key, x.left);
         else if (key > x.key) return 1 + size(x.left) + this._rank(key, x.right);
@@ -401,7 +401,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
 
     // add the keys between lo and hi in the subtree rooted at x
     // to the queue
-    _keys : function(x, queue, lo, hi) {
+    _keys : function _keys(x, queue, lo, hi) {
         if (!x) return;
         if (lo < x.key) this._keys(x.left, queue, lo, hi);
         if (lo <= x.key && hi >= x.key) queue.push(x.key);
@@ -424,7 +424,7 @@ RedBlackTree = new Y.Class('RedBlackTree', {
             lo || this.min(), hi || this.max(), context || this );
     },
     
-    _reduce : function(x, fn, acc, lo, hi, context){
+    _reduce : function _reduce(x, fn, acc, lo, hi, context){
         if (!x) return acc;
         if (lo < x.key) acc = this._reduce(x.left, fn, acc, lo, hi, context);
         if (lo <= x.key && hi >= x.key) acc = fn.call(context, acc, x.val, x.key, this);
index 291326d..594d90b 100644 (file)
@@ -1,34 +1,6 @@
-var undefined
-,   GRID_ELEMENT  = '#viewport'
-
-,   REF_SIZE      = 50
-,   CELL_SIZE     = REF_SIZE
-,   SCALE         = CELL_SIZE / REF_SIZE
-,   GRID_OFFSET   = 0
-
-,   COLUMNS       = 10
-,   ROWS          = 10
-,   CAPACITY      = 32
-
-,   FRAME_RATE    = 30
-,   MS_PER_FRAME  = 1000 / FRAME_RATE
-
-,   NOW           = new Date().getTime() // Current tick's timestamp (ms)
-,   ELAPSED       = MS_PER_FRAME         // Time (ms) since previous tick
-,   FRAMETH       = ELAPSED / 1000       // Ratio of second completed
-,   TICKS         = 0                    // Ticks since start of game
-
-,   PI            = Math.PI
-,   TWO_PI        = PI*2
-,   HALF_PI       = PI/2
-
-;
-
-
-
 Game = new Y.Class('Game', {
     
-    init : function(viewport){
+    init : function init(viewport){
         this.loop = new EventLoop(this, FRAME_RATE);
         
         // Seal all methods
@@ -47,16 +19,19 @@ Game = new Y.Class('Game', {
     /**
      * Main Event Loop.
      */
-    tick : function(evt){
+    tick : function tick(evt){
         var d = evt.data;
         
-        NOW     = d.now;
-        ELAPSED = d.elapsed;
-        TICKS   = d.ticks;
+        NOW      = d.now;
+        ELAPSED  = d.elapsed;
+        TICKS    = d.ticks;
+        SECONDTH = ELAPSED / 1000;
+        SQUARETH = REF_SIZE * SECONDTH
+        
+        this.units.invoke('act');
         
         this.root.draw();
         
-        this.units.invoke('act');
         // XXX: Collect the dead
         
         // this.grid.removeOverlay(this.el);
index d70c4ae..2a1d21a 100644 (file)
@@ -1,7 +1,7 @@
 
 Y(Game.prototype).extend({
     
-    initMap : function(){
+    initMap : function initMap(){
         var self = this;
         
         this.pathmap = new PathMap(0,0, COLUMNS*REF_SIZE, ROWS*REF_SIZE, CAPACITY);
@@ -11,12 +11,10 @@ Y(Game.prototype).extend({
                 .appendTo(this.viewport);
         this.level =
             new Layer()
-                .width( root._width )
-                .height( root._height)
+                .width(  root._width  )
+                .height( root._height )
                 .appendTo(this.root);
         
-        // this.root.ctx.scale(1.0, 1.0);
-        
         this.byId = {};
         this.units    = new Y.YArray();
         this.bullets  = new Y.YArray();
@@ -33,20 +31,20 @@ Y(Game.prototype).extend({
     
     // *** Path Map Management *** //
     
-    addBlocker : function(agent){
+    addBlocker : function addBlocker(agent){
         var bb = agent.boundingBox;
         if (agent.blocking && bb)
             agent.region = this.pathmap.set(bb.x1,bb.y1, bb.x2,bb.y2, agent);
         return agent;
     },
     
-    removeBlocker : function(agent){
+    removeBlocker : function removeBlocker(agent){
         if (agent.region)
             this.pathmap.remove(agent.region);
         return agent;
     },
     
-    updateBlocker : function(agent){
+    updateBlocker : function updateBlocker(agent){
         this.removeBlocker(agent);
         this.addBlocker(agent);
     },
@@ -54,7 +52,7 @@ Y(Game.prototype).extend({
     
     // *** Agent Management *** //
     
-    addUnit : function(unit, col,row){
+    addUnit : function addUnit(unit, col,row){
         unit.game = this;
         
         // Center unit in square
@@ -76,7 +74,7 @@ Y(Game.prototype).extend({
         return unit;
     },
     
-    addAgent : function(agent){
+    addAgent : function addAgent(agent){
         agent.game = this;
         if (agent.id === undefined) return agent;
         
@@ -93,7 +91,7 @@ Y(Game.prototype).extend({
         return agent;
     },
     
-    killAgent : function(agent){
+    killAgent : function killAgent(agent){
         delete this.byId[agent.id];
         if (agent instanceof Ability)
             this.abilities.remove(agent);
@@ -104,18 +102,18 @@ Y(Game.prototype).extend({
         return agent;
     },
     
-    moveAgentTo : function(agent, x,y){
+    moveAgentTo : function moveAgentTo(agent, x,y){
         this.removeBlocker(agent);
         agent.setLocation(x,y);
         this.addBlocker(agent);
         return agent;
     },
     
-    getUnitAt : function(x,y){
+    getUnitAt : function getUnitAt(x,y){
         return this.grid.get(x,y);
     },
     
-    getUnitsAt : function(x1,y1, x2,y2){
+    getUnitsAt : function getUnitsAt(x1,y1, x2,y2){
         return this.grid.get(x1,y1, x2,y2);
     }
     
@@ -123,8 +121,7 @@ Y(Game.prototype).extend({
 
 Y(Game.prototype).extend({
     
-    // Ehh.
-    resize : function(){
+    resize : function resize(){
         var ratio = COLUMNS / ROWS
         ,   el = this.el
         ,   p  = el.parent()
index 810c0bb..e4295b6 100644 (file)
@@ -17,14 +17,14 @@ Player = new Y.Class('Player', {
     target : null,
     
     
-    init : function(game, tank){
+    init : function init(game, tank){
         Y.bindAll(this);
         
         this.activeKeys = new Y.YArray();
         
         this.game = game;
         this.tank = tank;
-        tank.act = this.act;
+        tank.act = this.act; // Override tank actions with player control
         
         $(window)
             .bind('keydown',   this.keydown)
@@ -33,7 +33,7 @@ Player = new Y.Class('Player', {
             .bind('mouseup',   this.mouseup);
     },
     
-    // queueMove : function(dir){
+    // queueMove : function queueMove(dir){
     //     var self = this;
     //     return function(evt){
     //         self.action = Actions.MOVE;
@@ -42,24 +42,24 @@ Player = new Y.Class('Player', {
     //     };
     // },
     
-    updateMeta : function(evt){
+    updateMeta : function updateMeta(evt){
         this.shift = evt.shiftKey;
         this.alt   = evt.altKey;
         this.meta  = evt.metaKey;
         this.ctrl  = evt.ctrlKey;
     },
     
-    keydown : function(evt){
+    keydown : function keydown(evt){
         this.activeKeys.push(evt.which+'');
         this.updateMeta(evt);
     },
     
-    keyup : function(evt){
+    keyup : function keyup(evt){
         this.activeKeys.remove(evt.which+'');
         this.updateMeta(evt);
     },
     
-    mousedown : function(evt){
+    mousedown : function mousedown(evt){
         switch (evt.which) {
             case 1: evt.leftMouse   = true; break;
             case 2: evt.rightMouse  = true; break;
@@ -68,7 +68,7 @@ Player = new Y.Class('Player', {
         this.updateMeta(evt);
     },
     
-    mouseup : function(evt){
+    mouseup : function mouseup(evt){
         switch (evt.which) {
             case 1: evt.leftMouse   = false; break;
             case 2: evt.rightMouse  = false; break;
@@ -77,7 +77,16 @@ Player = new Y.Class('Player', {
         this.updateMeta(evt);
     },
     
-    act : function(){
+    act : function act(){
+        var t = this.tank;
+        if (t.dead) return this;
+        
+        var r = TWO_PI * (TICKS % 30)/30;
+        // console.log('tank.shape.rotate(', r, ')');
+        t.shape.rotate(r);
+    },
+    
+    act_ : function act_(){
         if (this.tank.dead) return this;
         
         var active = this.activeKeys;
@@ -90,9 +99,9 @@ Player = new Y.Class('Player', {
         return this;
     },
     
-    move : function(dir){
+    move : function move(dir){
         var tank  = this.tank
-        ,   toLoc = tank.loc.moveBy(dir, (tank.stats.move * REF_SIZE * FRAMETH));
+        ,   toLoc = tank.loc.moveByAngle(dir, (tank.stats.move * SQUARETH));
         this.game.moveAgentTo(tank, toLoc.x, toLoc.y);
     }
     
diff --git a/src/tanks/globals.js b/src/tanks/globals.js
new file mode 100644 (file)
index 0000000..7d16030
--- /dev/null
@@ -0,0 +1,32 @@
+var undefined
+,   GRID_ELEMENT  = '#viewport'
+
+,   REF_SIZE      = 50
+,   CELL_SIZE     = REF_SIZE
+,   SCALE         = CELL_SIZE / REF_SIZE
+,   GRID_OFFSET   = 0
+
+,   COLUMNS       = 10
+,   ROWS          = 10
+,   CAPACITY      = 32
+
+,   FRAME_RATE    = 30
+,   MS_PER_FRAME  = 1000 / FRAME_RATE
+
+,   NOW           = new Date().getTime() // Current tick's timestamp (ms)
+,   ELAPSED       = MS_PER_FRAME         // Time (ms) since previous tick
+,   TICKS         = 0                    // Ticks since start of game
+
+
+/// Common Components of Computation ///
+
+,   SECONDTH       = ELAPSED / 1000       // Amount of second completed in this tick
+,   SQUARETH      = REF_SIZE * SECONDTH   // Amount of square/second covered in this tick
+
+,   PI            = Math.PI
+,   HALF_PI       = PI/2
+,   PI_AND_HALF   = PI + HALF_PI
+,   TWO_PI        = PI*2
+
+;
+
index 02bf453..a5473d3 100644 (file)
@@ -75,13 +75,13 @@ jQuery(function($){
     fixOverlayText();
     
     // Fix grid-size on resize
-    $(window).bind('resize', function(evt){
-        // LBT.resize(evt);
-        
-        if (!LBT.loop.running) {
-            LBT.start();
-            LBT.stop();
-        }
-    });
+    // $(window).bind('resize', function(evt){
+    //     LBT.resize(evt);
+    //     
+    //     if (!LBT.loop.running) {
+    //         LBT.start();
+    //         LBT.stop();
+    //     }
+    // });
     
 });
\ No newline at end of file
index 2ccd6fb..4d8b390 100644 (file)
@@ -16,58 +16,25 @@ Tank = new Y.Class('Tank', Thing, {
     },
     
     
-    init : function(align){
+    init : function init(align){
         Thing.init.call(this, align);
         this.bullets = new Y.YArray();
     },
     
-    /**
-     * Determines what the creep should do -- move, attack, etc.
-     */
-    act : function(){
-        if (this.dead) return this;
-        
-        this.cooldowns.invoke('update', NOW);
-        
-        var bb = this.boundingBox
-        ,   x1 = Calc.rangeX(this), x2 = bb.left.x
-        ,   y1 = bb.top.y,          y2 = bb.bottom.y
-        ,   units = this.game
-                .getUnitsAt(x1,y1, x2,y2)
-                .filter(this.filterTarget, this)
-        ,   target = this.closest(units)
-        ;
-        if (target)
-            this.attack(target);
-        else
-            this.move();
-        
-        if (bb.x1 <= MIN_X_DIST || bb.x2 >= MAX_X_DIST)
-            this.destroy();
-        
-        return this;
-    },
-    
-    filterTarget : function(unit){ return unit.align !== this.align; },
-    
-    move : function(dir){
-        var toLoc = this.loc.moveBy(dir, (this.stats.move * REF_SIZE * FRAMETH));
-        this.game.moveAgentTo(this, toLoc.x, toLoc.y);
-        return this;
-    },
+    filterTarget : function filterTarget(unit){ return unit.align !== this.align; },
     
-    attack : function(unit){
+    attack : function attack(unit){
         var atk_cool = this.cooldowns.attr('attack');
         if ( atk_cool.activate(NOW) )
             this.doAttack(unit);
         return this;
     },
     
-    doAttack : function(target){
+    doAttack : function doAttack(target){
         this.fireProjectile(target);
     },
     
-    fireProjectile : function(target){
+    fireProjectile : function fireProjectile(target){
         var AbilityType = this.projectile
         ,   p = new AbilityType(this, target);
         this.bullets.push(p);
@@ -83,7 +50,7 @@ Tank = new Y.Class('Tank', Thing, {
      * Sets up unit appearance for minimal updates. Called once at start,
      * or when the world needs to be redrawn from scratch.
      */
-    render : function( parent ){
+    render : function render( parent ){
         if (this.shape) this.shape.remove();
         
         var w = this.width
index 7eb317d..c1e8ee7 100644 (file)
@@ -1,6 +1,6 @@
 Thing = new Evt.Class('Thing', {
     
-    init : function(align){
+    init : function init(align){
         this.id    = Thing.THING_ID++;
         this.align = align || 0;
         
@@ -29,21 +29,21 @@ Thing = new Evt.Class('Thing', {
     boundingBox : null,
     
     // Rotation (rads)
-    vec : 0,
+    rotation : 0,
     
     // Bounding box dimensions
     width  : REF_SIZE*0.7,
     height : REF_SIZE*0.6,
     
     
-    destroy : function(){
+    destroy : function destroy(){
         if (this.dead) return;
         
         this.dead = true;
         this.fire('destroy', this);
     },
     
-    setLocation : function(x,y){
+    setLocation : function setLocation(x,y){
         var loc = this.loc;
         if (loc && loc.x === x && loc.y === y)
             return loc;
@@ -56,14 +56,13 @@ Thing = new Evt.Class('Thing', {
     
     
     
-    
     // *** Gameplay Methods *** //
     
-    fillStats : function(){
+    fillStats : function fillStats(){
         this.stats = Thing.fillStats(this.stats);
     },
     
-    createCooldowns : function(){
+    createCooldowns : function createCooldowns(){
         this.cooldowns = Y({
             attack: new Cooldown(1000 * this.stats.speed)
         });
@@ -72,7 +71,33 @@ Thing = new Evt.Class('Thing', {
     /**
      * Determines what the creep should do -- move, attack, etc.
      */
-    act : function(){
+    act : function act(){
+        if (this.dead) return this;
+        
+        this.cooldowns.invoke('update', NOW);
+        
+        var bb = this.boundingBox
+        ,   x1 = Calc.rangeX(this), x2 = bb.left.x
+        ,   y1 = bb.top.y,          y2 = bb.bottom.y
+        ,   units = this.game
+                .getUnitsAt(x1,y1, x2,y2)
+                .filter(this.filterTarget, this)
+        ,   target = this.closest(units)
+        ;
+        if (target)
+            this.attack(target);
+        else
+            this.move();
+        
+        if (bb.x1 <= MIN_X_DIST || bb.x2 >= MAX_X_DIST)
+            this.destroy();
+        
+        return this;
+    },
+    
+    move : function move(){
+        var toLoc = this.loc.moveByAngle(this.rotation, this.stats.move * SQUARETH);
+        this.game.moveAgentTo(this, toLoc.x, toLoc.y);
         return this;
     },
     
@@ -83,18 +108,18 @@ Thing = new Evt.Class('Thing', {
      * Sets up unit appearance for minimal updates. Called once at start,
      * or when the world needs to be redrawn from scratch.
      */
-    render : function( parent ){
+    render : function render( parent ){
         return this;
     },
     
-    draw : function(){
+    draw : function draw(){
         if (this.dead) 
             this.shape.hide();
         else
             this.shape.draw();
     },
     
-    toString : function(){
+    toString : function toString(){
         return this.className+'(id='+this.id+', loc='+this.loc+')';
     }
     
@@ -103,7 +128,7 @@ Thing = new Evt.Class('Thing', {
 Y(Thing).extend({
     THING_ID : 0,
     
-    fillStats : function(stats){
+    fillStats : function fillStats(stats){
         var st = Y(stats)
         ,   stats = st.clone().end()
         ;
diff --git a/src/tanks/util/calc.js b/src/tanks/util/calc.js
new file mode 100644 (file)
index 0000000..7e14ba2
--- /dev/null
@@ -0,0 +1,5 @@
+Calc = {
+    
+    
+    
+};
\ No newline at end of file
index bc71d9b..43e6140 100644 (file)
@@ -1,31 +1,38 @@
 Grid = new Y.Class('Grid', Rect, {
     _cssClasses : 'portal layer shape rect grid',
     
-    init : function(cols,rows, size){
+    init : function init(cols,rows, size){
         this.cols = cols;
         this.rows = rows;
         this.size = size;
         Rect.init.call(this, cols*size, rows*size);
     },
     
-    drawShape : function(ctx){
-        var size = this.size
-        ,   rows = this.rows
-        ,   cols = this.cols
-        ,   w = this._width
-        ,   h = this._height;
+    drawShape : function drawShape(ctx){
+        var size =  this.size
+        ,   rows =  this.rows
+        ,   cols =  this.cols
+        ,   w    =  this._width
+        ,   h    =  this._height
+        // ,   cx   = -this.originX
+        // ,   cy   = -this.originY
+        ;
         
         ctx.lineWidth   = 0.5;
         ctx.strokeStyle = '#6E6E6E';
         
         for (var row=0, y=0; row<=rows; y = (++row) * size){
-            ctx.moveTo(0,y);
-            ctx.lineTo(w,y);
+            ctx.moveTo(0, y);
+            ctx.lineTo(w, y);
+            // ctx.moveTo(cx,   cy+y);
+            // ctx.lineTo(cx+w, cy+y);
         }
         
         for (var col=0, x=0; col<=cols; x = (++col) * size){
-            ctx.moveTo(x,0);
-            ctx.lineTo(x,h);
+            ctx.moveTo(x, 0);
+            ctx.lineTo(x, h);
+            // ctx.moveTo(cx+x, cy);
+            // ctx.lineTo(cx+x, cy+h);
         }
         
         ctx.stroke();
index a8d1707..9e3726f 100644 (file)
@@ -1,6 +1,6 @@
 PathMap = new Y.Class('PathMap', QuadTree, {
     
-    overlay : function(gridEl){
+    overlay : function overlay(gridEl){
         var w = this.width  *SCALE
         ,   h = this.height *SCALE
         ,   canvas = $('.overlay', gridEl)[0];
@@ -43,7 +43,7 @@ PathMap = new Y.Class('PathMap', QuadTree, {
         $(canvas).show();
     },
     
-    removeOverlay : function(gridEl){
+    removeOverlay : function removeOverlay(gridEl){
         $('.overlay', gridEl).hide();
     }