From ae878fd63077d4c95f2de9053a6f0951b55239eb Mon Sep 17 00:00:00 2001 From: wout Date: Wed, 20 Feb 2013 19:10:03 +0100 Subject: Created separate classes for SVG.ViewBox anSVG.BBox --- README.md | 18 +- Rakefile | 2 +- dist/svg.js | 1053 ++++++++++++++++++++++++++++-------------------------- dist/svg.min.js | 4 +- src/arrange.js | 58 +-- src/bbox.js | 18 + src/container.js | 193 +++++----- src/defs.js | 8 +- src/doc.js | 42 +-- src/element.js | 137 ++++--- src/ellipse.js | 22 +- src/event.js | 36 +- src/fx.js | 130 +++---- src/gradient.js | 56 +-- src/group.js | 12 +- src/image.js | 14 +- src/line.js | 28 +- src/mask.js | 16 +- src/nested.js | 10 +- src/path.js | 12 +- src/pattern.js | 20 +- src/poly.js | 26 +- src/rect.js | 8 +- src/shape.js | 8 +- src/sugar.js | 48 +-- src/svg.js | 18 +- src/text.js | 58 +-- src/viewbox.js | 35 ++ src/wrap.js | 46 +-- 29 files changed, 1123 insertions(+), 1013 deletions(-) create mode 100644 src/bbox.js create mode 100644 src/viewbox.js diff --git a/README.md b/README.md index 5c9a8a9..4aec740 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,9 @@ This will generate the following output: ``` + By default the svg canvas follows the dimensions of its parent, in this case `#paper`: + ```javascript var draw = svg('paper').size('100%', '100%'); ``` @@ -46,6 +48,20 @@ if (SVG.supported) { } ``` +### ViewBox + +The `viewBox` attribute of an `` element can be managed with the `viewbox()` method. When supplied with arguments it will act as a setter: + +```javascript +draw.viewbox(0, 0, 297, 210); +``` + +Without any attributes a an instance of `SVG.ViewBox` will be returned: + +```javascript +var box = draw.viewbox(); +``` + ## Elements @@ -274,7 +290,7 @@ draw.clear(); ```javascript path.bbox(); ``` -This will return an object with the following values: +This will return an instance of `SVG.BBox` containing the following values: ```javascript { height: 20, width: 20, y: 20, x: 10, cx: 30, cy: 20 } diff --git a/Rakefile b/Rakefile index 183b67b..0f2db64 100644 --- a/Rakefile +++ b/Rakefile @@ -1,7 +1,7 @@ SVGJS_VERSION = '0.5' # all available modules in the correct loading order -MODULES = %w[ svg element container fx event group arrange defs mask pattern gradient doc shape wrap rect ellipse line poly path image text nested sugar ] +MODULES = %w[ svg viewbox bbox element container fx event group arrange defs mask pattern gradient doc shape wrap rect ellipse line poly path image text nested sugar ] # how many bytes in a "kilobyte" KILO = 1024 diff --git a/dist/svg.js b/dist/svg.js index 0ee1a1a..dda9178 100644 --- a/dist/svg.js +++ b/dist/svg.js @@ -1,10 +1,10 @@ -/* svg.js v0.5-6-g3ebe05f - svg element container fx event group arrange defs mask pattern gradient doc shape wrap rect ellipse line poly path image text nested sugar - svgjs.com/license */ +/* svg.js v0.5-8-g5020240 - svg viewbox bbox element container fx event group arrange defs mask pattern gradient doc shape wrap rect ellipse line poly path image text nested sugar - svgjs.com/license */ (function() { this.svg = function(element) { if (SVG.supported) - return new SVG.Doc(element); - }; + return new SVG.Doc(element) + } // The main wrapping element this.SVG = { @@ -17,28 +17,81 @@ // Method for element creation , create: function(element) { - return document.createElementNS(this.ns, element); + return document.createElementNS(this.ns, element) } // Method for extending objects , extend: function(object, module) { for (var key in module) - object.prototype[key] = module[key]; + object.prototype[key] = module[key] } - }; + } // svg support test SVG.supported = (function() { return !! document.createElementNS && - !! document.createElementNS(SVG.ns,'svg').createSVGRect; - })(); + !! document.createElementNS(SVG.ns,'svg').createSVGRect + })() if (!SVG.supported) return false; - SVG.Element = function Element(node) { + SVG.ViewBox = function(element) { + var width, height + , box = element.bbox() + , view = (element.attr('viewBox') || '').match(/[\d\.]+/g) + + /* clone attributes */ + this.x = box.x + this.y = box.y + this.width = box.width + this.height = box.height + + if (view) { + /* get width and height from viewbox */ + width = parseFloat(view[2]) + height = parseFloat(view[3]) + + /* calculate real pixel dimensions on parent SVG.Doc element */ + if (element instanceof SVG.Doc) { + this.x = 0 + this.y = 0 + this.width = element.node.offsetWidth + this.height = element.node.offsetHeight + } + + /* calculate zoom accoring to viewbox */ + this.scale = (this.width / this.height > width / height) ? + this.height / height : + this.width / width + + } else { + this.scale = 1 + } + + } + + SVG.BBox = function(element) { + /* actual, native bounding box */ + var box = element.node.getBBox() + + /* include translations on x an y */ + this.x = box.x + element.trans.x + this.y = box.y + element.trans.y + + /* add the center */ + this.cx = box.x + element.trans.x + box.width / 2 + this.cy = box.y + element.trans.y + box.height / 2 + + /* plain width and height */ + this.width = box.width + this.height = box.height + + } + + SVG.Element = function(node) { /* keep reference to the element node */ if (this.node = node) - this.type = node.nodeName; + this.type = node.nodeName /* initialize attribute store with defaults */ this.attrs = { @@ -57,7 +110,7 @@ r: 0, rx: 0, ry: 0 - }; + } /* initialize transformation store with defaults */ this.trans = { @@ -68,9 +121,9 @@ rotation: 0, skewX: 0, skewY: 0 - }; + } - }; + } // SVG.extend(SVG.Element, { @@ -79,41 +132,41 @@ return this.attr({ x: x, y: y - }); + }) }, // Move element by its center center: function(x, y) { - var box = this.bbox(); + var box = this.bbox() - return this.move(x - box.width / 2, y - box.height / 2); + return this.move(x - box.width / 2, y - box.height / 2) }, // Set element size to given width and height size: function(width, height) { return this.attr({ width: width, height: height - }); + }) }, // Clone element clone: function() { - var clone; + var clone /* if this is a wrapped shape */ if (this instanceof SVG.Wrap) { /* build new wrapped shape */ - clone = this.parent[this.child.node.nodeName](); - clone.attrs = this.attrs; + clone = this.parent[this.child.node.nodeName]() + clone.attrs = this.attrs /* copy child attributes and transformations */ - clone.child.trans = this.child.trans; - clone.child.attr(this.child.attrs).transform({}); + clone.child.trans = this.child.trans + clone.child.attr(this.child.attrs).transform({}) /* re-plot shape */ if (clone.plot) - clone.plot(this.child.attrs[this.child instanceof SVG.Path ? 'd' : 'points']); + clone.plot(this.child.attrs[this.child instanceof SVG.Path ? 'd' : 'points']) } else { - var name = this.node.nodeName; + var name = this.node.nodeName /* invoke shape method with shape-specific arguments */ clone = name == 'rect' ? @@ -126,35 +179,35 @@ this.parent[name](this.content) : name == 'g' ? this.parent.group() : - this.parent[name](); + this.parent[name]() - clone.attr(this.attrs); + clone.attr(this.attrs) } /* copy transformations */ - clone.trans = this.trans; + clone.trans = this.trans /* apply attributes and translations */ - return clone.transform({}); + return clone.transform({}) }, // Remove element remove: function() { - return this.parent != null ? this.parent.remove(this) : void 0; + return this.parent != null ? this.parent.remove(this) : void 0 }, // Get parent document doc: function() { - return this._parent(SVG.Doc); + return this._parent(SVG.Doc) }, // Get parent nested document nested: function() { - return this._parent(SVG.Nested); + return this._parent(SVG.Nested) }, // Set svg element attribute attr: function(a, v, n) { if (arguments.length < 2) { /* apply every attribute individually if an object is passed */ if (typeof a == 'object') - for (v in a) this.attr(v, a[v]); + for (v in a) this.attr(v, a[v]) /* act as a getter for style attributes */ else if (this._isStyle(a)) @@ -162,26 +215,26 @@ this.content : a == 'leading' ? this[a] : - this.style[a]; + this.style[a] /* act as a getter if the first and only argument is not an object */ else - return this.attrs[a]; + return this.attrs[a] } else { /* store value */ - this.attrs[a] = v; + this.attrs[a] = v /* treat x differently on text elements */ if (a == 'x' && this._isText()) for (var i = this.lines.length - 1; i >= 0; i--) - this.lines[i].attr(a, v); + this.lines[i].attr(a, v) /* set the actual attribute */ else n != null ? this.node.setAttributeNS(n, a, v) : - this.node.setAttribute(a, v); + this.node.setAttribute(a, v) /* if the passed argument belongs to the style as well, add it there */ if (this._isStyle(a)) { @@ -189,317 +242,311 @@ this.text(v) : a == 'leading' ? this[a] = v : - this.style[a] = v; + this.style[a] = v - this.text(this.content); + this.text(this.content) } } - return this; + return this }, // Manage transformations transform: function(o) { /* act as a getter if the first argument is a string */ if (typeof o === 'string') - return this.trans[o]; + return this.trans[o] /* ... otherwise continue as a setter */ - var key, transform = []; + var key, transform = [] /* merge values */ for (key in o) if (o[key] != null) - this.trans[key] = o[key]; + this.trans[key] = o[key] /* alias current transformations */ - o = this.trans; + o = this.trans /* add rotation */ if (o.rotation != 0) { - var box = this.bbox(); - transform.push('rotate(' + o.rotation + ',' + (o.cx != null ? o.cx : box.cx) + ',' + (o.cy != null ? o.cy : box.cy) + ')'); + var box = this.bbox() + transform.push('rotate(' + o.rotation + ',' + (o.cx != null ? o.cx : box.cx) + ',' + (o.cy != null ? o.cy : box.cy) + ')') } /* add scale */ - transform.push('scale(' + o.scaleX + ',' + o.scaleY + ')'); + transform.push('scale(' + o.scaleX + ',' + o.scaleY + ')') /* add skew on x axis */ if (o.skewX != 0) - transform.push('skewX(' + o.skewX + ')'); + transform.push('skewX(' + o.skewX + ')') /* add skew on y axis */ if (o.skewY != 0) transform.push('skewY(' + o.skewY + ')') /* add translation */ - transform.push('translate(' + o.x + ',' + o.y + ')'); + transform.push('translate(' + o.x + ',' + o.y + ')') /* add only te required transformations */ - return this.attr('transform', transform.join(' ')); + return this.attr('transform', transform.join(' ')) }, // Store data values on svg nodes data: function(a, v, r) { if (arguments.length < 2) { try { - return JSON.parse(this.attr('data-' + a)); + return JSON.parse(this.attr('data-' + a)) } catch(e) { - return this.attr('data-' + a); - }; + return this.attr('data-' + a) + } } else { v === null ? this.node.removeAttribute('data-' + a) : - this.attr('data-' + a, r === true ? v : JSON.stringify(v)); + this.attr('data-' + a, r === true ? v : JSON.stringify(v)) } - return this; + return this }, // Get bounding box bbox: function() { - /* actual, native bounding box */ - var box = this.node.getBBox(); - - return { - /* include translations on x an y */ - x: box.x + this.trans.x, - y: box.y + this.trans.y, - - /* add the center */ - cx: box.x + this.trans.x + box.width / 2, - cy: box.y + this.trans.y + box.height / 2, - - /* plain width and height */ - width: box.width, - height: box.height - }; + return new SVG.BBox(this) }, // Checks whether the given point inside the bounding box of the element inside: function(x, y) { - var box = this.bbox(); + var box = this.bbox() return x > box.x && y > box.y && x < box.x + box.width && - y < box.y + box.height; + y < box.y + box.height }, // Show element show: function() { - this.node.style.display = ''; + this.node.style.display = '' - return this; + return this }, // Hide element hide: function() { - this.node.style.display = 'none'; + this.node.style.display = 'none' - return this; + return this }, // Is element visible? visible: function() { - return this.node.style.display != 'none'; + return this.node.style.display != 'none' }, // Private: find svg parent by instance _parent: function(parent) { - var element = this; + var element = this while (element != null && !(element instanceof parent)) - element = element.parent; + element = element.parent - return element; + return element }, // Private: tester method for style detection _isStyle: function(attr) { - return typeof attr == 'string' && this._isText() ? (/^font|text|leading/).test(attr) : false; + return typeof attr == 'string' && this._isText() ? (/^font|text|leading/).test(attr) : false }, // Private: element type tester _isText: function() { - return this instanceof SVG.Text; + return this instanceof SVG.Text } - }); + }) - SVG.Container = function Container(element) { - this.constructor.call(this, element); - }; + SVG.Container = function(element) { + this.constructor.call(this, element) + } // Inherit from SVG.Element - SVG.Container.prototype = new SVG.Element(); + SVG.Container.prototype = new SVG.Element // SVG.extend(SVG.Container, { // Add given element at a position add: function(element, index) { if (!this.has(element)) { - index = index == null ? this.children().length : index; - this.children().splice(index, 0, element); - this.node.insertBefore(element.node, this.node.childNodes[index] || null); - element.parent = this; + index = index == null ? this.children().length : index + this.children().splice(index, 0, element) + this.node.insertBefore(element.node, this.node.childNodes[index] || null) + element.parent = this } - return this; - }, + return this + } // Basically does the same as `add()` but returns the added element - put: function(element, index) { - this.add(element, index); - return element; - }, + , put: function(element, index) { + this.add(element, index) + return element + } // Checks if the given element is a child - has: function(element) { - return this.children().indexOf(element) >= 0; - }, + , has: function(element) { + return this.children().indexOf(element) >= 0 + } // Returns all child elements - children: function() { - return this._children || (this._children = []); - }, + , children: function() { + return this._children || (this._children = []) + } // Iterates over all children and invokes a given block - each: function(block) { + , each: function(block) { var index, - children = this.children(); + children = this.children() for (index = 0, length = children.length; index < length; index++) if (children[index] instanceof SVG.Shape) - block.apply(children[index], [index, children]); + block.apply(children[index], [index, children]) - return this; - }, + return this + } // Remove a given child element - remove: function(element) { - return this.removeAt(this.children().indexOf(element)); - }, + , remove: function(element) { + return this.removeAt(this.children().indexOf(element)) + } // Remove a child element at a given position - removeAt: function(index) { + , removeAt: function(index) { if (0 <= index && index < this.children().length) { - var element = this.children()[index]; - this.children().splice(index, 1); - this.node.removeChild(element.node); - element.parent = null; + var element = this.children()[index] + this.children().splice(index, 1) + this.node.removeChild(element.node) + element.parent = null } - return this; - }, + return this + } // Returns defs element - defs: function() { - return this._defs || (this._defs = this.put(new SVG.Defs(), 0)); - }, + , defs: function() { + return this._defs || (this._defs = this.put(new SVG.Defs(), 0)) + } // Re-level defs to first positon in element stack - level: function() { - return this.remove(this.defs()).put(this.defs(), 0); - }, + , level: function() { + return this.remove(this.defs()).put(this.defs(), 0) + } // Create a group element - group: function() { - return this.put(new SVG.G()); - }, + , group: function() { + return this.put(new SVG.G()) + } // Create a rect element - rect: function(width, height) { - return this.put(new SVG.Rect().size(width, height)); - }, + , rect: function(width, height) { + return this.put(new SVG.Rect().size(width, height)) + } // Create circle element, based on ellipse - circle: function(diameter) { - return this.ellipse(diameter); - }, + , circle: function(diameter) { + return this.ellipse(diameter) + } // Create an ellipse - ellipse: function(width, height) { - return this.put(new SVG.Ellipse().size(width, height)); - }, + , ellipse: function(width, height) { + return this.put(new SVG.Ellipse().size(width, height)) + } // Create a wrapped polyline element - polyline: function(points) { - return this.put(new SVG.Wrap(new SVG.Polyline())).plot(points); - }, + , polyline: function(points) { + return this.put(new SVG.Wrap(new SVG.Polyline())).plot(points) + } // Create a wrapped polygon element - polygon: function(points) { - return this.put(new SVG.Wrap(new SVG.Polygon())).plot(points); - }, + , polygon: function(points) { + return this.put(new SVG.Wrap(new SVG.Polygon())).plot(points) + } // Create a wrapped path element - path: function(data) { - return this.put(new SVG.Wrap(new SVG.Path())).plot(data); - }, + , path: function(data) { + return this.put(new SVG.Wrap(new SVG.Path())).plot(data) + } // Create image element, load image and set its size - image: function(source, width, height) { - width = width != null ? width : 100; - return this.put(new SVG.Image().load(source).size(width, height != null ? height : width)); - }, + , image: function(source, width, height) { + width = width != null ? width : 100 + return this.put(new SVG.Image().load(source).size(width, height != null ? height : width)) + } // Create text element - text: function(text) { - return this.put(new SVG.Text().text(text)); - }, + , text: function(text) { + return this.put(new SVG.Text().text(text)) + } // Create nested svg document - nested: function() { - return this.put(new SVG.Nested()); - }, + , nested: function() { + return this.put(new SVG.Nested()) + } // Create gradient element in defs - gradient: function(type, block) { - return this.defs().gradient(type, block); - }, + , gradient: function(type, block) { + return this.defs().gradient(type, block) + } // Create pattern element in defs - pattern: function(width, height, block) { - return this.defs().pattern(width, height, block); - }, + , pattern: function(width, height, block) { + return this.defs().pattern(width, height, block) + } // Create masking element - mask: function() { - return this.defs().put(new SVG.Mask()); - }, + , mask: function() { + return this.defs().put(new SVG.Mask()) + } // Get first child, skipping the defs node - first: function() { - return this.children()[0] instanceof SVG.Defs ? this.children()[1] : this.children()[0]; - }, + , first: function() { + return this.children()[0] instanceof SVG.Defs ? this.children()[1] : this.children()[0] + } // Get the last child - last: function() { - return this.children()[this.children().length - 1]; - }, + , last: function() { + return this.children()[this.children().length - 1] + } + // Get the viewBox and calculate the zoom value + , viewbox: function() { + /* act as a getter if there are no arguments */ + if (arguments.length == 0) + return new SVG.ViewBox(this) + + /* otherwise act as a setter */ + return this.attr('viewBox', Array.prototype.slice.call(arguments).join(' ')) + } // Remove all elements in this container - clear: function() { - this._children = []; + , clear: function() { + this._children = [] while (this.node.hasChildNodes()) - this.node.removeChild(this.node.lastChild); + this.node.removeChild(this.node.lastChild) - return this; + return this } - }); + }) - SVG.FX = function FX(element) { + SVG.FX = function(element) { /* store target element */ - this.target = element; - }; + this.target = element + } // SVG.extend(SVG.FX, { // Add animation parameters and start animation animate: function(duration, ease) { /* ensure default duration and easing */ - duration = duration == null ? 1000 : duration; - ease = ease || '<>'; + duration = duration == null ? 1000 : duration + ease = ease || '<>' var akeys, tkeys, tvalues, element = this.target, fx = this, start = (new Date).getTime(), - finish = start + duration; + finish = start + duration /* start animation */ this.interval = setInterval(function(){ // This code was borrowed from the emile.js micro framework by Thomas Fuchs, aka MadRobby. var index, time = (new Date).getTime(), - pos = time > finish ? 1 : (time - start) / duration; + pos = time > finish ? 1 : (time - start) / duration /* collect attribute keys */ if (akeys == null) { - akeys = []; + akeys = [] for (var key in fx.attrs) - akeys.push(key); - }; + akeys.push(key) + } /* collect transformation keys */ if (tkeys == null) { - tkeys = []; + tkeys = [] for (var key in fx.trans) - tkeys.push(key); + tkeys.push(key) - tvalues = {}; - }; + tvalues = {} + } /* apply easing */ pos = ease == '<>' ? @@ -512,110 +559,110 @@ pos : typeof ease == 'function' ? ease(pos) : - pos; + pos /* run all position properties */ if (fx._move) - element.move(fx._at(fx._move.x, pos), fx._at(fx._move.y, pos)); + element.move(fx._at(fx._move.x, pos), fx._at(fx._move.y, pos)) else if (fx._center) - element.move(fx._at(fx._center.x, pos), fx._at(fx._center.y, pos)); + element.move(fx._at(fx._center.x, pos), fx._at(fx._center.y, pos)) /* run all size properties */ if (fx._size) - element.size(fx._at(fx._size.width, pos), fx._at(fx._size.height, pos)); + element.size(fx._at(fx._size.width, pos), fx._at(fx._size.height, pos)) /* animate attributes */ for (index = akeys.length - 1; index >= 0; index--) - element.attr(akeys[index], fx._at(fx.attrs[akeys[index]], pos)); + element.attr(akeys[index], fx._at(fx.attrs[akeys[index]], pos)) /* animate transformations */ if (tkeys.length > 0) { for (index = tkeys.length - 1; index >= 0; index--) - tvalues[tkeys[index]] = fx._at(fx.trans[tkeys[index]], pos); + tvalues[tkeys[index]] = fx._at(fx.trans[tkeys[index]], pos) - element.transform(tvalues); + element.transform(tvalues) } /* finish off animation */ if (time > finish) { - clearInterval(fx.interval); - fx._after ? fx._after.apply(element, [fx]) : fx.stop(); + clearInterval(fx.interval) + fx._after ? fx._after.apply(element, [fx]) : fx.stop() } - }, duration > 10 ? 10 : duration); + }, duration > 10 ? 10 : duration) - return this; + return this }, // Add animatable attributes attr: function(a, v, n) { if (typeof a == 'object') for (var key in a) - this.attr(key, a[key]); + this.attr(key, a[key]) else - this.attrs[a] = { from: this.target.attr(a), to: v }; + this.attrs[a] = { from: this.target.attr(a), to: v } return this; }, // Add animatable transformations transform: function(o) { for (var key in o) - this.trans[key] = { from: this.target.trans[key], to: o[key] }; + this.trans[key] = { from: this.target.trans[key], to: o[key] } - return this; + return this }, // Add animatable move move: function(x, y) { - var box = this.target.bbox(); + var box = this.target.bbox() this._move = { x: { from: box.x, to: x }, y: { from: box.y, to: y } - }; + } - return this; + return this }, // Add animatable size size: function(width, height) { - var box = this.target.bbox(); + var box = this.target.bbox() this._size = { width: { from: box.width, to: width }, height: { from: box.height, to: height } - }; + } - return this; + return this }, // Add animatable center center: function(x, y) { - var box = this.target.bbox(); + var box = this.target.bbox() this._move = { x: { from: box.cx, to: x }, y: { from: box.cy, to: y } - }; + } - return this; + return this }, // Callback after animation after: function(after) { - this._after = after; + this._after = after - return this; + return this }, // Stop running animation stop: function() { /* stop current animation */ - clearInterval(this.interval); + clearInterval(this.interval) /* reset storage for properties that need animation */ - this.attrs = {}; - this.trans = {}; - this._move = null; - this._size = null; - this._after = null; + this.attrs = {} + this.trans = {} + this._move = null + this._size = null + this._after = null - return this; + return this }, // Private: at position according to from and to _at: function(o, pos) { @@ -628,45 +675,45 @@ this._color(o, pos) : /* for all other values wait until pos has reached 1 to return the final value */ - pos < 1 ? o.from : o.to; + pos < 1 ? o.from : o.to }, // Private: tween color _color: function(o, pos) { - var from, to; + var from, to /* convert FROM hex to rgb */ - from = this._h2r(o.from || '#000'); + from = this._h2r(o.from || '#000') /* convert TO hex to rgb */ - to = this._h2r(o.to); + to = this._h2r(o.to) /* tween color and return hex */ return this._r2h({ r: ~~(from.r + (to.r - from.r) * pos), g: ~~(from.g + (to.g - from.g) * pos), b: ~~(from.b + (to.b - from.b) * pos) - }); + }) }, // Private: convert hex to rgb object _h2r: function(hex) { /* parse full hex */ - var match = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(this._fh(hex)); + var match = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(this._fh(hex)) /* if the hex is successfully parsed, return it in rgb, otherwise return black */ return match ? { r: parseInt(match[1], 16), g: parseInt(match[2], 16), b: parseInt(match[3], 16) - } : { r: 0, g: 0, b: 0 }; + } : { r: 0, g: 0, b: 0 } }, // Private: convert rgb object to hex string _r2h: function(rgb) { - return '#' + this._c2h(rgb.r) + this._c2h(rgb.g) + this._c2h(rgb.b); + return '#' + this._c2h(rgb.r) + this._c2h(rgb.g) + this._c2h(rgb.b) }, // Private: convert component to hex _c2h: function(c) { - var hex = c.toString(16); - return hex.length == 1 ? '0' + hex : hex; + var hex = c.toString(16) + return hex.length == 1 ? '0' + hex : hex }, // Private: force potential 3-based hex to 6-based _fh: function(hex) { @@ -675,32 +722,32 @@ hex.substring(1, 2), hex.substring(1, 2), hex.substring(2, 3), hex.substring(2, 3), hex.substring(3, 4), hex.substring(3, 4) - ].join('') : hex; + ].join('') : hex } - }); + }) // SVG.extend(SVG.Element, { // Get fx module or create a new one, then animate with given duration and ease animate: function(duration, ease) { - return (this.fx || (this.fx = new SVG.FX(this))).stop().animate(duration, ease); + return (this.fx || (this.fx = new SVG.FX(this))).stop().animate(duration, ease) }, // Stop current animation; this is an alias to the fx instance stop: function() { - this.fx.stop(); + this.fx.stop() - return this; + return this } - }); + }) // Usage: // rect.animate(1500, '>').move(200, 300).after(function() { - // this.fill({ color: '#f06' }); - // }); + // this.fill({ color: '#f06' }) + // }) - [ 'click', + ;[ 'click', 'dblclick', 'mousedown', 'mouseup', @@ -716,172 +763,172 @@ /* add event to SVG.Element */ SVG.Element.prototype[event] = function(f) { - var self = this; + var self = this /* bind event to element rather than element node */ this.node['on' + event] = typeof f == 'function' ? function() { return f.apply(self, arguments); } - : null; + : null - return this; - }; + return this + } - }); + }) // Add event binder in the SVG namespace SVG.on = function(node, event, listener) { if (node.addEventListener) - node.addEventListener(event, listener, false); + node.addEventListener(event, listener, false) else - node.attachEvent('on' + event, listener); - }; + node.attachEvent('on' + event, listener) + } // Add event unbinder in the SVG namespace SVG.off = function(node, event, listener) { if (node.removeEventListener) - node.removeEventListener(event, listener, false); + node.removeEventListener(event, listener, false) else - node.detachEvent('on' + event, listener); - }; + node.detachEvent('on' + event, listener) + } // SVG.extend(SVG.Element, { // Bind given event to listener on: function(event, listener) { - SVG.on(this.node, event, listener); + SVG.on(this.node, event, listener) - return this; + return this }, // Unbind event from listener off: function(event, listener) { - SVG.off(this.node, event, listener); + SVG.off(this.node, event, listener) - return this; + return this } }); - SVG.G = function G() { - this.constructor.call(this, SVG.create('g')); - }; + SVG.G = function() { + this.constructor.call(this, SVG.create('g')) + } // Inherit from SVG.Container - SVG.G.prototype = new SVG.Container(); + SVG.G.prototype = new SVG.Container SVG.extend(SVG.G, { // Get defs defs: function() { - return this.doc().defs(); + return this.doc().defs() } - }); + }) SVG.extend(SVG.Element, { // Get all siblings, including myself siblings: function() { - return this.parent.children(); - }, + return this.parent.children() + } // Get the curent position siblings - position: function() { - return this.siblings().indexOf(this); - }, + , position: function() { + return this.siblings().indexOf(this) + } // Get the next element (will return null if there is none) - next: function() { - return this.siblings()[this.position() + 1]; - }, + , next: function() { + return this.siblings()[this.position() + 1] + } // Get the next element (will return null if there is none) - previous: function() { - return this.siblings()[this.position() - 1]; - }, + , previous: function() { + return this.siblings()[this.position() - 1] + } // Send given element one step forward - forward: function() { - return this.parent.remove(this).put(this, this.position() + 1); - }, + , forward: function() { + return this.parent.remove(this).put(this, this.position() + 1) + } // Send given element one step backward - backward: function() { - var i; + , backward: function() { + var i - this.parent.level(); + this.parent.level() - i = this.position(); + i = this.position() if (i > 1) - this.parent.remove(this).add(this, i - 1); + this.parent.remove(this).add(this, i - 1) - return this; - }, + return this + } // Send given element all the way to the front - front: function() { - return this.parent.remove(this).put(this); - }, + , front: function() { + return this.parent.remove(this).put(this) + } // Send given element all the way to the back - back: function() { - this.parent.level(); + , back: function() { + this.parent.level() if (this.position() > 1) - this.parent.remove(this).add(this, 0); + this.parent.remove(this).add(this, 0) - return this; + return this } - }); + }) - SVG.Defs = function Defs() { - this.constructor.call(this, SVG.create('defs')); - }; + SVG.Defs = function() { + this.constructor.call(this, SVG.create('defs')) + } // Inherits from SVG.Container - SVG.Defs.prototype = new SVG.Container(); + SVG.Defs.prototype = new SVG.Container - SVG.Mask = function Mask() { - this.constructor.call(this, SVG.create('mask')); + SVG.Mask = function() { + this.constructor.call(this, SVG.create('mask')) /* set unique id */ - this.attr('id', (this.id = 'svgjs_element_' + (SVG.did++))); - }; + this.attr('id', (this.id = 'svgjs_element_' + (SVG.did++))) + } // Inherit from SVG.Container - SVG.Mask.prototype = new SVG.Container(); + SVG.Mask.prototype = new SVG.Container SVG.extend(SVG.Element, { // Distribute mask to svg element maskWith: function(element) { /* use given mask or create a new one */ - this.mask = element instanceof SVG.Mask ? element : this.parent.mask().add(element); + this.mask = element instanceof SVG.Mask ? element : this.parent.mask().add(element) - return this.attr('mask', 'url(#' + this.mask.id + ')'); + return this.attr('mask', 'url(#' + this.mask.id + ')') } - }); + }) - SVG.Pattern = function Pattern(type) { - this.constructor.call(this, SVG.create('pattern')); + SVG.Pattern = function(type) { + this.constructor.call(this, SVG.create('pattern')) /* set unique id */ - this.attr('id', (this.id = 'svgjs_element_' + (SVG.did++))); - }; + this.attr('id', (this.id = 'svgjs_element_' + (SVG.did++))) + } // Inherit from SVG.Container - SVG.Pattern.prototype = new SVG.Container(); + SVG.Pattern.prototype = new SVG.Container // SVG.extend(SVG.Pattern, { // Return the fill id fill: function() { - return 'url(#' + this.id + ')'; + return 'url(#' + this.id + ')' } - }); + }) // SVG.extend(SVG.Defs, { /* define gradient */ pattern: function(width, height, block) { - var element = this.put(new SVG.Pattern()); + var element = this.put(new SVG.Pattern()) /* invoke passed block */ - block(element); + block(element) return element.attr({ x: 0, @@ -889,23 +936,23 @@ width: width, height: height, patternUnits: 'userSpaceOnUse' - }); + }) } }); - SVG.Gradient = function Gradient(type) { - this.constructor.call(this, SVG.create(type + 'Gradient')); + SVG.Gradient = function(type) { + this.constructor.call(this, SVG.create(type + 'Gradient')) /* set unique id */ - this.attr('id', (this.id = 'svgjs_element_' + (SVG.did++))); + this.attr('id', (this.id = 'svgjs_element_' + (SVG.did++))) /* store type */ - this.type = type; - }; + this.type = type + } // Inherit from SVG.Container - SVG.Gradient.prototype = new SVG.Container(); + SVG.Gradient.prototype = new SVG.Container // SVG.extend(SVG.Gradient, { @@ -913,67 +960,67 @@ from: function(x, y) { return this.type == 'radial' ? this.attr({ fx: x + '%', fy: y + '%' }) : - this.attr({ x1: x + '%', y1: y + '%' }); + this.attr({ x1: x + '%', y1: y + '%' }) }, // To position to: function(x, y) { return this.type == 'radial' ? this.attr({ cx: x + '%', cy: y + '%' }) : - this.attr({ x2: x + '%', y2: y + '%' }); + this.attr({ x2: x + '%', y2: y + '%' }) }, // Radius for radial gradient radius: function(radius) { return this.type == 'radial' ? this.attr({ r: radius + '%' }) : - this; + this }, // Add a color stop at: function(stop) { - return this.put(new SVG.Stop(stop)); + return this.put(new SVG.Stop(stop)) }, // Update gradient update: function(block) { /* remove all stops */ while (this.node.hasChildNodes()) - this.node.removeChild(this.node.lastChild); + this.node.removeChild(this.node.lastChild) /* invoke passed block */ - block(this); + block(this) - return this; + return this }, // Return the fill id fill: function() { - return 'url(#' + this.id + ')'; + return 'url(#' + this.id + ')' } - }); + }) // SVG.extend(SVG.Defs, { /* define gradient */ gradient: function(type, block) { - var element = this.put(new SVG.Gradient(type)); + var element = this.put(new SVG.Gradient(type)) /* invoke passed block */ - block(element); + block(element) - return element; + return element } - }); + }) - SVG.Stop = function Stop(stop) { - this.constructor.call(this, SVG.create('stop')); + SVG.Stop = function(stop) { + this.constructor.call(this, SVG.create('stop')) /* immediatelly build stop */ - this.update(stop); - }; + this.update(stop) + } // Inherit from SVG.Element - SVG.Stop.prototype = new SVG.Element(); + SVG.Stop.prototype = new SVG.Element() // SVG.extend(SVG.Stop, { @@ -982,44 +1029,44 @@ update: function(o) { var index, style = '', - attr = ['opacity', 'color']; + attr = ['opacity', 'color'] /* build style attribute */ for (index = attr.length - 1; index >= 0; index--) if (o[attr[index]] != null) - style += 'stop-' + attr[index] + ':' + o[attr[index]] + ';'; + style += 'stop-' + attr[index] + ':' + o[attr[index]] + ';' /* set attributes */ return this.attr({ offset: (o.offset != null ? o.offset : this.attrs.offset || 0) + '%', style: style - }); + }) } - }); + }) - SVG.Doc = function Doc(element) { - this.constructor.call(this, SVG.create('svg')); + SVG.Doc = function(element) { + this.constructor.call(this, SVG.create('svg')) /* ensure the presence of a html element */ this.parent = typeof element == 'string' ? document.getElementById(element) : - element; + element /* set svg element attributes and create the node */ this. attr({ xmlns: SVG.ns, version: '1.1', width: '100%', height: '100%' }). attr('xlink', SVG.xlink, SVG.ns). - defs(); + defs() /* ensure correct rendering for safari */ this.stage(); - }; + } // Inherits from SVG.Container - SVG.Doc.prototype = new SVG.Container(); + SVG.Doc.prototype = new SVG.Container // Hack for safari preventing text to be rendered in one line. // Basically it sets the position of the svg node to absolute @@ -1027,57 +1074,57 @@ SVG.Doc.prototype.stage = function() { var check, element = this, - wrapper = document.createElement('div'); + wrapper = document.createElement('div') /* set temp wrapper to position relative */ - wrapper.style.cssText = 'position:relative;height:100%;'; + wrapper.style.cssText = 'position:relative;height:100%;' /* put element into wrapper */ - element.parent.appendChild(wrapper); - wrapper.appendChild(element.node); + element.parent.appendChild(wrapper) + wrapper.appendChild(element.node) /* check for dom:ready */ check = function() { if (document.readyState === 'complete') { - element.attr('style', 'position:absolute;'); + element.attr('style', 'position:absolute;') setTimeout(function() { /* set position back to relative */ - element.attr('style', 'position:relative;'); + element.attr('style', 'position:relative;') /* remove temp wrapper */ - element.parent.removeChild(element.node.parentNode); - element.node.parentNode.removeChild(element.node); - element.parent.appendChild(element.node); + element.parent.removeChild(element.node.parentNode) + element.node.parentNode.removeChild(element.node) + element.parent.appendChild(element.node) - }, 5); + }, 5) } else { - setTimeout(check, 10); + setTimeout(check, 10) } - }; + } - check(); + check() - return this; - }; + return this + } - SVG.Shape = function Shape(element) { - this.constructor.call(this, element); - }; + SVG.Shape = function(element) { + this.constructor.call(this, element) + } // Inherit from SVG.Element - SVG.Shape.prototype = new SVG.Element(); + SVG.Shape.prototype = new SVG.Element() - SVG.Wrap = function Wrap(element) { - this.constructor.call(this, SVG.create('g')); + SVG.Wrap = function(element) { + this.constructor.call(this, SVG.create('g')) /* insert and store child */ - this.node.insertBefore(element.node, null); - this.child = element; - this.type = element.node.nodeName; - }; + this.node.insertBefore(element.node, null) + this.child = element + this.type = element.node.nodeName + } // inherit from SVG.Shape - SVG.Wrap.prototype = new SVG.Shape(); + SVG.Wrap.prototype = new SVG.Shape() SVG.extend(SVG.Wrap, { // Move wrapper around @@ -1085,147 +1132,147 @@ return this.transform({ x: x, y: y - }); + }) }, // Set the actual size in pixels size: function(width, height) { - var scale = width / this._b.width; + var scale = width / this._b.width this.child.transform({ scaleX: scale, scaleY: height != null ? height / this._b.height : scale - }); + }) - return this; + return this }, // Move by center center: function(x, y) { return this.move( x + (this._b.width * this.child.trans.scaleX) / -2, y + (this._b.height * this.child.trans.scaleY) / -2 - ); + ) }, // Create distributed attr attr: function(a, v, n) { /* call individual attributes if an object is given */ if (typeof a == 'object') { - for (v in a) this.attr(v, a[v]); + for (v in a) this.attr(v, a[v]) /* act as a getter if only one argument is given */ } else if (arguments.length < 2) { - return a == 'transform' ? this.attrs[a] : this.child.attrs[a]; + return a == 'transform' ? this.attrs[a] : this.child.attrs[a] /* apply locally for certain attributes */ } else if (a == 'transform') { - this.attrs[a] = v; + this.attrs[a] = v n != null ? this.node.setAttributeNS(n, a, v) : - this.node.setAttribute(a, v); + this.node.setAttribute(a, v) /* apply attributes to child */ } else { - this.child.attr(a, v, n); + this.child.attr(a, v, n) } - return this; + return this }, // Distribute plot method to child plot: function(data) { /* plot new shape */ - this.child.plot(data); + this.child.plot(data) /* get and store new bbox */ - this._b = this.child.bbox(); + this._b = this.child.bbox() /* reposition element withing wrapper */ this.child.transform({ x: -this._b.x, y: -this._b.y - }); + }) - return this; + return this } - }); + }) - SVG.Rect = function Rect() { - this.constructor.call(this, SVG.create('rect')); - }; + SVG.Rect = function() { + this.constructor.call(this, SVG.create('rect')) + } // Inherit from SVG.Shape - SVG.Rect.prototype = new SVG.Shape(); + SVG.Rect.prototype = new SVG.Shape() - SVG.Ellipse = function Ellipse() { - this.constructor.call(this, SVG.create('ellipse')); - }; + SVG.Ellipse = function() { + this.constructor.call(this, SVG.create('ellipse')) + } // Inherit from SVG.Shape - SVG.Ellipse.prototype = new SVG.Shape(); + SVG.Ellipse.prototype = new SVG.Shape() // SVG.extend(SVG.Ellipse, { // Custom move function move: function(x, y) { - this.attrs.x = x; - this.attrs.y = y; + this.attrs.x = x + this.attrs.y = y - return this.center(); + return this.center() }, // Custom size function size: function(width, height) { return this. attr({ rx: width / 2, ry: (height != null ? height : width) / 2 }). - center(); + center() }, // Custom center function center: function(x, y) { return this.attr({ cx: x || (this.attrs.x || 0) + (this.attrs.rx || 0), cy: y || (this.attrs.y || 0) + (this.attrs.ry || 0) - }); + }) } - }); + }) // Usage: - // draw.ellipse(200, 100); + // draw.ellipse(200, 100) - SVG.Line = function Line() { - this.constructor.call(this, SVG.create('line')); - }; + SVG.Line = function() { + this.constructor.call(this, SVG.create('line')) + } // Inherit from SVG.Shape - SVG.Line.prototype = new SVG.Shape(); + SVG.Line.prototype = new SVG.Shape() // Add required methods SVG.extend(SVG.Line, { // Move line move: function(x, y) { - var bbox = this.bbox(); + var bbox = this.bbox() return this.attr({ x1: this.attr('x1') - bbox.x + x, y1: this.attr('y1') - bbox.y + y, x2: this.attr('x2') - bbox.x + x, y2: this.attr('y2') - bbox.y + y - }); + }) }, // Move element by its center center: function(x, y) { - var bbox = this.bbox(); + var bbox = this.bbox() - return this.move(x - bbox.width / 2, y - bbox.height / 2); + return this.move(x - bbox.width / 2, y - bbox.height / 2) }, // Set line size by width and height size: function(width, height) { - var bbox = this.bbox(); + var bbox = this.bbox() - this.attr(this.attr('x1') < this.attr('x2') ? 'x2' : 'x1', bbox.x + width); - return this.attr(this.attr('y1') < this.attr('y2') ? 'y2' : 'y1', bbox.y + height); + this.attr(this.attr('x1') < this.attr('x2') ? 'x2' : 'x1', bbox.x + width) + return this.attr(this.attr('y1') < this.attr('y2') ? 'y2' : 'y1', bbox.y + height) } - }); + }) // Extend all container modules SVG.extend(SVG.Container, { @@ -1235,45 +1282,45 @@ y1: y1, x2: x2, y2: y2 - })); + })) } - }); + }) SVG.Poly = { // Set polygon data with default zero point if no data is passed plot: function(points) { - this.attr('points', points || '0,0'); + this.attr('points', points || '0,0') - return this; + return this } - }; + } - SVG.Polyline = function Polyline() { - this.constructor.call(this, SVG.create('polyline')); - }; + SVG.Polyline = function() { + this.constructor.call(this, SVG.create('polyline')) + } // Inherit from SVG.Shape - SVG.Polyline.prototype = new SVG.Shape(); + SVG.Polyline.prototype = new SVG.Shape() // Add polygon-specific functions - SVG.extend(SVG.Polyline, SVG.Poly); + SVG.extend(SVG.Polyline, SVG.Poly) - SVG.Polygon = function Polygon() { - this.constructor.call(this, SVG.create('polygon')); - }; + SVG.Polygon = function() { + this.constructor.call(this, SVG.create('polygon')) + } // Inherit from SVG.Shape - SVG.Polygon.prototype = new SVG.Shape(); + SVG.Polygon.prototype = new SVG.Shape() // Add polygon-specific functions - SVG.extend(SVG.Polygon, SVG.Poly); + SVG.extend(SVG.Polygon, SVG.Poly) - SVG.Path = function Path() { - this.constructor.call(this, SVG.create('path')); - }; + SVG.Path = function() { + this.constructor.call(this, SVG.create('path')) + } // Inherit from SVG.Shape - SVG.Path.prototype = new SVG.Shape(); + SVG.Path.prototype = new SVG.Shape() SVG.extend(SVG.Path, { @@ -1282,186 +1329,186 @@ this.transform({ x: x, y: y - }); + }) }, /* set path data */ plot: function(data) { - return this.attr('d', data || 'M0,0'); + return this.attr('d', data || 'M0,0') } }); - SVG.Image = function Image() { - this.constructor.call(this, SVG.create('image')); - }; + SVG.Image = function() { + this.constructor.call(this, SVG.create('image')) + } // Inherit from SVG.Element - SVG.Image.prototype = new SVG.Shape(); + SVG.Image.prototype = new SVG.Shape() SVG.extend(SVG.Image, { /* (re)load image */ load: function(url) { - this.src = url; - return (url ? this.attr('xlink:href', url, SVG.xlink) : this); + this.src = url + return (url ? this.attr('xlink:href', url, SVG.xlink) : this) } - }); + }) - var _styleAttr = ['size', 'family', 'weight', 'stretch', 'variant', 'style']; + var _styleAttr = ['size', 'family', 'weight', 'stretch', 'variant', 'style'] - SVG.Text = function Text() { - this.constructor.call(this, SVG.create('text')); + SVG.Text = function() { + this.constructor.call(this, SVG.create('text')) /* define default style */ - this.style = { 'font-size': 16, 'font-family': 'Helvetica', 'text-anchor': 'start' }; - this.leading = 1.2; - }; + this.style = { 'font-size': 16, 'font-family': 'Helvetica', 'text-anchor': 'start' } + this.leading = 1.2 + } // Inherit from SVG.Element - SVG.Text.prototype = new SVG.Shape(); + SVG.Text.prototype = new SVG.Shape() SVG.extend(SVG.Text, { // Set the text content text: function(text) { /* update the content */ - this.content = text = text || 'text'; - this.lines = []; + this.content = text = text || 'text' + this.lines = [] var index, length, tspan, style = this._style(), parent = this.doc(), lines = text.split("\n"), - size = this.style['font-size']; + size = this.style['font-size'] /* remove existing child nodes */ while (this.node.hasChildNodes()) - this.node.removeChild(this.node.lastChild); + this.node.removeChild(this.node.lastChild) /* build new lines */ for (index = 0, length = lines.length; index < length; index++) { /* create new tspan and set attributes */ - tspan = new TSpan(). + tspan = new SVG.TSpan(). text(lines[index]). attr({ dy: size * this.leading - (index == 0 ? size * 0.3 : 0), x: (this.attrs.x || 0), style: style - }); + }) /* add new tspan */ - this.node.appendChild(tspan.node); - this.lines.push(tspan); - }; + this.node.appendChild(tspan.node) + this.lines.push(tspan) + } /* set style */ - return this.attr('style', style); + return this.attr('style', style) }, // Build style based on _styleAttr _style: function() { - var index, style = ''; + var index, style = '' for (index = _styleAttr.length - 1; index >= 0; index--) if (this.style['font-' + _styleAttr[index]] != null) - style += 'font-' + _styleAttr[index] + ':' + this.style['font-' + _styleAttr[index]] + ';'; + style += 'font-' + _styleAttr[index] + ':' + this.style['font-' + _styleAttr[index]] + ';' - style += 'text-anchor:' + this.style['text-anchor'] + ';'; + style += 'text-anchor:' + this.style['text-anchor'] + ';' - return style; + return style } - }); + }) - function TSpan() { - this.constructor.call(this, SVG.create('tspan')); - }; + SVG.TSpan = function() { + this.constructor.call(this, SVG.create('tspan')) + } // Inherit from SVG.Shape - TSpan.prototype = new SVG.Shape(); + SVG.TSpan.prototype = new SVG.Shape() // Include the container object - SVG.extend(TSpan, { + SVG.extend(SVG.TSpan, { // Set text content text: function(text) { - this.node.appendChild(document.createTextNode(text)); + this.node.appendChild(document.createTextNode(text)) - return this; + return this } }); - SVG.Nested = function Nested() { - this.constructor.call(this, SVG.create('svg')); - this.attr('overflow', 'visible'); - }; + SVG.Nested = function() { + this.constructor.call(this, SVG.create('svg')) + this.attr('overflow', 'visible') + } // Inherit from SVG.Container - SVG.Nested.prototype = new SVG.Container(); + SVG.Nested.prototype = new SVG.Container - SVG._stroke = ['color', 'width', 'opacity', 'linecap', 'linejoin', 'miterlimit', 'dasharray', 'dashoffset']; - SVG._fill = ['color', 'opacity', 'rule']; + SVG._stroke = ['color', 'width', 'opacity', 'linecap', 'linejoin', 'miterlimit', 'dasharray', 'dashoffset'] + SVG._fill = ['color', 'opacity', 'rule'] // Prepend correct color prefix var _colorPrefix = function(type, attr) { - return attr == 'color' ? type : type + '-' + attr; - }; + return attr == 'color' ? type : type + '-' + attr + } /* Add sugar for fill and stroke */ - ['fill', 'stroke'].forEach(function(method) { + ;['fill', 'stroke'].forEach(function(method) { // Set fill color and opacity SVG.Shape.prototype[method] = function(o) { - var index; + var indexOf if (typeof o == 'string') - this.attr(method, o); + this.attr(method, o) else /* set all attributes from _fillAttr and _strokeAttr list */ for (index = SVG['_' + method].length - 1; index >= 0; index--) if (o[SVG['_' + method][index]] != null) - this.attr(_colorPrefix(method, SVG['_' + method][index]), o[SVG['_' + method][index]]); + this.attr(_colorPrefix(method, SVG['_' + method][index]), o[SVG['_' + method][index]]) - return this; - }; + return this + } - }); + }) - [SVG.Element, SVG.FX].forEach(function(module) { + ;[SVG.Element, SVG.FX].forEach(function(module) { if (module) { SVG.extend(module, { // Rotation rotate: function(angle) { return this.transform({ rotation: angle || 0 - }); + }) }, // Skew skew: function(x, y) { return this.transform({ skewX: x || 0, skewY: y || 0 - }); + }) }, // Scale scale: function(x, y) { return this.transform({ scaleX: x, scaleY: y == null ? x : y - }); + }) }, // Opacity opacity: function(value) { - return this.attr('opacity', value); + return this.attr('opacity', value) } - }); + }) } - }); + }) if (SVG.G) { SVG.extend(SVG.G, { @@ -1470,17 +1517,17 @@ return this.transform({ x: x, y: y - }); + }) } - }); + }) } if (SVG.Text) { SVG.extend(SVG.Text, { // Set font font: function(o) { - var key, attr = {}; + var key, attr = {} for (key in o) key == 'leading' ? @@ -1489,12 +1536,12 @@ attr['text-anchor'] = o[key] : _styleAttr.indexOf(key) > -1 ? attr['font-'+ key] = o[key] : - void 0; + void 0 - return this.attr(attr).text(this.content); + return this.attr(attr).text(this.content) } - }); + }) } diff --git a/dist/svg.min.js b/dist/svg.min.js index 3247907..70f0bab 100644 --- a/dist/svg.min.js +++ b/dist/svg.min.js @@ -1,2 +1,2 @@ -/* svg.js v0.5-6-g3ebe05f - svg element container fx event group arrange defs mask pattern gradient doc shape wrap rect ellipse line poly path image text nested sugar - svgjs.com/license */ -(function(){function t(){this.constructor.call(this,SVG.create("tspan"))}this.svg=function(e){if(SVG.supported)return new SVG.Doc(e)},this.SVG={ns:"http://www.w3.org/2000/svg",xlink:"http://www.w3.org/1999/xlink",did:0,create:function(e){return document.createElementNS(this.ns,e)},extend:function(e,t){for(var n in t)e.prototype[n]=t[n]}},SVG.supported=function(){return!!document.createElementNS&&!!document.createElementNS(SVG.ns,"svg").createSVGRect}();if(!SVG.supported)return!1;SVG.Element=function(t){if(this.node=t)this.type=t.nodeName;this.attrs={"fill-opacity":1,"stroke-opacity":1,"stroke-width":0,fill:"#000",stroke:"#000",opacity:1,x:0,y:0,cx:0,cy:0,width:0,height:0,r:0,rx:0,ry:0},this.trans={x:0,y:0,scaleX:1,scaleY:1,rotation:0,skewX:0,skewY:0}},SVG.extend(SVG.Element,{move:function(e,t){return this.attr({x:e,y:t})},center:function(e,t){var n=this.bbox();return this.move(e-n.width/2,t-n.height/2)},size:function(e,t){return this.attr({width:e,height:t})},clone:function(){var e;if(this instanceof SVG.Wrap)e=this.parent[this.child.node.nodeName](),e.attrs=this.attrs,e.child.trans=this.child.trans,e.child.attr(this.child.attrs).transform({}),e.plot&&e.plot(this.child.attrs[this.child instanceof SVG.Path?"d":"points"]);else{var t=this.node.nodeName;e=t=="rect"?this.parent[t](this.attrs.width,this.attrs.height):t=="ellipse"?this.parent[t](this.attrs.rx*2,this.attrs.ry*2):t=="image"?this.parent[t](this.src):t=="text"?this.parent[t](this.content):t=="g"?this.parent.group():this.parent[t](),e.attr(this.attrs)}return e.trans=this.trans,e.transform({})},remove:function(){return this.parent!=null?this.parent.remove(this):void 0},doc:function(){return this._parent(SVG.Doc)},nested:function(){return this._parent(SVG.Nested)},attr:function(e,t,n){if(arguments.length<2){if(typeof e!="object")return this._isStyle(e)?e=="text"?this.content:e=="leading"?this[e]:this.style[e]:this.attrs[e];for(t in e)this.attr(t,e[t])}else{this.attrs[e]=t;if(e=="x"&&this._isText())for(var r=this.lines.length-1;r>=0;r--)this.lines[r].attr(e,t);else n!=null?this.node.setAttributeNS(n,e,t):this.node.setAttribute(e,t);this._isStyle(e)&&(e=="text"?this.text(t):e=="leading"?this[e]=t:this.style[e]=t,this.text(this.content))}return this},transform:function(e){if(typeof e=="string")return this.trans[e];var t,n=[];for(t in e)e[t]!=null&&(this.trans[t]=e[t]);e=this.trans;if(e.rotation!=0){var r=this.bbox();n.push("rotate("+e.rotation+","+(e.cx!=null?e.cx:r.cx)+","+(e.cy!=null?e.cy:r.cy)+")")}return n.push("scale("+e.scaleX+","+e.scaleY+")"),e.skewX!=0&&n.push("skewX("+e.skewX+")"),e.skewY!=0&&n.push("skewY("+e.skewY+")"),n.push("translate("+e.x+","+e.y+")"),this.attr("transform",n.join(" "))},data:function(e,t,n){if(arguments.length<2)try{return JSON.parse(this.attr("data-"+e))}catch(r){return this.attr("data-"+e)}else t===null?this.node.removeAttribute("data-"+e):this.attr("data-"+e,n===!0?t:JSON.stringify(t));return this},bbox:function(){var e=this.node.getBBox();return{x:e.x+this.trans.x,y:e.y+this.trans.y,cx:e.x+this.trans.x+e.width/2,cy:e.y+this.trans.y+e.height/2,width:e.width,height:e.height}},inside:function(e,t){var n=this.bbox();return e>n.x&&t>n.y&&e=0},children:function(){return this._children||(this._children=[])},each:function(e){var t,n=this.children();for(t=0,length=n.length;t";var n,r,i,s=this.target,o=this,u=(new Date).getTime(),a=u+e;return this.interval=setInterval(function(){var f,l=(new Date).getTime(),c=l>a?1:(l-u)/e;if(n==null){n=[];for(var h in o.attrs)n.push(h)}if(r==null){r=[];for(var h in o.trans)r.push(h);i={}}c=t=="<>"?-Math.cos(c*Math.PI)/2+.5:t==">"?Math.sin(c*Math.PI/2):t=="<"?-Math.cos(c*Math.PI/2)+1:t=="-"?c:typeof t=="function"?t(c):c,o._move?s.move(o._at(o._move.x,c),o._at(o._move.y,c)):o._center&&s.move(o._at(o._center.x,c),o._at(o._center.y,c)),o._size&&s.size(o._at(o._size.width,c),o._at(o._size.height,c));for(f=n.length-1;f>=0;f--)s.attr(n[f],o._at(o.attrs[n[f]],c));if(r.length>0){for(f=r.length-1;f>=0;f--)i[r[f]]=o._at(o.trans[r[f]],c);s.transform(i)}l>a&&(clearInterval(o.interval),o._after?o._after.apply(s,[o]):o.stop())},e>10?10:e),this},attr:function(e,t,n){if(typeof e=="object")for(var r in e)this.attr(r,e[r]);else this.attrs[e]={from:this.target.attr(e),to:t};return this},transform:function(e){for(var t in e)this.trans[t]={from:this.target.trans[t],to:e[t]};return this},move:function(e,t){var n=this.target.bbox();return this._move={x:{from:n.x,to:e},y:{from:n.y,to:t}},this},size:function(e,t){var n=this.target.bbox();return this._size={width:{from:n.width,to:e},height:{from:n.height,to:t}},this},center:function(e,t){var n=this.target.bbox();return this._move={x:{from:n.cx,to:e},y:{from:n.cy,to:t}},this},after:function(e){return this._after=e,this},stop:function(){return clearInterval(this.interval),this.attrs={},this.trans={},this._move=null,this._size=null,this._after=null,this},_at:function(e,t){return typeof e.from=="number"?e.from+(e.to-e.from)*t:e.to.r||/^#/.test(e.to)?this._color(e,t):t<1?e.from:e.to},_color:function(e,t){var n,r;return n=this._h2r(e.from||"#000"),r=this._h2r(e.to),this._r2h({r:~~(n.r+(r.r-n.r)*t),g:~~(n.g+(r.g-n.g)*t),b:~~(n.b+(r.b-n.b)*t)})},_h2r:function(e){var t=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(this._fh(e));return t?{r:parseInt(t[1],16),g:parseInt(t[2],16),b:parseInt(t[3],16)}:{r:0,g:0,b:0}},_r2h:function(e){return"#"+this._c2h(e.r)+this._c2h(e.g)+this._c2h(e.b)},_c2h:function(e){var t=e.toString(16);return t.length==1?"0"+t:t},_fh:function(e){return e.length==4?["#",e.substring(1,2),e.substring(1,2),e.substring(2,3),e.substring(2,3),e.substring(3,4),e.substring(3,4)].join(""):e}}),SVG.extend(SVG.Element,{animate:function(e,t){return(this.fx||(this.fx=new SVG.FX(this))).stop().animate(e,t)},stop:function(){return this.fx.stop(),this}}),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","mouseenter","mouseleave","touchstart","touchend","touchmove","touchcancel"].forEach(function(e){SVG.Element.prototype[e]=function(t){var n=this;return this.node["on"+e]=typeof t=="function"?function(){return t.apply(n,arguments)}:null,this}}),SVG.on=function(e,t,n){e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent("on"+t,n)},SVG.off=function(e,t,n){e.removeEventListener?e.removeEventListener(t,n,!1):e.detachEvent("on"+t,n)},SVG.extend(SVG.Element,{on:function(e,t){return SVG.on(this.node,e,t),this},off:function(e,t){return SVG.off(this.node,e,t),this}}),SVG.G=function(){this.constructor.call(this,SVG.create("g"))},SVG.G.prototype=new SVG.Container,SVG.extend(SVG.G,{defs:function(){return this.doc().defs()}}),SVG.extend(SVG.Element,{siblings:function(){return this.parent.children()},position:function(){return this.siblings().indexOf(this)},next:function(){return this.siblings()[this.position()+1]},previous:function(){return this.siblings()[this.position()-1]},forward:function(){return this.parent.remove(this).put(this,this.position()+1)},backward:function(){var e;return this.parent.level(),e=this.position(),e>1&&this.parent.remove(this).add(this,e-1),this},front:function(){return this.parent.remove(this).put(this)},back:function(){return this.parent.level(),this.position()>1&&this.parent.remove(this).add(this,0),this}}),SVG.Defs=function(){this.constructor.call(this,SVG.create("defs"))},SVG.Defs.prototype=new SVG.Container,SVG.Mask=function(){this.constructor.call(this,SVG.create("mask")),this.attr("id",this.id="svgjs_element_"+SVG.did++)},SVG.Mask.prototype=new SVG.Container,SVG.extend(SVG.Element,{maskWith:function(e){return this.mask=e instanceof SVG.Mask?e:this.parent.mask().add(e),this.attr("mask","url(#"+this.mask.id+")")}}),SVG.Pattern=function(t){this.constructor.call(this,SVG.create("pattern")),this.attr("id",this.id="svgjs_element_"+SVG.did++)},SVG.Pattern.prototype=new SVG.Container,SVG.extend(SVG.Pattern,{fill:function(){return"url(#"+this.id+")"}}),SVG.extend(SVG.Defs,{pattern:function(e,t,n){var r=this.put(new SVG.Pattern);return n(r),r.attr({x:0,y:0,width:e,height:t,patternUnits:"userSpaceOnUse"})}}),SVG.Gradient=function(t){this.constructor.call(this,SVG.create(t+"Gradient")),this.attr("id",this.id="svgjs_element_"+SVG.did++),this.type=t},SVG.Gradient.prototype=new SVG.Container,SVG.extend(SVG.Gradient,{from:function(e,t){return this.type=="radial"?this.attr({fx:e+"%",fy:t+"%"}):this.attr({x1:e+"%",y1:t+"%"})},to:function(e,t){return this.type=="radial"?this.attr({cx:e+"%",cy:t+"%"}):this.attr({x2:e+"%",y2:t+"%"})},radius:function(e){return this.type=="radial"?this.attr({r:e+"%"}):this},at:function(e){return this.put(new SVG.Stop(e))},update:function(e){while(this.node.hasChildNodes())this.node.removeChild(this.node.lastChild);return e(this),this},fill:function(){return"url(#"+this.id+")"}}),SVG.extend(SVG.Defs,{gradient:function(e,t){var n=this.put(new SVG.Gradient(e));return t(n),n}}),SVG.Stop=function(t){this.constructor.call(this,SVG.create("stop")),this.update(t)},SVG.Stop.prototype=new SVG.Element,SVG.extend(SVG.Stop,{update:function(e){var t,n="",r=["opacity","color"];for(t=r.length-1;t>=0;t--)e[r[t]]!=null&&(n+="stop-"+r[t]+":"+e[r[t]]+";");return this.attr({offset:(e.offset!=null?e.offset:this.attrs.offset||0)+"%",style:n})}}),SVG.Doc=function(t){this.constructor.call(this,SVG.create("svg")),this.parent=typeof t=="string"?document.getElementById(t):t,this.attr({xmlns:SVG.ns,version:"1.1",width:"100%",height:"100%"}).attr("xlink",SVG.xlink,SVG.ns).defs(),this.stage()},SVG.Doc.prototype=new SVG.Container,SVG.Doc.prototype.stage=function(){var e,t=this,n=document.createElement("div");return n.style.cssText="position:relative;height:100%;",t.parent.appendChild(n),n.appendChild(t.node),e=function(){document.readyState==="complete"?(t.attr("style","position:absolute;"),setTimeout(function(){t.attr("style","position:relative;"),t.parent.removeChild(t.node.parentNode),t.node.parentNode.removeChild(t.node),t.parent.appendChild(t.node)},5)):setTimeout(e,10)},e(),this},SVG.Shape=function(t){this.constructor.call(this,t)},SVG.Shape.prototype=new SVG.Element,SVG.Wrap=function(t){this.constructor.call(this,SVG.create("g")),this.node.insertBefore(t.node,null),this.child=t,this.type=t.node.nodeName},SVG.Wrap.prototype=new SVG.Shape,SVG.extend(SVG.Wrap,{move:function(e,t){return this.transform({x:e,y:t})},size:function(e,t){var n=e/this._b.width;return this.child.transform({scaleX:n,scaleY:t!=null?t/this._b.height:n}),this},center:function(e,t){return this.move(e+this._b.width*this.child.trans.scaleX/-2,t+this._b.height*this.child.trans.scaleY/-2)},attr:function(e,t,n){if(typeof e=="object")for(t in e)this.attr(t,e[t]);else{if(arguments.length<2)return e=="transform"?this.attrs[e]:this.child.attrs[e];e=="transform"?(this.attrs[e]=t,n!=null?this.node.setAttributeNS(n,e,t):this.node.setAttribute(e,t)):this.child.attr(e,t,n)}return this},plot:function(e){return this.child.plot(e),this._b=this.child.bbox(),this.child.transform({x:-this._b.x,y:-this._b.y}),this}}),SVG.Rect=function(){this.constructor.call(this,SVG.create("rect"))},SVG.Rect.prototype=new SVG.Shape,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()},size:function(e,t){return this.attr({rx:e/2,ry:(t!=null?t:e)/2}).center()},center:function(e,t){return this.attr({cx:e||(this.attrs.x||0)+(this.attrs.rx||0),cy:t||(this.attrs.y||0)+(this.attrs.ry||0)})}}),SVG.Line=function(){this.constructor.call(this,SVG.create("line"))},SVG.Line.prototype=new SVG.Shape,SVG.extend(SVG.Line,{move:function(e,t){var n=this.bbox();return this.attr({x1:this.attr("x1")-n.x+e,y1:this.attr("y1")-n.y+t,x2:this.attr("x2")-n.x+e,y2:this.attr("y2")-n.y+t})},center:function(e,t){var n=this.bbox();return this.move(e-n.width/2,t-n.height/2)},size:function(e,t){var n=this.bbox();return this.attr(this.attr("x1")=0;t--)this.style["font-"+e[t]]!=null&&(n+="font-"+e[t]+":"+this.style["font-"+e[t]]+";");return n+="text-anchor:"+this.style["text-anchor"]+";",n}}),t.prototype=new SVG.Shape,SVG.extend(t,{text:function(e){return this.node.appendChild(document.createTextNode(e)),this}}),SVG.Nested=function(){this.constructor.call(this,SVG.create("svg")),this.attr("overflow","visible")},SVG.Nested.prototype=new SVG.Container,SVG._stroke=["color","width","opacity","linecap","linejoin","miterlimit","dasharray","dashoffset"],SVG._fill=["color","opacity","rule"];var n=function(e,t){return t=="color"?e:e+"-"+t};["fill","stroke"].forEach(function(e){SVG.Shape.prototype[e]=function(t){var r;if(typeof t=="string")this.attr(e,t);else for(r=SVG["_"+e].length-1;r>=0;r--)t[SVG["_"+e][r]]!=null&&this.attr(n(e,SVG["_"+e][r]),t[SVG["_"+e][r]]);return this}}),[SVG.Element,SVG.FX].forEach(function(e){e&&SVG.extend(e,{rotate:function(e){return this.transform({rotation:e||0})},skew:function(e,t){return this.transform({skewX:e||0,skewY:t||0})},scale:function(e,t){return this.transform({scaleX:e,scaleY:t==null?e:t})},opacity:function(e){return this.attr("opacity",e)}})}),SVG.G&&SVG.extend(SVG.G,{move:function(e,t){return this.transform({x:e,y:t})}}),SVG.Text&&SVG.extend(SVG.Text,{font:function(t){var n,r={};for(n in t)n=="leading"?r[n]=t[n]:n=="anchor"?r["text-anchor"]=t[n]:e.indexOf(n)>-1?r["font-"+n]=t[n]:void 0;return this.attr(r).text(this.content)}})}).call(this); \ No newline at end of file +/* svg.js v0.5-8-g5020240 - svg viewbox bbox element container fx event group arrange defs mask pattern gradient doc shape wrap rect ellipse line poly path image text nested sugar - svgjs.com/license */ +(function(){this.svg=function(e){if(SVG.supported)return new SVG.Doc(e)},this.SVG={ns:"http://www.w3.org/2000/svg",xlink:"http://www.w3.org/1999/xlink",did:0,create:function(e){return document.createElementNS(this.ns,e)},extend:function(e,t){for(var n in t)e.prototype[n]=t[n]}},SVG.supported=function(){return!!document.createElementNS&&!!document.createElementNS(SVG.ns,"svg").createSVGRect}();if(!SVG.supported)return!1;SVG.ViewBox=function(e){var t,n,r=e.bbox(),i=(e.attr("viewBox")||"").match(/[\d\.]+/g);this.x=r.x,this.y=r.y,this.width=r.width,this.height=r.height,i?(t=parseFloat(i[2]),n=parseFloat(i[3]),e instanceof SVG.Doc&&(this.x=0,this.y=0,this.width=e.node.offsetWidth,this.height=e.node.offsetHeight),this.scale=this.width/this.height>t/n?this.height/n:this.width/t):this.scale=1},SVG.BBox=function(e){var t=e.node.getBBox();this.x=t.x+e.trans.x,this.y=t.y+e.trans.y,this.cx=t.x+e.trans.x+t.width/2,this.cy=t.y+e.trans.y+t.height/2,this.width=t.width,this.height=t.height},SVG.Element=function(e){if(this.node=e)this.type=e.nodeName;this.attrs={"fill-opacity":1,"stroke-opacity":1,"stroke-width":0,fill:"#000",stroke:"#000",opacity:1,x:0,y:0,cx:0,cy:0,width:0,height:0,r:0,rx:0,ry:0},this.trans={x:0,y:0,scaleX:1,scaleY:1,rotation:0,skewX:0,skewY:0}},SVG.extend(SVG.Element,{move:function(e,t){return this.attr({x:e,y:t})},center:function(e,t){var n=this.bbox();return this.move(e-n.width/2,t-n.height/2)},size:function(e,t){return this.attr({width:e,height:t})},clone:function(){var e;if(this instanceof SVG.Wrap)e=this.parent[this.child.node.nodeName](),e.attrs=this.attrs,e.child.trans=this.child.trans,e.child.attr(this.child.attrs).transform({}),e.plot&&e.plot(this.child.attrs[this.child instanceof SVG.Path?"d":"points"]);else{var t=this.node.nodeName;e=t=="rect"?this.parent[t](this.attrs.width,this.attrs.height):t=="ellipse"?this.parent[t](this.attrs.rx*2,this.attrs.ry*2):t=="image"?this.parent[t](this.src):t=="text"?this.parent[t](this.content):t=="g"?this.parent.group():this.parent[t](),e.attr(this.attrs)}return e.trans=this.trans,e.transform({})},remove:function(){return this.parent!=null?this.parent.remove(this):void 0},doc:function(){return this._parent(SVG.Doc)},nested:function(){return this._parent(SVG.Nested)},attr:function(e,t,n){if(arguments.length<2){if(typeof e!="object")return this._isStyle(e)?e=="text"?this.content:e=="leading"?this[e]:this.style[e]:this.attrs[e];for(t in e)this.attr(t,e[t])}else{this.attrs[e]=t;if(e=="x"&&this._isText())for(var r=this.lines.length-1;r>=0;r--)this.lines[r].attr(e,t);else n!=null?this.node.setAttributeNS(n,e,t):this.node.setAttribute(e,t);this._isStyle(e)&&(e=="text"?this.text(t):e=="leading"?this[e]=t:this.style[e]=t,this.text(this.content))}return this},transform:function(e){if(typeof e=="string")return this.trans[e];var t,n=[];for(t in e)e[t]!=null&&(this.trans[t]=e[t]);e=this.trans;if(e.rotation!=0){var r=this.bbox();n.push("rotate("+e.rotation+","+(e.cx!=null?e.cx:r.cx)+","+(e.cy!=null?e.cy:r.cy)+")")}return n.push("scale("+e.scaleX+","+e.scaleY+")"),e.skewX!=0&&n.push("skewX("+e.skewX+")"),e.skewY!=0&&n.push("skewY("+e.skewY+")"),n.push("translate("+e.x+","+e.y+")"),this.attr("transform",n.join(" "))},data:function(e,t,n){if(arguments.length<2)try{return JSON.parse(this.attr("data-"+e))}catch(r){return this.attr("data-"+e)}else t===null?this.node.removeAttribute("data-"+e):this.attr("data-"+e,n===!0?t:JSON.stringify(t));return this},bbox:function(){return new SVG.BBox(this)},inside:function(e,t){var n=this.bbox();return e>n.x&&t>n.y&&e=0},children:function(){return this._children||(this._children=[])},each:function(e){var t,n=this.children();for(t=0,length=n.length;t";var n,r,i,s=this.target,o=this,u=(new Date).getTime(),a=u+e;return this.interval=setInterval(function(){var f,l=(new Date).getTime(),c=l>a?1:(l-u)/e;if(n==null){n=[];for(var h in o.attrs)n.push(h)}if(r==null){r=[];for(var h in o.trans)r.push(h);i={}}c=t=="<>"?-Math.cos(c*Math.PI)/2+.5:t==">"?Math.sin(c*Math.PI/2):t=="<"?-Math.cos(c*Math.PI/2)+1:t=="-"?c:typeof t=="function"?t(c):c,o._move?s.move(o._at(o._move.x,c),o._at(o._move.y,c)):o._center&&s.move(o._at(o._center.x,c),o._at(o._center.y,c)),o._size&&s.size(o._at(o._size.width,c),o._at(o._size.height,c));for(f=n.length-1;f>=0;f--)s.attr(n[f],o._at(o.attrs[n[f]],c));if(r.length>0){for(f=r.length-1;f>=0;f--)i[r[f]]=o._at(o.trans[r[f]],c);s.transform(i)}l>a&&(clearInterval(o.interval),o._after?o._after.apply(s,[o]):o.stop())},e>10?10:e),this},attr:function(e,t,n){if(typeof e=="object")for(var r in e)this.attr(r,e[r]);else this.attrs[e]={from:this.target.attr(e),to:t};return this},transform:function(e){for(var t in e)this.trans[t]={from:this.target.trans[t],to:e[t]};return this},move:function(e,t){var n=this.target.bbox();return this._move={x:{from:n.x,to:e},y:{from:n.y,to:t}},this},size:function(e,t){var n=this.target.bbox();return this._size={width:{from:n.width,to:e},height:{from:n.height,to:t}},this},center:function(e,t){var n=this.target.bbox();return this._move={x:{from:n.cx,to:e},y:{from:n.cy,to:t}},this},after:function(e){return this._after=e,this},stop:function(){return clearInterval(this.interval),this.attrs={},this.trans={},this._move=null,this._size=null,this._after=null,this},_at:function(e,t){return typeof e.from=="number"?e.from+(e.to-e.from)*t:e.to.r||/^#/.test(e.to)?this._color(e,t):t<1?e.from:e.to},_color:function(e,t){var n,r;return n=this._h2r(e.from||"#000"),r=this._h2r(e.to),this._r2h({r:~~(n.r+(r.r-n.r)*t),g:~~(n.g+(r.g-n.g)*t),b:~~(n.b+(r.b-n.b)*t)})},_h2r:function(e){var t=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(this._fh(e));return t?{r:parseInt(t[1],16),g:parseInt(t[2],16),b:parseInt(t[3],16)}:{r:0,g:0,b:0}},_r2h:function(e){return"#"+this._c2h(e.r)+this._c2h(e.g)+this._c2h(e.b)},_c2h:function(e){var t=e.toString(16);return t.length==1?"0"+t:t},_fh:function(e){return e.length==4?["#",e.substring(1,2),e.substring(1,2),e.substring(2,3),e.substring(2,3),e.substring(3,4),e.substring(3,4)].join(""):e}}),SVG.extend(SVG.Element,{animate:function(e,t){return(this.fx||(this.fx=new SVG.FX(this))).stop().animate(e,t)},stop:function(){return this.fx.stop(),this}}),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","mouseenter","mouseleave","touchstart","touchend","touchmove","touchcancel"].forEach(function(e){SVG.Element.prototype[e]=function(t){var n=this;return this.node["on"+e]=typeof t=="function"?function(){return t.apply(n,arguments)}:null,this}}),SVG.on=function(e,t,n){e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent("on"+t,n)},SVG.off=function(e,t,n){e.removeEventListener?e.removeEventListener(t,n,!1):e.detachEvent("on"+t,n)},SVG.extend(SVG.Element,{on:function(e,t){return SVG.on(this.node,e,t),this},off:function(e,t){return SVG.off(this.node,e,t),this}}),SVG.G=function(){this.constructor.call(this,SVG.create("g"))},SVG.G.prototype=new SVG.Container,SVG.extend(SVG.G,{defs:function(){return this.doc().defs()}}),SVG.extend(SVG.Element,{siblings:function(){return this.parent.children()},position:function(){return this.siblings().indexOf(this)},next:function(){return this.siblings()[this.position()+1]},previous:function(){return this.siblings()[this.position()-1]},forward:function(){return this.parent.remove(this).put(this,this.position()+1)},backward:function(){var e;return this.parent.level(),e=this.position(),e>1&&this.parent.remove(this).add(this,e-1),this},front:function(){return this.parent.remove(this).put(this)},back:function(){return this.parent.level(),this.position()>1&&this.parent.remove(this).add(this,0),this}}),SVG.Defs=function(){this.constructor.call(this,SVG.create("defs"))},SVG.Defs.prototype=new SVG.Container,SVG.Mask=function(){this.constructor.call(this,SVG.create("mask")),this.attr("id",this.id="svgjs_element_"+SVG.did++)},SVG.Mask.prototype=new SVG.Container,SVG.extend(SVG.Element,{maskWith:function(e){return this.mask=e instanceof SVG.Mask?e:this.parent.mask().add(e),this.attr("mask","url(#"+this.mask.id+")")}}),SVG.Pattern=function(e){this.constructor.call(this,SVG.create("pattern")),this.attr("id",this.id="svgjs_element_"+SVG.did++)},SVG.Pattern.prototype=new SVG.Container,SVG.extend(SVG.Pattern,{fill:function(){return"url(#"+this.id+")"}}),SVG.extend(SVG.Defs,{pattern:function(e,t,n){var r=this.put(new SVG.Pattern);return n(r),r.attr({x:0,y:0,width:e,height:t,patternUnits:"userSpaceOnUse"})}}),SVG.Gradient=function(e){this.constructor.call(this,SVG.create(e+"Gradient")),this.attr("id",this.id="svgjs_element_"+SVG.did++),this.type=e},SVG.Gradient.prototype=new SVG.Container,SVG.extend(SVG.Gradient,{from:function(e,t){return this.type=="radial"?this.attr({fx:e+"%",fy:t+"%"}):this.attr({x1:e+"%",y1:t+"%"})},to:function(e,t){return this.type=="radial"?this.attr({cx:e+"%",cy:t+"%"}):this.attr({x2:e+"%",y2:t+"%"})},radius:function(e){return this.type=="radial"?this.attr({r:e+"%"}):this},at:function(e){return this.put(new SVG.Stop(e))},update:function(e){while(this.node.hasChildNodes())this.node.removeChild(this.node.lastChild);return e(this),this},fill:function(){return"url(#"+this.id+")"}}),SVG.extend(SVG.Defs,{gradient:function(e,t){var n=this.put(new SVG.Gradient(e));return t(n),n}}),SVG.Stop=function(e){this.constructor.call(this,SVG.create("stop")),this.update(e)},SVG.Stop.prototype=new SVG.Element,SVG.extend(SVG.Stop,{update:function(e){var t,n="",r=["opacity","color"];for(t=r.length-1;t>=0;t--)e[r[t]]!=null&&(n+="stop-"+r[t]+":"+e[r[t]]+";");return this.attr({offset:(e.offset!=null?e.offset:this.attrs.offset||0)+"%",style:n})}}),SVG.Doc=function(e){this.constructor.call(this,SVG.create("svg")),this.parent=typeof e=="string"?document.getElementById(e):e,this.attr({xmlns:SVG.ns,version:"1.1",width:"100%",height:"100%"}).attr("xlink",SVG.xlink,SVG.ns).defs(),this.stage()},SVG.Doc.prototype=new SVG.Container,SVG.Doc.prototype.stage=function(){var e,t=this,n=document.createElement("div");return n.style.cssText="position:relative;height:100%;",t.parent.appendChild(n),n.appendChild(t.node),e=function(){document.readyState==="complete"?(t.attr("style","position:absolute;"),setTimeout(function(){t.attr("style","position:relative;"),t.parent.removeChild(t.node.parentNode),t.node.parentNode.removeChild(t.node),t.parent.appendChild(t.node)},5)):setTimeout(e,10)},e(),this},SVG.Shape=function(e){this.constructor.call(this,e)},SVG.Shape.prototype=new SVG.Element,SVG.Wrap=function(e){this.constructor.call(this,SVG.create("g")),this.node.insertBefore(e.node,null),this.child=e,this.type=e.node.nodeName},SVG.Wrap.prototype=new SVG.Shape,SVG.extend(SVG.Wrap,{move:function(e,t){return this.transform({x:e,y:t})},size:function(e,t){var n=e/this._b.width;return this.child.transform({scaleX:n,scaleY:t!=null?t/this._b.height:n}),this},center:function(e,t){return this.move(e+this._b.width*this.child.trans.scaleX/-2,t+this._b.height*this.child.trans.scaleY/-2)},attr:function(e,t,n){if(typeof e=="object")for(t in e)this.attr(t,e[t]);else{if(arguments.length<2)return e=="transform"?this.attrs[e]:this.child.attrs[e];e=="transform"?(this.attrs[e]=t,n!=null?this.node.setAttributeNS(n,e,t):this.node.setAttribute(e,t)):this.child.attr(e,t,n)}return this},plot:function(e){return this.child.plot(e),this._b=this.child.bbox(),this.child.transform({x:-this._b.x,y:-this._b.y}),this}}),SVG.Rect=function(){this.constructor.call(this,SVG.create("rect"))},SVG.Rect.prototype=new SVG.Shape,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()},size:function(e,t){return this.attr({rx:e/2,ry:(t!=null?t:e)/2}).center()},center:function(e,t){return this.attr({cx:e||(this.attrs.x||0)+(this.attrs.rx||0),cy:t||(this.attrs.y||0)+(this.attrs.ry||0)})}}),SVG.Line=function(){this.constructor.call(this,SVG.create("line"))},SVG.Line.prototype=new SVG.Shape,SVG.extend(SVG.Line,{move:function(e,t){var n=this.bbox();return this.attr({x1:this.attr("x1")-n.x+e,y1:this.attr("y1")-n.y+t,x2:this.attr("x2")-n.x+e,y2:this.attr("y2")-n.y+t})},center:function(e,t){var n=this.bbox();return this.move(e-n.width/2,t-n.height/2)},size:function(e,t){var n=this.bbox();return this.attr(this.attr("x1")=0;t--)this.style["font-"+e[t]]!=null&&(n+="font-"+e[t]+":"+this.style["font-"+e[t]]+";");return n+="text-anchor:"+this.style["text-anchor"]+";",n}}),SVG.TSpan=function(){this.constructor.call(this,SVG.create("tspan"))},SVG.TSpan.prototype=new SVG.Shape,SVG.extend(SVG.TSpan,{text:function(e){return this.node.appendChild(document.createTextNode(e)),this}}),SVG.Nested=function(){this.constructor.call(this,SVG.create("svg")),this.attr("overflow","visible")},SVG.Nested.prototype=new SVG.Container,SVG._stroke=["color","width","opacity","linecap","linejoin","miterlimit","dasharray","dashoffset"],SVG._fill=["color","opacity","rule"];var t=function(e,t){return t=="color"?e:e+"-"+t};["fill","stroke"].forEach(function(e){SVG.Shape.prototype[e]=function(n){var r;if(typeof n=="string")this.attr(e,n);else for(index=SVG["_"+e].length-1;index>=0;index--)n[SVG["_"+e][index]]!=null&&this.attr(t(e,SVG["_"+e][index]),n[SVG["_"+e][index]]);return this}}),[SVG.Element,SVG.FX].forEach(function(e){e&&SVG.extend(e,{rotate:function(e){return this.transform({rotation:e||0})},skew:function(e,t){return this.transform({skewX:e||0,skewY:t||0})},scale:function(e,t){return this.transform({scaleX:e,scaleY:t==null?e:t})},opacity:function(e){return this.attr("opacity",e)}})}),SVG.G&&SVG.extend(SVG.G,{move:function(e,t){return this.transform({x:e,y:t})}}),SVG.Text&&SVG.extend(SVG.Text,{font:function(t){var n,r={};for(n in t)n=="leading"?r[n]=t[n]:n=="anchor"?r["text-anchor"]=t[n]:e.indexOf(n)>-1?r["font-"+n]=t[n]:void 0;return this.attr(r).text(this.content)}})}).call(this); \ No newline at end of file diff --git a/src/arrange.js b/src/arrange.js index 441a9c3..47134ed 100644 --- a/src/arrange.js +++ b/src/arrange.js @@ -4,49 +4,49 @@ SVG.extend(SVG.Element, { // Get all siblings, including myself siblings: function() { - return this.parent.children(); - }, + return this.parent.children() + } // Get the curent position siblings - position: function() { - return this.siblings().indexOf(this); - }, +, position: function() { + return this.siblings().indexOf(this) + } // Get the next element (will return null if there is none) - next: function() { - return this.siblings()[this.position() + 1]; - }, +, next: function() { + return this.siblings()[this.position() + 1] + } // Get the next element (will return null if there is none) - previous: function() { - return this.siblings()[this.position() - 1]; - }, +, previous: function() { + return this.siblings()[this.position() - 1] + } // Send given element one step forward - forward: function() { - return this.parent.remove(this).put(this, this.position() + 1); - }, +, forward: function() { + return this.parent.remove(this).put(this, this.position() + 1) + } // Send given element one step backward - backward: function() { - var i; +, backward: function() { + var i - this.parent.level(); + this.parent.level() - i = this.position(); + i = this.position() if (i > 1) - this.parent.remove(this).add(this, i - 1); + this.parent.remove(this).add(this, i - 1) - return this; - }, + return this + } // Send given element all the way to the front - front: function() { - return this.parent.remove(this).put(this); - }, +, front: function() { + return this.parent.remove(this).put(this) + } // Send given element all the way to the back - back: function() { - this.parent.level(); +, back: function() { + this.parent.level() if (this.position() > 1) - this.parent.remove(this).add(this, 0); + this.parent.remove(this).add(this, 0) - return this; + return this } -}); \ No newline at end of file +}) \ No newline at end of file diff --git a/src/bbox.js b/src/bbox.js new file mode 100644 index 0000000..d70ac68 --- /dev/null +++ b/src/bbox.js @@ -0,0 +1,18 @@ + +SVG.BBox = function(element) { + /* actual, native bounding box */ + var box = element.node.getBBox() + + /* include translations on x an y */ + this.x = box.x + element.trans.x + this.y = box.y + element.trans.y + + /* add the center */ + this.cx = box.x + element.trans.x + box.width / 2 + this.cy = box.y + element.trans.y + box.height / 2 + + /* plain width and height */ + this.width = box.width + this.height = box.height + +} \ No newline at end of file diff --git a/src/container.js b/src/container.js index 1f0998a..a78d93f 100644 --- a/src/container.js +++ b/src/container.js @@ -1,139 +1,148 @@ -SVG.Container = function Container(element) { - this.constructor.call(this, element); -}; +SVG.Container = function(element) { + this.constructor.call(this, element) +} // Inherit from SVG.Element -SVG.Container.prototype = new SVG.Element(); +SVG.Container.prototype = new SVG.Element // SVG.extend(SVG.Container, { // Add given element at a position add: function(element, index) { if (!this.has(element)) { - index = index == null ? this.children().length : index; - this.children().splice(index, 0, element); - this.node.insertBefore(element.node, this.node.childNodes[index] || null); - element.parent = this; + index = index == null ? this.children().length : index + this.children().splice(index, 0, element) + this.node.insertBefore(element.node, this.node.childNodes[index] || null) + element.parent = this } - return this; - }, + return this + } // Basically does the same as `add()` but returns the added element - put: function(element, index) { - this.add(element, index); - return element; - }, +, put: function(element, index) { + this.add(element, index) + return element + } // Checks if the given element is a child - has: function(element) { - return this.children().indexOf(element) >= 0; - }, +, has: function(element) { + return this.children().indexOf(element) >= 0 + } // Returns all child elements - children: function() { - return this._children || (this._children = []); - }, +, children: function() { + return this._children || (this._children = []) + } // Iterates over all children and invokes a given block - each: function(block) { +, each: function(block) { var index, - children = this.children(); + children = this.children() for (index = 0, length = children.length; index < length; index++) if (children[index] instanceof SVG.Shape) - block.apply(children[index], [index, children]); + block.apply(children[index], [index, children]) - return this; - }, + return this + } // Remove a given child element - remove: function(element) { - return this.removeAt(this.children().indexOf(element)); - }, +, remove: function(element) { + return this.removeAt(this.children().indexOf(element)) + } // Remove a child element at a given position - removeAt: function(index) { +, removeAt: function(index) { if (0 <= index && index < this.children().length) { - var element = this.children()[index]; - this.children().splice(index, 1); - this.node.removeChild(element.node); - element.parent = null; + var element = this.children()[index] + this.children().splice(index, 1) + this.node.removeChild(element.node) + element.parent = null } - return this; - }, + return this + } // Returns defs element - defs: function() { - return this._defs || (this._defs = this.put(new SVG.Defs(), 0)); - }, +, defs: function() { + return this._defs || (this._defs = this.put(new SVG.Defs(), 0)) + } // Re-level defs to first positon in element stack - level: function() { - return this.remove(this.defs()).put(this.defs(), 0); - }, +, level: function() { + return this.remove(this.defs()).put(this.defs(), 0) + } // Create a group element - group: function() { - return this.put(new SVG.G()); - }, +, group: function() { + return this.put(new SVG.G()) + } // Create a rect element - rect: function(width, height) { - return this.put(new SVG.Rect().size(width, height)); - }, +, rect: function(width, height) { + return this.put(new SVG.Rect().size(width, height)) + } // Create circle element, based on ellipse - circle: function(diameter) { - return this.ellipse(diameter); - }, +, circle: function(diameter) { + return this.ellipse(diameter) + } // Create an ellipse - ellipse: function(width, height) { - return this.put(new SVG.Ellipse().size(width, height)); - }, +, ellipse: function(width, height) { + return this.put(new SVG.Ellipse().size(width, height)) + } // Create a wrapped polyline element - polyline: function(points) { - return this.put(new SVG.Wrap(new SVG.Polyline())).plot(points); - }, +, polyline: function(points) { + return this.put(new SVG.Wrap(new SVG.Polyline())).plot(points) + } // Create a wrapped polygon element - polygon: function(points) { - return this.put(new SVG.Wrap(new SVG.Polygon())).plot(points); - }, +, polygon: function(points) { + return this.put(new SVG.Wrap(new SVG.Polygon())).plot(points) + } // Create a wrapped path element - path: function(data) { - return this.put(new SVG.Wrap(new SVG.Path())).plot(data); - }, +, path: function(data) { + return this.put(new SVG.Wrap(new SVG.Path())).plot(data) + } // Create image element, load image and set its size - image: function(source, width, height) { - width = width != null ? width : 100; - return this.put(new SVG.Image().load(source).size(width, height != null ? height : width)); - }, +, image: function(source, width, height) { + width = width != null ? width : 100 + return this.put(new SVG.Image().load(source).size(width, height != null ? height : width)) + } // Create text element - text: function(text) { - return this.put(new SVG.Text().text(text)); - }, +, text: function(text) { + return this.put(new SVG.Text().text(text)) + } // Create nested svg document - nested: function() { - return this.put(new SVG.Nested()); - }, +, nested: function() { + return this.put(new SVG.Nested()) + } // Create gradient element in defs - gradient: function(type, block) { - return this.defs().gradient(type, block); - }, +, gradient: function(type, block) { + return this.defs().gradient(type, block) + } // Create pattern element in defs - pattern: function(width, height, block) { - return this.defs().pattern(width, height, block); - }, +, pattern: function(width, height, block) { + return this.defs().pattern(width, height, block) + } // Create masking element - mask: function() { - return this.defs().put(new SVG.Mask()); - }, +, mask: function() { + return this.defs().put(new SVG.Mask()) + } // Get first child, skipping the defs node - first: function() { - return this.children()[0] instanceof SVG.Defs ? this.children()[1] : this.children()[0]; - }, +, first: function() { + return this.children()[0] instanceof SVG.Defs ? this.children()[1] : this.children()[0] + } // Get the last child - last: function() { - return this.children()[this.children().length - 1]; - }, +, last: function() { + return this.children()[this.children().length - 1] + } + // Get the viewBox and calculate the zoom value +, viewbox: function() { + /* act as a getter if there are no arguments */ + if (arguments.length == 0) + return new SVG.ViewBox(this) + + /* otherwise act as a setter */ + return this.attr('viewBox', Array.prototype.slice.call(arguments).join(' ')) + } // Remove all elements in this container - clear: function() { - this._children = []; +, clear: function() { + this._children = [] while (this.node.hasChildNodes()) - this.node.removeChild(this.node.lastChild); + this.node.removeChild(this.node.lastChild) - return this; + return this } -}); \ No newline at end of file +}) \ No newline at end of file diff --git a/src/defs.js b/src/defs.js index 8714663..48a8f28 100644 --- a/src/defs.js +++ b/src/defs.js @@ -1,9 +1,9 @@ // ### The defs node // -SVG.Defs = function Defs() { - this.constructor.call(this, SVG.create('defs')); -}; +SVG.Defs = function() { + this.constructor.call(this, SVG.create('defs')) +} // Inherits from SVG.Container -SVG.Defs.prototype = new SVG.Container(); \ No newline at end of file +SVG.Defs.prototype = new SVG.Container \ No newline at end of file diff --git a/src/doc.js b/src/doc.js index ce67b1c..ac314f3 100644 --- a/src/doc.js +++ b/src/doc.js @@ -1,26 +1,26 @@ // ### This module accounts for the main svg document // -SVG.Doc = function Doc(element) { - this.constructor.call(this, SVG.create('svg')); +SVG.Doc = function(element) { + this.constructor.call(this, SVG.create('svg')) /* ensure the presence of a html element */ this.parent = typeof element == 'string' ? document.getElementById(element) : - element; + element /* set svg element attributes and create the node */ this. attr({ xmlns: SVG.ns, version: '1.1', width: '100%', height: '100%' }). attr('xlink', SVG.xlink, SVG.ns). - defs(); + defs() /* ensure correct rendering for safari */ this.stage(); -}; +} // Inherits from SVG.Container -SVG.Doc.prototype = new SVG.Container(); +SVG.Doc.prototype = new SVG.Container // Hack for safari preventing text to be rendered in one line. // Basically it sets the position of the svg node to absolute @@ -28,35 +28,35 @@ SVG.Doc.prototype = new SVG.Container(); SVG.Doc.prototype.stage = function() { var check, element = this, - wrapper = document.createElement('div'); + wrapper = document.createElement('div') /* set temp wrapper to position relative */ - wrapper.style.cssText = 'position:relative;height:100%;'; + wrapper.style.cssText = 'position:relative;height:100%;' /* put element into wrapper */ - element.parent.appendChild(wrapper); - wrapper.appendChild(element.node); + element.parent.appendChild(wrapper) + wrapper.appendChild(element.node) /* check for dom:ready */ check = function() { if (document.readyState === 'complete') { - element.attr('style', 'position:absolute;'); + element.attr('style', 'position:absolute;') setTimeout(function() { /* set position back to relative */ - element.attr('style', 'position:relative;'); + element.attr('style', 'position:relative;') /* remove temp wrapper */ - element.parent.removeChild(element.node.parentNode); - element.node.parentNode.removeChild(element.node); - element.parent.appendChild(element.node); + element.parent.removeChild(element.node.parentNode) + element.node.parentNode.removeChild(element.node) + element.parent.appendChild(element.node) - }, 5); + }, 5) } else { - setTimeout(check, 10); + setTimeout(check, 10) } - }; + } - check(); + check() - return this; -}; \ No newline at end of file + return this +} \ No newline at end of file diff --git a/src/element.js b/src/element.js index cced952..a44547c 100644 --- a/src/element.js +++ b/src/element.js @@ -2,10 +2,10 @@ // ### Used by nearly every other module // -SVG.Element = function Element(node) { +SVG.Element = function(node) { /* keep reference to the element node */ if (this.node = node) - this.type = node.nodeName; + this.type = node.nodeName /* initialize attribute store with defaults */ this.attrs = { @@ -24,7 +24,7 @@ SVG.Element = function Element(node) { r: 0, rx: 0, ry: 0 - }; + } /* initialize transformation store with defaults */ this.trans = { @@ -35,9 +35,9 @@ SVG.Element = function Element(node) { rotation: 0, skewX: 0, skewY: 0 - }; + } -}; +} // SVG.extend(SVG.Element, { @@ -46,41 +46,41 @@ SVG.extend(SVG.Element, { return this.attr({ x: x, y: y - }); + }) }, // Move element by its center center: function(x, y) { - var box = this.bbox(); + var box = this.bbox() - return this.move(x - box.width / 2, y - box.height / 2); + return this.move(x - box.width / 2, y - box.height / 2) }, // Set element size to given width and height size: function(width, height) { return this.attr({ width: width, height: height - }); + }) }, // Clone element clone: function() { - var clone; + var clone /* if this is a wrapped shape */ if (this instanceof SVG.Wrap) { /* build new wrapped shape */ - clone = this.parent[this.child.node.nodeName](); - clone.attrs = this.attrs; + clone = this.parent[this.child.node.nodeName]() + clone.attrs = this.attrs /* copy child attributes and transformations */ - clone.child.trans = this.child.trans; - clone.child.attr(this.child.attrs).transform({}); + clone.child.trans = this.child.trans + clone.child.attr(this.child.attrs).transform({}) /* re-plot shape */ if (clone.plot) - clone.plot(this.child.attrs[this.child instanceof SVG.Path ? 'd' : 'points']); + clone.plot(this.child.attrs[this.child instanceof SVG.Path ? 'd' : 'points']) } else { - var name = this.node.nodeName; + var name = this.node.nodeName /* invoke shape method with shape-specific arguments */ clone = name == 'rect' ? @@ -93,35 +93,35 @@ SVG.extend(SVG.Element, { this.parent[name](this.content) : name == 'g' ? this.parent.group() : - this.parent[name](); + this.parent[name]() - clone.attr(this.attrs); + clone.attr(this.attrs) } /* copy transformations */ - clone.trans = this.trans; + clone.trans = this.trans /* apply attributes and translations */ - return clone.transform({}); + return clone.transform({}) }, // Remove element remove: function() { - return this.parent != null ? this.parent.remove(this) : void 0; + return this.parent != null ? this.parent.remove(this) : void 0 }, // Get parent document doc: function() { - return this._parent(SVG.Doc); + return this._parent(SVG.Doc) }, // Get parent nested document nested: function() { - return this._parent(SVG.Nested); + return this._parent(SVG.Nested) }, // Set svg element attribute attr: function(a, v, n) { if (arguments.length < 2) { /* apply every attribute individually if an object is passed */ if (typeof a == 'object') - for (v in a) this.attr(v, a[v]); + for (v in a) this.attr(v, a[v]) /* act as a getter for style attributes */ else if (this._isStyle(a)) @@ -129,26 +129,26 @@ SVG.extend(SVG.Element, { this.content : a == 'leading' ? this[a] : - this.style[a]; + this.style[a] /* act as a getter if the first and only argument is not an object */ else - return this.attrs[a]; + return this.attrs[a] } else { /* store value */ - this.attrs[a] = v; + this.attrs[a] = v /* treat x differently on text elements */ if (a == 'x' && this._isText()) for (var i = this.lines.length - 1; i >= 0; i--) - this.lines[i].attr(a, v); + this.lines[i].attr(a, v) /* set the actual attribute */ else n != null ? this.node.setAttributeNS(n, a, v) : - this.node.setAttribute(a, v); + this.node.setAttribute(a, v) /* if the passed argument belongs to the style as well, add it there */ if (this._isStyle(a)) { @@ -156,131 +156,116 @@ SVG.extend(SVG.Element, { this.text(v) : a == 'leading' ? this[a] = v : - this.style[a] = v; + this.style[a] = v - this.text(this.content); + this.text(this.content) } } - return this; + return this }, // Manage transformations transform: function(o) { /* act as a getter if the first argument is a string */ if (typeof o === 'string') - return this.trans[o]; + return this.trans[o] /* ... otherwise continue as a setter */ - var key, transform = []; + var key, transform = [] /* merge values */ for (key in o) if (o[key] != null) - this.trans[key] = o[key]; + this.trans[key] = o[key] /* alias current transformations */ - o = this.trans; + o = this.trans /* add rotation */ if (o.rotation != 0) { - var box = this.bbox(); - transform.push('rotate(' + o.rotation + ',' + (o.cx != null ? o.cx : box.cx) + ',' + (o.cy != null ? o.cy : box.cy) + ')'); + var box = this.bbox() + transform.push('rotate(' + o.rotation + ',' + (o.cx != null ? o.cx : box.cx) + ',' + (o.cy != null ? o.cy : box.cy) + ')') } /* add scale */ - transform.push('scale(' + o.scaleX + ',' + o.scaleY + ')'); + transform.push('scale(' + o.scaleX + ',' + o.scaleY + ')') /* add skew on x axis */ if (o.skewX != 0) - transform.push('skewX(' + o.skewX + ')'); + transform.push('skewX(' + o.skewX + ')') /* add skew on y axis */ if (o.skewY != 0) transform.push('skewY(' + o.skewY + ')') /* add translation */ - transform.push('translate(' + o.x + ',' + o.y + ')'); + transform.push('translate(' + o.x + ',' + o.y + ')') /* add only te required transformations */ - return this.attr('transform', transform.join(' ')); + return this.attr('transform', transform.join(' ')) }, // Store data values on svg nodes data: function(a, v, r) { if (arguments.length < 2) { try { - return JSON.parse(this.attr('data-' + a)); + return JSON.parse(this.attr('data-' + a)) } catch(e) { - return this.attr('data-' + a); - }; + return this.attr('data-' + a) + } } else { v === null ? this.node.removeAttribute('data-' + a) : - this.attr('data-' + a, r === true ? v : JSON.stringify(v)); + this.attr('data-' + a, r === true ? v : JSON.stringify(v)) } - return this; + return this }, // Get bounding box bbox: function() { - /* actual, native bounding box */ - var box = this.node.getBBox(); - - return { - /* include translations on x an y */ - x: box.x + this.trans.x, - y: box.y + this.trans.y, - - /* add the center */ - cx: box.x + this.trans.x + box.width / 2, - cy: box.y + this.trans.y + box.height / 2, - - /* plain width and height */ - width: box.width, - height: box.height - }; + return new SVG.BBox(this) }, // Checks whether the given point inside the bounding box of the element inside: function(x, y) { - var box = this.bbox(); + var box = this.bbox() return x > box.x && y > box.y && x < box.x + box.width && - y < box.y + box.height; + y < box.y + box.height }, // Show element show: function() { - this.node.style.display = ''; + this.node.style.display = '' - return this; + return this }, // Hide element hide: function() { - this.node.style.display = 'none'; + this.node.style.display = 'none' - return this; + return this }, // Is element visible? visible: function() { - return this.node.style.display != 'none'; + return this.node.style.display != 'none' }, // Private: find svg parent by instance _parent: function(parent) { - var element = this; + var element = this while (element != null && !(element instanceof parent)) - element = element.parent; + element = element.parent - return element; + return element }, // Private: tester method for style detection _isStyle: function(attr) { - return typeof attr == 'string' && this._isText() ? (/^font|text|leading/).test(attr) : false; + return typeof attr == 'string' && this._isText() ? (/^font|text|leading/).test(attr) : false }, // Private: element type tester _isText: function() { - return this instanceof SVG.Text; + return this instanceof SVG.Text } -}); +}) diff --git a/src/ellipse.js b/src/ellipse.js index ad3e02e..f9398cf 100644 --- a/src/ellipse.js +++ b/src/ellipse.js @@ -1,36 +1,36 @@ // -SVG.Ellipse = function Ellipse() { - this.constructor.call(this, SVG.create('ellipse')); -}; +SVG.Ellipse = function() { + this.constructor.call(this, SVG.create('ellipse')) +} // Inherit from SVG.Shape -SVG.Ellipse.prototype = new SVG.Shape(); +SVG.Ellipse.prototype = new SVG.Shape() // SVG.extend(SVG.Ellipse, { // Custom move function move: function(x, y) { - this.attrs.x = x; - this.attrs.y = y; + this.attrs.x = x + this.attrs.y = y - return this.center(); + return this.center() }, // Custom size function size: function(width, height) { return this. attr({ rx: width / 2, ry: (height != null ? height : width) / 2 }). - center(); + center() }, // Custom center function center: function(x, y) { return this.attr({ cx: x || (this.attrs.x || 0) + (this.attrs.rx || 0), cy: y || (this.attrs.y || 0) + (this.attrs.ry || 0) - }); + }) } -}); +}) // Usage: -// draw.ellipse(200, 100); \ No newline at end of file +// draw.ellipse(200, 100) \ No newline at end of file diff --git a/src/event.js b/src/event.js index a2bb3f0..df3cd6a 100644 --- a/src/event.js +++ b/src/event.js @@ -1,9 +1,9 @@ // ### Manage events on elements // rect.click(function() { -// this.fill({ color: '#f06' }); -// }); -[ 'click', +// this.fill({ color: '#f06' }) +// }) +;[ 'click', 'dblclick', 'mousedown', 'mouseup', @@ -19,46 +19,46 @@ /* add event to SVG.Element */ SVG.Element.prototype[event] = function(f) { - var self = this; + var self = this /* bind event to element rather than element node */ this.node['on' + event] = typeof f == 'function' ? function() { return f.apply(self, arguments); } - : null; + : null - return this; - }; + return this + } -}); +}) // Add event binder in the SVG namespace SVG.on = function(node, event, listener) { if (node.addEventListener) - node.addEventListener(event, listener, false); + node.addEventListener(event, listener, false) else - node.attachEvent('on' + event, listener); -}; + node.attachEvent('on' + event, listener) +} // Add event unbinder in the SVG namespace SVG.off = function(node, event, listener) { if (node.removeEventListener) - node.removeEventListener(event, listener, false); + node.removeEventListener(event, listener, false) else - node.detachEvent('on' + event, listener); -}; + node.detachEvent('on' + event, listener) +} // SVG.extend(SVG.Element, { // Bind given event to listener on: function(event, listener) { - SVG.on(this.node, event, listener); + SVG.on(this.node, event, listener) - return this; + return this }, // Unbind event from listener off: function(event, listener) { - SVG.off(this.node, event, listener); + SVG.off(this.node, event, listener) - return this; + return this } }); \ No newline at end of file diff --git a/src/fx.js b/src/fx.js index a3ae5ec..7aa60a9 100644 --- a/src/fx.js +++ b/src/fx.js @@ -1,44 +1,44 @@ -SVG.FX = function FX(element) { +SVG.FX = function(element) { /* store target element */ - this.target = element; -}; + this.target = element +} // SVG.extend(SVG.FX, { // Add animation parameters and start animation animate: function(duration, ease) { /* ensure default duration and easing */ - duration = duration == null ? 1000 : duration; - ease = ease || '<>'; + duration = duration == null ? 1000 : duration + ease = ease || '<>' var akeys, tkeys, tvalues, element = this.target, fx = this, start = (new Date).getTime(), - finish = start + duration; + finish = start + duration /* start animation */ this.interval = setInterval(function(){ // This code was borrowed from the emile.js micro framework by Thomas Fuchs, aka MadRobby. var index, time = (new Date).getTime(), - pos = time > finish ? 1 : (time - start) / duration; + pos = time > finish ? 1 : (time - start) / duration /* collect attribute keys */ if (akeys == null) { - akeys = []; + akeys = [] for (var key in fx.attrs) - akeys.push(key); - }; + akeys.push(key) + } /* collect transformation keys */ if (tkeys == null) { - tkeys = []; + tkeys = [] for (var key in fx.trans) - tkeys.push(key); + tkeys.push(key) - tvalues = {}; - }; + tvalues = {} + } /* apply easing */ pos = ease == '<>' ? @@ -51,110 +51,110 @@ SVG.extend(SVG.FX, { pos : typeof ease == 'function' ? ease(pos) : - pos; + pos /* run all position properties */ if (fx._move) - element.move(fx._at(fx._move.x, pos), fx._at(fx._move.y, pos)); + element.move(fx._at(fx._move.x, pos), fx._at(fx._move.y, pos)) else if (fx._center) - element.move(fx._at(fx._center.x, pos), fx._at(fx._center.y, pos)); + element.move(fx._at(fx._center.x, pos), fx._at(fx._center.y, pos)) /* run all size properties */ if (fx._size) - element.size(fx._at(fx._size.width, pos), fx._at(fx._size.height, pos)); + element.size(fx._at(fx._size.width, pos), fx._at(fx._size.height, pos)) /* animate attributes */ for (index = akeys.length - 1; index >= 0; index--) - element.attr(akeys[index], fx._at(fx.attrs[akeys[index]], pos)); + element.attr(akeys[index], fx._at(fx.attrs[akeys[index]], pos)) /* animate transformations */ if (tkeys.length > 0) { for (index = tkeys.length - 1; index >= 0; index--) - tvalues[tkeys[index]] = fx._at(fx.trans[tkeys[index]], pos); + tvalues[tkeys[index]] = fx._at(fx.trans[tkeys[index]], pos) - element.transform(tvalues); + element.transform(tvalues) } /* finish off animation */ if (time > finish) { - clearInterval(fx.interval); - fx._after ? fx._after.apply(element, [fx]) : fx.stop(); + clearInterval(fx.interval) + fx._after ? fx._after.apply(element, [fx]) : fx.stop() } - }, duration > 10 ? 10 : duration); + }, duration > 10 ? 10 : duration) - return this; + return this }, // Add animatable attributes attr: function(a, v, n) { if (typeof a == 'object') for (var key in a) - this.attr(key, a[key]); + this.attr(key, a[key]) else - this.attrs[a] = { from: this.target.attr(a), to: v }; + this.attrs[a] = { from: this.target.attr(a), to: v } return this; }, // Add animatable transformations transform: function(o) { for (var key in o) - this.trans[key] = { from: this.target.trans[key], to: o[key] }; + this.trans[key] = { from: this.target.trans[key], to: o[key] } - return this; + return this }, // Add animatable move move: function(x, y) { - var box = this.target.bbox(); + var box = this.target.bbox() this._move = { x: { from: box.x, to: x }, y: { from: box.y, to: y } - }; + } - return this; + return this }, // Add animatable size size: function(width, height) { - var box = this.target.bbox(); + var box = this.target.bbox() this._size = { width: { from: box.width, to: width }, height: { from: box.height, to: height } - }; + } - return this; + return this }, // Add animatable center center: function(x, y) { - var box = this.target.bbox(); + var box = this.target.bbox() this._move = { x: { from: box.cx, to: x }, y: { from: box.cy, to: y } - }; + } - return this; + return this }, // Callback after animation after: function(after) { - this._after = after; + this._after = after - return this; + return this }, // Stop running animation stop: function() { /* stop current animation */ - clearInterval(this.interval); + clearInterval(this.interval) /* reset storage for properties that need animation */ - this.attrs = {}; - this.trans = {}; - this._move = null; - this._size = null; - this._after = null; + this.attrs = {} + this.trans = {} + this._move = null + this._size = null + this._after = null - return this; + return this }, // Private: at position according to from and to _at: function(o, pos) { @@ -167,45 +167,45 @@ SVG.extend(SVG.FX, { this._color(o, pos) : /* for all other values wait until pos has reached 1 to return the final value */ - pos < 1 ? o.from : o.to; + pos < 1 ? o.from : o.to }, // Private: tween color _color: function(o, pos) { - var from, to; + var from, to /* convert FROM hex to rgb */ - from = this._h2r(o.from || '#000'); + from = this._h2r(o.from || '#000') /* convert TO hex to rgb */ - to = this._h2r(o.to); + to = this._h2r(o.to) /* tween color and return hex */ return this._r2h({ r: ~~(from.r + (to.r - from.r) * pos), g: ~~(from.g + (to.g - from.g) * pos), b: ~~(from.b + (to.b - from.b) * pos) - }); + }) }, // Private: convert hex to rgb object _h2r: function(hex) { /* parse full hex */ - var match = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(this._fh(hex)); + var match = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(this._fh(hex)) /* if the hex is successfully parsed, return it in rgb, otherwise return black */ return match ? { r: parseInt(match[1], 16), g: parseInt(match[2], 16), b: parseInt(match[3], 16) - } : { r: 0, g: 0, b: 0 }; + } : { r: 0, g: 0, b: 0 } }, // Private: convert rgb object to hex string _r2h: function(rgb) { - return '#' + this._c2h(rgb.r) + this._c2h(rgb.g) + this._c2h(rgb.b); + return '#' + this._c2h(rgb.r) + this._c2h(rgb.g) + this._c2h(rgb.b) }, // Private: convert component to hex _c2h: function(c) { - var hex = c.toString(16); - return hex.length == 1 ? '0' + hex : hex; + var hex = c.toString(16) + return hex.length == 1 ? '0' + hex : hex }, // Private: force potential 3-based hex to 6-based _fh: function(hex) { @@ -214,26 +214,26 @@ SVG.extend(SVG.FX, { hex.substring(1, 2), hex.substring(1, 2), hex.substring(2, 3), hex.substring(2, 3), hex.substring(3, 4), hex.substring(3, 4) - ].join('') : hex; + ].join('') : hex } -}); +}) // SVG.extend(SVG.Element, { // Get fx module or create a new one, then animate with given duration and ease animate: function(duration, ease) { - return (this.fx || (this.fx = new SVG.FX(this))).stop().animate(duration, ease); + return (this.fx || (this.fx = new SVG.FX(this))).stop().animate(duration, ease) }, // Stop current animation; this is an alias to the fx instance stop: function() { - this.fx.stop(); + this.fx.stop() - return this; + return this } -}); +}) // Usage: // rect.animate(1500, '>').move(200, 300).after(function() { -// this.fill({ color: '#f06' }); -// }); +// this.fill({ color: '#f06' }) +// }) diff --git a/src/gradient.js b/src/gradient.js index 07bb748..f3ba85c 100644 --- a/src/gradient.js +++ b/src/gradient.js @@ -1,15 +1,15 @@ -SVG.Gradient = function Gradient(type) { - this.constructor.call(this, SVG.create(type + 'Gradient')); +SVG.Gradient = function(type) { + this.constructor.call(this, SVG.create(type + 'Gradient')) /* set unique id */ - this.attr('id', (this.id = 'svgjs_element_' + (SVG.did++))); + this.attr('id', (this.id = 'svgjs_element_' + (SVG.did++))) /* store type */ - this.type = type; -}; + this.type = type +} // Inherit from SVG.Container -SVG.Gradient.prototype = new SVG.Container(); +SVG.Gradient.prototype = new SVG.Container // SVG.extend(SVG.Gradient, { @@ -17,67 +17,67 @@ SVG.extend(SVG.Gradient, { from: function(x, y) { return this.type == 'radial' ? this.attr({ fx: x + '%', fy: y + '%' }) : - this.attr({ x1: x + '%', y1: y + '%' }); + this.attr({ x1: x + '%', y1: y + '%' }) }, // To position to: function(x, y) { return this.type == 'radial' ? this.attr({ cx: x + '%', cy: y + '%' }) : - this.attr({ x2: x + '%', y2: y + '%' }); + this.attr({ x2: x + '%', y2: y + '%' }) }, // Radius for radial gradient radius: function(radius) { return this.type == 'radial' ? this.attr({ r: radius + '%' }) : - this; + this }, // Add a color stop at: function(stop) { - return this.put(new SVG.Stop(stop)); + return this.put(new SVG.Stop(stop)) }, // Update gradient update: function(block) { /* remove all stops */ while (this.node.hasChildNodes()) - this.node.removeChild(this.node.lastChild); + this.node.removeChild(this.node.lastChild) /* invoke passed block */ - block(this); + block(this) - return this; + return this }, // Return the fill id fill: function() { - return 'url(#' + this.id + ')'; + return 'url(#' + this.id + ')' } -}); +}) // SVG.extend(SVG.Defs, { /* define gradient */ gradient: function(type, block) { - var element = this.put(new SVG.Gradient(type)); + var element = this.put(new SVG.Gradient(type)) /* invoke passed block */ - block(element); + block(element) - return element; + return element } -}); +}) -SVG.Stop = function Stop(stop) { - this.constructor.call(this, SVG.create('stop')); +SVG.Stop = function(stop) { + this.constructor.call(this, SVG.create('stop')) /* immediatelly build stop */ - this.update(stop); -}; + this.update(stop) +} // Inherit from SVG.Element -SVG.Stop.prototype = new SVG.Element(); +SVG.Stop.prototype = new SVG.Element() // SVG.extend(SVG.Stop, { @@ -86,19 +86,19 @@ SVG.extend(SVG.Stop, { update: function(o) { var index, style = '', - attr = ['opacity', 'color']; + attr = ['opacity', 'color'] /* build style attribute */ for (index = attr.length - 1; index >= 0; index--) if (o[attr[index]] != null) - style += 'stop-' + attr[index] + ':' + o[attr[index]] + ';'; + style += 'stop-' + attr[index] + ':' + o[attr[index]] + ';' /* set attributes */ return this.attr({ offset: (o.offset != null ? o.offset : this.attrs.offset || 0) + '%', style: style - }); + }) } -}); +}) diff --git a/src/group.js b/src/group.js index 5c6df10..3fc8f88 100644 --- a/src/group.js +++ b/src/group.js @@ -1,14 +1,14 @@ -SVG.G = function G() { - this.constructor.call(this, SVG.create('g')); -}; +SVG.G = function() { + this.constructor.call(this, SVG.create('g')) +} // Inherit from SVG.Container -SVG.G.prototype = new SVG.Container(); +SVG.G.prototype = new SVG.Container SVG.extend(SVG.G, { // Get defs defs: function() { - return this.doc().defs(); + return this.doc().defs() } -}); \ No newline at end of file +}) \ No newline at end of file diff --git a/src/image.js b/src/image.js index b9340e4..bc60c0e 100644 --- a/src/image.js +++ b/src/image.js @@ -1,16 +1,16 @@ -SVG.Image = function Image() { - this.constructor.call(this, SVG.create('image')); -}; +SVG.Image = function() { + this.constructor.call(this, SVG.create('image')) +} // Inherit from SVG.Element -SVG.Image.prototype = new SVG.Shape(); +SVG.Image.prototype = new SVG.Shape() SVG.extend(SVG.Image, { /* (re)load image */ load: function(url) { - this.src = url; - return (url ? this.attr('xlink:href', url, SVG.xlink) : this); + this.src = url + return (url ? this.attr('xlink:href', url, SVG.xlink) : this) } -}); \ No newline at end of file +}) \ No newline at end of file diff --git a/src/line.js b/src/line.js index b5dd2ef..1e783e4 100644 --- a/src/line.js +++ b/src/line.js @@ -1,37 +1,37 @@ -SVG.Line = function Line() { - this.constructor.call(this, SVG.create('line')); -}; +SVG.Line = function() { + this.constructor.call(this, SVG.create('line')) +} // Inherit from SVG.Shape -SVG.Line.prototype = new SVG.Shape(); +SVG.Line.prototype = new SVG.Shape() // Add required methods SVG.extend(SVG.Line, { // Move line move: function(x, y) { - var bbox = this.bbox(); + var bbox = this.bbox() return this.attr({ x1: this.attr('x1') - bbox.x + x, y1: this.attr('y1') - bbox.y + y, x2: this.attr('x2') - bbox.x + x, y2: this.attr('y2') - bbox.y + y - }); + }) }, // Move element by its center center: function(x, y) { - var bbox = this.bbox(); + var bbox = this.bbox() - return this.move(x - bbox.width / 2, y - bbox.height / 2); + return this.move(x - bbox.width / 2, y - bbox.height / 2) }, // Set line size by width and height size: function(width, height) { - var bbox = this.bbox(); + var bbox = this.bbox() - this.attr(this.attr('x1') < this.attr('x2') ? 'x2' : 'x1', bbox.x + width); - return this.attr(this.attr('y1') < this.attr('y2') ? 'y2' : 'y1', bbox.y + height); + this.attr(this.attr('x1') < this.attr('x2') ? 'x2' : 'x1', bbox.x + width) + return this.attr(this.attr('y1') < this.attr('y2') ? 'y2' : 'y1', bbox.y + height) } -}); +}) // Extend all container modules SVG.extend(SVG.Container, { @@ -41,6 +41,6 @@ SVG.extend(SVG.Container, { y1: y1, x2: x2, y2: y2 - })); + })) } -}); \ No newline at end of file +}) \ No newline at end of file diff --git a/src/mask.js b/src/mask.js index c33b93a..708b982 100644 --- a/src/mask.js +++ b/src/mask.js @@ -1,21 +1,21 @@ -SVG.Mask = function Mask() { - this.constructor.call(this, SVG.create('mask')); +SVG.Mask = function() { + this.constructor.call(this, SVG.create('mask')) /* set unique id */ - this.attr('id', (this.id = 'svgjs_element_' + (SVG.did++))); -}; + this.attr('id', (this.id = 'svgjs_element_' + (SVG.did++))) +} // Inherit from SVG.Container -SVG.Mask.prototype = new SVG.Container(); +SVG.Mask.prototype = new SVG.Container SVG.extend(SVG.Element, { // Distribute mask to svg element maskWith: function(element) { /* use given mask or create a new one */ - this.mask = element instanceof SVG.Mask ? element : this.parent.mask().add(element); + this.mask = element instanceof SVG.Mask ? element : this.parent.mask().add(element) - return this.attr('mask', 'url(#' + this.mask.id + ')'); + return this.attr('mask', 'url(#' + this.mask.id + ')') } -}); \ No newline at end of file +}) \ No newline at end of file diff --git a/src/nested.js b/src/nested.js index d2aafdb..45820f2 100644 --- a/src/nested.js +++ b/src/nested.js @@ -1,7 +1,7 @@ -SVG.Nested = function Nested() { - this.constructor.call(this, SVG.create('svg')); - this.attr('overflow', 'visible'); -}; +SVG.Nested = function() { + this.constructor.call(this, SVG.create('svg')) + this.attr('overflow', 'visible') +} // Inherit from SVG.Container -SVG.Nested.prototype = new SVG.Container(); \ No newline at end of file +SVG.Nested.prototype = new SVG.Container \ No newline at end of file diff --git a/src/path.js b/src/path.js index 5d7a3a5..e62f8d1 100644 --- a/src/path.js +++ b/src/path.js @@ -1,9 +1,9 @@ -SVG.Path = function Path() { - this.constructor.call(this, SVG.create('path')); -}; +SVG.Path = function() { + this.constructor.call(this, SVG.create('path')) +} // Inherit from SVG.Shape -SVG.Path.prototype = new SVG.Shape(); +SVG.Path.prototype = new SVG.Shape() SVG.extend(SVG.Path, { @@ -12,12 +12,12 @@ SVG.extend(SVG.Path, { this.transform({ x: x, y: y - }); + }) }, /* set path data */ plot: function(data) { - return this.attr('d', data || 'M0,0'); + return this.attr('d', data || 'M0,0') } }); \ No newline at end of file diff --git a/src/pattern.js b/src/pattern.js index c12978e..82a2339 100644 --- a/src/pattern.js +++ b/src/pattern.js @@ -1,31 +1,31 @@ -SVG.Pattern = function Pattern(type) { - this.constructor.call(this, SVG.create('pattern')); +SVG.Pattern = function(type) { + this.constructor.call(this, SVG.create('pattern')) /* set unique id */ - this.attr('id', (this.id = 'svgjs_element_' + (SVG.did++))); -}; + this.attr('id', (this.id = 'svgjs_element_' + (SVG.did++))) +} // Inherit from SVG.Container -SVG.Pattern.prototype = new SVG.Container(); +SVG.Pattern.prototype = new SVG.Container // SVG.extend(SVG.Pattern, { // Return the fill id fill: function() { - return 'url(#' + this.id + ')'; + return 'url(#' + this.id + ')' } -}); +}) // SVG.extend(SVG.Defs, { /* define gradient */ pattern: function(width, height, block) { - var element = this.put(new SVG.Pattern()); + var element = this.put(new SVG.Pattern()) /* invoke passed block */ - block(element); + block(element) return element.attr({ x: 0, @@ -33,7 +33,7 @@ SVG.extend(SVG.Defs, { width: width, height: height, patternUnits: 'userSpaceOnUse' - }); + }) } }); \ No newline at end of file diff --git a/src/poly.js b/src/poly.js index 395b0bf..9e89570 100644 --- a/src/poly.js +++ b/src/poly.js @@ -1,28 +1,28 @@ SVG.Poly = { // Set polygon data with default zero point if no data is passed plot: function(points) { - this.attr('points', points || '0,0'); + this.attr('points', points || '0,0') - return this; + return this } -}; +} -SVG.Polyline = function Polyline() { - this.constructor.call(this, SVG.create('polyline')); -}; +SVG.Polyline = function() { + this.constructor.call(this, SVG.create('polyline')) +} // Inherit from SVG.Shape -SVG.Polyline.prototype = new SVG.Shape(); +SVG.Polyline.prototype = new SVG.Shape() // Add polygon-specific functions -SVG.extend(SVG.Polyline, SVG.Poly); +SVG.extend(SVG.Polyline, SVG.Poly) -SVG.Polygon = function Polygon() { - this.constructor.call(this, SVG.create('polygon')); -}; +SVG.Polygon = function() { + this.constructor.call(this, SVG.create('polygon')) +} // Inherit from SVG.Shape -SVG.Polygon.prototype = new SVG.Shape(); +SVG.Polygon.prototype = new SVG.Shape() // Add polygon-specific functions -SVG.extend(SVG.Polygon, SVG.Poly); \ No newline at end of file +SVG.extend(SVG.Polygon, SVG.Poly) \ No newline at end of file diff --git a/src/rect.js b/src/rect.js index 3f42558..0a398be 100644 --- a/src/rect.js +++ b/src/rect.js @@ -1,6 +1,6 @@ -SVG.Rect = function Rect() { - this.constructor.call(this, SVG.create('rect')); -}; +SVG.Rect = function() { + this.constructor.call(this, SVG.create('rect')) +} // Inherit from SVG.Shape -SVG.Rect.prototype = new SVG.Shape(); \ No newline at end of file +SVG.Rect.prototype = new SVG.Shape() \ No newline at end of file diff --git a/src/shape.js b/src/shape.js index a6be4c7..a11bbc4 100644 --- a/src/shape.js +++ b/src/shape.js @@ -1,6 +1,6 @@ -SVG.Shape = function Shape(element) { - this.constructor.call(this, element); -}; +SVG.Shape = function(element) { + this.constructor.call(this, element) +} // Inherit from SVG.Element -SVG.Shape.prototype = new SVG.Element(); \ No newline at end of file +SVG.Shape.prototype = new SVG.Element() \ No newline at end of file diff --git a/src/sugar.js b/src/sugar.js index c8b71fb..e076491 100644 --- a/src/sugar.js +++ b/src/sugar.js @@ -1,65 +1,65 @@ // Define list of available attributes for stroke and fill -SVG._stroke = ['color', 'width', 'opacity', 'linecap', 'linejoin', 'miterlimit', 'dasharray', 'dashoffset']; -SVG._fill = ['color', 'opacity', 'rule']; +SVG._stroke = ['color', 'width', 'opacity', 'linecap', 'linejoin', 'miterlimit', 'dasharray', 'dashoffset'] +SVG._fill = ['color', 'opacity', 'rule'] // Prepend correct color prefix var _colorPrefix = function(type, attr) { - return attr == 'color' ? type : type + '-' + attr; -}; + return attr == 'color' ? type : type + '-' + attr +} /* Add sugar for fill and stroke */ -['fill', 'stroke'].forEach(function(method) { +;['fill', 'stroke'].forEach(function(method) { // Set fill color and opacity SVG.Shape.prototype[method] = function(o) { - var index; + var indexOf if (typeof o == 'string') - this.attr(method, o); + this.attr(method, o) else /* set all attributes from _fillAttr and _strokeAttr list */ for (index = SVG['_' + method].length - 1; index >= 0; index--) if (o[SVG['_' + method][index]] != null) - this.attr(_colorPrefix(method, SVG['_' + method][index]), o[SVG['_' + method][index]]); + this.attr(_colorPrefix(method, SVG['_' + method][index]), o[SVG['_' + method][index]]) - return this; - }; + return this + } -}); +}) -[SVG.Element, SVG.FX].forEach(function(module) { +;[SVG.Element, SVG.FX].forEach(function(module) { if (module) { SVG.extend(module, { // Rotation rotate: function(angle) { return this.transform({ rotation: angle || 0 - }); + }) }, // Skew skew: function(x, y) { return this.transform({ skewX: x || 0, skewY: y || 0 - }); + }) }, // Scale scale: function(x, y) { return this.transform({ scaleX: x, scaleY: y == null ? x : y - }); + }) }, // Opacity opacity: function(value) { - return this.attr('opacity', value); + return this.attr('opacity', value) } - }); + }) } -}); +}) if (SVG.G) { SVG.extend(SVG.G, { @@ -68,17 +68,17 @@ if (SVG.G) { return this.transform({ x: x, y: y - }); + }) } - }); + }) } if (SVG.Text) { SVG.extend(SVG.Text, { // Set font font: function(o) { - var key, attr = {}; + var key, attr = {} for (key in o) key == 'leading' ? @@ -87,11 +87,11 @@ if (SVG.Text) { attr['text-anchor'] = o[key] : _styleAttr.indexOf(key) > -1 ? attr['font-'+ key] = o[key] : - void 0; + void 0 - return this.attr(attr).text(this.content); + return this.attr(attr).text(this.content) } - }); + }) } diff --git a/src/svg.js b/src/svg.js index d8088be..f017e77 100644 --- a/src/svg.js +++ b/src/svg.js @@ -1,16 +1,16 @@ // Use the `svg()` function to create a SVG document within a given html element. The first argument can either be an id of the element or the selected element itself. // -// var draw = svg('paper').size(300, 300); -// var rect = draw.rect(100, 100).attr({ fill: '#f06' }); +// var draw = svg('paper').size(300, 300) +// var rect = draw.rect(100, 100).attr({ fill: '#f06' }) // Shortcut for creating a svg document this.svg = function(element) { if (SVG.supported) - return new SVG.Doc(element); -}; + return new SVG.Doc(element) +} // The main wrapping element this.SVG = { @@ -23,20 +23,20 @@ this.SVG = { // Method for element creation , create: function(element) { - return document.createElementNS(this.ns, element); + return document.createElementNS(this.ns, element) } // Method for extending objects , extend: function(object, module) { for (var key in module) - object.prototype[key] = module[key]; + object.prototype[key] = module[key] } -}; +} // svg support test SVG.supported = (function() { return !! document.createElementNS && - !! document.createElementNS(SVG.ns,'svg').createSVGRect; -})(); + !! document.createElementNS(SVG.ns,'svg').createSVGRect +})() if (!SVG.supported) return false; \ No newline at end of file diff --git a/src/text.js b/src/text.js index ecd8811..6201269 100644 --- a/src/text.js +++ b/src/text.js @@ -1,85 +1,85 @@ // List font style attributes as they should be applied to style -var _styleAttr = ['size', 'family', 'weight', 'stretch', 'variant', 'style']; +var _styleAttr = ['size', 'family', 'weight', 'stretch', 'variant', 'style'] -SVG.Text = function Text() { - this.constructor.call(this, SVG.create('text')); +SVG.Text = function() { + this.constructor.call(this, SVG.create('text')) /* define default style */ - this.style = { 'font-size': 16, 'font-family': 'Helvetica', 'text-anchor': 'start' }; - this.leading = 1.2; -}; + this.style = { 'font-size': 16, 'font-family': 'Helvetica', 'text-anchor': 'start' } + this.leading = 1.2 +} // Inherit from SVG.Element -SVG.Text.prototype = new SVG.Shape(); +SVG.Text.prototype = new SVG.Shape() SVG.extend(SVG.Text, { // Set the text content text: function(text) { /* update the content */ - this.content = text = text || 'text'; - this.lines = []; + this.content = text = text || 'text' + this.lines = [] var index, length, tspan, style = this._style(), parent = this.doc(), lines = text.split("\n"), - size = this.style['font-size']; + size = this.style['font-size'] /* remove existing child nodes */ while (this.node.hasChildNodes()) - this.node.removeChild(this.node.lastChild); + this.node.removeChild(this.node.lastChild) /* build new lines */ for (index = 0, length = lines.length; index < length; index++) { /* create new tspan and set attributes */ - tspan = new TSpan(). + tspan = new SVG.TSpan(). text(lines[index]). attr({ dy: size * this.leading - (index == 0 ? size * 0.3 : 0), x: (this.attrs.x || 0), style: style - }); + }) /* add new tspan */ - this.node.appendChild(tspan.node); - this.lines.push(tspan); - }; + this.node.appendChild(tspan.node) + this.lines.push(tspan) + } /* set style */ - return this.attr('style', style); + return this.attr('style', style) }, // Build style based on _styleAttr _style: function() { - var index, style = ''; + var index, style = '' for (index = _styleAttr.length - 1; index >= 0; index--) if (this.style['font-' + _styleAttr[index]] != null) - style += 'font-' + _styleAttr[index] + ':' + this.style['font-' + _styleAttr[index]] + ';'; + style += 'font-' + _styleAttr[index] + ':' + this.style['font-' + _styleAttr[index]] + ';' - style += 'text-anchor:' + this.style['text-anchor'] + ';'; + style += 'text-anchor:' + this.style['text-anchor'] + ';' - return style; + return style } -}); +}) -function TSpan() { - this.constructor.call(this, SVG.create('tspan')); -}; +SVG.TSpan = function() { + this.constructor.call(this, SVG.create('tspan')) +} // Inherit from SVG.Shape -TSpan.prototype = new SVG.Shape(); +SVG.TSpan.prototype = new SVG.Shape() // Include the container object -SVG.extend(TSpan, { +SVG.extend(SVG.TSpan, { // Set text content text: function(text) { - this.node.appendChild(document.createTextNode(text)); + this.node.appendChild(document.createTextNode(text)) - return this; + return this } }); \ No newline at end of file diff --git a/src/viewbox.js b/src/viewbox.js new file mode 100644 index 0000000..b6ccfab --- /dev/null +++ b/src/viewbox.js @@ -0,0 +1,35 @@ + +SVG.ViewBox = function(element) { + var width, height + , box = element.bbox() + , view = (element.attr('viewBox') || '').match(/[\d\.]+/g) + + /* clone attributes */ + this.x = box.x + this.y = box.y + this.width = box.width + this.height = box.height + + if (view) { + /* get width and height from viewbox */ + width = parseFloat(view[2]) + height = parseFloat(view[3]) + + /* calculate real pixel dimensions on parent SVG.Doc element */ + if (element instanceof SVG.Doc) { + this.x = 0 + this.y = 0 + this.width = element.node.offsetWidth + this.height = element.node.offsetHeight + } + + /* calculate zoom accoring to viewbox */ + this.scale = (this.width / this.height > width / height) ? + this.height / height : + this.width / width + + } else { + this.scale = 1 + } + +} \ No newline at end of file diff --git a/src/wrap.js b/src/wrap.js index be343a3..d3c6b8f 100644 --- a/src/wrap.js +++ b/src/wrap.js @@ -1,14 +1,14 @@ -SVG.Wrap = function Wrap(element) { - this.constructor.call(this, SVG.create('g')); +SVG.Wrap = function(element) { + this.constructor.call(this, SVG.create('g')) /* insert and store child */ - this.node.insertBefore(element.node, null); - this.child = element; - this.type = element.node.nodeName; -}; + this.node.insertBefore(element.node, null) + this.child = element + this.type = element.node.nodeName +} // inherit from SVG.Shape -SVG.Wrap.prototype = new SVG.Shape(); +SVG.Wrap.prototype = new SVG.Shape() SVG.extend(SVG.Wrap, { // Move wrapper around @@ -16,66 +16,66 @@ SVG.extend(SVG.Wrap, { return this.transform({ x: x, y: y - }); + }) }, // Set the actual size in pixels size: function(width, height) { - var scale = width / this._b.width; + var scale = width / this._b.width this.child.transform({ scaleX: scale, scaleY: height != null ? height / this._b.height : scale - }); + }) - return this; + return this }, // Move by center center: function(x, y) { return this.move( x + (this._b.width * this.child.trans.scaleX) / -2, y + (this._b.height * this.child.trans.scaleY) / -2 - ); + ) }, // Create distributed attr attr: function(a, v, n) { /* call individual attributes if an object is given */ if (typeof a == 'object') { - for (v in a) this.attr(v, a[v]); + for (v in a) this.attr(v, a[v]) /* act as a getter if only one argument is given */ } else if (arguments.length < 2) { - return a == 'transform' ? this.attrs[a] : this.child.attrs[a]; + return a == 'transform' ? this.attrs[a] : this.child.attrs[a] /* apply locally for certain attributes */ } else if (a == 'transform') { - this.attrs[a] = v; + this.attrs[a] = v n != null ? this.node.setAttributeNS(n, a, v) : - this.node.setAttribute(a, v); + this.node.setAttribute(a, v) /* apply attributes to child */ } else { - this.child.attr(a, v, n); + this.child.attr(a, v, n) } - return this; + return this }, // Distribute plot method to child plot: function(data) { /* plot new shape */ - this.child.plot(data); + this.child.plot(data) /* get and store new bbox */ - this._b = this.child.bbox(); + this._b = this.child.bbox() /* reposition element withing wrapper */ this.child.transform({ x: -this._b.x, y: -this._b.y - }); + }) - return this; + return this } -}); \ No newline at end of file +}) \ No newline at end of file -- cgit v1.2.3