summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-x[-rw-r--r--]src/data.js0
-rwxr-xr-xsrc/default.js4
-rwxr-xr-xsrc/doc.js65
-rwxr-xr-xsrc/element.js61
-rwxr-xr-xsrc/fx.js774
-rwxr-xr-x[-rw-r--r--]src/hyperlink.js0
-rwxr-xr-x[-rw-r--r--]src/inventor.js0
-rwxr-xr-xsrc/path.js2
-rwxr-xr-x[-rw-r--r--]src/patharray.js337
-rwxr-xr-x[-rw-r--r--]src/pattern.js0
-rwxr-xr-x[-rw-r--r--]src/pointarray.js2
-rwxr-xr-xsrc/regex.js3
-rwxr-xr-x[-rw-r--r--]src/relative.js34
-rwxr-xr-xsrc/sugar.js47
-rwxr-xr-xsrc/svg.js8
-rwxr-xr-xsrc/text.js220
16 files changed, 732 insertions, 825 deletions
diff --git a/src/data.js b/src/data.js
index 1adbd52..1adbd52 100644..100755
--- a/src/data.js
+++ b/src/data.js
diff --git a/src/default.js b/src/default.js
index e8eeecd..b9819a7 100755
--- a/src/default.js
+++ b/src/default.js
@@ -30,6 +30,10 @@ SVG.defaults = {
, offset: 0
, 'stop-opacity': 1
, 'stop-color': '#000000'
+ /* text */
+ , 'font-size': 16
+ , 'font-family': 'Helvetica, Arial, sans-serif'
+ , 'text-anchor': 'start'
}
// Default transformation values
diff --git a/src/doc.js b/src/doc.js
index 5129dd9..a10bffe 100755
--- a/src/doc.js
+++ b/src/doc.js
@@ -21,11 +21,11 @@ SVG.Doc = SVG.invent({
this._defs.parent = this
this.node.appendChild(this._defs.node)
- /* turno of sub pixel offset by default */
- this.doSubPixelOffsetFix = false
+ /* turn off sub pixel offset by default */
+ this.doSpof = false
/* ensure correct rendering */
- if (this.parent.nodeName != 'svg')
+ if (this.parent != this.node)
this.stage()
}
@@ -34,50 +34,20 @@ SVG.Doc = SVG.invent({
// Add class methods
, extend: {
- // Hack for safari preventing text to be rendered in one line.
- // Basically it sets the position of the svg node to absolute
- // when the dom is loaded, and resets it to relative a few milliseconds later.
- // It also handles sub-pixel offset rendering properly.
+ /* enable drawing */
stage: function() {
- var check
- , element = this
- , wrapper = document.createElement('div')
+ var element = this
- /* set temporary wrapper to position relative */
- wrapper.style.cssText = 'position:relative;height:100%;'
+ /* insert element */
+ this.parent.appendChild(this.node)
- /* put element into wrapper */
- element.parent.appendChild(wrapper)
- wrapper.appendChild(element.node)
-
- /* check for dom:ready */
- check = function() {
- if (document.readyState === 'complete') {
- element.style('position:absolute;')
- setTimeout(function() {
- /* set position back to relative */
- element.style('position:relative;overflow:hidden;')
-
- /* remove temporary wrapper */
- element.parent.removeChild(element.node.parentNode)
- element.node.parentNode.removeChild(element.node)
- element.parent.appendChild(element.node)
-
- /* after wrapping is done, fix sub-pixel offset */
- element.subPixelOffsetFix()
-
- /* make sure sub-pixel offset is fixed every time the window is resized */
- SVG.on(window, 'resize', function() {
- element.subPixelOffsetFix()
- })
-
- }, 5)
- } else {
- setTimeout(check, 10)
- }
- }
-
- check()
+ /* 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
}
@@ -89,8 +59,8 @@ SVG.Doc = SVG.invent({
// Fix for possible sub-pixel offset. See:
// https://bugzilla.mozilla.org/show_bug.cgi?id=608812
- , subPixelOffsetFix: function() {
- if (this.doSubPixelOffsetFix) {
+ , spof: function() {
+ if (this.doSpof) {
var pos = this.node.getScreenCTM()
if (pos)
@@ -102,8 +72,9 @@ SVG.Doc = SVG.invent({
return this
}
+ // Enable sub-pixel offset
, fixSubPixelOffset: function() {
- this.doSubPixelOffsetFix = true
+ this.doSpof = true
return this
}
diff --git a/src/element.js b/src/element.js
index 9ae2cd3..116e8d1 100755
--- a/src/element.js
+++ b/src/element.js
@@ -147,33 +147,18 @@ SVG.Element = SVG.invent({
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
- }
+ 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)
-
/* 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)
@@ -192,7 +177,7 @@ SVG.Element = SVG.invent({
}
/* ensure full hex color */
- if (SVG.Color.test(v) || SVG.Color.isRgb(v))
+ if (SVG.Color.isColor(v))
v = new SVG.Color(v)
/* ensure correct numeric values */
@@ -203,23 +188,21 @@ SVG.Element = SVG.invent({
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)
-
- /* rebuild if required */
- if (this.rebuild)
- this.rebuild(a, v)
+ /* if the passed attribute is leading... */
+ if (a == 'leading') {
+ /* ... call the leading method instead */
+ if (this.leading)
+ this.leading(v)
+ } else {
+ /* 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 && (a == 'font-size' || a == 'x'))
+ this.rebuild(a, v)
}
return this
@@ -388,10 +371,6 @@ SVG.Element = SVG.invent({
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) {
diff --git a/src/fx.js b/src/fx.js
index 41629ed..e64f2ad 100755
--- a/src/fx.js
+++ b/src/fx.js
@@ -1,431 +1,439 @@
-SVG.FX = function(element) {
- /* store target element */
- this.target = element
-}
+SVG.FX = SVG.invent({
+ // Initialize FX object
+ create: function(element) {
+ /* store target element */
+ this.target = element
+ }
-SVG.extend(SVG.FX, {
- // Add animation parameters and start animation
- animate: function(d, ease, delay) {
- var akeys, tkeys, skeys, key
- , element = this.target
- , fx = this
-
- /* dissect object if one is passed */
- if (typeof d == 'object') {
- delay = d.delay
- ease = d.ease
- d = d.duration
- }
+ // Add class methods
+, extend: {
+ // Add animation parameters and start animation
+ animate: function(d, ease, delay) {
+ var akeys, tkeys, skeys, key
+ , element = this.target
+ , fx = this
+
+ /* dissect object if one is passed */
+ if (typeof d == 'object') {
+ delay = d.delay
+ ease = d.ease
+ d = d.duration
+ }
- /* ensure default duration and easing */
- d = d == '=' ? d : d == null ? 1000 : new SVG.Number(d).valueOf()
- ease = ease || '<>'
-
- /* process values */
- fx.to = function(pos) {
- var i
-
- /* normalise pos */
- pos = pos < 0 ? 0 : pos > 1 ? 1 : pos
-
- /* collect attribute keys */
- if (akeys == null) {
- akeys = []
- for (key in fx.attrs)
- akeys.push(key)
-
- /* make sure morphable elements are scaled, translated and morphed all together */
- if (element.morphArray && (fx._plot || akeys.indexOf('points') > -1)) {
- /* get destination */
- var box
- , p = new element.morphArray(fx._plot || fx.attrs.points || element.array)
-
- /* add size */
- if (fx._size) p.size(fx._size.width.to, fx._size.height.to)
-
- /* add movement */
- box = p.bbox()
- if (fx._x) p.move(fx._x.to, box.y)
- else if (fx._cx) p.move(fx._cx.to - box.width / 2, box.y)
-
- box = p.bbox()
- if (fx._y) p.move(box.x, fx._y.to)
- else if (fx._cy) p.move(box.x, fx._cy.to - box.height / 2)
-
- /* delete element oriented changes */
- delete fx._x
- delete fx._y
- delete fx._cx
- delete fx._cy
- delete fx._size
-
- fx._plot = element.array.morph(p)
+ /* ensure default duration and easing */
+ d = d == '=' ? d : d == null ? 1000 : new SVG.Number(d).valueOf()
+ ease = ease || '<>'
+
+ /* process values */
+ fx.to = function(pos) {
+ var i
+
+ /* normalise pos */
+ pos = pos < 0 ? 0 : pos > 1 ? 1 : pos
+
+ /* collect attribute keys */
+ if (akeys == null) {
+ akeys = []
+ for (key in fx.attrs)
+ akeys.push(key)
+
+ /* make sure morphable elements are scaled, translated and morphed all together */
+ if (element.morphArray && (fx._plot || akeys.indexOf('points') > -1)) {
+ /* get destination */
+ var box
+ , p = new element.morphArray(fx._plot || fx.attrs.points || element.array)
+
+ /* add size */
+ if (fx._size) p.size(fx._size.width.to, fx._size.height.to)
+
+ /* add movement */
+ box = p.bbox()
+ if (fx._x) p.move(fx._x.to, box.y)
+ else if (fx._cx) p.move(fx._cx.to - box.width / 2, box.y)
+
+ box = p.bbox()
+ if (fx._y) p.move(box.x, fx._y.to)
+ else if (fx._cy) p.move(box.x, fx._cy.to - box.height / 2)
+
+ /* delete element oriented changes */
+ delete fx._x
+ delete fx._y
+ delete fx._cx
+ delete fx._cy
+ delete fx._size
+
+ fx._plot = element.array.morph(p)
+ }
}
- }
- /* collect transformation keys */
- if (tkeys == null) {
- tkeys = []
- for (key in fx.trans)
- tkeys.push(key)
- }
+ /* collect transformation keys */
+ if (tkeys == null) {
+ tkeys = []
+ for (key in fx.trans)
+ tkeys.push(key)
+ }
- /* collect style keys */
- if (skeys == null) {
- skeys = []
- for (key in fx.styles)
- skeys.push(key)
- }
+ /* collect style keys */
+ if (skeys == null) {
+ skeys = []
+ for (key in fx.styles)
+ skeys.push(key)
+ }
- /* apply easing */
- pos = ease == '<>' ?
- (-Math.cos(pos * Math.PI) / 2) + 0.5 :
- ease == '>' ?
- Math.sin(pos * Math.PI / 2) :
- ease == '<' ?
- -Math.cos(pos * Math.PI / 2) + 1 :
- ease == '-' ?
- pos :
- typeof ease == 'function' ?
- ease(pos) :
- pos
-
- /* run plot function */
- if (fx._plot) {
- element.plot(fx._plot.at(pos))
+ /* apply easing */
+ pos = ease == '<>' ?
+ (-Math.cos(pos * Math.PI) / 2) + 0.5 :
+ ease == '>' ?
+ Math.sin(pos * Math.PI / 2) :
+ ease == '<' ?
+ -Math.cos(pos * Math.PI / 2) + 1 :
+ ease == '-' ?
+ pos :
+ typeof ease == 'function' ?
+ ease(pos) :
+ pos
+
+ /* run plot function */
+ if (fx._plot) {
+ element.plot(fx._plot.at(pos))
+
+ } else {
+ /* run all x-position properties */
+ if (fx._x)
+ element.x(at(fx._x, pos))
+ else if (fx._cx)
+ element.cx(at(fx._cx, pos))
+
+ /* run all y-position properties */
+ if (fx._y)
+ element.y(at(fx._y, pos))
+ else if (fx._cy)
+ element.cy(at(fx._cy, pos))
+
+ /* run all size properties */
+ if (fx._size)
+ element.size(at(fx._size.width, pos), at(fx._size.height, pos))
+ }
- } else {
- /* run all x-position properties */
- if (fx._x)
- element.x(at(fx._x, pos))
- else if (fx._cx)
- element.cx(at(fx._cx, pos))
-
- /* run all y-position properties */
- if (fx._y)
- element.y(at(fx._y, pos))
- else if (fx._cy)
- element.cy(at(fx._cy, pos))
-
- /* run all size properties */
- if (fx._size)
- element.size(at(fx._size.width, pos), at(fx._size.height, pos))
+ /* run all viewbox properties */
+ if (fx._viewbox)
+ element.viewbox(
+ at(fx._viewbox.x, pos)
+ , at(fx._viewbox.y, pos)
+ , at(fx._viewbox.width, pos)
+ , at(fx._viewbox.height, pos)
+ )
+
+ /* animate attributes */
+ for (i = akeys.length - 1; i >= 0; i--)
+ element.attr(akeys[i], at(fx.attrs[akeys[i]], pos))
+
+ /* animate transformations */
+ for (i = tkeys.length - 1; i >= 0; i--)
+ element.transform(tkeys[i], at(fx.trans[tkeys[i]], pos))
+
+ /* animate styles */
+ for (i = skeys.length - 1; i >= 0; i--)
+ element.style(skeys[i], at(fx.styles[skeys[i]], pos))
+
+ /* callback for each keyframe */
+ if (fx._during)
+ fx._during.call(element, pos, function(from, to) {
+ return at({ from: from, to: to }, pos)
+ })
}
+
+ if (typeof d === 'number') {
+ /* delay animation */
+ this.timeout = setTimeout(function() {
+ var start = new Date().getTime()
+
+ /* initialize situation object */
+ fx.situation = {
+ interval: 1000 / 60
+ , start: start
+ , play: true
+ , finish: start + d
+ , duration: d
+ }
- /* run all viewbox properties */
- if (fx._viewbox)
- element.viewbox(
- at(fx._viewbox.x, pos)
- , at(fx._viewbox.y, pos)
- , at(fx._viewbox.width, pos)
- , at(fx._viewbox.height, pos)
- )
-
- /* animate attributes */
- for (i = akeys.length - 1; i >= 0; i--)
- element.attr(akeys[i], at(fx.attrs[akeys[i]], pos))
-
- /* animate transformations */
- for (i = tkeys.length - 1; i >= 0; i--)
- element.transform(tkeys[i], at(fx.trans[tkeys[i]], pos))
-
- /* animate styles */
- for (i = skeys.length - 1; i >= 0; i--)
- element.style(skeys[i], at(fx.styles[skeys[i]], pos))
-
- /* callback for each keyframe */
- if (fx._during)
- fx._during.call(element, pos, function(from, to) {
- return at({ from: from, to: to }, pos)
- })
- }
-
- if (typeof d === 'number') {
- /* delay animation */
- this.timeout = setTimeout(function() {
- var start = new Date().getTime()
-
- /* initialize situation object */
- fx.situation = {
- interval: 1000 / 60
- , start: start
- , play: true
- , finish: start + d
- , duration: d
- }
-
- /* render function */
- fx.render = function(){
-
- if (fx.situation.play === true) {
- // This code was borrowed from the emile.js micro framework by Thomas Fuchs, aka MadRobby.
- var time = new Date().getTime()
- , pos = time > fx.situation.finish ? 1 : (time - fx.situation.start) / d
-
- /* process values */
- fx.to(pos)
+ /* render function */
+ fx.render = function(){
- /* finish off animation */
- if (time > fx.situation.finish) {
- if (fx._plot)
- element.plot(new SVG.PointArray(fx._plot.destination).settle())
-
- if (fx._loop === true || (typeof fx._loop == 'number' && fx._loop > 1)) {
- if (typeof fx._loop == 'number')
- --fx._loop
- fx.animate(d, ease, delay)
+ if (fx.situation.play === true) {
+ // This code was borrowed from the emile.js micro framework by Thomas Fuchs, aka MadRobby.
+ var time = new Date().getTime()
+ , pos = time > fx.situation.finish ? 1 : (time - fx.situation.start) / d
+
+ /* process values */
+ fx.to(pos)
+
+ /* finish off animation */
+ if (time > fx.situation.finish) {
+ if (fx._plot)
+ element.plot(new SVG.PointArray(fx._plot.destination).settle())
+
+ if (fx._loop === true || (typeof fx._loop == 'number' && fx._loop > 1)) {
+ if (typeof fx._loop == 'number')
+ --fx._loop
+ fx.animate(d, ease, delay)
+ } else {
+ fx._after ? fx._after.apply(element, [fx]) : fx.stop()
+ }
+
} else {
- fx._after ? fx._after.apply(element, [fx]) : fx.stop()
+ requestAnimFrame(fx.render)
}
-
} else {
requestAnimFrame(fx.render)
}
- } else {
- requestAnimFrame(fx.render)
+
}
+
+ /* start animation */
+ fx.render()
- }
+ }, new SVG.Number(delay).valueOf())
+ }
+
+ return this
+ }
+ // Get bounding box of target element
+ , bbox: function() {
+ return this.target.bbox()
+ }
+ // Add animatable attributes
+ , attr: function(a, v) {
+ if (typeof a == 'object') {
+ for (var key in a)
+ this.attr(key, a[key])
+
+ } else {
+ var from = this.target.attr(a)
- /* start animation */
- fx.render()
-
- }, new SVG.Number(delay).valueOf())
+ this.attrs[a] = SVG.Color.isColor(from) ?
+ new SVG.Color(from).morph(v) :
+ SVG.regex.unit.test(from) ?
+ new SVG.Number(from).morph(v) :
+ { from: from, to: v }
+ }
+
+ return this
}
-
- return this
- }
- // Get bounding box of target element
-, bbox: function() {
- return this.target.bbox()
- }
- // Add animatable attributes
-, attr: function(a, v) {
- if (typeof a == 'object') {
- for (var key in a)
- this.attr(key, a[key])
-
- } else {
- var from = this.target.attr(a)
-
- this.attrs[a] = SVG.Color.isColor(from) ?
- new SVG.Color(from).morph(v) :
- SVG.regex.unit.test(from) ?
- new SVG.Number(from).morph(v) :
- { from: from, to: v }
+ // Add animatable transformations
+ , transform: function(o, v) {
+ if (arguments.length == 1) {
+ /* parse matrix string */
+ o = this.target._parseMatrix(o)
+
+ /* dlete matrixstring from object */
+ delete o.matrix
+
+ /* store matrix values */
+ for (v in o)
+ this.trans[v] = { from: this.target.trans[v], to: o[v] }
+
+ } else {
+ /* apply transformations as object if key value arguments are given*/
+ var transform = {}
+ transform[o] = v
+
+ this.transform(transform)
+ }
+
+ return this
}
-
- return this
- }
- // Add animatable transformations
-, transform: function(o, v) {
- if (arguments.length == 1) {
- /* parse matrix string */
- o = this.target._parseMatrix(o)
+ // Add animatable styles
+ , style: function(s, v) {
+ if (typeof s == 'object')
+ for (var key in s)
+ this.style(key, s[key])
- /* dlete matrixstring from object */
- delete o.matrix
+ else
+ this.styles[s] = { from: this.target.style(s), to: v }
- /* store matrix values */
- for (v in o)
- this.trans[v] = { from: this.target.trans[v], to: o[v] }
+ return this
+ }
+ // Animatable x-axis
+ , x: function(x) {
+ this._x = { from: this.target.x(), to: x }
- } else {
- /* apply transformations as object if key value arguments are given*/
- var transform = {}
- transform[o] = v
+ return this
+ }
+ // Animatable y-axis
+ , y: function(y) {
+ this._y = { from: this.target.y(), to: y }
- this.transform(transform)
+ return this
}
-
- return this
- }
- // Add animatable styles
-, style: function(s, v) {
- if (typeof s == 'object')
- for (var key in s)
- this.style(key, s[key])
-
- else
- this.styles[s] = { from: this.target.style(s), to: v }
-
- return this
- }
- // Animatable x-axis
-, x: function(x) {
- this._x = { from: this.target.x(), to: x }
-
- return this
- }
- // Animatable y-axis
-, y: function(y) {
- this._y = { from: this.target.y(), to: y }
-
- return this
- }
- // Animatable center x-axis
-, cx: function(x) {
- this._cx = { from: this.target.cx(), to: x }
-
- return this
- }
- // Animatable center y-axis
-, cy: function(y) {
- this._cy = { from: this.target.cy(), to: y }
-
- return this
- }
- // Add animatable move
-, move: function(x, y) {
- return this.x(x).y(y)
- }
- // Add animatable center
-, center: function(x, y) {
- return this.cx(x).cy(y)
- }
- // Add animatable size
-, size: function(width, height) {
- if (this.target instanceof SVG.Text) {
- /* animate font size for Text elements */
- this.attr('font-size', width)
+ // Animatable center x-axis
+ , cx: function(x) {
+ this._cx = { from: this.target.cx(), to: x }
- } else {
- /* animate bbox based size for all other elements */
- var box = this.target.bbox()
+ return this
+ }
+ // Animatable center y-axis
+ , cy: function(y) {
+ this._cy = { from: this.target.cy(), to: y }
+
+ return this
+ }
+ // Add animatable move
+ , move: function(x, y) {
+ return this.x(x).y(y)
+ }
+ // Add animatable center
+ , center: function(x, y) {
+ return this.cx(x).cy(y)
+ }
+ // Add animatable size
+ , size: function(width, height) {
+ if (this.target instanceof SVG.Text) {
+ /* animate font size for Text elements */
+ this.attr('font-size', width)
+
+ } else {
+ /* animate bbox based size for all other elements */
+ var box = this.target.bbox()
- this._size = {
- width: { from: box.width, to: width }
- , height: { from: box.height, to: height }
+ this._size = {
+ width: { from: box.width, to: width }
+ , height: { from: box.height, to: height }
+ }
}
+
+ return this
}
-
- return this
- }
- // Add animatable plot
-, plot: function(p) {
- this._plot = p
+ // Add animatable plot
+ , plot: function(p) {
+ this._plot = p
- return this
- }
- // Add animatable viewbox
-, viewbox: function(x, y, width, height) {
- if (this.target instanceof SVG.Container) {
- var box = this.target.viewbox()
+ return this
+ }
+ // Add animatable viewbox
+ , viewbox: function(x, y, width, height) {
+ if (this.target instanceof SVG.Container) {
+ var box = this.target.viewbox()
+
+ this._viewbox = {
+ x: { from: box.x, to: x }
+ , y: { from: box.y, to: y }
+ , width: { from: box.width, to: width }
+ , height: { from: box.height, to: height }
+ }
+ }
- this._viewbox = {
- x: { from: box.x, to: x }
- , y: { from: box.y, to: y }
- , width: { from: box.width, to: width }
- , height: { from: box.height, to: height }
+ return this
+ }
+ // Add animateable gradient update
+ , update: function(o) {
+ if (this.target instanceof SVG.Stop) {
+ if (o.opacity != null) this.attr('stop-opacity', o.opacity)
+ if (o.color != null) this.attr('stop-color', o.color)
+ if (o.offset != null) this.attr('offset', new SVG.Number(o.offset))
}
+
+ return this
}
-
- return this
- }
- // Add animateable gradient update
-, update: function(o) {
- if (this.target instanceof SVG.Stop) {
- if (o.opacity != null) this.attr('stop-opacity', o.opacity)
- if (o.color != null) this.attr('stop-color', o.color)
- if (o.offset != null) this.attr('offset', new SVG.Number(o.offset))
+ // Add callback for each keyframe
+ , during: function(during) {
+ this._during = during
+
+ return this
}
-
- return this
- }
- // Add callback for each keyframe
-, during: function(during) {
- this._during = during
-
- return this
- }
- // Callback after animation
-, after: function(after) {
- this._after = after
-
- return this
- }
- // Make loopable
-, loop: function(times) {
- this._loop = times || true
-
- return this
- }
- // Stop running animation
-, stop: function() {
- /* stop current animation */
- clearTimeout(this.timeout)
- clearInterval(this.interval)
-
- /* reset storage for properties that need animation */
- this.attrs = {}
- this.trans = {}
- this.styles = {}
- this.situation = {}
-
- delete this._x
- delete this._y
- delete this._cx
- delete this._cy
- delete this._size
- delete this._plot
- delete this._loop
- delete this._after
- delete this._during
- delete this._viewbox
-
- return this
- }
- // Pause running animation
-, pause: function() {
- if (this.situation.play === true) {
- this.situation.play = false
- this.situation.pause = new Date().getTime()
+ // Callback after animation
+ , after: function(after) {
+ this._after = after
+
+ return this
}
+ // Make loopable
+ , loop: function(times) {
+ this._loop = times || true
- return this
- }
- // Play running animation
-, play: function() {
- if (this.situation.play === false) {
- var pause = new Date().getTime() - this.situation.pause
+ return this
+ }
+ // Stop running animation
+ , stop: function() {
+ /* stop current animation */
+ clearTimeout(this.timeout)
+ clearInterval(this.interval)
- this.situation.finish += pause
- this.situation.start += pause
- this.situation.play = true
+ /* reset storage for properties that need animation */
+ this.attrs = {}
+ this.trans = {}
+ this.styles = {}
+ this.situation = {}
+
+ delete this._x
+ delete this._y
+ delete this._cx
+ delete this._cy
+ delete this._size
+ delete this._plot
+ delete this._loop
+ delete this._after
+ delete this._during
+ delete this._viewbox
+
+ return this
}
+ // Pause running animation
+ , pause: function() {
+ if (this.situation.play === true) {
+ this.situation.play = false
+ this.situation.pause = new Date().getTime()
+ }
- return this
- }
-
-})
+ return this
+ }
+ // Play running animation
+ , play: function() {
+ if (this.situation.play === false) {
+ var pause = new Date().getTime() - this.situation.pause
+
+ this.situation.finish += pause
+ this.situation.start += pause
+ this.situation.play = true
+ }
-SVG.extend(SVG.Element, {
- // Get fx module or create a new one, then animate with given duration and ease
- animate: function(d, ease, delay) {
- return (this.fx || (this.fx = new SVG.FX(this))).stop().animate(d, ease, delay)
- }
- // Stop current animation; this is an alias to the fx instance
-, stop: function() {
- if (this.fx)
- this.fx.stop()
+ return this
+ }
- return this
}
- // Pause current animation
-, pause: function() {
- if (this.fx)
- this.fx.pause()
- return this
- }
- // Play paused current animation
-, play: function() {
- if (this.fx)
- this.fx.play()
+ // Define parent class
+, parent: SVG.Element
- return this
+ // Add method to parent elements
+, construct: {
+ // Get fx module or create a new one, then animate with given duration and ease
+ animate: function(d, ease, delay) {
+ return (this.fx || (this.fx = new SVG.FX(this))).stop().animate(d, ease, delay)
+ }
+ // Stop current animation; this is an alias to the fx instance
+ , stop: function() {
+ if (this.fx)
+ this.fx.stop()
+
+ return this
+ }
+ // Pause current animation
+ , pause: function() {
+ if (this.fx)
+ this.fx.pause()
+
+ return this
+ }
+ // Play paused current animation
+ , play: function() {
+ if (this.fx)
+ this.fx.play()
+
+ return this
+ }
+
}
-
})
// Calculate position according to from and to
diff --git a/src/hyperlink.js b/src/hyperlink.js
index 1981d52..1981d52 100644..100755
--- a/src/hyperlink.js
+++ b/src/hyperlink.js
diff --git a/src/inventor.js b/src/inventor.js
index f8244f5..f8244f5 100644..100755
--- a/src/inventor.js
+++ b/src/inventor.js
diff --git a/src/path.js b/src/path.js
index 0345487..ad231dc 100755
--- a/src/path.js
+++ b/src/path.js
@@ -9,7 +9,7 @@ SVG.Path = SVG.invent({
, extend: {
// Plot new poly points
plot: function(p) {
- return this.attr('d', (this.array = new SVG.PathArray(p, [{ type:'M',x:0,y:0 }])))
+ return this.attr('d', (this.array = new SVG.PathArray(p, [['M', 0, 0]])))
}
// Move by left top corner
, move: function(x, y) {
diff --git a/src/patharray.js b/src/patharray.js
index 314f53e..2ccb7d5 100644..100755
--- a/src/patharray.js
+++ b/src/patharray.js
@@ -9,48 +9,7 @@ SVG.PathArray.prototype = new SVG.Array
SVG.extend(SVG.PathArray, {
// Convert array to string
toString: function() {
- for (var s, i = 0, il = this.value.length, array = []; i < il; i++) {
- s = [this.value[i].type]
-
- switch(this.value[i].type) {
- case 'H':
- s.push(this.value[i].x)
- break
- case 'V':
- s.push(this.value[i].y)
- break
- case 'M':
- case 'L':
- case 'T':
- case 'S':
- case 'Q':
- case 'C':
- if (/[QC]/.test(this.value[i].type))
- s.push(this.value[i].x1, this.value[i].y1)
- if (/[CS]/.test(this.value[i].type))
- s.push(this.value[i].x2, this.value[i].y2)
-
- s.push(this.value[i].x, this.value[i].y)
-
- break
- case 'A':
- s.push(
- this.value[i].r1
- , this.value[i].r2
- , this.value[i].a
- , this.value[i].l
- , this.value[i].s
- , this.value[i].x
- , this.value[i].y
- )
- break
- }
-
- /* add to array */
- array.push(s.join(' '))
- }
-
- return array.join(' ')
+ return arrayToString(this.value)
}
// Move path string
, move: function(x, y) {
@@ -63,45 +22,35 @@ SVG.extend(SVG.PathArray, {
if (!isNaN(x) && !isNaN(y)) {
/* move every point */
- for (var i = this.value.length - 1; i >= 0; i--) {
- switch (this.value[i].type) {
- case 'H':
- /* move along x axis only */
- this.value[i].x += x
- break
- case 'V':
- /* move along y axis only */
- this.value[i].y += y
- break
- case 'M':
- case 'L':
- case 'T':
- case 'S':
- case 'Q':
- case 'C':
- /* move first point along x and y axes */
- this.value[i].x += x
- this.value[i].y += y
-
- /* move third points along x and y axes */
- if (/[CQ]/.test(this.value[i].type)) {
- this.value[i].x1 += x
- this.value[i].y1 += y
- }
+ for (var l, i = this.value.length - 1; i >= 0; i--) {
+ l = this.value[i][0]
- /* move second points along x and y axes */
- if (/[CS]/.test(this.value[i].type)) {
- this.value[i].x2 += x
- this.value[i].y2 += y
- }
+ if (l == 'M' || l == 'L' || l == 'T') {
+ this.value[i][1] += x
+ this.value[i][2] += y
+
+ } else if (l == 'H') {
+ this.value[i][1] += x
+
+ } else if (l == 'V') {
+ this.value[i][1] += y
+
+ } else if (l == 'C' || l == 'S' || l == 'Q') {
+ this.value[i][1] += x
+ this.value[i][2] += y
+ this.value[i][3] += x
+ this.value[i][4] += y
+
+ if (l == 'C') {
+ this.value[i][5] += x
+ this.value[i][6] += y
+ }
- break
- case 'A':
- /* only move position values */
- this.value[i].x += x
- this.value[i].y += y
- break
+ } else if (l == 'A') {
+ this.value[i][6] += x
+ this.value[i][7] += y
}
+
}
}
@@ -110,61 +59,51 @@ SVG.extend(SVG.PathArray, {
// Resize path string
, size: function(width, height) {
/* get bounding box of current situation */
- var box = this.bbox()
+ var i, l, box = this.bbox()
/* recalculate position of all points according to new size */
- for (var i = this.value.length - 1; i >= 0; i--) {
- switch (this.value[i].type) {
- case 'H':
- /* move along x axis only */
- this.value[i].x = ((this.value[i].x - box.x) * width) / box.width + box.x
- break
- case 'V':
- /* move along y axis only */
- this.value[i].y = ((this.value[i].y - box.y) * height) / box.height + box.y
- break
- case 'M':
- case 'L':
- case 'T':
- case 'S':
- case 'Q':
- case 'C':
- this.value[i].x = ((this.value[i].x - box.x) * width) / box.width + box.x
- this.value[i].y = ((this.value[i].y - box.y) * height) / box.height + box.y
-
- /* move third points along x and y axes */
- if (/[CQ]/.test(this.value[i].type)) {
- this.value[i].x1 = ((this.value[i].x1 - box.x) * width) / box.width + box.x
- this.value[i].y1 = ((this.value[i].y1 - box.y) * height) / box.height + box.y
- }
+ for (i = this.value.length - 1; i >= 0; i--) {
+ l = this.value[i][0]
- /* move second points along x and y axes */
- if (/[CS]/.test(this.value[i].type)) {
- this.value[i].x2 = ((this.value[i].x2 - box.x) * width) / box.width + box.x
- this.value[i].y2 = ((this.value[i].y2 - box.y) * height) / box.height + box.y
- }
+ if (l == 'M' || l == 'L' || l == 'T') {
+ this.value[i][1] = ((this.value[i][1] - box.x) * width) / box.width + box.x
+ this.value[i][2] = ((this.value[i][2] - box.y) * height) / box.height + box.y
+
+ } else if (l == 'H') {
+ this.value[i][1] = ((this.value[i][1] - box.x) * width) / box.width + box.x
+
+ } else if (l == 'V') {
+ this.value[i][1] = ((this.value[i][1] - box.y) * height) / box.height + box.y
- break
- case 'A':
- /* resize radii */
- this.value[i].values.r1 = (this.value[i].values.r1 * width) / box.width
- this.value[i].values.r2 = (this.value[i].values.r2 * height) / box.height
+ } else if (l == 'C' || l == 'S' || l == 'Q') {
+ this.value[i][1] = ((this.value[i][1] - box.x) * width) / box.width + box.x
+ this.value[i][2] = ((this.value[i][2] - box.y) * height) / box.height + box.y
+ this.value[i][3] = ((this.value[i][3] - box.x) * width) / box.width + box.x
+ this.value[i][4] = ((this.value[i][4] - box.y) * height) / box.height + box.y
- /* move position values */
- this.value[i].values.x = ((this.value[i].values.x - box.x) * width) / box.width + box.x
- this.value[i].values.y = ((this.value[i].values.y - box.y) * height) / box.height + box.y
- break
+ if (l == 'C') {
+ this.value[i][5] = ((this.value[i][5] - box.x) * width) / box.width + box.x
+ this.value[i][6] = ((this.value[i][6] - box.y) * height) / box.height + box.y
+ }
+
+ } else if (l == 'A') {
+ /* resize radii */
+ this.value[i][1] = (this.value[i][1] * width) / box.width
+ this.value[i][2] = (this.value[i][2] * height) / box.height
+
+ /* move position values */
+ this.value[i][6] = ((this.value[i][6] - box.x) * width) / box.width + box.x
+ this.value[i][7] = ((this.value[i][7] - box.y) * height) / box.height + box.y
}
+
}
return this
}
// Absolutize and parse path to array
, parse: function(array) {
- array = array.valueOf()
-
- /* if already is an array, no need to parse it */
- if (Array.isArray(array)) return array
+ /* if it's already is a patharray, no need to parse it */
+ if (array instanceof SVG.PathArray) return array.valueOf()
/* prepare for parsing */
var i, il, x0, y0, x1, y1, x2, y2, s, seg, segs
@@ -172,7 +111,7 @@ SVG.extend(SVG.PathArray, {
, y = 0
/* populate working path */
- SVG.parser.path.setAttribute('d', array)
+ SVG.parser.path.setAttribute('d', typeof array === 'string' ? array : arrayToString(array))
/* get segments */
segs = SVG.parser.path.pathSegList
@@ -181,7 +120,8 @@ SVG.extend(SVG.PathArray, {
seg = segs.getItem(i)
s = seg.pathSegTypeAsLetter
- if (/[MLHVCSQTA]/.test(s)) {
+ /* yes, this IS quite verbose but also about 30 times faster than .test() with a precompiled regex */
+ if (s == 'M' || s == 'L' || s == 'H' || s == 'V' || s == 'C' || s == 'S' || s == 'Q' || s == 'T' || s == 'A') {
if ('x' in seg) x = seg.x
if ('y' in seg) y = seg.y
@@ -193,44 +133,32 @@ SVG.extend(SVG.PathArray, {
if ('x' in seg) x += seg.x
if ('y' in seg) y += seg.y
- switch(s){
- case 'm':
- segs.replaceItem(SVG.parser.path.createSVGPathSegMovetoAbs(x, y), i)
- break
- case 'l':
- segs.replaceItem(SVG.parser.path.createSVGPathSegLinetoAbs(x, y), i)
- break
- case 'h':
- segs.replaceItem(SVG.parser.path.createSVGPathSegLinetoHorizontalAbs(x), i)
- break
- case 'v':
- segs.replaceItem(SVG.parser.path.createSVGPathSegLinetoVerticalAbs(y), i)
- break
- case 'c':
- segs.replaceItem(SVG.parser.path.createSVGPathSegCurvetoCubicAbs(x, y, x1, y1, x2, y2), i)
- break
- case 's':
- segs.replaceItem(SVG.parser.path.createSVGPathSegCurvetoCubicSmoothAbs(x, y, x2, y2), i)
- break
- case 'q':
- segs.replaceItem(SVG.parser.path.createSVGPathSegCurvetoQuadraticAbs(x, y, x1, y1), i)
- break
- case 't':
- segs.replaceItem(SVG.parser.path.createSVGPathSegCurvetoQuadraticSmoothAbs(x, y), i)
- break
- case 'a':
- segs.replaceItem(SVG.parser.path.createSVGPathSegArcAbs(x, y, seg.r1, seg.r2, seg.angle, seg.largeArcFlag, seg.sweepFlag), i)
- break
- case 'z':
- case 'Z':
- x = x0
- y = y0
- break
+ if (s == 'm')
+ segs.replaceItem(SVG.parser.path.createSVGPathSegMovetoAbs(x, y), i)
+ else if (s == 'l')
+ segs.replaceItem(SVG.parser.path.createSVGPathSegLinetoAbs(x, y), i)
+ else if (s == 'h')
+ segs.replaceItem(SVG.parser.path.createSVGPathSegLinetoHorizontalAbs(x), i)
+ else if (s == 'v')
+ segs.replaceItem(SVG.parser.path.createSVGPathSegLinetoVerticalAbs(y), i)
+ else if (s == 'c')
+ segs.replaceItem(SVG.parser.path.createSVGPathSegCurvetoCubicAbs(x, y, x1, y1, x2, y2), i)
+ else if (s == 's')
+ segs.replaceItem(SVG.parser.path.createSVGPathSegCurvetoCubicSmoothAbs(x, y, x2, y2), i)
+ else if (s == 'q')
+ segs.replaceItem(SVG.parser.path.createSVGPathSegCurvetoQuadraticAbs(x, y, x1, y1), i)
+ else if (s == 't')
+ segs.replaceItem(SVG.parser.path.createSVGPathSegCurvetoQuadraticSmoothAbs(x, y), i)
+ else if (s == 'a')
+ segs.replaceItem(SVG.parser.path.createSVGPathSegArcAbs(x, y, seg.r1, seg.r2, seg.angle, seg.largeArcFlag, seg.sweepFlag), i)
+ else if (s == 'z' || s == 'Z') {
+ x = x0
+ y = y0
}
}
/* record the start of a subpath */
- if (/[Mm]/.test(s)) {
+ if (s == 'M' || s == 'm') {
x0 = x
y0 = y
}
@@ -238,48 +166,30 @@ SVG.extend(SVG.PathArray, {
/* build internal representation */
array = []
- segs = SVG.parser.path.pathSegList
+ segs = SVG.parser.path.pathSegList
for (i = 0, il = segs.numberOfItems; i < il; ++i) {
seg = segs.getItem(i)
- s = {}
-
- switch (seg.pathSegTypeAsLetter) {
- case 'M':
- case 'L':
- case 'T':
- case 'S':
- case 'Q':
- case 'C':
- if (/[QC]/.test(seg.pathSegTypeAsLetter)) {
- s.x1 = seg.x1
- s.y1 = seg.y1
- }
-
- if (/[SC]/.test(seg.pathSegTypeAsLetter)) {
- s.x2 = seg.x2
- s.y2 = seg.y2
- }
-
- break
- case 'A':
- s = {
- r1: seg.r1
- , r2: seg.r2
- , a: seg.angle
- , l: seg.largeArcFlag|0
- , s: seg.sweepFlag|0
- }
- break
- }
-
- /* make the letter, x and y values accessible as key/values */
- s.type = seg.pathSegTypeAsLetter
- s.x = seg.x
- s.y = seg.y
+ s = seg.pathSegTypeAsLetter
+ x = [s]
+
+ if (s == 'M' || s == 'L' || s == 'T')
+ x.push(seg.x, seg.y)
+ else if (s == 'H')
+ x.push(seg.x)
+ else if (s == 'V')
+ x.push(seg.y)
+ else if (s == 'C')
+ x.push(seg.x1, seg.y1, seg.x2, seg.y2, seg.x, seg.y)
+ else if (s == 'S')
+ x.push(seg.x2, seg.y2, seg.x, seg.y)
+ else if (s == 'Q')
+ x.push(seg.x1, seg.y1, seg.x, seg.y)
+ else if (s == 'A')
+ x.push(seg.r1, seg.r2, seg.angle, seg.largeArcFlag|0, seg.sweepFlag|0, seg.x, seg.y)
/* store segment */
- array.push(s)
+ array.push(x)
}
return array
@@ -291,4 +201,41 @@ SVG.extend(SVG.PathArray, {
return SVG.parser.path.getBBox()
}
-}) \ No newline at end of file
+})
+
+// PathArray Helpers
+function arrayToString(a) {
+ for (var i = 0, il = a.length, s = ''; i < il; i++) {
+ s += a[i][0]
+
+ if (a[i][1] != null) {
+ s += a[i][1]
+
+ if (a[i][2] != null) {
+ s += ' '
+ s += a[i][2]
+
+ if (a[i][3] != null) {
+ s += ' '
+ s += a[i][3]
+ s += ' '
+ s += a[i][4]
+
+ if (a[i][5] != null) {
+ s += ' '
+ s += a[i][5]
+ s += ' '
+ s += a[i][6]
+
+ if (a[i][7] != null) {
+ s += ' '
+ s += a[i][7]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return s + ' '
+} \ No newline at end of file
diff --git a/src/pattern.js b/src/pattern.js
index e5398d2..e5398d2 100644..100755
--- a/src/pattern.js
+++ b/src/pattern.js
diff --git a/src/pointarray.js b/src/pointarray.js
index 28dbf3e..16f3283 100644..100755
--- a/src/pointarray.js
+++ b/src/pointarray.js
@@ -76,8 +76,6 @@ SVG.extend(SVG.PointArray, {
}
// Get bounding box of points
, bbox: function() {
- if (this._cachedBBox) return this._cachedBBox
-
SVG.parser.poly.setAttribute('points', this.toString())
return SVG.parser.poly.getBBox()
diff --git a/src/regex.js b/src/regex.js
index 3a28e64..c75b46f 100755
--- a/src/regex.js
+++ b/src/regex.js
@@ -23,9 +23,6 @@ SVG.regex = {
/* test css declaration */
, isCss: /[^:]+:[^;]+;?/
- /* test css property */
-, isStyle: /^font|text|leading|cursor/
-
/* test for blank string */
, isBlank: /^(\s+)?$/
diff --git a/src/relative.js b/src/relative.js
index 2d02c08..7759bb9 100644..100755
--- a/src/relative.js
+++ b/src/relative.js
@@ -1,28 +1,16 @@
//
SVG.extend(SVG.Element, SVG.FX, {
- // Relative methods
- relative: function() {
- var b, e = this
-
- return {
- // Move over x axis
- x: function(x) {
- b = e.bbox()
-
- return e.x(b.x + (x || 0))
- }
- // Move over y axis
- , y: function(y) {
- b = e.bbox()
-
- return e.y(b.y + (y || 0))
- }
- // Move over x and y axes
- , move: function(x, y) {
- this.x(x)
- return this.y(y)
- }
- }
+ // Relative move over x axis
+ dx: function(x) {
+ return this.x(this.x() + x)
+ }
+ // Relative move over y axis
+, dy: function(y) {
+ return this.y(this.y() + y)
+ }
+ // Relative move over x and y axes
+, dmove: function(x, y) {
+ return this.dx(x).dy(y)
}
}) \ No newline at end of file
diff --git a/src/sugar.js b/src/sugar.js
index 5c71afc..1a96c23 100755
--- a/src/sugar.js
+++ b/src/sugar.js
@@ -1,28 +1,25 @@
// Define list of available attributes for stroke and fill
-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
+var sugar = {
+ stroke: ['color', 'width', 'opacity', 'linecap', 'linejoin', 'miterlimit', 'dasharray', 'dashoffset']
+, fill: ['color', 'opacity', 'rule']
+, prefix: function(t, a) {
+ return a == 'color' ? t : t + '-' + a
+ }
}
/* Add sugar for fill and stroke */
-;['fill', 'stroke'].forEach(function(method) {
- var extension = {}
+;['fill', 'stroke'].forEach(function(m) {
+ var i, extension = {}
- extension[method] = function(o) {
- var indexOf
-
+ extension[m] = function(o) {
if (typeof o == 'string' || SVG.Color.isRgb(o) || (o && typeof o.fill === 'function'))
- this.attr(method, o)
+ this.attr(m, 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]])
+ /* set all attributes from sugar.fill and sugar.stroke list */
+ for (i = sugar[m].length - 1; i >= 0; i--)
+ if (o[sugar[m][i]] != null)
+ this.attr(sugar.prefix(m, sugar[m][i]), o[sugar[m][i]])
return this
}
@@ -72,7 +69,7 @@ SVG.extend(SVG.Element, SVG.FX, {
})
-SVG.extend(SVG.Rect, SVG.Ellipse, {
+SVG.extend(SVG.Rect, SVG.Ellipse, SVG.FX, {
// Add x and y radius
radius: function(x, y) {
return this.attr({ rx: x, ry: y || x })
@@ -95,12 +92,14 @@ SVG.extend(SVG.Path, {
SVG.extend(SVG.Text, SVG.FX, {
// Set font
font: function(o) {
- for (var key in o)
- key == 'anchor' ?
- this.attr('text-anchor', o[key]) :
- _styleAttr.indexOf(key) > -1 ?
- this.attr('font-'+ key, o[key]) :
- this.attr(key, o[key])
+ for (var k in o)
+ k == 'leading' ?
+ this.leading(o[k]) :
+ k == 'anchor' ?
+ this.attr('text-anchor', o[k]) :
+ k == 'size' || k == 'family' || k == 'weight' || k == 'stretch' || k == 'variant' || k == 'style' ?
+ this.attr('font-'+ k, o[k]) :
+ this.attr(k, o[k])
return this
}
diff --git a/src/svg.js b/src/svg.js
index 364a786..07afa7a 100755
--- a/src/svg.js
+++ b/src/svg.js
@@ -66,13 +66,17 @@ SVG.prepare = function(element) {
/* select document body and create invisible svg element */
var body = document.getElementsByTagName('body')[0]
, draw = (body ? new SVG.Doc(body) : element.nested()).size(2, 2)
+ , path = SVG.create('path')
+
+ /* insert parsers */
+ draw.node.appendChild(path)
/* create parser object */
SVG.parser = {
body: body || element.parent
, draw: draw.style('opacity:0;position:fixed;left:100%;top:100%;overflow:hidden')
- , poly: draw.polygon().node
- , path: draw.path().node
+ , poly: draw.polyline().node
+ , path: path
}
}
diff --git a/src/text.js b/src/text.js
index 73ef290..9d95b55 100755
--- a/src/text.js
+++ b/src/text.js
@@ -1,21 +1,15 @@
-// List font style attributes as they should be applied to style
-var _styleAttr = ('size family weight stretch variant style').split(' ')
-
SVG.Text = SVG.invent({
// Initialize node
create: function() {
this.constructor.call(this, SVG.create('text'))
- /* define default style */
- this.styles = {
- 'font-size': 16
- , 'font-family': 'Helvetica, Arial, sans-serif'
- , 'text-anchor': 'start'
- }
-
- this._leading = new SVG.Number('1.2em')
- this._rebuild = true
+ this._leading = new SVG.Number(1.3) /* store leading value for rebuilding */
+ this._rebuild = true /* enable automatic updating of dy values */
+ this._build = false /* disable build mode for adding multiple lines */
+
+ /* set default font */
+ this.attr('font-family', SVG.defaults.attrs['font-family'])
}
// Inherit from
@@ -24,96 +18,68 @@ SVG.Text = SVG.invent({
// Add class methods
, extend: {
// Move over x-axis
- x: function(x, a) {
+ x: function(x) {
/* act as getter */
if (x == null)
- return a ? this.attr('x') : this.bbox().x
+ return this.attr('x')
- /* set x taking anchor in mind */
- if (!a) {
- a = this.style('text-anchor')
- x = a == 'start' ? x : a == 'end' ? x + this.bbox().width : x + this.bbox().width / 2
- }
-
- /* move lines as well if no textPath si present */
+ /* move lines as well if no textPath is present */
if (!this.textPath)
this.lines.each(function() { if (this.newLined) this.x(x) })
return this.attr('x', x)
}
+ // Move over y-axis
+ , y: function(y) {
+ /* act as getter */
+ if (y == null)
+ return this.attr('y')
+
+ return this.attr('y', y + this.attr('y') - this.bbox().y)
+ }
// Move center over x-axis
- , cx: function(x, a) {
+ , cx: function(x) {
return x == null ? this.bbox().cx : this.x(x - this.bbox().width / 2)
}
// Move center over y-axis
- , cy: function(y, a) {
- return y == null ? this.bbox().cy : this.y(a ? y : y - this.bbox().height / 2)
+ , cy: function(y) {
+ return y == null ? this.bbox().cy : this.y(y - this.bbox().height / 2)
}
// Move element to given x and y values
- , move: function(x, y, a) {
- return this.x(x, a).y(y)
+ , move: function(x, y) {
+ return this.x(x).y(y)
}
// Move element by its center
- , center: function(x, y, a) {
- return this.cx(x, a).cy(y, a)
+ , center: function(x, y) {
+ return this.cx(x).cy(y)
}
// Set the text content
, text: function(text) {
/* act as getter */
- if (text == null)
- return this.content
+ if (!text) return this.content
- /* remove existing lines */
- this.clear()
+ /* remove existing content */
+ this.clear().build(true)
if (typeof text === 'function') {
- this._rebuild = false
-
+ /* call block */
text.call(this, this)
} else {
- this._rebuild = true
-
- /* make sure text is not blank */
- text = SVG.regex.isBlank.test(text) ? 'text' : text
-
- var i, il
- , lines = text.split('\n')
+ /* store text and make sure text is not blank */
+ text = (this.content = (SVG.regex.isBlank.test(text) ? 'text' : text)).split('\n')
/* build new lines */
- for (i = 0, il = lines.length; i < il; i++)
- this.tspan(lines[i]).newLine()
-
- this.rebuild()
+ for (var i = 0, il = text.length; i < il; i++)
+ this.tspan(text[i]).newLine()
}
- return this
- }
- // Create a tspan
- , tspan: function(text) {
- var node = this.textPath ? this.textPath.node : this.node
- , tspan = new SVG.TSpan().text(text)
- , style = this.style()
-
- /* add new tspan */
- node.appendChild(tspan.node)
- this.lines.add(tspan)
-
- /* add style if any */
- if (!SVG.regex.isBlank.test(style))
- tspan.style(style)
-
- /* store content */
- this.content += text
-
- /* store text parent */
- tspan.parent = this
-
- return tspan
+ /* disable build mode and rebuild lines */
+ return this.build(false).rebuild()
}
// Set font size
, size: function(size) {
- return this.attr('font-size', size)
+ return this.attr('font-size', size).rebuild()
}
// Set / get leading
, leading: function(value) {
@@ -122,47 +88,34 @@ SVG.Text = SVG.invent({
return this._leading
/* act as setter */
- value = new SVG.Number(value)
- this._leading = value
+ this._leading = new SVG.Number(value)
- /* apply leading */
- this.lines.each(function() {
- if (this.newLined)
- this.attr('dy', value)
- })
-
- return this
+ return this.rebuild()
}
- // rebuild appearance type
- , rebuild: function() {
+ // Rebuild appearance type
+ , rebuild: function(rebuild) {
var self = this
+ /* store new rebuild flag if given */
+ if (typeof rebuild == 'boolean')
+ this._rebuild = rebuild
+
/* define position of all lines */
if (this._rebuild) {
- this.lines.attr({
- x: this.attr('x')
- , dy: this._leading
- , style: this.style()
+ this.lines.each(function() {
+ if (this.newLined) {
+ if (!this.textPath)
+ this.attr('x', self.attr('x'))
+ this.attr('dy', self._leading * new SVG.Number(self.attr('font-size')))
+ }
})
}
return this
}
- // Clear all lines
- , clear: function() {
- var node = this.textPath ? this.textPath.node : this.node
-
- /* remove existing child nodes */
- while (node.hasChildNodes())
- node.removeChild(node.lastChild)
-
- /* refresh lines */
- delete this.lines
- this.lines = new SVG.Set
-
- /* initialize content */
- this.content = ''
-
+ // Enable / disable build mode
+ , build: function(build) {
+ this._build = !!build
return this
}
}
@@ -173,7 +126,12 @@ SVG.Text = SVG.invent({
text: function(text) {
return this.put(new SVG.Text).text(text)
}
+ // Create plain text element
+ , plain: function(text) {
+ return this.put(new SVG.Text).plain(text)
+ }
}
+
})
SVG.TSpan = SVG.invent({
@@ -187,8 +145,8 @@ SVG.TSpan = SVG.invent({
, extend: {
// Set text content
text: function(text) {
- this.node.appendChild(document.createTextNode(text))
-
+ typeof text === 'function' ? text.call(this, this) : this.plain(text)
+
return this
}
// Shortcut dx
@@ -201,12 +159,66 @@ SVG.TSpan = SVG.invent({
}
// Create new line
, newLine: function() {
+ /* fetch text parent */
+ var t = this.doc(SVG.Text)
+
+ /* mark new line */
this.newLined = true
- this.parent.content += '\n'
- this.dy(this.parent._leading)
- return this.attr('x', this.parent.x())
+
+ /* apply new hy¡n */
+ return this.dy(t._leading * t.attr('font-size')).attr('x', t.x())
}
}
})
+SVG.extend(SVG.Text, SVG.TSpan, {
+ // Create plain text node
+ plain: function(text) {
+ /* clear if build mode is disabled */
+ if (this._build === false)
+ this.clear()
+
+ /* create text node */
+ this.node.appendChild(document.createTextNode((this.content = text)))
+
+ return this
+ }
+ // Create a tspan
+, tspan: function(text) {
+ var node = (this.textPath || this).node
+ , tspan = new SVG.TSpan
+
+ /* clear if build mode is disabled */
+ if (this._build === false)
+ this.clear()
+
+ /* 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)
+ this.lines.add(tspan)
+
+ return tspan.text(text)
+ }
+ // Clear all lines
+, clear: function() {
+ var node = (this.textPath || this).node
+
+ /* remove existing child nodes */
+ while (node.hasChildNodes())
+ node.removeChild(node.lastChild)
+
+ /* reset content references */
+ if (this instanceof SVG.Text) {
+ delete this.lines
+ this.lines = new SVG.Set
+ this.content = ''
+ }
+
+ return this
+ }
+})
+