diff options
author | wout <wout@impinc.co.uk> | 2014-02-03 15:14:47 +0100 |
---|---|---|
committer | wout <wout@impinc.co.uk> | 2014-02-03 15:14:47 +0100 |
commit | e2304534e0cfb6f6f4ab8c37ea5275ae26cd455a (patch) | |
tree | 2386e9f361d9c5fa1308387aeeaf33f00241b3c5 /src/element.js | |
parent | 7a29817ffd764cf7ab6906250b57f234801c94e0 (diff) | |
download | svg.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-x | src/element.js | 764 |
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 + } } } |