summaryrefslogtreecommitdiffstats
path: root/src/element.js
diff options
context:
space:
mode:
authorwout <wout@impinc.co.uk>2014-02-03 15:14:47 +0100
committerwout <wout@impinc.co.uk>2014-02-03 15:14:47 +0100
commite2304534e0cfb6f6f4ab8c37ea5275ae26cd455a (patch)
tree2386e9f361d9c5fa1308387aeeaf33f00241b3c5 /src/element.js
parent7a29817ffd764cf7ab6906250b57f234801c94e0 (diff)
downloadsvg.js-e2304534e0cfb6f6f4ab8c37ea5275ae26cd455a.tar.gz
svg.js-e2304534e0cfb6f6f4ab8c37ea5275ae26cd455a.zip
Implemented SVG.invent function and bumped to v1.0rc3
Diffstat (limited to 'src/element.js')
-rwxr-xr-xsrc/element.js764
1 files changed, 382 insertions, 382 deletions
diff --git a/src/element.js b/src/element.js
index b75ed32..01146ab 100755
--- a/src/element.js
+++ b/src/element.js
@@ -1,420 +1,420 @@
-// ### Used by nearly every other module
-
-//
-SVG.Element = function(node) {
- /* make stroke value accessible dynamically */
- this._stroke = SVG.defaults.attrs.stroke
-
- /* initialize style store */
- this.styles = {}
-
- /* initialize transformation store with defaults */
- this.trans = SVG.defaults.trans()
-
- /* keep reference to the element node */
- if (this.node = node) {
- this.type = node.nodeName
- this.node.instance = this
- }
-}
-
-//
-SVG.extend(SVG.Element, {
- // Move over x-axis
- x: function(x) {
- if (x) {
- x = new SVG.Number(x)
- x.value /= this.trans.scaleX
- }
- return this.attr('x', x)
- }
- // Move over y-axis
-, y: function(y) {
- if (y) {
- y = new SVG.Number(y)
- y.value /= this.trans.scaleY
- }
- return this.attr('y', y)
- }
- // Move by center over x-axis
-, cx: function(x) {
- return x == null ? this.x() + this.width() / 2 : this.x(x - this.width() / 2)
- }
- // Move by center over y-axis
-, cy: function(y) {
- return y == null ? this.y() + this.height() / 2 : this.y(y - this.height() / 2)
- }
- // Move element to given x and y values
-, move: function(x, y) {
- return this.x(x).y(y)
- }
- // Move element by its center
-, center: function(x, y) {
- return this.cx(x).cy(y)
- }
- // Set width of element
-, width: function(width) {
- return this.attr('width', width)
- }
- // Set height of element
-, height: function(height) {
- return this.attr('height', height)
- }
- // Set element size to given width and height
-, size: function(width, height) {
- var p = this._proportionalSize(width, height)
-
- return this.attr({
- width: new SVG.Number(p.width)
- , height: new SVG.Number(p.height)
- })
- }
- // Clone element
-, clone: function() {
- var clone , attr
- , type = this.type
+SVG.Element = SVG.invent({
+ // Initialize node
+ create: function(node) {
+ /* make stroke value accessible dynamically */
+ this._stroke = SVG.defaults.attrs.stroke
- /* invoke shape method with shape-specific arguments */
- clone = type == 'rect' || type == 'ellipse' ?
- this.parent[type](0,0) :
- type == 'line' ?
- this.parent[type](0,0,0,0) :
- type == 'image' ?
- this.parent[type](this.src) :
- type == 'text' ?
- this.parent[type](this.content) :
- type == 'path' ?
- this.parent[type](this.attr('d')) :
- type == 'polyline' || type == 'polygon' ?
- this.parent[type](this.attr('points')) :
- type == 'g' ?
- this.parent.group() :
- this.parent[type]()
+ /* initialize style store */
+ this.styles = {}
- /* apply attributes attributes */
- attr = this.attr()
- delete attr.id
- clone.attr(attr)
+ /* initialize transformation store with defaults */
+ this.trans = SVG.defaults.trans()
- /* copy transformations */
- clone.trans = this.trans
-
- /* apply attributes and translations */
- return clone.transform({})
- }
- // Remove element
-, remove: function() {
- if (this.parent)
- this.parent.removeElement(this)
-
- return this
+ /* keep reference to the element node */
+ if (this.node = node) {
+ this.type = node.nodeName
+ this.node.instance = this
+ }
}
- // Replace element
-, replace: function(element) {
- this.after(element).remove()
- return element
- }
- // Add element to given container and return self
-, addTo: function(parent) {
- return parent.put(this)
- }
- // Add element to given container and return container
-, putIn: function(parent) {
- return parent.add(this)
- }
- // Get parent document
-, doc: function(type) {
- return this._parent(type || SVG.Doc)
- }
- // Set svg element attribute
-, attr: function(a, v, n) {
- if (a == null) {
- /* get an object of attributes */
- a = {}
- v = this.node.attributes
- for (n = v.length - 1; n >= 0; n--)
- a[v[n].nodeName] = SVG.regex.test(v[n].nodeValue, 'isNumber') ? parseFloat(v[n].nodeValue) : v[n].nodeValue
+ // Add class methods
+, extend: {
+ // Move over x-axis
+ x: function(x) {
+ if (x) {
+ x = new SVG.Number(x)
+ x.value /= this.trans.scaleX
+ }
+ return this.attr('x', x)
+ }
+ // Move over y-axis
+ , y: function(y) {
+ if (y) {
+ y = new SVG.Number(y)
+ y.value /= this.trans.scaleY
+ }
+ return this.attr('y', y)
+ }
+ // Move by center over x-axis
+ , cx: function(x) {
+ return x == null ? this.x() + this.width() / 2 : this.x(x - this.width() / 2)
+ }
+ // Move by center over y-axis
+ , cy: function(y) {
+ return y == null ? this.y() + this.height() / 2 : this.y(y - this.height() / 2)
+ }
+ // Move element to given x and y values
+ , move: function(x, y) {
+ return this.x(x).y(y)
+ }
+ // Move element by its center
+ , center: function(x, y) {
+ return this.cx(x).cy(y)
+ }
+ // Set width of element
+ , width: function(width) {
+ return this.attr('width', width)
+ }
+ // Set height of element
+ , height: function(height) {
+ return this.attr('height', height)
+ }
+ // Set element size to given width and height
+ , size: function(width, height) {
+ var p = this._proportionalSize(width, height)
+
+ return this.attr({
+ width: new SVG.Number(p.width)
+ , height: new SVG.Number(p.height)
+ })
+ }
+ // Clone element
+ , clone: function() {
+ var clone , attr
+ , type = this.type
- return a
+ /* invoke shape method with shape-specific arguments */
+ clone = type == 'rect' || type == 'ellipse' ?
+ this.parent[type](0,0) :
+ type == 'line' ?
+ this.parent[type](0,0,0,0) :
+ type == 'image' ?
+ this.parent[type](this.src) :
+ type == 'text' ?
+ this.parent[type](this.content) :
+ type == 'path' ?
+ this.parent[type](this.attr('d')) :
+ type == 'polyline' || type == 'polygon' ?
+ this.parent[type](this.attr('points')) :
+ type == 'g' ?
+ this.parent.group() :
+ this.parent[type]()
- } else if (typeof a == 'object') {
- /* apply every attribute individually if an object is passed */
- for (v in a) this.attr(v, a[v])
+ /* apply attributes attributes */
+ attr = this.attr()
+ delete attr.id
+ clone.attr(attr)
- } else if (v === null) {
- /* remove value */
- this.node.removeAttribute(a)
+ /* copy transformations */
+ clone.trans = this.trans
- } else if (v == null) {
- /* act as a getter for style attributes */
- if (this._isStyle(a)) {
- return a == 'text' ?
- this.content :
- a == 'leading' && this.leading ?
- this.leading() :
- this.style(a)
+ /* apply attributes and translations */
+ return clone.transform({})
+ }
+ // Remove element
+ , remove: function() {
+ if (this.parent)
+ this.parent.removeElement(this)
- /* act as a getter if the first and only argument is not an object */
- } else {
- v = this.node.getAttribute(a)
- return v == null ?
- SVG.defaults.attrs[a] :
- SVG.regex.test(v, 'isNumber') ?
- parseFloat(v) : v
- }
-
- } else if (a == 'style') {
- /* redirect to the style method */
- return this.style(v)
-
- } else {
- /* treat x differently on text elements */
- if (a == 'x' && Array.isArray(this.lines))
- for (n = this.lines.length - 1; n >= 0; n--)
- this.lines[n].attr(a, v)
+ return this
+ }
+ // Replace element
+ , replace: function(element) {
+ this.after(element).remove()
+
+ return element
+ }
+ // Add element to given container and return self
+ , addTo: function(parent) {
+ return parent.put(this)
+ }
+ // Add element to given container and return container
+ , putIn: function(parent) {
+ return parent.add(this)
+ }
+ // Get parent document
+ , doc: function(type) {
+ return this._parent(type || SVG.Doc)
+ }
+ // Set svg element attribute
+ , attr: function(a, v, n) {
+ if (a == null) {
+ /* get an object of attributes */
+ a = {}
+ v = this.node.attributes
+ for (n = v.length - 1; n >= 0; n--)
+ a[v[n].nodeName] = SVG.regex.test(v[n].nodeValue, 'isNumber') ? parseFloat(v[n].nodeValue) : v[n].nodeValue
+
+ return a
+
+ } else if (typeof a == 'object') {
+ /* apply every attribute individually if an object is passed */
+ for (v in a) this.attr(v, a[v])
+
+ } else if (v === null) {
+ /* remove value */
+ this.node.removeAttribute(a)
+
+ } else if (v == null) {
+ /* act as a getter for style attributes */
+ if (this._isStyle(a)) {
+ return a == 'text' ?
+ this.content :
+ a == 'leading' && this.leading ?
+ this.leading() :
+ this.style(a)
+
+ /* act as a getter if the first and only argument is not an object */
+ } else {
+ v = this.node.getAttribute(a)
+ return v == null ?
+ SVG.defaults.attrs[a] :
+ SVG.regex.test(v, 'isNumber') ?
+ parseFloat(v) : v
+ }
- /* BUG FIX: some browsers will render a stroke if a color is given even though stroke width is 0 */
- if (a == 'stroke-width')
- this.attr('stroke', parseFloat(v) > 0 ? this._stroke : null)
- else if (a == 'stroke')
- this._stroke = v
+ } else if (a == 'style') {
+ /* redirect to the style method */
+ return this.style(v)
- /* ensure full hex color */
- if (SVG.Color.test(v) || SVG.Color.isRgb(v))
- v = new SVG.Color(v)
+ } else {
+ /* treat x differently on text elements */
+ if (a == 'x' && Array.isArray(this.lines))
+ for (n = this.lines.length - 1; n >= 0; n--)
+ this.lines[n].attr(a, v)
+
+ /* BUG FIX: some browsers will render a stroke if a color is given even though stroke width is 0 */
+ if (a == 'stroke-width')
+ this.attr('stroke', parseFloat(v) > 0 ? this._stroke : null)
+ else if (a == 'stroke')
+ this._stroke = v
+
+ /* ensure full hex color */
+ if (SVG.Color.test(v) || SVG.Color.isRgb(v))
+ v = new SVG.Color(v)
- /* ensure correct numeric values */
- else if (typeof v === 'number')
- v = new SVG.Number(v)
+ /* ensure correct numeric values */
+ else if (typeof v === 'number')
+ v = new SVG.Number(v)
- /* parse array values */
- else if (Array.isArray(v))
- v = new SVG.Array(v)
+ /* parse array values */
+ else if (Array.isArray(v))
+ v = new SVG.Array(v)
- /* set give attribute on node */
- n != null ?
- this.node.setAttributeNS(n, a, v.toString()) :
- this.node.setAttribute(a, v.toString())
-
- /* if the passed argument belongs in the style as well, add it there */
- if (this._isStyle(a)) {
- a == 'text' ?
- this.text(v) :
- a == 'leading' && this.leading ?
- this.leading(v) :
- this.style(a, v)
+ /* set give attribute on node */
+ n != null ?
+ this.node.setAttributeNS(n, a, v.toString()) :
+ this.node.setAttribute(a, v.toString())
- /* rebuild if required */
- if (this.rebuild)
- this.rebuild(a, v)
+ /* if the passed argument belongs in the style as well, add it there */
+ if (this._isStyle(a)) {
+ a == 'text' ?
+ this.text(v) :
+ a == 'leading' && this.leading ?
+ this.leading(v) :
+ this.style(a, v)
+
+ /* rebuild if required */
+ if (this.rebuild)
+ this.rebuild(a, v)
+ }
}
+
+ return this
}
-
- return this
- }
- // Manage transformations
-, transform: function(o, v) {
-
- if (arguments.length == 0) {
- /* act as a getter if no argument is given */
- return this.trans
+ // Manage transformations
+ , transform: function(o, v) {
+
+ if (arguments.length == 0) {
+ /* act as a getter if no argument is given */
+ return this.trans
+
+ } else if (typeof o === 'string') {
+ /* act as a getter if only one string argument is given */
+ if (arguments.length < 2)
+ return this.trans[o]
+
+ /* apply transformations as object if key value arguments are given*/
+ var transform = {}
+ transform[o] = v
+
+ return this.transform(transform)
+ }
+
+ /* ... otherwise continue as a setter */
+ var transform = []
- } else if (typeof o === 'string') {
- /* act as a getter if only one string argument is given */
- if (arguments.length < 2)
- return this.trans[o]
+ /* parse matrix */
+ o = this._parseMatrix(o)
- /* apply transformations as object if key value arguments are given*/
- var transform = {}
- transform[o] = v
+ /* merge values */
+ for (v in o)
+ if (o[v] != null)
+ this.trans[v] = o[v]
- return this.transform(transform)
+ /* compile matrix */
+ this.trans.matrix = this.trans.a
+ + ' ' + this.trans.b
+ + ' ' + this.trans.c
+ + ' ' + this.trans.d
+ + ' ' + this.trans.e
+ + ' ' + this.trans.f
+
+ /* alias current transformations */
+ o = this.trans
+
+ /* add matrix */
+ if (o.matrix != SVG.defaults.matrix)
+ transform.push('matrix(' + o.matrix + ')')
+
+ /* add rotation */
+ if (o.rotation != 0)
+ transform.push('rotate(' + o.rotation + ' ' + (o.cx == null ? this.bbox().cx : o.cx) + ' ' + (o.cy == null ? this.bbox().cy : o.cy) + ')')
+
+ /* add scale */
+ if (o.scaleX != 1 || o.scaleY != 1)
+ transform.push('scale(' + o.scaleX + ' ' + o.scaleY + ')')
+
+ /* add skew on x axis */
+ if (o.skewX != 0)
+ transform.push('skewX(' + o.skewX + ')')
+
+ /* add skew on y axis */
+ if (o.skewY != 0)
+ transform.push('skewY(' + o.skewY + ')')
+
+ /* add translation */
+ if (o.x != 0 || o.y != 0)
+ transform.push('translate(' + new SVG.Number(o.x / o.scaleX) + ' ' + new SVG.Number(o.y / o.scaleY) + ')')
+
+ /* update transformations, even if there are none */
+ if (transform.length == 0)
+ this.node.removeAttribute('transform')
+ else
+ this.node.setAttribute('transform', transform.join(' '))
+
+ return this
}
-
- /* ... otherwise continue as a setter */
- var transform = []
-
- /* parse matrix */
- o = this._parseMatrix(o)
-
- /* merge values */
- for (v in o)
- if (o[v] != null)
- this.trans[v] = o[v]
-
- /* compile matrix */
- this.trans.matrix = this.trans.a
- + ' ' + this.trans.b
- + ' ' + this.trans.c
- + ' ' + this.trans.d
- + ' ' + this.trans.e
- + ' ' + this.trans.f
-
- /* alias current transformations */
- o = this.trans
-
- /* add matrix */
- if (o.matrix != SVG.defaults.matrix)
- transform.push('matrix(' + o.matrix + ')')
-
- /* add rotation */
- if (o.rotation != 0)
- transform.push('rotate(' + o.rotation + ' ' + (o.cx == null ? this.bbox().cx : o.cx) + ' ' + (o.cy == null ? this.bbox().cy : o.cy) + ')')
-
- /* add scale */
- if (o.scaleX != 1 || o.scaleY != 1)
- transform.push('scale(' + o.scaleX + ' ' + o.scaleY + ')')
-
- /* add skew on x axis */
- if (o.skewX != 0)
- transform.push('skewX(' + o.skewX + ')')
-
- /* add skew on y axis */
- if (o.skewY != 0)
- transform.push('skewY(' + o.skewY + ')')
-
- /* add translation */
- if (o.x != 0 || o.y != 0)
- transform.push('translate(' + new SVG.Number(o.x / o.scaleX) + ' ' + new SVG.Number(o.y / o.scaleY) + ')')
-
- /* update transformations, even if there are none */
- if (transform.length == 0)
- this.node.removeAttribute('transform')
- else
- this.node.setAttribute('transform', transform.join(' '))
-
- return this
- }
- // Dynamic style generator
-, style: function(s, v) {
- if (arguments.length == 0) {
- /* get full style */
- return this.attr('style') || ''
-
- } else if (arguments.length < 2) {
- /* apply every style individually if an object is passed */
- if (typeof s == 'object') {
- for (v in s) this.style(v, s[v])
+ // Dynamic style generator
+ , style: function(s, v) {
+ if (arguments.length == 0) {
+ /* get full style */
+ return this.attr('style') || ''
- } else if (SVG.regex.isCss.test(s)) {
- /* parse css string */
- s = s.split(';')
+ } else if (arguments.length < 2) {
+ /* apply every style individually if an object is passed */
+ if (typeof s == 'object') {
+ for (v in s) this.style(v, s[v])
+
+ } else if (SVG.regex.isCss.test(s)) {
+ /* parse css string */
+ s = s.split(';')
- /* apply every definition individually */
- for (var i = 0; i < s.length; i++) {
- v = s[i].split(':')
+ /* apply every definition individually */
+ for (var i = 0; i < s.length; i++) {
+ v = s[i].split(':')
- if (v.length == 2)
- this.style(v[0].replace(/\s+/g, ''), v[1].replace(/^\s+/,'').replace(/\s+$/,''))
+ if (v.length == 2)
+ this.style(v[0].replace(/\s+/g, ''), v[1].replace(/^\s+/,'').replace(/\s+$/,''))
+ }
+ } else {
+ /* act as a getter if the first and only argument is not an object */
+ return this.styles[s]
}
+
+ } else if (v === null || SVG.regex.test(v, 'isBlank')) {
+ /* remove value */
+ delete this.styles[s]
+
} else {
- /* act as a getter if the first and only argument is not an object */
- return this.styles[s]
+ /* store value */
+ this.styles[s] = v
}
-
- } else if (v === null || SVG.regex.test(v, 'isBlank')) {
- /* remove value */
- delete this.styles[s]
- } else {
- /* store value */
- this.styles[s] = v
- }
-
- /* rebuild style string */
- s = ''
- for (v in this.styles)
- s += v + ':' + this.styles[v] + ';'
-
- /* apply style */
- if (s == '')
- this.node.removeAttribute('style')
- else
- this.node.setAttribute('style', s)
-
- return this
- }
- // Get bounding box
-, bbox: function() {
- return new SVG.BBox(this)
- }
- // Get rect box
-, rbox: function() {
- return new SVG.RBox(this)
- }
- // Checks whether the given point inside the bounding box of the element
-, inside: function(x, y) {
- var box = this.bbox()
-
- return x > box.x
- && y > box.y
- && x < box.x + box.width
- && y < box.y + box.height
- }
- // Show element
-, show: function() {
- return this.style('display', '')
- }
- // Hide element
-, hide: function() {
- return this.style('display', 'none')
- }
- // Is element visible?
-, visible: function() {
- return this.style('display') != 'none'
- }
- // Return id on string conversion
-, toString: function() {
- return this.attr('id')
- }
- // Private: find svg parent by instance
-, _parent: function(parent) {
- var element = this
-
- while (element != null && !(element instanceof parent))
- element = element.parent
-
- return element
- }
- // Private: tester method for style detection
-, _isStyle: function(a) {
- return typeof a == 'string' ? SVG.regex.test(a, 'isStyle') : false
- }
- // Private: parse a matrix string
-, _parseMatrix: function(o) {
- if (o.matrix) {
- /* split matrix string */
- var m = o.matrix.replace(/\s/g, '').split(',')
+ /* rebuild style string */
+ s = ''
+ for (v in this.styles)
+ s += v + ':' + this.styles[v] + ';'
- /* pasrse values */
- if (m.length == 6) {
- o.a = parseFloat(m[0])
- o.b = parseFloat(m[1])
- o.c = parseFloat(m[2])
- o.d = parseFloat(m[3])
- o.e = parseFloat(m[4])
- o.f = parseFloat(m[5])
- }
+ /* apply style */
+ if (s == '')
+ this.node.removeAttribute('style')
+ else
+ this.node.setAttribute('style', s)
+
+ return this
}
-
- return o
- }
- // Private: calculate proportional width and height values when necessary
-, _proportionalSize: function(width, height) {
- if (width == null || height == null) {
+ // Get bounding box
+ , bbox: function() {
+ return new SVG.BBox(this)
+ }
+ // Get rect box
+ , rbox: function() {
+ return new SVG.RBox(this)
+ }
+ // Checks whether the given point inside the bounding box of the element
+ , inside: function(x, y) {
var box = this.bbox()
+
+ return x > box.x
+ && y > box.y
+ && x < box.x + box.width
+ && y < box.y + box.height
+ }
+ // Show element
+ , show: function() {
+ return this.style('display', '')
+ }
+ // Hide element
+ , hide: function() {
+ return this.style('display', 'none')
+ }
+ // Is element visible?
+ , visible: function() {
+ return this.style('display') != 'none'
+ }
+ // Return id on string conversion
+ , toString: function() {
+ return this.attr('id')
+ }
+ // Private: find svg parent by instance
+ , _parent: function(parent) {
+ var element = this
+
+ while (element != null && !(element instanceof parent))
+ element = element.parent
- if (height == null)
- height = box.height / box.width * width
- else if (width == null)
- width = box.width / box.height * height
+ return element
}
-
- return {
- width: width
- , height: height
+ // Private: tester method for style detection
+ , _isStyle: function(a) {
+ return typeof a == 'string' ? SVG.regex.test(a, 'isStyle') : false
+ }
+ // Private: parse a matrix string
+ , _parseMatrix: function(o) {
+ if (o.matrix) {
+ /* split matrix string */
+ var m = o.matrix.replace(/\s/g, '').split(',')
+
+ /* pasrse values */
+ if (m.length == 6) {
+ o.a = parseFloat(m[0])
+ o.b = parseFloat(m[1])
+ o.c = parseFloat(m[2])
+ o.d = parseFloat(m[3])
+ o.e = parseFloat(m[4])
+ o.f = parseFloat(m[5])
+ }
+ }
+
+ return o
+ }
+ // Private: calculate proportional width and height values when necessary
+ , _proportionalSize: function(width, height) {
+ if (width == null || height == null) {
+ var box = this.bbox()
+
+ if (height == null)
+ height = box.height / box.width * width
+ else if (width == null)
+ width = box.width / box.height * height
+ }
+
+ return {
+ width: width
+ , height: height
+ }
}
}