diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/array.js | 6 | ||||
-rw-r--r-- | src/attr.js | 5 | ||||
-rw-r--r-- | src/boxes.js | 201 | ||||
-rw-r--r-- | src/clip.js | 43 | ||||
-rw-r--r-- | src/element.js | 6 | ||||
-rw-r--r-- | src/flatten.js (renamed from src/ungroup.js) | 10 | ||||
-rw-r--r-- | src/fx.js | 2 | ||||
-rw-r--r-- | src/gradient.js | 7 | ||||
-rw-r--r-- | src/helpers.js | 18 | ||||
-rw-r--r-- | src/mask.js | 44 | ||||
-rw-r--r-- | src/polyfill.js | 42 | ||||
-rw-r--r-- | src/selector.js | 13 | ||||
-rw-r--r-- | src/set.js | 8 | ||||
-rw-r--r-- | src/sugar.js | 4 | ||||
-rw-r--r-- | src/viewbox.js | 127 |
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 @@ -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 +}) @@ -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 |