From 1293edb66a5263f8f7064f16f11cbf6b8f550800 Mon Sep 17 00:00:00 2001 From: wout Date: Tue, 18 Dec 2012 19:54:12 +0100 Subject: [PATCH] Separated core from optional libraries --- Rakefile | 19 +++-- dist/svg.js | 175 +++++++++++++++++++++++++++++------------------ dist/svg.min.js | 4 +- src/arrange.js | 53 ++++++++++++++ src/circle.js | 12 ++-- src/clip.js | 18 +++++ src/container.js | 50 ++++---------- src/doc.js | 2 + src/element.js | 30 +++----- src/ellipse.js | 9 +-- 10 files changed, 233 insertions(+), 139 deletions(-) create mode 100644 src/arrange.js diff --git a/Rakefile b/Rakefile index 289849d..5d3dc72 100644 --- a/Rakefile +++ b/Rakefile @@ -1,12 +1,19 @@ SVGJS_VERSION = '0.1a' -CORE_MODULES = %w[ svg container element clip doc defs shape rect circle ellipse path image group ] +# all available modules in the correct loading order +ALL = %w[ svg container element arrange clip doc defs shape rect circle ellipse path image group sugar ] -OPTIONAL_MODULES = %w[ sugar ] +# required modules to make the library operational +CORE = %w[ circle container defs doc element ellipse image path rect shape svg ] -DEFAULT_MODULES = CORE_MODULES + OPTIONAL_MODULES +# optional modules +OPTIONAL = %w[ clip group arrange sugar ] -KILO = 1024 # how many bytes in a "kilobyte" +# modules used in the curren build +MODULES = CORE.concat(OPTIONAL).sort { |a,b| ALL.index(a) <=> ALL.index(b) } + +# how many bytes in a "kilobyte" +KILO = 1024 task :default => :dist @@ -38,7 +45,7 @@ class BuildTask < Rake::FileTask end -BuildTask.define_task 'dist/svg.js' => DEFAULT_MODULES.map {|m| "src/#{ m }.js" } do |task| +BuildTask.define_task 'dist/svg.js' => MODULES.map {|m| "src/#{ m }.js" } do |task| mkdir_p 'dist', :verbose => false svgjs = '' @@ -107,7 +114,7 @@ desc "List available modules" task :modules do Dir['src/**/*.js'].each do |file| name = file.gsub(/^src\//,'').gsub(/.js$/,'') - puts name + (DEFAULT_MODULES.include?(name) ? '*' : '') + puts name + (MODULES.include?(name) ? '*' : '') end puts "\n*included in default build" end diff --git a/dist/svg.js b/dist/svg.js index 1d6323c..9358be1 100644 --- a/dist/svg.js +++ b/dist/svg.js @@ -1,4 +1,4 @@ -/* svg.js 0.1a - svg container element clip doc defs shape rect circle ellipse path image group sugar - svgjs.com/license */ +/* svg.js 0.1a - svg container element arrange clip doc defs shape rect circle ellipse path image group sugar - svgjs.com/license */ (function() { this.SVG = { @@ -21,53 +21,23 @@ SVG.Container = { - add: function(e) { - return this.addAt(e); - }, - - addAt: function(e, i) { - if (!this.contains(e)) { + add: function(e, i) { + if (!this.has(e)) { i = i == null ? this.children().length : i; this.children().splice(i, 0, e); - this.node.insertBefore(e.node, this.node.childNodes[i + 1]); + this.node.insertBefore(e.node, this.node.childNodes[i]); e.parent = this; } return this; }, - contains: function(e) { + has: function(e) { return Array.prototype.indexOf.call(this.children(), e) >= 0; }, children: function() { - return this._children || []; - }, - - sendBack: function(e) { - var i = this.children().indexOf(e); - if (i !== -1) - return this.remove(e).addAt(e, i - 1); - }, - - bringForward: function(e) { - var i = this.children().indexOf(e); - if (i !== -1) - return this.remove(e).addAt(e, i + 1); - }, - - bringToFront: function(e) { - if (this.contains(e)) - this.remove(e).add(e); - - return this; - }, - - sendToBottom: function(e) { - if (this.contains(e)) - this.remove(e).addAt(e, 0); - - return this; + return this._children || (this._children = []); }, remove: function(e) { @@ -88,12 +58,20 @@ defs: function() { if (this._defs == null) { this._defs = new SVG.Defs(); - this.add(this._defs); + this.add(this._defs, 0); } return this._defs; }, + levelDefs: function() { + var d = this.defs(); + + this.remove(d).add(d, 0); + + return this; + }, + group: function() { var e = new SVG.G(); this.add(e); @@ -175,16 +153,20 @@ // move element to given x and y values move: function(x, y) { - this.attr('x', x); - this.attr('y', y); + this.attr({ + x: x, + y: y + }); return this; }, // set element size to given width and height size: function(w, h) { - this.attr('width', w); - this.attr('height', h); + this.attr({ + width: w, + height: h + }); return this; }, @@ -193,14 +175,14 @@ remove: function() { return this.parent != null ? this.parent.remove(this) : void 0; }, - + // get parent document parentDoc: function() { return this._parent(SVG.Doc); }, // get parent svg wrapper - parentSVG: function() { + mother: function() { return this.parentDoc(); }, @@ -237,6 +219,7 @@ for (var i = 0, s = l.length; i < s; i++) if (!r.test(l[i])) n.push(l[i]); + } else n = l; @@ -257,19 +240,6 @@ return b; }, - // clip element using another element - clip: function(block) { - var p = this.parentSVG().defs().clipPath(); - block(p); - - return this.clipTo(p); - }, - - // distribute clipping path to svg element - clipTo: function(p) { - return this.attr('clip-path', 'url(#' + p.id + ')'); - }, - // private: find svg parent _parent: function(pt) { var e = this; @@ -283,6 +253,58 @@ }); + SVG.extend(SVG.Element, { + + // get all siblings, including me + siblings: function() { + return this.mother().children(); + }, + + // send given element one step forwards + forward: function() { + var i = this.siblings().indexOf(this); + this.mother().remove(this).add(this, i + 1); + + return this; + }, + + // send given element one step backwards + backward: function() { + var i, p = this.mother(); + + p.levelDefs(); + + i = this.siblings().indexOf(this); + + if (i > 1) + p.remove(this).add(this, i - 1); + + return this; + }, + + // send given element all the way to the front + front: function() { + this.mother().remove(this).add(this); + + return this; + }, + + // send given element all the way to the back + back: function() { + var i, p = this.mother(); + + p.levelDefs(); + + i = this.siblings().indexOf(this); + + if (i > 1) + p.remove(this).add(this, 0); + + return this; + } + + }); + var clipID = 0; SVG.Clip = function Clip() { @@ -296,6 +318,24 @@ // include the container object SVG.extend(SVG.Clip, SVG.Container); + + // add clipping functionality to element + SVG.extend(SVG.Element, { + + // clip element using another element + clip: function(block) { + var p = this.mother().defs().clipPath(); + block(p); + + return this.clipTo(p); + }, + + // distribute clipping path to svg element + clipTo: function(p) { + return this.attr('clip-path', 'url(#' + p.id + ')'); + } + + }); SVG.Doc = function Doc(e) { @@ -305,6 +345,8 @@ this.attr('version', '1.1'); this.attr('xlink', SVG.xlink, SVG.ns); + this.defs(); + if (typeof e == 'string') e = document.getElementById(e); @@ -373,20 +415,20 @@ return this; }, - // custom size function - size: function(w, h) { + // custom size function (no height value here!) + size: function(w) { this.attr('r', w / 2); this.center(); return this; }, - // private: center - center: function(cx, cy) { + // position element by its center + center: function(x, y) { var r = this.attrs.r || 0; - this.attr('cx', cx || ((this.attrs.x || 0) + r)); - this.attr('cy', cy || ((this.attrs.y || 0) + r)); + this.attr('cx', x || ((this.attrs.x || 0) + r)); + this.attr('cy', y || ((this.attrs.y || 0) + r)); } }); @@ -418,10 +460,11 @@ return this; }, - - center: function(cx, cy) { - this.attr('cx', cx || ((this.attrs.x || 0) + (this.attrs.rx || 0))); - this.attr('cy', cy || ((this.attrs.y || 0) + (this.attrs.ry || 0))); + + // position element by its center + center: function(x, y) { + this.attr('cx', x || ((this.attrs.x || 0) + (this.attrs.rx || 0))); + this.attr('cy', y || ((this.attrs.y || 0) + (this.attrs.ry || 0))); } }); diff --git a/dist/svg.min.js b/dist/svg.min.js index 707a4f6..8e23f03 100644 --- a/dist/svg.min.js +++ b/dist/svg.min.js @@ -1,2 +1,2 @@ -/* svg.js 0.1a - svg container element clip doc defs shape rect circle ellipse path image group sugar - svgjs.com/license */ -(function(){this.SVG={ns:"http://www.w3.org/2000/svg",xlink:"http://www.w3.org/1999/xlink",create:function(e){return document.createElementNS(this.ns,e)},extend:function(e,t){for(var n in t)e.prototype[n]=t[n]}},this.svg=function(e){return new SVG.Doc(e)},SVG.Container={add:function(e){return this.addAt(e)},addAt:function(e,t){return this.contains(e)||(t=t==null?this.children().length:t,this.children().splice(t,0,e),this.node.insertBefore(e.node,this.node.childNodes[t+1]),e.parent=this),this},contains:function(e){return Array.prototype.indexOf.call(this.children(),e)>=0},children:function(){return this._children||[]},sendBack:function(e){var t=this.children().indexOf(e);if(t!==-1)return this.remove(e).addAt(e,t-1)},bringForward:function(e){var t=this.children().indexOf(e);if(t!==-1)return this.remove(e).addAt(e,t+1)},bringToFront:function(e){return this.contains(e)&&this.remove(e).add(e),this},sendToBottom:function(e){return this.contains(e)&&this.remove(e).addAt(e,0),this},remove:function(e){return this.removeAt(this.children().indexOf(e))},removeAt:function(e){if(0<=e&&e=0;n--)e[t[n]]!=null&&this.attr("stroke-"+t[n],e[t[n]]);return this}}),SVG.extend(SVG.Element,{rotate:function(e){var t=this.bbox();return e.x==null&&(e.x=t.cx),e.y==null&&(e.y=t.cy),this.transform("rotate("+(e.deg||0)+" "+e.x+" "+e.y+")",e.absolute),this}})}).call(this); \ No newline at end of file +/* svg.js 0.1a - svg container element arrange clip doc defs shape rect circle ellipse path image group sugar - svgjs.com/license */ +(function(){this.SVG={ns:"http://www.w3.org/2000/svg",xlink:"http://www.w3.org/1999/xlink",create:function(e){return document.createElementNS(this.ns,e)},extend:function(e,t){for(var n in t)e.prototype[n]=t[n]}},this.svg=function(e){return new SVG.Doc(e)},SVG.Container={add:function(e,t){return this.has(e)||(t=t==null?this.children().length:t,this.children().splice(t,0,e),this.node.insertBefore(e.node,this.node.childNodes[t]),e.parent=this),this},has:function(e){return Array.prototype.indexOf.call(this.children(),e)>=0},children:function(){return this._children||(this._children=[])},remove:function(e){return this.removeAt(this.children().indexOf(e))},removeAt:function(e){if(0<=e&&e1&&t.remove(this).add(this,e-1),this},front:function(){return this.mother().remove(this).add(this),this},back:function(){var e,t=this.mother();return t.levelDefs(),e=this.siblings().indexOf(this),e>1&&t.remove(this).add(this,0),this}});var e=0;SVG.Clip=function(){this.constructor.call(this,SVG.create("clipPath")),this.id="_"+e++,this.attr("id",this.id)},SVG.Clip.prototype=new SVG.Element,SVG.extend(SVG.Clip,SVG.Container),SVG.extend(SVG.Element,{clip:function(e){var t=this.mother().defs().clipPath();return e(t),this.clipTo(t)},clipTo:function(e){return this.attr("clip-path","url(#"+e.id+")")}}),SVG.Doc=function(t){this.constructor.call(this,SVG.create("svg")),this.attr("xmlns",SVG.ns),this.attr("version","1.1"),this.attr("xlink",SVG.xlink,SVG.ns),this.defs(),typeof t=="string"&&(t=document.getElementById(t)),t.appendChild(this.node)},SVG.Doc.prototype=new SVG.Element,SVG.extend(SVG.Doc,SVG.Container),SVG.Defs=function(){this.constructor.call(this,SVG.create("defs"))},SVG.Defs.prototype=new SVG.Element,SVG.extend(SVG.Defs,SVG.Container),SVG.extend(SVG.Defs,{clipPath:function(){var e=new SVG.Clip;return this.add(e),e}}),SVG.Shape=function(t){this.constructor.call(this,t)},SVG.Shape.prototype=new SVG.Element,SVG.Rect=function(){this.constructor.call(this,SVG.create("rect"))},SVG.Rect.prototype=new SVG.Shape,SVG.Circle=function(){this.constructor.call(this,SVG.create("circle"))},SVG.Circle.prototype=new SVG.Shape,SVG.extend(SVG.Circle,{move:function(e,t){return this.attrs.x=e,this.attrs.y=t,this.center(),this},size:function(e){return this.attr("r",e/2),this.center(),this},center:function(e,t){var n=this.attrs.r||0;this.attr("cx",e||(this.attrs.x||0)+n),this.attr("cy",t||(this.attrs.y||0)+n)}}),SVG.Ellipse=function(){this.constructor.call(this,SVG.create("ellipse"))},SVG.Ellipse.prototype=new SVG.Shape,SVG.extend(SVG.Ellipse,{move:function(e,t){return this.attrs.x=e,this.attrs.y=t,this.center(),this},size:function(e,t){return this.attr("rx",e/2),this.attr("ry",t/2),this.center(),this},center:function(e,t){this.attr("cx",e||(this.attrs.x||0)+(this.attrs.rx||0)),this.attr("cy",t||(this.attrs.y||0)+(this.attrs.ry||0))}}),SVG.Path=function(){this.constructor.call(this,SVG.create("path"))},SVG.Path.prototype=new SVG.Shape,SVG.extend(SVG.Path,{data:function(e){return this.attr("d",e),this}}),SVG.Image=function(){this.constructor.call(this,SVG.create("image"))},SVG.Image.prototype=new SVG.Element,SVG.extend(SVG.Image,SVG.Container),SVG.extend(SVG.Image,{load:function(e){return this.attr("href",e,SVG.xlink),this}}),SVG.G=function(){this.constructor.call(this,SVG.create("g"))},SVG.G.prototype=new SVG.Element,SVG.extend(SVG.G,SVG.Container),SVG.extend(SVG.Shape,{fill:function(e){return e.color!=null&&this.attr("fill",e.color),e.opacity!=null&&this.attr("fill-opacity",e.opacity),this},stroke:function(e){e.color&&this.attr("stroke",e.color);var t="width opacity linecap linejoin miterlimit dasharray dashoffset".split(" ");for(var n=t.length-1;n>=0;n--)e[t[n]]!=null&&this.attr("stroke-"+t[n],e[t[n]]);return this}}),SVG.extend(SVG.Element,{rotate:function(e){var t=this.bbox();return e.x==null&&(e.x=t.cx),e.y==null&&(e.y=t.cy),this.transform("rotate("+(e.deg||0)+" "+e.x+" "+e.y+")",e.absolute),this}})}).call(this); \ No newline at end of file diff --git a/src/arrange.js b/src/arrange.js new file mode 100644 index 0000000..d7fcb5f --- /dev/null +++ b/src/arrange.js @@ -0,0 +1,53 @@ + +// add backward / forward functionality to elements +SVG.extend(SVG.Element, { + + // get all siblings, including me + siblings: function() { + return this.mother().children(); + }, + + // send given element one step forwards + forward: function() { + var i = this.siblings().indexOf(this); + this.mother().remove(this).add(this, i + 1); + + return this; + }, + + // send given element one step backwards + backward: function() { + var i, p = this.mother(); + + p.levelDefs(); + + i = this.siblings().indexOf(this); + + if (i > 1) + p.remove(this).add(this, i - 1); + + return this; + }, + + // send given element all the way to the front + front: function() { + this.mother().remove(this).add(this); + + return this; + }, + + // send given element all the way to the back + back: function() { + var i, p = this.mother(); + + p.levelDefs(); + + i = this.siblings().indexOf(this); + + if (i > 1) + p.remove(this).add(this, 0); + + return this; + } + +}); \ No newline at end of file diff --git a/src/circle.js b/src/circle.js index 9576568..1fe95e5 100644 --- a/src/circle.js +++ b/src/circle.js @@ -18,20 +18,20 @@ SVG.extend(SVG.Circle, { return this; }, - // custom size function - size: function(w, h) { + // custom size function (no height value here!) + size: function(w) { this.attr('r', w / 2); this.center(); return this; }, - // private: center - center: function(cx, cy) { + // position element by its center + center: function(x, y) { var r = this.attrs.r || 0; - this.attr('cx', cx || ((this.attrs.x || 0) + r)); - this.attr('cy', cy || ((this.attrs.y || 0) + r)); + this.attr('cx', x || ((this.attrs.x || 0) + r)); + this.attr('cy', y || ((this.attrs.y || 0) + r)); } }); \ No newline at end of file diff --git a/src/clip.js b/src/clip.js index 189b62c..2266adb 100644 --- a/src/clip.js +++ b/src/clip.js @@ -13,3 +13,21 @@ SVG.Clip.prototype = new SVG.Element(); // include the container object SVG.extend(SVG.Clip, SVG.Container); + +// add clipping functionality to element +SVG.extend(SVG.Element, { + + // clip element using another element + clip: function(block) { + var p = this.mother().defs().clipPath(); + block(p); + + return this.clipTo(p); + }, + + // distribute clipping path to svg element + clipTo: function(p) { + return this.attr('clip-path', 'url(#' + p.id + ')'); + } + +}); diff --git a/src/container.js b/src/container.js index 9d8b5af..46e8200 100644 --- a/src/container.js +++ b/src/container.js @@ -1,53 +1,23 @@ SVG.Container = { - add: function(e) { - return this.addAt(e); - }, - - addAt: function(e, i) { - if (!this.contains(e)) { + add: function(e, i) { + if (!this.has(e)) { i = i == null ? this.children().length : i; this.children().splice(i, 0, e); - this.node.insertBefore(e.node, this.node.childNodes[i + 1]); + this.node.insertBefore(e.node, this.node.childNodes[i]); e.parent = this; } return this; }, - contains: function(e) { + has: function(e) { return Array.prototype.indexOf.call(this.children(), e) >= 0; }, children: function() { - return this._children || []; - }, - - sendBack: function(e) { - var i = this.children().indexOf(e); - if (i !== -1) - return this.remove(e).addAt(e, i - 1); - }, - - bringForward: function(e) { - var i = this.children().indexOf(e); - if (i !== -1) - return this.remove(e).addAt(e, i + 1); - }, - - bringToFront: function(e) { - if (this.contains(e)) - this.remove(e).add(e); - - return this; - }, - - sendToBottom: function(e) { - if (this.contains(e)) - this.remove(e).addAt(e, 0); - - return this; + return this._children || (this._children = []); }, remove: function(e) { @@ -68,12 +38,20 @@ SVG.Container = { defs: function() { if (this._defs == null) { this._defs = new SVG.Defs(); - this.add(this._defs); + this.add(this._defs, 0); } return this._defs; }, + levelDefs: function() { + var d = this.defs(); + + this.remove(d).add(d, 0); + + return this; + }, + group: function() { var e = new SVG.G(); this.add(e); diff --git a/src/doc.js b/src/doc.js index e361e29..e307d09 100644 --- a/src/doc.js +++ b/src/doc.js @@ -6,6 +6,8 @@ SVG.Doc = function Doc(e) { this.attr('version', '1.1'); this.attr('xlink', SVG.xlink, SVG.ns); + this.defs(); + if (typeof e == 'string') e = document.getElementById(e); diff --git a/src/element.js b/src/element.js index 39bca21..396d67e 100644 --- a/src/element.js +++ b/src/element.js @@ -9,16 +9,20 @@ SVG.extend(SVG.Element, { // move element to given x and y values move: function(x, y) { - this.attr('x', x); - this.attr('y', y); + this.attr({ + x: x, + y: y + }); return this; }, // set element size to given width and height size: function(w, h) { - this.attr('width', w); - this.attr('height', h); + this.attr({ + width: w, + height: h + }); return this; }, @@ -27,14 +31,14 @@ SVG.extend(SVG.Element, { remove: function() { return this.parent != null ? this.parent.remove(this) : void 0; }, - + // get parent document parentDoc: function() { return this._parent(SVG.Doc); }, // get parent svg wrapper - parentSVG: function() { + mother: function() { return this.parentDoc(); }, @@ -71,6 +75,7 @@ SVG.extend(SVG.Element, { for (var i = 0, s = l.length; i < s; i++) if (!r.test(l[i])) n.push(l[i]); + } else n = l; @@ -91,19 +96,6 @@ SVG.extend(SVG.Element, { return b; }, - // clip element using another element - clip: function(block) { - var p = this.parentSVG().defs().clipPath(); - block(p); - - return this.clipTo(p); - }, - - // distribute clipping path to svg element - clipTo: function(p) { - return this.attr('clip-path', 'url(#' + p.id + ')'); - }, - // private: find svg parent _parent: function(pt) { var e = this; diff --git a/src/ellipse.js b/src/ellipse.js index f1638ee..adc1fd6 100644 --- a/src/ellipse.js +++ b/src/ellipse.js @@ -26,10 +26,11 @@ SVG.extend(SVG.Ellipse, { return this; }, - - center: function(cx, cy) { - this.attr('cx', cx || ((this.attrs.x || 0) + (this.attrs.rx || 0))); - this.attr('cy', cy || ((this.attrs.y || 0) + (this.attrs.ry || 0))); + + // position element by its center + center: function(x, y) { + this.attr('cx', x || ((this.attrs.x || 0) + (this.attrs.rx || 0))); + this.attr('cy', y || ((this.attrs.y || 0) + (this.attrs.ry || 0))); } }); -- 2.39.5