From 91b01b9df11b33183ec4fc3fda3af3ff433a5e0f Mon Sep 17 00:00:00 2001 From: dsc Date: Sat, 30 Oct 2010 18:20:41 -0700 Subject: [PATCH] Added Shape.attr --- notes.md | 1 + src/Y/core.js | 17 +++-- src/Y/y-collection.js | 4 + src/Y/y-core.js | 185 +++++++++++++------------------------------------ src/Y/y-function.js | 3 + src/portal/layer.js | 3 - src/portal/shape.js | 99 +++++++++++++++++++++----- src/tanks/lttl.js | 15 +++- 8 files changed, 160 insertions(+), 167 deletions(-) diff --git a/notes.md b/notes.md index e69de29..1d5c4a2 100644 --- a/notes.md +++ b/notes.md @@ -0,0 +1 @@ +- Clipping is going to suck \ No newline at end of file diff --git a/src/Y/core.js b/src/Y/core.js index d394536..d7c0080 100644 --- a/src/Y/core.js +++ b/src/Y/core.js @@ -23,6 +23,11 @@ function attr(o, key, value, def){ if ( o && notSelfOrWrapped(o.attr) ) return o.attr.apply(o, slice.call(arguments,1)); + if ( !o || key === undefined ) return o; + + if ( isPlainObject(key) ) + return extend(o, key); + if ( value !== undefined || def !== undefined ){ o[key] = (value !== undefined ? value : def); return o; @@ -31,10 +36,12 @@ function attr(o, key, value, def){ } function extend( A, B ){ - return slice.call(arguments,1).reduce(function(A, donor){ - return reduce(donor, function(o, v, k){ - return attr(o, k, v, o[k]); - }, A); - }, A); + return slice.call(arguments,1).reduce(extend._extendall, A); } +extend._extendall = function(A, donor){ + return reduce(donor, extend._set, A); +}; +extend._set = function(o, v, k){ + return attr(o, k, v, o[k]); +}; diff --git a/src/Y/y-collection.js b/src/Y/y-collection.js index 70d0db6..4de7996 100644 --- a/src/Y/y-collection.js +++ b/src/Y/y-collection.js @@ -72,6 +72,10 @@ YBase.subclass('YCollection', { return -1; }, + 'has' : function( value ){ + return ( this.indexOf(value) !== -1 ); + }, + 'clone' : function(){ return Y({}).extend(this); }, diff --git a/src/Y/y-core.js b/src/Y/y-core.js index e05b110..10a9b26 100644 --- a/src/Y/y-core.js +++ b/src/Y/y-core.js @@ -11,160 +11,71 @@ Y.isPlainObject = isPlainObject; -function doPhase(phase, o, newY, args){ - var ps = Y.plugins.slice(0) // prevent mutation under iteration - , pslen = ps.length - , capture = (phase === 'capture') - ; - - for ( var i=0, plugin=ps[i]; i 1 ) { + + // Merge Arrays or Objects + // Y([0,1], [2,3], [4,5]) -> [0,1,2,3,4,5] + // Y({foo:1}, {bar:2}) -> { foo:1, bar:2 } + if ( args.every(isArray) || args.every(isPlainObject) ) { + r = extend.apply(this, args); + + // Convenience of Y(Y.range()) + } else if ( args.every(isNumber) ) { + r = Y.range.apply(this, A); + + // We got random stuff: wrap an Array of it + } else + return new Y.YArray( args ); + + return (newY ? Y(r) : r); + } - // Wrap as generic object if nothing matched - if (o !== _o || o._o) - return o; - else - return new Y.YObject(o); -} - -Y.plugins = []; -Y.plugins.byName = {}; - -/** - * @param {Object|Function} plugin should either be a function to be used as `call`, or an object - * with some set of methods from: - * - call: Invoked during bubbling to process input. Any non-false-y return value will be passed - * along as the Y() return value. All plugins with a `call` method will be invoked during - * bubbling, so non-matching plugins should not return a value. - * - capture: Invoked before bubbling to process input. A non-false-y return value will be - * returned as the Y() return value. All plugins with a `capture` method will be invoked during - * capture, and any truth-y response will prevent bubbling. It is therefore critical non- - * matching plugins do not return a value. - * - finally: Invoked after capture and/or bubbling to post-process the result. Any non-false-y - * return value will be passed along as the Y() return value. - * Methods are invoked with: - * - {Object} o: The current return value (or input) - * - {Boolean} newY: Whether `Y()` was invoked with the `new` keyword. - * - {Array} args: The original arguments, converted to an array. - */ -Y.plugin = function(plugin){ - if ( isFunction(plugin) ) - plugin = { 'call':plugin, 'name':plugin.name }; + // Do we have a type-specific wrapper? + var name = type_of(o) + , yname = 'Y' + name.charAt(0).toUpperCase() + name.slice(1) + , YType = Y[yname] + ; - plugin.name = plugin.name || plugin.className; + // if ( YType && YType !== Y.YObject || YType !== Y.YBase ) + // return new YType(o); + if ( YType ) + return new YType(o); - // Register plugin - Y.plugins.push(plugin); - if (plugin.name) Y.plugins.byName[plugin.name] = plugin; + // Add YFunction methods, since we can't subclass function + // if ( isFunction(o) ) + // return new Y.YFunction(o); - return plugin; -}; - -// Y( arguments, start=0, stop=arguments.length ) -// Cast `arguments` object to a real Array, optionally slicing at specified delimiters -Y.plugin({ - 'capture': function(o, newY, args){ - if ( o.prototype === undefined - && isNumber(o.length) - && !isArray(o) - && o.constructor === _Object ) - return slice.call(o, args[1] || 0, args[2] || o.length); - } -}); - -Y.plugin({ - 'finally': function(o, newY, args){ - return (newY ? Y(o) : o); - } -}); - -// Merge Arrays or Objects -// Y([0,1], [2,3], [4,5]) -> [0,1,2,3,4,5] -// Y({foo:1}, {bar:2}) -> { foo:1, bar:2 } -Y.plugin({ - 'capture': function(o, newY, args){ - if ((args.length > 1) && ( args.every(isArray) || args.every(isPlainObject) )) - return extend.apply(this, args); - } -}); - -// Convenience of Y(Y.range()) -Y.plugin({ - 'capture': function(o, newY, args){ - if ( (args.length > 1) && args.every(isNumber) ) - return Y.range.apply(this, A); - } -}); - - -// We got random stuff: wrap an Array of it -Y.plugin({ - 'capture': function(o, newY, args){ - if (args.length > 1) - return new Y.YArray(args); - } -}); - -function getYType(o){ - var name = type_of(o) - , yname = 'Y' + name.charAt(0).toUpperCase() + name.slice(1); - return Y[yname]; + // Finally, Generic object wrapper + return new Y.YObject(o); } -// Builtin type-specific wrappers -Y.plugin({ - 'call' : function(o, newY, args){ - var YType = getYType(o); - if ( YType && YType !== Y.YObject || YType !== Y.YBase ) - return new YType(o); - } -}); - - diff --git a/src/Y/y-function.js b/src/Y/y-function.js index f7654b4..91447cf 100644 --- a/src/Y/y-function.js +++ b/src/Y/y-function.js @@ -202,3 +202,6 @@ function mixinNames(o, Donor, names, override, yWrap){ } +Y(Y.reduce); +Y(Y.attr); +Y(Y.extend); diff --git a/src/portal/layer.js b/src/portal/layer.js index 53f1fe6..83613c2 100644 --- a/src/portal/layer.js +++ b/src/portal/layer.js @@ -34,9 +34,6 @@ Layer = new Y.Class('Layer', { ctx : null, dirty : true, - x: 0, - y: 0, - /// Setup /// diff --git a/src/portal/shape.js b/src/portal/shape.js index b2aef21..e0e3a63 100644 --- a/src/portal/shape.js +++ b/src/portal/shape.js @@ -1,25 +1,33 @@ +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', - _fill : false, // same as 'transparent' - _line_width : 0, // will ignore strokeStyle - _stroke : false, // same as 'transparent' - - - _updateStyle : function(ctx, apply, force){ - ctx.lineWidth = this._line_width; - ctx.strokeStyle = this._stroke || 'transparent'; - ctx.fillStyle = this._fill || 'transparent'; + attr : function(key, value, def){ + if (!key) return this; - if (apply) { - if (force || (this._line_width && this._stroke)) - ctx.stroke(); + if ( Y.isPlainObject(key) ) { + for (var k in key) + this.attr(k, key[k]); + return this; - if (force || this._fill) - ctx.fill(); - } - - 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); } }); @@ -27,7 +35,6 @@ Shape = new Y.Class('Shape', Layer, { Rect = new Y.Class('Rect', Shape, { _cssClasses : 'portal layer shape rect', - _fill : "#E73075", _width : 0, _height : 0, @@ -44,12 +51,66 @@ Rect = new Y.Class('Rect', Shape, { drawShape : function(ctx){ ctx.rect(0,0, this._width,this._height); - this._updateStyle(ctx, true); + ctx.fill(); return this; } }); +Triangle = new Y.Class('Triangle', Shape, { + x1: 0, y1: 0, + x2: 0, y2: 0, + _offsetX : 0, // We need our triangle to be in the first quadrant + _offsetY : 0, // so we'll have to offset any negative shapes at the position call + + init : function(x1,y1, x2,y2){ + Layer.init.call(this); + + var minX = Math.min(0, x1, x2); + if (minX < 0) { + var offX = this._offsetX = -minX; + x1 += offX; x2 += offX; + } + + var minY = Math.min(0, y1, y2); + if (minY < 0) { + var offY = this._offsetY = -minY; + Y1 += offY; y2 += offY; + } + + this.x1 = x1; this.y1 = y1; + this.x2 = x2; this.y2 = y2; + this.width( Math.max(0, x1, x2) ); + this.height( Math.max(0, y1, y2) ); + }, + + _calcOffset : function(which, values){ + var min = Math.min(0, Math.min.apply(Math, values)); + + if (min < 0) { + var off = this['_offset'+which] = -min; + x1 += off; x2 += off; + } + return + }, + + 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.offsetX; + if (pos.left !== undefined) pos.left -= this.offsetY; + + this.css(pos); + return this; + }, + +}); Ellipse = new Y.Class('Ellipse', Shape, { diff --git a/src/tanks/lttl.js b/src/tanks/lttl.js index 5dcafa1..fced4b3 100644 --- a/src/tanks/lttl.js +++ b/src/tanks/lttl.js @@ -5,10 +5,19 @@ v = $('#viewport'); L = new Layer(v) .width(v.width()) .height(v.height()) - .append( new Rect(50,50).position(50,50) ) .append( - new Rect(250,250).position(50,150) ) - .appendTo(v) + new Rect(50,50) + .position(50,50) + .attr({ + fillStyle : '#E73075' + }) + ).append( + R = new Rect(250,250) + .position(50,150) + .attr({ + fillStyle : '#E2EEF5' + }) + ).appendTo(v) .draw() ; -- 1.7.0.4