diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/adopter.js | 23 | ||||
-rwxr-xr-x | src/arrange.js | 16 | ||||
-rwxr-xr-x | src/clip.js | 8 | ||||
-rwxr-xr-x | src/doc.js | 81 | ||||
-rwxr-xr-x | src/element.js | 85 | ||||
-rwxr-xr-x | src/event.js | 11 | ||||
-rw-r--r-- | src/helpers.js | 5 | ||||
-rwxr-xr-x | src/hyperlink.js | 2 | ||||
-rwxr-xr-x | src/mask.js | 4 | ||||
-rwxr-xr-x | src/parent.js | 31 | ||||
-rw-r--r-- | src/polyfill.js | 14 | ||||
-rwxr-xr-x | src/rbox.js | 4 | ||||
-rw-r--r-- | src/selector.js | 19 | ||||
-rw-r--r-- | src/spof.js | 31 | ||||
-rwxr-xr-x | src/svg.js | 2 | ||||
-rwxr-xr-x | src/text.js | 1 | ||||
-rw-r--r-- | src/utilities.js | 14 | ||||
-rwxr-xr-x | src/viewbox.js | 8 |
18 files changed, 209 insertions, 150 deletions
diff --git a/src/adopter.js b/src/adopter.js new file mode 100644 index 0000000..c762a2b --- /dev/null +++ b/src/adopter.js @@ -0,0 +1,23 @@ +// Adopt existing svg elements +SVG.adopt = function(node) { + // Make sure a node isn't already adopted + if (node.instance) return node.instance + + // Initialize variables + var element + + // Adopt with element-specific settings + if (node.nodeName == 'svg') + element = node.parentNode instanceof SVGElement ? new SVG.Nested : new SVG.Doc + else if (node.nodeName == 'lineairGradient') + element = new SVG.Gradient('lineair') + else if (node.nodeName == 'radialGradient') + element = new SVG.Gradient('radial') + else + element = new SVG[capitalize(node.nodeName)] + + // Ensure references + element.type = node.nodeName + element.node = node + return node.instance = element +}
\ No newline at end of file diff --git a/src/arrange.js b/src/arrange.js index a48ec5d..5c4e878 100755 --- a/src/arrange.js +++ b/src/arrange.js @@ -4,11 +4,11 @@ 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.parent.index(this) + return this.parent().index(this) } // Get the next element (will return null if there is none) , next: function() { @@ -21,25 +21,25 @@ SVG.extend(SVG.Element, { // Send given element one step forward , forward: function() { var i = this.position() - return this.parent.removeElement(this).put(this, i + 1) + return this.parent().removeElement(this).put(this, i + 1) } // Send given element one step backward , backward: function() { var i = this.position() if (i > 0) - this.parent.removeElement(this).add(this, i - 1) + this.parent().removeElement(this).add(this, i - 1) return this } // Send given element all the way to the front , front: function() { - return this.parent.removeElement(this).put(this) + return this.parent().removeElement(this).put(this) } // Send given element all the way to the back , back: function() { if (this.position() > 0) - this.parent.removeElement(this).add(this, 0) + this.parent().removeElement(this).add(this, 0) return this } @@ -49,7 +49,7 @@ SVG.extend(SVG.Element, { var i = this.position() - this.parent.add(element, i) + this.parent().add(element, i) return this } @@ -59,7 +59,7 @@ SVG.extend(SVG.Element, { var i = this.position() - this.parent.add(element, i + 1) + this.parent().add(element, i + 1) return this } diff --git a/src/clip.js b/src/clip.js index e8a5e35..3fb5daa 100755 --- a/src/clip.js +++ b/src/clip.js @@ -1,4 +1,4 @@ -SVG.Clip = SVG.invent({ +SVG.ClipPath = SVG.invent({ // Initialize node create: function() { this.constructor.call(this, SVG.create('clipPath')) @@ -21,7 +21,7 @@ SVG.Clip = SVG.invent({ delete this.targets /* remove clipPath from parent */ - this.parent.removeElement(this) + this.parent().removeElement(this) return this } @@ -31,7 +31,7 @@ SVG.Clip = SVG.invent({ , construct: { // Create clipping element clip: function() { - return this.defs().put(new SVG.Clip) + return this.defs().put(new SVG.ClipPath) } } }) @@ -41,7 +41,7 @@ SVG.extend(SVG.Element, { // Distribute clipPath to svg element clipWith: function(element) { /* use given clip or create a new one */ - this.clipper = element instanceof SVG.Clip ? element : this.parent.clip().add(element) + this.clipper = element instanceof SVG.ClipPath ? element : this.parent().clip().add(element) /* store reverence on self in mask */ this.clipper.targets.push(this) @@ -1,32 +1,24 @@ SVG.Doc = SVG.invent({ // Initialize node create: function(element) { - /* ensure the presence of a html element */ - this.parent = typeof element == 'string' ? + /* ensure the presence of a dom element */ + element = typeof element == 'string' ? document.getElementById(element) : element /* If the target is an svg element, use that element as the main wrapper. This allows svg.js to work with svg documents as well. */ - this.constructor - .call(this, this.parent.nodeName == 'svg' ? this.parent : SVG.create('svg')) + if (element.nodeName == 'svg') { + this.constructor.call(this, element) + } else { + this.constructor.call(this, SVG.create('svg')) + element.appendChild(this.node) + } /* set svg element attributes */ this .attr({ xmlns: SVG.ns, version: '1.1', width: '100%', height: '100%' }) .attr('xmlns:xlink', SVG.xlink, SVG.xmlns) - - /* create the <defs> node */ - this._defs = new SVG.Defs - this._defs.parent = this - this.node.appendChild(this._defs.node) - - /* turn off sub pixel offset by default */ - this.doSpof = false - - /* ensure correct rendering */ - if (this.parent != this.node) - this.stage() } // Inherit from @@ -34,49 +26,26 @@ SVG.Doc = SVG.invent({ // Add class methods , extend: { - /* enable drawing */ - stage: function() { - var element = this - - /* insert element */ - this.parent.appendChild(this.node) - - /* fix sub-pixel offset */ - element.spof() - - /* make sure sub-pixel offset is fixed every time the window is resized */ - SVG.on(window, 'resize', function() { - element.spof() - }) - - return this - } - // Creates and returns defs element - , defs: function() { - return this._defs - } - - // Fix for possible sub-pixel offset. See: - // https://bugzilla.mozilla.org/show_bug.cgi?id=608812 - , spof: function() { - if (this.doSpof) { - var pos = this.node.getScreenCTM() - - if (pos) - this - .style('left', (-pos.e % 1) + 'px') - .style('top', (-pos.f % 1) + 'px') + defs: function() { + if (!this._defs) { + var defs + + // Find or create a defs element in this instance + if (defs = this.node.getElementsByTagName('defs')[0]) + this._defs = SVG.adopt(defs) + else + this._defs = new SVG.Defs + + // Make sure the defs node is at the end of the stack + this.node.appendChild(this._defs.node) } - - return this - } - - // Enable sub-pixel offset - , fixSubPixelOffset: function() { - this.doSpof = true - return this + return this._defs + } + // custom parent method + , parent: function() { + return this.node.parentNode.nodeName == '#document' ? null : this.node.parentNode } } diff --git a/src/element.js b/src/element.js index b12947b..c8eb5de 100755 --- a/src/element.js +++ b/src/element.js @@ -72,20 +72,20 @@ SVG.Element = SVG.invent({ /* invoke shape method with shape-specific arguments */ clone = type == 'rect' || type == 'ellipse' ? - this.parent[type](0,0) : + this.parent()[type](0,0) : type == 'line' ? - this.parent[type](0,0,0,0) : + this.parent()[type](0,0,0,0) : type == 'image' ? - this.parent[type](this.src) : + this.parent()[type](this.src) : type == 'text' ? - this.parent[type](this.content) : + this.parent()[type](this.content) : type == 'path' ? - this.parent[type](this.attr('d')) : + this.parent()[type](this.attr('d')) : type == 'polyline' || type == 'polygon' ? - this.parent[type](this.attr('points')) : + this.parent()[type](this.attr('points')) : type == 'g' ? - this.parent.group() : - this.parent[type]() + this.parent().group() : + this.parent()[type]() /* apply attributes attributes */ attr = this.attr() @@ -100,8 +100,8 @@ SVG.Element = SVG.invent({ } // Remove element , remove: function() { - if (this.parent) - this.parent.removeElement(this) + if (this.parent()) + this.parent().removeElement(this) return this } @@ -121,7 +121,7 @@ SVG.Element = SVG.invent({ } // Get parent document , doc: function(type) { - return this._parent(type || SVG.Doc) + return this.parent(type || SVG.Doc) } // Set svg element attribute , attr: function(a, v, n) { @@ -346,59 +346,54 @@ SVG.Element = SVG.invent({ } // Return array of classes on the node , classes: function() { - var classAttr = this.node.getAttribute('class') - if (classAttr === null) { - return [] - } else { - return classAttr.trim().split(/\s+/) - } + var attr = this.attr('class') + + return attr == null ? [] : attr.trim().split(/\s+/) } // Return true if class exists on the node, false otherwise - , hasClass: function(className) { - return this.classes().indexOf(className) != -1 + , hasClass: function(name) { + return this.classes().indexOf(name) != -1 } // Add class to the node - , addClass: function(className) { - var classArray - if (!(this.hasClass(className))) { - classArray = this.classes() - classArray.push(className) - this.node.setAttribute('class', classArray.join(' ')) + , addClass: function(name) { + if (!this.hasClass(name)) { + var array = this.classes() + array.push(name) + this.attr('class', array.join(' ')) } + return this } // Remove class from the node - , removeClass: function(className) { - var classArray - if (this.hasClass(className)) { - classArray = this.classes().filter(function(c) { - return c != className + , removeClass: function(name) { + if (this.hasClass(name)) { + var array = this.classes().filter(function(c) { + return c != name }) - this.node.setAttribute('class', classArray.join(' ')) + this.attr('class', array.join(' ')) } + return this } // Toggle the presence of a class on the node - , toggleClass: function(className) { - if (this.hasClass(className)) { - this.removeClass(className) - } else { - this.addClass(className) - } - return this + , toggleClass: function(name) { + return this.hasClass(name) ? this.removeClass(name) : this.addClass(name) } // Get referenced element form attribute value , reference: function(attr) { return SVG.get(this.attr(attr)) } - // Private: find svg parent by instance - , _parent: function(parent) { - var element = this - - while (element != null && !(element instanceof parent)) - element = element.parent + // Returns the parent element instance + , parent: function(type) { + // Get parent element + var parent = SVG.adopt(this.node.parentNode) - return element + // If a specific type is given, find a parent with that class + if (type) + while (!(parent instanceof type)) + parent = SVG.adopt(parent.node.parentNode) + + return parent } } }) diff --git a/src/event.js b/src/event.js index 8430fa0..6108155 100755 --- a/src/event.js +++ b/src/event.js @@ -34,7 +34,7 @@ SVG.listeners = {} // Event constructor SVG.registerEvent = function(event) { if (!SVG.events[event]) - SVG.events[event] = new Event(event) + SVG.events[event] = new CustomEvent(event) } // Add event binder in the SVG namespace @@ -65,9 +65,16 @@ SVG.extend(SVG.Element, { return this } // Fire given event -, fire: function(event) { +, fire: function(event, data) { + // Add detail data to event + SVG.events[event].detail = data + + // Dispatch event this.node.dispatchEvent(SVG.events[event]) + // Remove detail + delete SVG.events[event].detail + return this } })
\ No newline at end of file diff --git a/src/helpers.js b/src/helpers.js index c63c215..492039c 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -5,6 +5,11 @@ function camelCase(s) { }) } +// Capitalize first letter of a string +function capitalize(s) { + return s.charAt(0).toUpperCase() + s.slice(1) +} + // Ensure to six-based hex function fullHex(hex) { return hex.length == 4 ? diff --git a/src/hyperlink.js b/src/hyperlink.js index 1981d52..a967707 100755 --- a/src/hyperlink.js +++ b/src/hyperlink.js @@ -40,7 +40,7 @@ SVG.extend(SVG.Element, { else link.to(url) - return this.parent.put(link).put(this) + return this.parent().put(link).put(this) } })
\ No newline at end of file diff --git a/src/mask.js b/src/mask.js index 84d75b8..73f29c2 100755 --- a/src/mask.js +++ b/src/mask.js @@ -21,7 +21,7 @@ SVG.Mask = SVG.invent({ delete this.targets /* remove mask from parent */ - this.parent.removeElement(this) + this.parent().removeElement(this) return this } @@ -41,7 +41,7 @@ SVG.extend(SVG.Element, { // Distribute mask to svg element maskWith: function(element) { /* use given mask or create a new one */ - this.masker = element instanceof SVG.Mask ? element : this.parent.mask().add(element) + this.masker = element instanceof SVG.Mask ? element : this.parent().mask().add(element) /* store reverence on self in mask */ this.masker.targets.push(this) diff --git a/src/parent.js b/src/parent.js index 44514c2..55878ec 100755 --- a/src/parent.js +++ b/src/parent.js @@ -11,7 +11,9 @@ SVG.Parent = SVG.invent({ , extend: { // Returns all child elements children: function() { - return this._children || (this._children = []) + return SVG.utils.map(this.node.childNodes, function(node) { + return SVG.adopt(node) + }) } // Add given element at a position , add: function(element, i) { @@ -19,22 +21,10 @@ SVG.Parent = SVG.invent({ /* define insertion index if none given */ i = i == null ? this.children().length : i - /* remove references from previous parent */ - if (element.parent) - element.parent.children().splice(element.parent.index(element), 1) - /* add element references */ - this.children().splice(i, 0, element) this.node.insertBefore(element.node, this.node.childNodes[i] || null) - element.parent = this } - /* reposition defs */ - if (this._defs) { - this.node.removeChild(this._defs.node) - this.node.appendChild(this._defs.node) - } - return this } // Basically does the same as `add()` but returns the added element instead @@ -79,25 +69,22 @@ SVG.Parent = SVG.invent({ } // Remove a child element at a position , removeElement: function(element) { - this.children().splice(this.index(element), 1) this.node.removeChild(element.node) - element.parent = null return this } // Remove all elements in this container , clear: function() { - /* remove children */ - for (var i = this.children().length - 1; i >= 0; i--) - this.removeElement(this.children()[i]) + // Remove children + while(this.node.hasChildNodes()) + this.node.removeChild(this.node.lastChild) - /* remove defs node */ - if (this._defs) - this._defs.clear() + // Remove defs cache reference + delete this._defs return this } - , // Get defs + , // Get defs defs: function() { return this.doc().defs() } diff --git a/src/polyfill.js b/src/polyfill.js new file mode 100644 index 0000000..3a3c25c --- /dev/null +++ b/src/polyfill.js @@ -0,0 +1,14 @@ +// Add CustomEvent to IE9 and IE10 +if (typeof CustomEvent !== 'function') { + // Code from: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent + function CustomEvent (event, options) { + options = options || { bubbles: false, cancelable: false, detail: undefined } + var e = document.createEvent('CustomEvent') + e.initCustomEvent(event, options.bubbles, options.cancelable, options.detail) + return e + } + + CustomEvent.prototype = window.Event.prototype + + window.CustomEvent = CustomEvent +}
\ No newline at end of file diff --git a/src/rbox.js b/src/rbox.js index 54e08cb..598b3b4 100755 --- a/src/rbox.js +++ b/src/rbox.js @@ -10,7 +10,7 @@ SVG.RBox = function(element) { this.height = 0 if (element) { - e = element.doc().parent + e = element.doc().parent() zoom = element.doc().viewbox().zoom /* actual, native bounding box */ @@ -31,7 +31,7 @@ SVG.RBox = function(element) { /* calculate cumulative zoom from svg documents */ e = element - while (e = e.parent) { + while (e = e.parent()) { if (e.type == 'svg' && e.viewbox) { zoom *= e.viewbox().zoom this.x -= e.x() || 0 diff --git a/src/selector.js b/src/selector.js index 905e9f9..82aca37 100644 --- a/src/selector.js +++ b/src/selector.js @@ -1,5 +1,20 @@ // Method for getting an element by id SVG.get = function(id) { var node = document.getElementById(idFromReference(id) || id) - if (node) return node.instance -}
\ No newline at end of file + if (node) return SVG.adopt(node) +} + +// Select elements by query string +SVG.select = function(query, parent) { + return SVG.utils.map((parent || document).querySelectorAll(query), function(node) { + return SVG.adopt(node) + }) +} + +SVG.extend(SVG.Parent, { + // Scoped select method + select: function(query) { + return SVG.select(query, this.node) + } + +})
\ No newline at end of file diff --git a/src/spof.js b/src/spof.js new file mode 100644 index 0000000..cf4fe2f --- /dev/null +++ b/src/spof.js @@ -0,0 +1,31 @@ +// Fix for possible sub-pixel offset. See: +// https://bugzilla.mozilla.org/show_bug.cgi?id=608812 +SVG.extend(SVG.Doc, { + // Callback + spof: function() { + if (this.doSpof) { + var pos = this.node.getScreenCTM() + + if (pos) + this + .style('left', (-pos.e % 1) + 'px') + .style('top', (-pos.f % 1) + 'px') + } + + return this + } + + // Sub-pixel offset enabler +, fixSubPixelOffset: function() { + var self = this + + // Enable spof + this.doSpof = true + + // Make sure sub-pixel offset is fixed every time the window is resized + SVG.on(window, 'resize', function() { self.spof() }) + + return this.spof() + } + +})
\ No newline at end of file @@ -67,7 +67,7 @@ SVG.prepare = function(element) { /* create parser object */ SVG.parser = { - body: body || element.parent + body: body || element.parent() , draw: draw.style('opacity:0;position:fixed;left:100%;top:100%;overflow:hidden') , poly: draw.polyline().node , path: path diff --git a/src/text.js b/src/text.js index 1b6bd94..0581f88 100755 --- a/src/text.js +++ b/src/text.js @@ -192,7 +192,6 @@ SVG.extend(SVG.Text, SVG.TSpan, { /* add new tspan and reference */ node.appendChild(tspan.node) - tspan.parent = this /* only first level tspans are considered to be "lines" */ if (this instanceof SVG.Text) diff --git a/src/utilities.js b/src/utilities.js new file mode 100644 index 0000000..4770f9b --- /dev/null +++ b/src/utilities.js @@ -0,0 +1,14 @@ +SVG.utils = { + // Map function + map: function(array, block) { + var i + , il = array.length + , result = [] + + for (i = 0; i < il; i++) + result.push(block(array[i])) + + return result + } + +}
\ No newline at end of file diff --git a/src/viewbox.js b/src/viewbox.js index e8736aa..11a7138 100755 --- a/src/viewbox.js +++ b/src/viewbox.js @@ -15,13 +15,13 @@ SVG.ViewBox = function(element) { /* find nearest non-percentual dimensions */ while (width.unit == '%') { wm *= width.value - width = new SVG.Number(we instanceof SVG.Doc ? we.parent.offsetWidth : we.parent.width()) - we = we.parent + width = new SVG.Number(we instanceof SVG.Doc ? we.parent().offsetWidth : we.parent().width()) + we = we.parent() } while (height.unit == '%') { hm *= height.value - height = new SVG.Number(he instanceof SVG.Doc ? he.parent.offsetHeight : he.parent.height()) - he = he.parent + height = new SVG.Number(he instanceof SVG.Doc ? he.parent().offsetHeight : he.parent().height()) + he = he.parent() } /* ensure defaults */ |