"src/portal/layer.js",
"src/portal/shape.js",
+
+ "src/portal/math/math.js",
+ "src/portal/math/vec.js",
+ "src/portal/math/line.js",
+
"src/portal/util/quadtree.js",
"src/portal/util/rbtree.js",
"src/portal/util/eventloop.js",
// Generic Collection Functions
-function notSelfOrWrapped(fn){
+function notWrapped(fn){
var self = arguments.callee.caller;
return fn && fn !== self && fn.__wraps__ !== self;
}
return acc;
// fn = Function.toFunction(fn);
- if ( notSelfOrWrapped(o.reduce) )
+ if ( notWrapped(o.reduce) )
return o.reduce.apply(o, [fn, acc, cxt]);
cxt = cxt || o;
return acc;
}
-function set(o, key, value, def){
- if ( o && notSelfOrWrapped(o.set) )
- return o.set.apply(o, slice.call(arguments,1));
+function set(o, key, value, def){
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));
-
+function dset(o, key, value, def){
+ if ( o && notWrapped(o.set) )
+ return o.set.apply(o, slice.call(arguments,1));
+ else
+ return set(o, key, value, def);
+}
+
+function attr(o,key,value,def){
if ( !o || key === undefined ) return o;
- if ( isPlainObject(key) )
+ if ( Y.isPlainObject(key) )
return extend(o, key);
if ( value !== undefined || def !== undefined ){
- return set(o, key, value, def);
+ return dset(o, key, value, def);
} else
return o[key];
}
+function dattr(o, key, value, def){
+ if ( o && notWrapped(o.attr) )
+ return o.attr.apply(o, slice.call(arguments,1));
+ else
+ return attr(o, key, value, def);
+}
+
function extend( A, B ){
return slice.call(arguments,1).reduce(extend._extendall, A);
}
return reduce(donor, extend._set, A);
};
extend._set = function _set(o, v, k){
- return attr(o, k, v, o[k]);
+ return dattr(o, k, v, o[k]);
};
Y.reduce = reduce;
-Y.set = set;
-Y.attr = attr;
+Y.set = dset;
+Y.attr = dattr;
Y.extend = extend;
Y.isFunction = isFunction;
zrshift: function(x,y){ return x >>> y; },
// values
- nop: function(){},
+ nop: function(x){},
I: function(x){ return x; },
K: function(k){ return function(){ return k; }; },
val: function(def,o){ return o !== undefined ? o : def; },
ok: function(o){ return o !== undefined && o !== null; },
- // values & accessors
- has: function(k,o){ return k in o; },
- get: function(k,o){ return o[k] },
- getdef: function(def,k,o){ return (k in o ? o[k] : def); },
- set: function(o,k,v){ if (o && k !== undefined) o[k] = v; return o; },
+ // reduce-ordered values & accessors
+ khas: function(k,o){ return k in o; },
+ kget: function(k,o){ return o[k] },
+ defkget: function(def,k,o){ return (k in o ? o[k] : def); },
+ vkset: function(o,v,k){ if (o && k !== undefined) o[k] = v; return o; },
+
+ // curry-ordered values & accessors
+ has: function(o,k){ return k in o; },
+ get: function(o,k){ return o[k] },
+ getdef: function(o,k,def){ return (k in o ? o[k] : def); },
+ set: set,
+ attr: attr,
method: function(name){
var args = Y(arguments,1);
return function(obj){
(function($, undefined){
+var CONTEXT_ATTRS = Y([
+ 'globalAlpha', 'globalCompositeOperation',
+ 'strokeStyle', 'fillStyle',
+ 'lineWidth', 'lineCap', 'lineJoin', 'miterLimit',
+ 'shadowOffsetX', 'shadowOffsetY', 'shadowBlur', 'shadowColor'
+]);
+
+
+
Layer = new Y.Class('Layer', {
_cssClasses : 'portal layer',
/// Attributes ///
+
+ attr : function attr(key, value, def){
+ if (!key) return this;
+
+ if ( Y.isPlainObject(key) ) {
+ for (var k in key)
+ this.attr(k, key[k]);
+ return this;
+
+ // } else if ( CONTEXT_ATTRS.has(key) ) {
+ // var r = Y.attr(this.ctx, key, value, def);
+ //
+ // if (r === this.ctx) {
+ // // This implies we set a property
+ // this.dirty = true;
+ // return this;
+ // } else
+ // return r;
+ //
+ } else
+ return Y.op.attr(this, key, value, def);
+ },
+
/**
* Changes the layer's width and then updates the canvas.
*/
/// Drawing Functions ///
- // for debugging
- point : function point(x,y, color){
- var ctx = this.ctx;
- this._openPath(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.
},
_openPath : function _openPath(ctx){
- var w = this.canvasWidth
+ var self = this
+ , w = this.canvasWidth
, h = this.canvasHeight
, neg = this.negBleed
;
// ctx.scale(this.absScaleX, this.absScaleY);
+ // Set context attributes
+ CONTEXT_ATTRS.forEach(function(name){
+ if (self[name] === undefined)
+ delete ctx[name];
+ else
+ ctx[name] = self[name];
+ });
+
return this;
},
return this;
},
+ // for debugging
+ point : function point(x,y, color){
+ var ctx = this.ctx;
+ // this._openPath(ctx);
+
+ var r = 2;
+ ctx.beginPath();
+ ctx.arc(x,y, r, 0, Math.PI*2, false);
+ ctx.fillStyle = color || '#FFFFFF';
+ ctx.fill();
+ ctx.closePath();
+
+ // this._closePath(ctx);
+ return this;
+ },
+
$('<style />')
.text([
'.portal.layer { position:absolute; z-index:1; top:0; left:0; line-height:0; }',
+ // '.portal.layer { outline:1px solid #000000; }',
'.portal.layer canvas { z-index:0; }'
].join('\n'))
.appendTo('head');
+(function(){
+
+var
+HALF_PI = Math.PI/2,
+SIN_HALF_PI = Math.sin(HALF_PI),
+COS_HALF_PI = Math.cos(HALF_PI);
+
+
/**
* A line in the cartesian plane.
*/
math.Line = new Y.Class('Line', math.Vec, {
- init : function init(x1,y1, x2,y2, t){
+ init : function init(x1,y1, x2,y2, tdist){
this.x1 = x1; this.y1 = y1; this.p1 = new math.Vec(x1,y1);
this.x2 = x2; this.y2 = y2; this.p2 = new math.Vec(x2,y2);
, xi = this.xint = -y1/m + x1
;
math.Vec.init.call(this, xdelta, ydelta);
- this.setT(t);
+
+ this.theta = Math.atan2(ydelta, xdelta);
+ this._cos = Math.cos(this.theta);
+ this._sin = Math.sin(this.theta);
+ this.setTScale(tdist);
+ },
+
+ clone : function clone(){
+ return new math.Line(this.x1,this.y1, this.x2,this.y2, this.tdist);
},
- setT : function setT(t){
- this.t = 1/(t || 1);
- this.pa = this.t*this.x;
- this.pb = this.t*this.y;
+ setTScale : function setTScale(tdist){
+ if (tdist) {
+ this.tdist = tdist;
+ this.pa = tdist * this._cos;
+ this.pb = tdist * this._sin;
+ } else {
+ this.tdist = this.y / this._sin;
+ this.pa = this.x;
+ this.pb = this.y;
+ }
return this;
},
pcalc : function parametric(t){
- return new math.Vec( this.x1 + this.pa*t ,
- this.y1 + this.pb*t );
+ return new math.Vec( this.x1 + t*this.pa ,
+ this.y1 + t*this.pb );
+ },
+
+ pointX : function pointX(x){
+ return new math.Vec(x, this.calcY(x));
+ },
+
+ pointY : function pointY(y){
+ return new math.Vec(this.calcX(y), y);
},
calcY : function calcY(x){
},
base : function base(){
- return new math.Line(0,0, this.x,this.y);
+ if (!this._base)
+ this._base = new math.Line(0,0, this.x,this.y);
+ return this._base;
+ },
+
+ tangent : function tangent(at){
+ var _theta = Math.PI/2 + this.theta
+ , x = (at.x !== this.x1 ? this.x1 : this.x2) - at.x
+ , y = (at.y !== this.y1 ? this.y1 : this.y2) - at.y
+ , _x = at.x + y
+ , _y = at.y - x
+ return new math.Line(at.x,at.y, _x,_y, this.tdist);
},
toString : function toString(){
- return 'Line('+this.x1+','+this.y1+', '+this.x2+','+this.y2+', slope='+this.slope+')';
+ return 'Line('+this.x1.toFixed(2)+','+this.y1.toFixed(2)+', '+
+ this.x2.toFixed(2)+','+this.y2.toFixed(2)+', '+
+ 'slope='+this.slope.toFixed(3)+')';
}
-});
\ No newline at end of file
+});
+
+})();
},
toString : function toString(){
- return 'Vec('+this.x+','+this.y+')';
+ return 'Vec('+this.x.toFixed(3)+','+this.y.toFixed(3)+')';
}
});
-CONTEXT_ATTRS = Y([
- 'globalAlpha', 'globalCompositeOperation', 'strokeStyle', 'fillStyle',
- 'lineWidth', 'lineCap', 'lineJoin', 'miterLimit', 'shadowOffsetX',
- 'shadowOffsetY', 'shadowBlur', 'shadowColor'
-]);
-
-
Shape = new Y.Class('Shape', Layer, {
_cssClasses : 'portal layer shape',
- attr : function attr(key, value, def){
- if (!key) return this;
-
- if ( Y.isPlainObject(key) ) {
- for (var k in key)
- this.attr(k, key[k]);
- return this;
-
- } else if ( CONTEXT_ATTRS.has(key) ) {
- var r = Y.attr(this.ctx, key, value, def);
-
- if (r === this.ctx) {
- // This implies we set a property
- this.dirty = true;
- return this;
- } else
- return r;
-
- } else
- return Y.attr(this, key, value, def);
- },
-
_calcDimension : function _calcDimension(which, values){
values.unshift(0);
var self = this
Rect = new Y.Class('Rect', Shape, {
_cssClasses : 'portal layer shape rect',
- init : function init(w, h){
+ init : function initRect(w, h){
Layer.init.call(this);
this.width(w)
- .height(h)
- .origin(w/2, h/2);
+ .height(h);
+ // .origin(w/2, h/2);
},
drawShape : function drawShape(ctx){
Circle = new Y.Class('Circle', Shape, {
_cssClasses : 'portal layer shape circle',
- init : function init(radius){
+ init : function initCircle(radius){
Layer.init.call(this);
var d = radius * 2;
- this.radius = radius;
- this.width(d).height(d)
- .origin(radius,radius);
+ this.radius = this.negBleed.x = this.negBleed.y = radius;
+ this.width(d).height(d);
+ // .origin(radius,radius);
},
drawShape : function drawShape(ctx){
var r = this.radius;
- ctx.arc(r,r, r, 0, Math.PI*2, false);
+ ctx.arc(0,0, r, 0, Math.PI*2, false);
ctx.fill();
}
* together to make the numbered coordinates.
* x0 and y0 will always be 0.
*/
- init : function init(xs, ys){
+ init : function initPolygon(xs, ys){
Layer.init.call(this);
var xs = this._calcDimension('x', xs)
this.points = Y(xs).zip(ys).map(Loc.instantiate, Loc);
this.width(w)
- .height(h)
- .origin(w/2, h/2);
+ .height(h);
+ // .origin(w/2, h/2);
},
drawShape : function drawShape(ctx){
});
// Er, this won't do. It's only a line-segment.
-Line = new Y.Class('Line', Polygon, {
+Line = new Y.Class('Line', Shape, {
+ _cssClasses : 'portal layer shape line',
+
+ init : function initLine(x,y){
+ Layer.init.call(this);
+
+ this.sublayer = jQuery('<div style="overflow:hidden" />')
+ .append(this.canvas)
+ .appendTo(this.layer);