// exports['instantiate'] = instantiate;
// exports['fabricate'] = fabricate;
-
, FN = "constructor"
, PT = "prototype"
, OP = _Object[PT]
+, FP = _Function[PT]
, slice = _Array[PT].slice
, getProto = _Object.getPrototypeOf
}
function type( o ) {
+ if ( o === null || o === undefined )
+ return o;
+
+ // If this is a Y.Class or similar, it will help us out
+ if (o.__class__)
+ return o.__class__;
+
switch ( typeof(o) ) {
- case "undefined" : return undefined;
case "string" : return _String;
case "number" : return _Number; // Note: NaN and Infinity are Number literals
case "boolean" : return _Boolean;
case "function" :
// If the function has a user-specified prototype, we can probably assume
// it's meant to be a class constructor (and therefore, a type)
- if ( o[PT] && o[PT] !== _Function[PT] )
+ var oP = o[PT];
+ if ( oP && !(oP === FP || oP === _Function[PT]) )
return o;
else
return _Function;
case "object" :
default :
- // Null is an object, obv
- if ( o === null )
- return null;
-
- return KNOWN_CLASSES[o.className] || o.__class__
- || (o[FN] && o[FN] !== _Object) ? o[FN] : _Object;
+ return (o[FN] && o[FN] !== _Object) ? o[FN] : _Object;
}
}
, getDesc = _Object.getOwnPropertyDescriptor
, setDesc = _Object.defineProperty
-, classToString = function toString(){ return this.className+"()"; }
+, objToString = _Object[P].toString
+, classToString = function toString(){ return this.className+"()"; }
;
// Private delegating constructor -- must be defined for every
this.posBleed = new Loc(0,0);
this.boundingBox = new BoundingBox(0,0, 0,0);
+ this._origin = this.boundingBox.origin;
- this._origin = new Loc('50%','50%');
this.transform = {
rotate : 0,
scale : new Loc(1.0,1.0),
this.layerWidth = w;
- var origin = this._origin
+ var bb = this.boundingBox.resize(w, this.layerHeight)
+ , ro = bb.relOrigin
, nb = this.negBleed
- , v = this.canvasWidth = Math.ceil(w + nb.x + this.posBleed.x); // HTMLCanvas.width is a long
+ , cw = this.canvasWidth = Math.ceil(w + nb.x + this.posBleed.x); // HTMLCanvas.width is a long
- this.boundingBox = this.boundingBox.resize(w, this.layerHeight);
- this.layer.width(w).css('margin-left', (-nb.x)+'px')
+ this.layer.css({
+ 'width' : w,
+ 'left' : bb.x1,
+ 'margin-left' : -ro.x
+ });
- // this.canvas.width(v);
this.canvas.css({
- 'width' : v+'px',
- 'margin-left' : (-nb)+'px'
+ 'width' : cw,
+ 'margin-left' : -nb.x
});
- this.canvas[0].width = v;
-
+ this.canvas[0].width = cw;
return this;
},
return this.layerHeight;
this.layerHeight = h;
- this.boundingBox = this.boundingBox.resize(this.layerWidth, h);
-
- var nb = this.negBleed.y
- , v = this.canvasHeight = Math.ceil(h + nb + this.posBleed.y); // HTMLCanvas.height is a long
- this.layer.height(h).css('margin-top', (-nb)+'px')
- this.canvas.height(v);
- // this.canvas.css({
- // 'height' : v+'px',
- // 'margin-top' : (-nb)+'px'
- // });
- this.canvas[0].height = v;
+
+ var bb = this.boundingBox.resize(this.layerWidth, h)
+ , ro = bb.relOrigin
+ , nb = this.negBleed
+ , ch = this.canvasHeight = Math.ceil(h + nb.y + this.posBleed.y); // HTMLCanvas.height is a long
+
+ this.layer.css({
+ 'height' : h,
+ 'top' : bb.y1,
+ 'margin-top' : -ro.y
+ });
+
+ this.canvas.css({
+ 'height' : ch,
+ 'margin-top' : -nb.y
+ });
+ this.canvas[0].height = ch;
return this;
},
return this.layer.position();
if ( Y.isPlainObject(x) ){
- y = x.y;
- x = x.x;
+ y = x.y; x = x.x;
}
- // if (pos.x !== undefined) pos.x -= this.offsetX;
- // if (pos.y !== undefined) pos.y -= this.offsetY;
-
- this.boundingBox = this.boundingBox.relocate(x,y);
- this.loc = this.boundingBox.midpoint();
-
- var origin = this.origin();
- this.css({
- 'left' : x,
- 'top' : y,
- 'margin-left' : -origin.x,
- 'margin-top' : -origin.y
+ var bbox = this.boundingBox.relocate(x,y);
+ this.css({
+ 'left' : bbox.x1,
+ 'top' : bbox.y1
});
return this;
},
css : makeDelegate('css'),
/** Position relative to document. */
- offset : makeDelegate('offset'),
+ // offset : makeDelegate('offset'),
* to all sublayers (preserving knowledge of their individual scaling).
*/
scale : function scale(sx,sy){
- var o = this.transform.scale;
+ var ts = this.transform.scale;
if (arguments.length === 0)
- return o.absolute(this.layerWidth, this.layerHeight);
+ return ts;
- o.x = sx;
- o.y = sy;
+ ts.x = sx;
+ ts.y = sy;
this.dirty = true;
return this._applyTransforms();
},
* Translates draw calls by (x,y) within this layer only. This allows you to
* functionally move the coordinate system of the layer.
*/
- translate : function translate(x,y){
- var o = this.transform.translate;
+ translate : function translate(tx,ty){
+ var tt = this.transform.translate;
if (arguments.length === 0)
- return o.absolute(this.layerWidth, this.layerHeight);
+ return tt;
- o.x = x;
- o.y = y;
+ tt.x = tx;
+ tt.y = ty;
this.dirty = true;
return this;
},
var Y = require('Y').Y
+, Loc = require('ezl/loc/loc').Loc
, math = require('ezl/math')
, Vec = math.Vec
, Line = math.Line
, Rect = math.Rect
+
+, X1 = 0, Y1 = 1
+, X2 = 2, Y2 = 3
,
+
BoundingBox =
exports['BoundingBox'] =
Rect.subclass('BoundingBox', {
- attr : Y.attr.methodize(),
+ init : function initRect(_x1,_y1, _x2,_y2, originX, originY){
+ Rect.init.call(this, _x1,_y1, _x2,_y2);
+
+ if (originX === undefined) originX = '50%';
+ if (originY === undefined) originY = '50%';
+ this._origin = new Loc(originX,originY);
+ },
+
+ /**
+ * Changes origin definition without moving the bounds.
+ * Use relocate() to change the position by moving the origin.
+ */
+ set originX(v){ this._origin.x = v; return v; },
+ get originX(){ return this._origin.absolute(this.width,this.height, this.x1,this.x2).x; },
+
+ set originY(v){ this._origin.y = v; return v; },
+ get originY(){ return this._origin.absolute(this.width,this.height, this.x1,this.x2).y; },
+
+ /**
+ * Accessor for the realized numeric origin.
+ */
+ get absOrigin() { return this._origin.absolute(this.width,this.height, this.x1,this.x2); },
+ get relOrigin() { return this._origin.absolute(this.width,this.height); },
+
+ get origin(){ return this._origin; },
relocate : function relocate(x,y){
- return new BoundingBox(x,y, x+this.width,y+this.height);
+ var _x1 = this[X1], _y1 = this[Y1]
+ , _x2 = this[X2], _y2 = this[Y2]
+
+ , abs = this._origin.absolute(_x1-_x1, _y2-_y1, _x1,_y1)
+ , dx1 = _x1 - abs.x, dy1 = _y1 - abs.y
+ , dx2 = _x2 - abs.x, dy2 = _y2 - abs.y
+
+ , x1 = x + dx1, y1 = y + dy1
+ , x2 = x + dx2, y2 = y + dy2
+ ;
+ return this.set4(x1,y1, x2,y2);
},
resize : function resize(w,h){
- var x = this.x1, y = this.y1;
- return new BoundingBox(x,y, x+w,y+h);
+ var x1 = this[X1], y1 = this[Y1]
+ , x2 = this[X2], y2 = this[Y2]
+ , wOld = x2-x1, hOld = y2-y1
+
+ , p, abs, diff, o = this._origin
+ , xp = o.xPercentage, yp = o.yPercentage
+ ;
+ if ( xp !== null ) {
+ diff = w - wOld;
+ abs = x1 + xp*wOld;
+ x1 = abs - xp*diff;
+ x2 = abs + (1-xp)*diff;
+ } else
+ x2 = x1 + w;
+
+ if ( yp !== null ) {
+ diff = h - hOld;
+ abs = y1 + yp*hOld;
+ y1 = abs - yp*diff;
+ y2 = abs + (1-yp)*diff;
+ } else
+ y2 = y1 + h;
+
+ return this.set4(x1,y1, x2,y2);
},
clone : function clone(){
- return new BoundingBox(this[0],this[1], this[2],this[3]);
+ var o = this._origin;
+ return new BoundingBox(this[X1],this[Y1], this[X2],this[Y2], o[X1], o[Y1]);
}
});
// Vec.init.call(this, x,y);
// },
- 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(),
-
- clone : function clone(){
- return new Loc(this.x, this.y);
- },
-
moveBy : function moveBy(x,y){
return new Loc(this.x+x, this.y+y);
},
return Loc.Square.fromLoc(this.x, this.y);
},
+ get xIsPercentage(){ return Y.isString(this.x); },
+ get yIsPercentage(){ return Y.isString(this.x); },
+
+ get xPercentage(){ var x = this.x; return Y.isString(x) ? parseFloat(x.slice(0,-1))/100 : null; },
+ get yPercentage(){ var y = this.y; return Y.isString(y) ? parseFloat(y.slice(0,-1))/100 : null; },
+
/**
* Converts relative locations like ('50%','50%') to a numeric location.
*/
- absolute : function absolute(w,h){
- var x = this.x, y = this.y
- return new Loc( Y.isString(x) ? parseFloat(x.slice(0,-1))/100 * w : x
- , Y.isString(y) ? parseFloat(y.slice(0,-1))/100 * h : y );
+ absolute : function absolute(w,h, x1,y1){
+ var x = this.x, y = this.y;
+ return new Loc( (x1 || 0) + (Y.isString(x) ? parseFloat(x.slice(0,-1))/100 * w : x)
+ , (y1 || 0) + (Y.isString(y) ? parseFloat(y.slice(0,-1))/100 * h : y) );
},
toUnits : function toUnits(units){
var Y = require('Y').Y
, Vec = require('ezl/math/vec').Vec
+, X1 = 0, Y1 = 1
+, X2 = 2, Y2 = 3
,
init : function initRect(_x1,_y1, _x2,_y2){
if (_x1 instanceof Array && _y1 instanceof Array) {
- _y2 = _y1[1]; _x2 = _y1[0];
- _y1 = _x1[1]; _x1 = _x1[0];
+ _y2 = _y1[Y1]; _x2 = _y1[X1];
+ _y1 = _x1[Y1]; _x1 = _x1[X1];
}
var x1 = Math.min(_x1,_x2), x2 = Math.max(_x1,_x2)
, y1 = Math.min(_y1,_y2), y2 = Math.max(_y1,_y2);
this.length = 4;
- this[0] = x1; this[1] = y1;
- this[2] = x2; this[3] = y2;
+ this.set4(x1,y1, x2,y2);
},
- get x1(){ return this[0]; }, set x1(v){ this[0] = v; },
- get y1(){ return this[1]; }, set y1(v){ this[1] = v; },
- get x2(){ return this[2]; }, set x2(v){ this[2] = v; },
- get y2(){ return this[3]; }, set y2(v){ this[3] = v; },
+ /**
+ * @protected
+ */
+ set4 : function set4(x1,y1, x2,y2){
+ this[X1] = x1; this[Y1] = y1;
+ this[X2] = x2; this[Y2] = y2;
+ return this;
+ },
+
+ get x1(){ return this[X1]; }, set x1(v){ this[X1] = v; return v; },
+ get y1(){ return this[Y1]; }, set y1(v){ this[Y1] = v; return v; },
+ get x2(){ return this[X2]; }, set x2(v){ this[X2] = v; return v; },
+ get y2(){ return this[Y2]; }, set y2(v){ this[Y2] = v; return v; },
+
+ get p1(){ return new Vec(this[X1],this[Y1]); },
+ set p1(v){ this[X1] = v.x; this[Y1] = this.y; return v; },
+ get p2(){ return new Vec(this[X2],this[Y2]); },
+ set p2(v){ this[X2] = v.x; this[Y2] = this.y; return v; },
- get p1(){ return new Vec(this[0],this[1]); },
- set p1(v){ this[0] = v.x; this[1] = this.y },
- get p2(){ return new Vec(this[2],this[3]); },
- set p2(v){ this[2] = v.x; this[3] = this.y },
+ get width(){ return this[X2] - this[X1]; },
+ get height(){ return this[Y2] - this[Y1]; },
- // TODO: .origin
- // TODO: Scale w/h proportionally if .origin is percentage
- get width(){ return this[2] - this[0]; },
- get height(){ return this[3] - this[1]; },
+ attr : Y.attr.methodize(),
get midpoint(){
- return new Vec( this[0] + (this[2]-this[0]) / 2
- , this[1] + (this[3]-this[1]) / 2 );
+ return new Vec( this[X1] + (this[X2]-this[X1]) / 2
+ , this[Y1] + (this[Y2]-this[Y1]) / 2 );
},
contains : function contains(x,y){
- return ( x >= this[0] && x <= this[2] &&
- y >= this[1] && y <= this[3] );
+ return ( x >= this[X1] && x <= this[X2] &&
+ y >= this[Y1] && y <= this[Y2] );
},
intersects : function intersects(line){
- var x1 = this[0], x2 = this[2]
- , y1 = this[1], y2 = this[3]
+ var x1 = this[X1], x2 = this[X2]
+ , y1 = this[Y1], y2 = this[Y2]
, cx1,cy1, cx2,cy2 ;
return ( ( (cx1 = line.calcX(y1)) >= x1 && cx1 <= x2 )
|| ( (cy1 = line.calcY(x1)) >= y1 && cy1 <= y2 )
},
clone : function clone(){
- return new Rect(this[0],this[1], this[2],this[3]);
+ return new this.__class__(this[X1],this[Y1], this[X2],this[Y2]);
},
toString : function toString(){
var Y = require('Y').Y
+, _X = 0, _Y = 1
,
/**
new Y.Class('Vec', [], {
init : function init(x, y){
- this.length = 2;
-
if ( x instanceof Array ) {
- y = x[1]; x = x[0];
+ y = x[_Y]; x = x[_X];
}
+ this.length = 2;
this.setXY(x,y);
},
- equals : function equals(b){
- return (this.x === b.x) && (this.y === b.y);
- },
-
- clone : function clone(){
- return new Vec(this.x, this.y);
- },
+