aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/array.js6
-rw-r--r--src/attr.js5
-rw-r--r--src/boxes.js201
-rw-r--r--src/clip.js43
-rw-r--r--src/element.js6
-rw-r--r--src/flatten.js (renamed from src/ungroup.js)10
-rw-r--r--src/fx.js2
-rw-r--r--src/gradient.js7
-rw-r--r--src/helpers.js18
-rw-r--r--src/mask.js44
-rw-r--r--src/polyfill.js42
-rw-r--r--src/selector.js13
-rw-r--r--src/set.js8
-rw-r--r--src/sugar.js4
-rw-r--r--src/viewbox.js127
15 files changed, 165 insertions, 371 deletions
diff --git a/src/array.js b/src/array.js
index 9947242..b532296 100644
--- a/src/array.js
+++ b/src/array.js
@@ -64,11 +64,7 @@ SVG.extend(SVG.Array, {
// if already is an array, no need to parse it
if (Array.isArray(array)) return array
- return this.split(array)
- }
- // Strip unnecessary whitespace
-, split: function(string) {
- return string.trim().split(SVG.regex.delimiter).map(parseFloat)
+ return array.trim().split(SVG.regex.delimiter).map(parseFloat)
}
// Reverse array
, reverse: function() {
diff --git a/src/attr.js b/src/attr.js
index 134ac19..c88d34c 100644
--- a/src/attr.js
+++ b/src/attr.js
@@ -28,11 +28,6 @@ SVG.extend(SVG.Element, {
parseFloat(v) : v
} else {
- // 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
// convert image fill and stroke to patterns
if (a == 'fill' || a == 'stroke') {
diff --git a/src/boxes.js b/src/boxes.js
index 3db523e..5ab261a 100644
--- a/src/boxes.js
+++ b/src/boxes.js
@@ -1,15 +1,20 @@
SVG.Box = SVG.invent({
- create: function(x, y, width, height) {
- if (typeof x == 'object' && !(x instanceof SVG.Element)) {
- // chromes getBoundingClientRect has no x and y property
- return SVG.Box.call(this, x.left != null ? x.left : x.x , x.top != null ? x.top : x.y, x.width, x.height)
- } else if (arguments.length == 4) {
- this.x = x
- this.y = y
- this.width = width
- this.height = height
-
- }
+ create: function(source) {
+ var base = [0,0,0,0]
+ source = typeof source === 'string' ?
+ source.split(SVG.regex.delimiter).map(parseFloat) :
+ Array.isArray(source) ?
+ source :
+ typeof source == 'object' ?
+ [source.left != null ? source.left : source.x, source.top != null ? source.top : source.y, source.width, source.height] :
+ arguments.length == 4 ?
+ [].slice.call(arguments) :
+ base
+
+ this.x = source[0]
+ this.y = source[1]
+ this.width = source[2]
+ this.height = source[3]
// add center, right, bottom...
fullBox(this)
@@ -17,15 +22,14 @@ SVG.Box = SVG.invent({
, extend: {
// Merge rect box with another, return a new instance
merge: function(box) {
- var b = new this.constructor()
-
- // merge boxes
- b.x = Math.min(this.x, box.x)
- b.y = Math.min(this.y, box.y)
- b.width = Math.max(this.x + this.width, box.x + box.width) - b.x
- b.height = Math.max(this.y + this.height, box.y + box.height) - b.y
-
- return fullBox(b)
+ var x = Math.min(this.x, box.x)
+ , y = Math.min(this.y, box.y)
+
+ return new SVG.Box(
+ x, y,
+ Math.max(this.x + this.width, box.x + box.width) - x,
+ Math.max(this.y + this.height, box.y + box.height) - y
+ )
}
, transform: function(m) {
@@ -46,124 +50,89 @@ SVG.Box = SVG.invent({
yMax = Math.max(yMax,p.y)
})
- bbox = new this.constructor()
- bbox.x = xMin
- bbox.width = xMax-xMin
- bbox.y = yMin
- bbox.height = yMax-yMin
-
- fullBox(bbox)
-
- return bbox
+ return new SVG.Box(
+ xMin, yMin,
+ xMax-xMin,
+ yMax-yMin
+ )
}
- }
-})
-SVG.BBox = SVG.invent({
- // Initialize
- create: function(element) {
- SVG.Box.apply(this, [].slice.call(arguments))
-
- // get values if element is given
- if (element instanceof SVG.Element) {
- var box
+ , addOffset: function() {
+ // offset by window scroll position, because getBoundingClientRect changes when window is scrolled
+ this.x += window.pageXOffset
+ this.y += window.pageYOffset
+ return this
+ }
+ , toString: function() {
+ return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height
+ }
+ , morph: function(x, y, width, height){
+ this.destination = new SVG.Box(x, y, width, height)
+ return this
+ }
- // yes this is ugly, but Firefox can be a bitch when it comes to elements that are not yet rendered
- try {
+ , at: function(pos) {
- if (!document.documentElement.contains){
- // This is IE - it does not support contains() for top-level SVGs
- var topParent = element.node;
- while (topParent.parentNode){
- topParent = topParent.parentNode;
- }
- if (topParent != document) throw new Exception('Element not in the dom')
- } else {
- // the element is NOT in the dom, throw error
- if(!document.documentElement.contains(element.node)) throw new Exception('Element not in the dom')
- }
+ if(!this.destination) return this
- // find native bbox
- box = element.node.getBBox()
- } catch(e) {
- if(element instanceof SVG.Shape){
- var clone = element.clone(SVG.parser.draw).show()
- box = clone.bbox()
- clone.remove()
- }else{
- box = {
- x: element.node.clientLeft
- , y: element.node.clientTop
- , width: element.node.clientWidth
- , height: element.node.clientHeight
- }
- }
- }
+ return new SVG.Box(
+ this.x + (this.destination.x - this.x) * pos
+ , this.y + (this.destination.y - this.y) * pos
+ , this.width + (this.destination.width - this.width) * pos
+ , this.height + (this.destination.height - this.height) * pos
+ )
- SVG.Box.call(this, box)
}
-
}
- // Define ancestor
-, inherit: SVG.Box
-
- // Define Parent
+ // Define Parent
, parent: SVG.Element
// Constructor
, construct: {
// Get bounding box
bbox: function() {
- return new SVG.BBox(this)
- }
- }
-
-})
-
-SVG.BBox.prototype.constructor = SVG.BBox
-
+ var box
-SVG.extend(SVG.Element, {
- tbox: function(){
- console.warn('Use of TBox is deprecated and mapped to RBox. Use .rbox() instead.')
- return this.rbox(this.doc())
- }
-})
+ try {
+ // find native bbox
+ box = this.node.getBBox()
-SVG.RBox = SVG.invent({
- // Initialize
- create: function(element) {
- SVG.Box.apply(this, [].slice.call(arguments))
+ if(isNulledBox(box) && !domContains(this.node)) {
+ throw new Exception('Element not in the dom')
+ }
+ } catch(e) {
+ try {
+ var clone = this.clone(SVG.parser.draw).show()
+ box = clone.node.getBBox()
+ clone.remove()
+ } catch(e) {
+ console.warn('Getting a bounding box of this element is not possible')
+ }
+ }
- if (element instanceof SVG.Element) {
- SVG.Box.call(this, element.node.getBoundingClientRect())
+ return new SVG.Box(box)
}
- }
-
-, inherit: SVG.Box
-
- // define Parent
-, parent: SVG.Element
-, extend: {
- addOffset: function() {
- // offset by window scroll position, because getBoundingClientRect changes when window is scrolled
- this.x += window.pageXOffset
- this.y += window.pageYOffset
- return this
+ , rbox: function(el) {
+ // IE11 throws an error when element not in dom
+ try{
+ var box = new SVG.Box(this.node.getBoundingClientRect())
+ if (el) return box.transform(el.screenCTM().inverse())
+ return box.addOffset()
+ } catch(e) {
+ return new SVG.Box()
+ }
}
}
+})
- // Constructor
-, construct: {
- // Get rect box
- rbox: function(el) {
- if (el) return new SVG.RBox(this).transform(el.screenCTM().inverse())
- return new SVG.RBox(this).addOffset()
- }
- }
+SVG.extend(SVG.Doc, SVG.Nested, SVG.Symbol, SVG.Image, SVG.Pattern, SVG.Marker, SVG.ForeignObject, SVG.View, {
+ viewbox: function(x, y, width, height) {
+ // act as getter
+ if(x == null) return new SVG.Box(this.attr('viewBox'))
+ // act as setter
+ return this.attr('viewBox', new SVG.Box(x, y, width, height))
+ }
})
-
-SVG.RBox.prototype.constructor = SVG.RBox
diff --git a/src/clip.js b/src/clip.js
index 2a92e44..70e2499 100644
--- a/src/clip.js
+++ b/src/clip.js
@@ -1,11 +1,6 @@
SVG.ClipPath = SVG.invent({
// Initialize node
- create: function() {
- this.constructor.call(this, SVG.create('clipPath'))
-
- // keep references to clipped elements
- this.targets = []
- }
+ create: 'clipPath'
// Inherit from
, inherit: SVG.Container
@@ -14,19 +9,22 @@ SVG.ClipPath = SVG.invent({
, extend: {
// Unclip all clipped elements and remove itself
remove: function() {
- // unclip all targets
- for (var i = this.targets.length - 1; i >= 0; i--)
- if (this.targets[i])
- this.targets[i].unclip()
- this.targets = []
+ // unclip all targets
+ this.targets().each(function() {
+ this.unclip()
+ })
- // remove clipPath from parent
+ // remove clipPath from parent
this.parent().removeElement(this)
-
+
return this
}
+
+ , targets: function() {
+ return SVG.select('svg [clip-path*="' +this.id() +'"]')
+ }
}
-
+
// Add parent method
, construct: {
// Create clipping element
@@ -40,19 +38,18 @@ SVG.ClipPath = SVG.invent({
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.ClipPath ? element : this.parent().clip().add(element)
+ // use given clip or create a new one
+ var clipper = element instanceof SVG.ClipPath ? element : this.parent().clip().add(element)
- // store reverence on self in mask
- this.clipper.targets.push(this)
-
- // apply mask
- return this.attr('clip-path', 'url("#' + this.clipper.attr('id') + '")')
+ // apply mask
+ return this.attr('clip-path', 'url("#' + clipper.attr('id') + '")')
}
// Unclip element
, unclip: function() {
- delete this.clipper
return this.attr('clip-path', null)
}
-
+, clipper: function() {
+ return this.reference('clip-path')
+ }
+
}) \ No newline at end of file
diff --git a/src/element.js b/src/element.js
index 9bb8a0a..230aa4b 100644
--- a/src/element.js
+++ b/src/element.js
@@ -2,8 +2,7 @@
SVG.Element = SVG.invent({
// Initialize node
create: function(node) {
- // make stroke value accessible dynamically
- this._stroke = SVG.defaults.attrs.stroke
+ // last fired event on node
this._event = null
// initialize data object
@@ -13,9 +12,6 @@ SVG.Element = SVG.invent({
if (this.node = node) {
this.type = node.nodeName
this.node.instance = this
-
- // store current attribute value
- this._stroke = node.getAttribute('stroke') || this._stroke
}
}
diff --git a/src/ungroup.js b/src/flatten.js
index 7f26915..e3742aa 100644
--- a/src/ungroup.js
+++ b/src/flatten.js
@@ -1,6 +1,5 @@
SVG.extend(SVG.Parent, {
-
- ungroup: function(parent, depth) {
+ flatten: function(parent, depth) {
if(depth === 0 || this instanceof SVG.Defs) return this
parent = parent || (this instanceof SVG.Doc ? this : this.parent(SVG.Parent))
@@ -8,17 +7,12 @@ SVG.extend(SVG.Parent, {
this.each(function(){
if(this instanceof SVG.Defs) return this
- if(this instanceof SVG.Parent) return this.ungroup(parent, depth-1)
+ if(this instanceof SVG.Parent) return this.flatten(parent, depth-1)
return this.toParent(parent)
})
this.node.firstChild || this.remove()
return this
- },
-
- flatten: function(parent, depth) {
- return this.ungroup(parent, depth)
}
-
}) \ No newline at end of file
diff --git a/src/fx.js b/src/fx.js
index 98ded65..9fbbdd8 100644
--- a/src/fx.js
+++ b/src/fx.js
@@ -858,7 +858,7 @@ SVG.extend(SVG.FX, {
// Add animatable viewbox
, viewbox: function(x, y, width, height) {
if (this.target() instanceof SVG.Container) {
- this.add('viewbox', new SVG.ViewBox(x, y, width, height))
+ this.add('viewbox', new SVG.Box(x, y, width, height))
}
return this
diff --git a/src/gradient.js b/src/gradient.js
index 17145e6..a16c092 100644
--- a/src/gradient.js
+++ b/src/gradient.js
@@ -2,9 +2,6 @@ SVG.Gradient = SVG.invent({
// Initialize node
create: function(type) {
this.constructor.call(this, SVG.create(type + 'Gradient'))
-
- // store type
- this.type = type
}
// Inherit from
@@ -55,13 +52,13 @@ SVG.Gradient = SVG.invent({
SVG.extend(SVG.Gradient, SVG.FX, {
// From position
from: function(x, y) {
- return (this._target || this).type == 'radial' ?
+ return (this._target || this).type == 'radialGradient' ?
this.attr({ fx: new SVG.Number(x), fy: new SVG.Number(y) }) :
this.attr({ x1: new SVG.Number(x), y1: new SVG.Number(y) })
}
// To position
, to: function(x, y) {
- return (this._target || this).type == 'radial' ?
+ return (this._target || this).type == 'radialGradient' ?
this.attr({ cx: new SVG.Number(x), cy: new SVG.Number(y) }) :
this.attr({ x2: new SVG.Number(x), y2: new SVG.Number(y) })
}
diff --git a/src/helpers.js b/src/helpers.js
index e3ad6f0..744a712 100644
--- a/src/helpers.js
+++ b/src/helpers.js
@@ -1,3 +1,17 @@
+function isNulledBox(box) {
+ return !box.w && !box.h && !box.x && !box.y
+}
+
+function domContains(node) {
+ return (document.documentElement.contains || function(node) {
+ // This is IE - it does not support contains() for top-level SVGs
+ while (node.parentNode){
+ node = node.parentNode;
+ }
+ return node == document
+ }).call(document.documentElement, node)
+}
+
function pathRegReplace(a, b, c, d) {
return c + d.replace(SVG.regex.dots, ' .')
}
@@ -163,10 +177,10 @@ function fullBox(b) {
// Get id from reference string
function idFromReference(url) {
- var m = url.toString().match(SVG.regex.reference)
+ var m = (url || '').toString().match(SVG.regex.reference)
if (m) return m[1]
}
// Create matrix array for looping
-var abcdef = 'abcdef'.split('') \ No newline at end of file
+var abcdef = 'abcdef'.split('')
diff --git a/src/mask.js b/src/mask.js
index 51e61e9..86951ad 100644
--- a/src/mask.js
+++ b/src/mask.js
@@ -1,11 +1,6 @@
SVG.Mask = SVG.invent({
// Initialize node
- create: function() {
- this.constructor.call(this, SVG.create('mask'))
-
- // keep references to masked elements
- this.targets = []
- }
+ create: 'mask'
// Inherit from
, inherit: SVG.Container
@@ -14,19 +9,22 @@ SVG.Mask = SVG.invent({
, extend: {
// Unmask all masked elements and remove itself
remove: function() {
- // unmask all targets
- for (var i = this.targets.length - 1; i >= 0; i--)
- if (this.targets[i])
- this.targets[i].unmask()
- this.targets = []
+ // unmask all targets
+ this.targets().each(function() {
+ this.unmask()
+ })
- // remove mask from parent
+ // remove mask from parent
this.parent().removeElement(this)
-
+
return this
}
+
+ , targets: function() {
+ return SVG.select('svg [mask*="' +this.id() +'"]')
+ }
}
-
+
// Add parent method
, construct: {
// Create masking element
@@ -40,19 +38,17 @@ SVG.Mask = SVG.invent({
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)
-
- // store reverence on self in mask
- this.masker.targets.push(this)
-
- // apply mask
- return this.attr('mask', 'url("#' + this.masker.attr('id') + '")')
+ // use given mask or create a new one
+ var masker = element instanceof SVG.Mask ? element : this.parent().mask().add(element)
+
+ // apply mask
+ return this.attr('mask', 'url("#' + masker.attr('id') + '")')
}
// Unmask element
, unmask: function() {
- delete this.masker
return this.attr('mask', null)
}
-
+, masker: function() {
+ return this.reference('mask')
+ }
})
diff --git a/src/polyfill.js b/src/polyfill.js
deleted file mode 100644
index 06ae0fd..0000000
--- a/src/polyfill.js
+++ /dev/null
@@ -1,42 +0,0 @@
-// Add CustomEvent to IE9 and IE10
-if (typeof CustomEvent !== 'function') {
- // Code from: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent
- var CustomEvent = function(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
-}
-
-// requestAnimationFrame / cancelAnimationFrame Polyfill with fallback based on Paul Irish
-(function(w) {
- var lastTime = 0
- var vendors = ['moz', 'webkit']
-
- for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
- w.requestAnimationFrame = w[vendors[x] + 'RequestAnimationFrame']
- w.cancelAnimationFrame = w[vendors[x] + 'CancelAnimationFrame'] ||
- w[vendors[x] + 'CancelRequestAnimationFrame']
- }
-
- w.requestAnimationFrame = w.requestAnimationFrame ||
- function(callback) {
- var currTime = new Date().getTime()
- var timeToCall = Math.max(0, 16 - (currTime - lastTime))
-
- var id = w.setTimeout(function() {
- callback(currTime + timeToCall)
- }, timeToCall)
-
- lastTime = currTime + timeToCall
- return id
- }
-
- w.cancelAnimationFrame = w.cancelAnimationFrame || w.clearTimeout;
-
-}(window)) \ No newline at end of file
diff --git a/src/selector.js b/src/selector.js
index fe87e4e..90a8714 100644
--- a/src/selector.js
+++ b/src/selector.js
@@ -13,10 +13,19 @@ SVG.select = function(query, parent) {
)
}
+SVG.$$ = function(query, parent) {
+ return SVG.utils.map((parent || document).querySelectorAll(query), function(node) {
+ return SVG.adopt(node)
+ })
+}
+
+SVG.$ = function(query, parent) {
+ return SVG.adopt((parent || document).querySelector(query))
+}
+
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/set.js b/src/set.js
index 9da52c7..677916d 100644
--- a/src/set.js
+++ b/src/set.js
@@ -72,17 +72,17 @@ SVG.Set = SVG.invent({
, bbox: function(){
// return an empty box of there are no members
if (this.members.length == 0)
- return new SVG.RBox()
+ return new SVG.Box()
// get the first rbox and update the target bbox
- var rbox = this.members[0].rbox(this.members[0].doc())
+ var box = this.members[0].rbox(this.members[0].doc())
this.each(function() {
// user rbox for correct position and visual representation
- rbox = rbox.merge(this.rbox(this.doc()))
+ box = box.merge(this.rbox(this.doc()))
})
- return rbox
+ return box
}
}
diff --git a/src/sugar.js b/src/sugar.js
index e577ea7..d58c6c8 100644
--- a/src/sugar.js
+++ b/src/sugar.js
@@ -82,7 +82,7 @@ SVG.extend(SVG.Rect, SVG.Ellipse, SVG.Circle, SVG.Gradient, SVG.FX, {
// Add x and y radius
radius: function(x, y) {
var type = (this._target || this).type;
- return type == 'radial' || type == 'circle' ?
+ return type == 'radialGradient' || type == 'radialGradient' ?
this.attr('r', new SVG.Number(x)) :
this.rx(x).ry(y == null ? x : y)
}
@@ -95,7 +95,7 @@ SVG.extend(SVG.Path, {
}
// Get point at length
, pointAt: function(length) {
- return this.node.getPointAtLength(length)
+ return new SVG.Point(this.node.getPointAtLength(length))
}
})
diff --git a/src/viewbox.js b/src/viewbox.js
deleted file mode 100644
index 8ce7e04..0000000
--- a/src/viewbox.js
+++ /dev/null
@@ -1,127 +0,0 @@
-
-SVG.ViewBox = SVG.invent({
-
- create: function(source) {
- var i, base = [0, 0, 0, 0]
-
- var x, y, width, height, box, view, we, he
- , wm = 1 // width multiplier
- , hm = 1 // height multiplier
- , reg = /[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?/gi
-
- if(source instanceof SVG.Element){
-
- we = source
- he = source
- view = (source.attr('viewBox') || '').match(reg)
- box = source.bbox
-
- // get dimensions of current node
- width = new SVG.Number(source.width())
- height = new SVG.Number(source.height())
-
- // 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()
- }
- while (height.unit == '%') {
- hm *= height.value
- height = new SVG.Number(he instanceof SVG.Doc ? he.parent().offsetHeight : he.parent().height())
- he = he.parent()
- }
-
- // ensure defaults
- this.x = 0
- this.y = 0
- this.width = width * wm
- this.height = height * hm
- this.zoom = 1
-
- if (view) {
- // get width and height from viewbox
- x = parseFloat(view[0])
- y = parseFloat(view[1])
- width = parseFloat(view[2])
- height = parseFloat(view[3])
-
- // calculate zoom accoring to viewbox
- this.zoom = ((this.width / this.height) > (width / height)) ?
- this.height / height :
- this.width / width
-
- // calculate real pixel dimensions on parent SVG.Doc element
- this.x = x
- this.y = y
- this.width = width
- this.height = height
-
- }
-
- }else{
-
- // ensure source as object
- source = typeof source === 'string' ?
- source.match(reg).map(function(el){ return parseFloat(el) }) :
- Array.isArray(source) ?
- source :
- typeof source == 'object' ?
- [source.x, source.y, source.width, source.height] :
- arguments.length == 4 ?
- [].slice.call(arguments) :
- base
-
- this.x = source[0]
- this.y = source[1]
- this.width = source[2]
- this.height = source[3]
- }
-
-
- }
-
-, extend: {
-
- toString: function() {
- return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height
- }
- , morph: function(x, y, width, height){
- this.destination = new SVG.ViewBox(x, y, width, height)
- return this
- }
-
- , at: function(pos) {
-
- if(!this.destination) return this
-
- return new SVG.ViewBox([
- this.x + (this.destination.x - this.x) * pos
- , this.y + (this.destination.y - this.y) * pos
- , this.width + (this.destination.width - this.width) * pos
- , this.height + (this.destination.height - this.height) * pos
- ])
-
- }
-
- }
-
- // Define parent
-, parent: SVG.Container
-
- // Add parent method
-, construct: {
-
- // get/set viewbox
- viewbox: function(x, y, width, height) {
- if (arguments.length == 0)
- // act as a getter if there are no arguments
- return new SVG.ViewBox(this)
-
- // otherwise act as a setter
- return this.attr('viewBox', new SVG.ViewBox(x, y, width, height))
- }
-
- }
-
-}) \ No newline at end of file