]> source.dussan.org Git - svg.js.git/commitdiff
convert everything to es6 classes and imports
authorUlrich-Matthias Schäfer <ulima.ums@googlemail.com>
Thu, 25 Oct 2018 21:28:12 +0000 (23:28 +0200)
committerUlrich-Matthias Schäfer <ulima.ums@googlemail.com>
Thu, 25 Oct 2018 21:28:12 +0000 (23:28 +0200)
66 files changed:
src/A.js
src/Animator.js
src/ArrayPolyfill.js [new file with mode: 0644]
src/Bare.js
src/Box.js
src/Circle.js [new file with mode: 0644]
src/ClipPath.js
src/Color.js
src/Container.js
src/Controller.js
src/Defs.js
src/Doc.js
src/Element.js
src/Ellipse.js
src/EventTarget.js
src/G.js
src/Gradient.js
src/HtmlNode.js
src/Image.js
src/Line.js
src/Marker.js
src/Mask.js
src/Matrix.js
src/Morphable.js
src/Parent.js
src/Path.js
src/PathArray.js
src/Pattern.js
src/Point.js
src/PointArray.js
src/Polygon.js
src/Polyline.js [new file with mode: 0644]
src/Queue.js
src/Rect.js
src/Runner.js
src/SVGArray.js
src/SVGNumber.js
src/Shape.js
src/Symbol.js
src/Text.js
src/TextPath.js
src/Timeline.js
src/arrange.js
src/attr.js
src/circled.js [new file with mode: 0644]
src/classes.js [new file with mode: 0644]
src/css.js
src/data.js
src/defaults.js [new file with mode: 0644]
src/event.js
src/flatten.js
src/gradiented.js [new file with mode: 0644]
src/helpers.js
src/memory.js
src/namespaces.js [new file with mode: 0644]
src/parser.js
src/pointed.js
src/regex.js
src/selector.js
src/stop.js [new file with mode: 0644]
src/sugar.js
src/svg.js
src/tools.js [new file with mode: 0644]
src/transform.js
src/use.js
src/utils.js [new file with mode: 0644]

index cb0a3411c7379fcc9944f89a40799769be2b574f..72e13e400bb6b3a900f936b35526b8031d93e143 100644 (file)
--- a/src/A.js
+++ b/src/A.js
@@ -1,35 +1,34 @@
-SVG.A = SVG.invent({
-  // Initialize node
-  create: 'a',
+import {Container, Element} from './classes.js'
+import {nodeOrNew, addFactory} from './tools.js'
+import {xlink} from './namespaces.js'
 
-  // Inherit from
-  inherit: SVG.Container,
+export default class A extends Container {
+  constructor (node) {
+    super(nodeOrNew('a', node))
+  }
 
-  // Add class methods
-  extend: {
-    // Link url
-    to: function (url) {
-      return this.attr('href', url, SVG.xlink)
-    },
-    // Link target attribute
-    target: function (target) {
-      return this.attr('target', target)
-    }
-  },
+  // Link url
+  to (url) {
+    return this.attr('href', url, xlink)
+  }
 
-  // Add parent method
-  construct: {
-    // Create a hyperlink element
-    link: function (url) {
-      return this.put(new SVG.A()).to(url)
-    }
+  // Link target attribute
+  target (target) {
+    return this.attr('target', target)
+  }
+}
+
+addFactory(Container, {
+  // Create a hyperlink element
+  link: function (url) {
+    return this.put(new A()).to(url)
   }
 })
 
-SVG.extend(SVG.Element, {
+addFactory(Element, {
   // Create a hyperlink element
   linkTo: function (url) {
-    var link = new SVG.A()
+    var link = new A()
 
     if (typeof url === 'function') { url.call(link, link) } else {
       link.to(url)
@@ -37,5 +36,4 @@ SVG.extend(SVG.Element, {
 
     return this.parent().put(link).put(this)
   }
-
 })
index eb8ca726ec1884e0e9c744587b077971679a1b8b..d49ab121720a4734e57b187c5232d3d60eb9ff1b 100644 (file)
@@ -1,65 +1,65 @@
-/* global requestAnimationFrame */
+import Queue from './Queue.js'
 
-SVG.Animator = {
+export default {
   nextDraw: null,
-  frames: new SVG.Queue(),
-  timeouts: new SVG.Queue(),
+  frames: new Queue(),
+  timeouts: new Queue(),
   timer: window.performance || window.Date,
   transforms: [],
 
-  frame: function (fn) {
+  frame (fn) {
     // Store the node
-    var node = SVG.Animator.frames.push({ run: fn })
+    var node = Animator.frames.push({ run: fn })
 
     // Request an animation frame if we don't have one
-    if (SVG.Animator.nextDraw === null) {
-      SVG.Animator.nextDraw = requestAnimationFrame(SVG.Animator._draw)
+    if (Animator.nextDraw === null) {
+      Animator.nextDraw = window.requestAnimationFrame(Animator._draw)
     }
 
     // Return the node so we can remove it easily
     return node
   },
 
-  transform_frame: function (fn, id) {
-    SVG.Animator.transforms[id] = fn
+  transform_frame (fn, id) {
+    Animator.transforms[id] = fn
   },
 
-  timeout: function (fn, delay) {
+  timeout (fn, delay) {
     delay = delay || 0
 
     // Work out when the event should fire
-    var time = SVG.Animator.timer.now() + delay
+    var time = Animator.timer.now() + delay
 
     // Add the timeout to the end of the queue
-    var node = SVG.Animator.timeouts.push({ run: fn, time: time })
+    var node = Animator.timeouts.push({ run: fn, time: time })
 
     // Request another animation frame if we need one
-    if (SVG.Animator.nextDraw === null) {
-      SVG.Animator.nextDraw = requestAnimationFrame(SVG.Animator._draw)
+    if (Animator.nextDraw === null) {
+      Animator.nextDraw = window.requestAnimationFrame(Animator._draw)
     }
 
     return node
   },
 
-  cancelFrame: function (node) {
-    SVG.Animator.frames.remove(node)
+  cancelFrame (node) {
+    Animator.frames.remove(node)
   },
 
-  clearTimeout: function (node) {
-    SVG.Animator.timeouts.remove(node)
+  clearTimeout (node) {
+    Animator.timeouts.remove(node)
   },
 
-  _draw: function (now) {
+  _draw (now) {
     // Run all the timeouts we can run, if they are not ready yet, add them
     // to the end of the queue immediately! (bad timeouts!!! [sarcasm])
     var nextTimeout = null\r
-    var lastTimeout = SVG.Animator.timeouts.last()
-    while ((nextTimeout = SVG.Animator.timeouts.shift())) {
+    var lastTimeout = Animator.timeouts.last()
+    while ((nextTimeout = Animator.timeouts.shift())) {
       // Run the timeout if its time, or push it to the end
       if (now >= nextTimeout.time) {
         nextTimeout.run()
       } else {
-        SVG.Animator.timeouts.push(nextTimeout)
+        Animator.timeouts.push(nextTimeout)
       }
 
       // If we hit the last item, we should stop shifting out more items
@@ -68,16 +68,16 @@ SVG.Animator = {
 
     // Run all of the animation frames
     var nextFrame = null
-    var lastFrame = SVG.Animator.frames.last()
-    while ((nextFrame !== lastFrame) && (nextFrame = SVG.Animator.frames.shift())) {
+    var lastFrame = Animator.frames.last()
+    while ((nextFrame !== lastFrame) && (nextFrame = Animator.frames.shift())) {
       nextFrame.run()
     }
 
-    SVG.Animator.transforms.forEach(function (el) { el() })
+    Animator.transforms.forEach(function (el) { el() })
 
     // If we have remaining timeouts or frames, draw until we don't anymore
-    SVG.Animator.nextDraw = SVG.Animator.timeouts.first() || SVG.Animator.frames.first()
-        ? requestAnimationFrame(SVG.Animator._draw)
+    Animator.nextDraw = Animator.timeouts.first() || Animator.frames.first()
+        ? window.requestAnimationFrame(Animator._draw)
         : null
   }
 }
diff --git a/src/ArrayPolyfill.js b/src/ArrayPolyfill.js
new file mode 100644 (file)
index 0000000..596b2ca
--- /dev/null
@@ -0,0 +1 @@
+export default Array
index 393ce6ee88bdbd738422fa9aee88e11b277e733e..783fa6a7c29d1f1d38ae285bf2831fba3bc8bfea 100644 (file)
@@ -1,27 +1,13 @@
+import {nodeOrNew} from './tools.js'
+import Parent from './Parent.js'
 
-SVG.Bare = SVG.invent({
-  // Initialize
-  create: function (element, inherit) {
-    // construct element
-    SVG.Element.call(this, SVG.create(element))
-
-    // inherit custom methods
-    if (inherit) {
-      for (var method in inherit.prototype) {
-        if (typeof inherit.prototype[method] === 'function') {
-          this[method] = inherit.prototype[method]
-        }
-      }
+export default function Bare (element, inherit) {
+  return class Custom extends inherit {
+    constructor (node) {
+      super(nodeOrNew(element, node))
     }
-  },
 
-  // Inherit from
-  inherit: SVG.Element,
-
-  // Add methods
-  extend: {
-    // Insert some plain text
-    words: function (text) {
+    words (text) {
       // remove contents
       while (this.node.hasChildNodes()) {
         this.node.removeChild(this.node.lastChild)
@@ -33,11 +19,20 @@ SVG.Bare = SVG.invent({
       return this
     }
   }
-})
+}
 
-SVG.extend(SVG.Parent, {
+export let constructors = {
   // Create an element that is not described by SVG.js
   element: function (element, inherit) {
-    return this.put(new SVG.Bare(element, inherit))
+    let custom = createCustom(element, inherit)
+    return this.put(new custom())
   }
-})
+}
+
+// extend(Parent, {
+//   // Create an element that is not described by SVG.js
+//   element: function (element, inherit) {
+//     let custom = createCustom(element, inherit)
+//     return this.put(new custom())
+//   }
+// })
index a9247ef367530367a0769c620b6ba6d8a4b56f0a..0c98dd55143ab222f1505a40e50679bbb754de1b 100644 (file)
@@ -1,9 +1,13 @@
-/* globals fullBox, domContains, isNulledBox, Exception */
-
-SVG.Box = SVG.invent({
-  create: function (source) {
+import {Parent, Doc, Symbol, Image, Pattern, Marker, Point} from './classes.js'
+import parser from './parser.js'
+import {fullBox, domContains, isNulledBox} from './helpers.js'
+import {extend} from './tools.js'
+import {delimiter} from './regex.js'
+
+export default class Box {
+  constructor (source) {
     var base = [0, 0, 0, 0]
-    source = typeof source === 'string' ? source.split(SVG.regex.delimiter).map(parseFloat)
+    source = typeof source === 'string' ? source.split(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]
@@ -17,125 +21,104 @@ SVG.Box = SVG.invent({
 
     // add center, right, bottom...
     fullBox(this)
-  },
-  extend: {
-    // Merge rect box with another, return a new instance
-    merge: function (box) {
-      var x = Math.min(this.x, box.x)
-      var 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) {
-      var xMin = Infinity
-      var xMax = -Infinity
-      var yMin = Infinity
-      var yMax = -Infinity
-
-      var pts = [
-        new SVG.Point(this.x, this.y),
-        new SVG.Point(this.x2, this.y),
-        new SVG.Point(this.x, this.y2),
-        new SVG.Point(this.x2, this.y2)
-      ]
-
-      pts.forEach(function (p) {
-        p = p.transform(m)
-        xMin = Math.min(xMin, p.x)
-        xMax = Math.max(xMax, p.x)
-        yMin = Math.min(yMin, p.y)
-        yMax = Math.max(yMax, p.y)
-      })
-
-      return new SVG.Box(
-        xMin, yMin,
-        xMax - xMin,
-        yMax - yMin
-      )
-    },
-
-    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
-    },
-    toArray: 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
-    },
-
-    at: function (pos) {
-      if (!this.destination) return this
-
-      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
-      )
-    }
+  }
+
+  // Merge rect box with another, return a new instance
+  merge (box) {
+    let x = Math.min(this.x, box.x)
+    let y = Math.min(this.y, box.y)
+    let width = Math.max(this.x + this.width, box.x + box.width) - x
+    let height = Math.max(this.y + this.height, box.y + box.height) - y
+
+    return new Box(x, y, width, height)
+  }
+
+  transform (m) {
+    let xMin = Infinity
+    let xMax = -Infinity
+    let yMin = Infinity
+    let yMax = -Infinity
+
+    let pts = [
+      new Point(this.x, this.y),
+      new Point(this.x2, this.y),
+      new Point(this.x, this.y2),
+      new Point(this.x2, this.y2)
+    ]
+
+    pts.forEach(function (p) {
+      p = p.transform(m)
+      xMin = Math.min(xMin, p.x)
+      xMax = Math.max(xMax, p.x)
+      yMin = Math.min(yMin, p.y)
+      yMax = Math.max(yMax, p.y)
+    })
+
+    return new Box(
+      xMin, yMin,
+      xMax - xMin,
+      yMax - yMin
+    )
+  }
+
+  addOffset () {
+    // offset by window scroll position, because getBoundingClientRect changes when window is scrolled
+    this.x += window.pageXOffset
+    this.y += window.pageYOffset
+    return this
+  }
+
+  toString () {
+    return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height
+  }
+
+  toArray () {
+    return [this.x, this.y, this.width, this.height]
+  }
+}
+
+
+extend(Parent, {
+  // Get bounding box
+  bbox () {
+    return new Box(getBox((node) => node.getBBox()))
   },
 
-    // Define Parent
-  parent: SVG.Element,
-
-  // Constructor
-  construct: {
-    // Get bounding box
-    bbox: function () {
-      var box
-
-      try {
-        // find native bbox
-        box = this.node.getBBox()
-
-        if (isNulledBox(box) && !domContains(this.node)) {
-          throw new Exception('Element not in the dom')
-        }
-      } catch (e) {
-        try {
-          var clone = this.clone(SVG.parser().svg).show()
-          box = clone.node.getBBox()
-          clone.remove()
-        } catch (e) {
-          console.warn('Getting a bounding box of this element is not possible')
-        }
-      }
-
-      return new SVG.Box(box)
-    },
-
-    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()
-      }
-    }
+  rbox (el) {
+    let box = new Box(getBox((node) => node.getBoundingClientRect()))
+    if (el) return box.transform(el.screenCTM().inverse())
+    return box.addOffset()
   }
 })
 
-SVG.extend([SVG.Doc, SVG.Symbol, SVG.Image, SVG.Pattern, SVG.Marker, SVG.ForeignObject, SVG.View], {
+function getBox(cb) {
+  let box
+
+  try {
+    box = cb(this.node)
+
+    if (isNulledBox(box) && !domContains(this.node)) {
+      throw new Error('Element not in the dom')
+    }
+  } catch (e) {
+    try {
+      let clone = this.clone(parser().svg).show()
+      box = cb(clone.node)
+      clone.remove()
+    } catch (e) {
+      console.warn('Getting a bounding box of this element is not possible')
+    }
+  }
+  return box
+}
+
+
+extend([Doc, Symbol, Image, Pattern, Marker], {
   viewbox: function (x, y, width, height) {
     // act as getter
-    if (x == null) return new SVG.Box(this.attr('viewBox'))
+    if (x == null) return new Box(this.attr('viewBox'))
 
     // act as setter
-    return this.attr('viewBox', new SVG.Box(x, y, width, height))
+    return this.attr('viewBox', new Box(x, y, width, height))
   }
 })
diff --git a/src/Circle.js b/src/Circle.js
new file mode 100644 (file)
index 0000000..fc8be72
--- /dev/null
@@ -0,0 +1,34 @@
+import SVGNumber from './SVGNumber.js'
+import Parent from './Parent.js'
+import {x, y, cx, cy, width, height, size} from './circled.js'
+
+export default class Circle extends Shape {
+  constructor (node) {
+    super(nodeOrNew('circle', node))
+  }
+
+  radius (r) {
+    return this.attr('r', r)
+  }
+
+  // Radius x value
+  rx (rx) {
+    return this.attr('r', rx)
+  }
+
+  // Alias radius x value
+  ry (ry) {
+    return this.rx(ry)
+  }
+}
+
+extend(Circle, {x, y, cx, cy, width, height, size})
+
+addFactory(Parent, {
+  // Create circle element
+  circle (size) {
+    return this.put(new Circle())
+      .radius(new SVGNumber(size).divide(2))
+      .move(0, 0)
+  }
+})
index 63fff74ef12aaf56b251fbec3cceb549a811706c..ef820e57105ac319ce5705c38170927dc89b42fc 100644 (file)
@@ -1,53 +1,54 @@
-SVG.ClipPath = SVG.invent({
-  // Initialize node
-  create: 'clipPath',
-
-  // Inherit from
-  inherit: SVG.Container,
-
-  // Add class methods
-  extend: {
-    // Unclip all clipped elements and remove itself
-    remove: function () {
-      // unclip all targets
-      this.targets().forEach(function (el) {
-        el.unclip()
-      })
-
-      // remove clipPath from parent
-      return SVG.Element.prototype.remove.call(this)
-    },
-
-    targets: function () {
-      return SVG.select('svg [clip-path*="' + this.id() + '"]')
-    }
-  },
+import Container from './Container.js'
+import Element from './Element.js'
+import {nodeOrNew, extend} from './tools.js'
+import find from './selector.js'
+
+export default class ClipPath extends Container {
+  constructor (node) {
+    super(nodeOrNew('clipPath', node))
+  }
+
+  // Unclip all clipped elements and remove itself
+  remove () {
+    // unclip all targets
+    this.targets().forEach(function (el) {
+      el.unclip()
+    })
+
+    // remove clipPath from parent
+    return super.remove()
+  }
 
-  // Add parent method
-  construct: {
-    // Create clipping element
-    clip: function () {
-      return this.defs().put(new SVG.ClipPath())
-    }
+  targets () {
+    return find('svg [clip-path*="' + this.id() + '"]')
+  }
+}
+
+addFactory(Container, {
+  // Create clipping element
+  clip: function() {
+    return this.defs().put(new ClipPath)
   }
 })
 
-//
-SVG.extend(SVG.Element, {
+extend(Element, {
   // Distribute clipPath to svg element
-  clipWith: function (element) {
+  clipWith (element) {
     // use given clip or create a new one
-    var clipper = element instanceof SVG.ClipPath ? element : this.parent().clip().add(element)
+    let clipper = element instanceof ClipPath
+      ? element
+      : this.parent().clip().add(element)
 
     // apply mask
     return this.attr('clip-path', 'url("#' + clipper.id() + '")')
   },
+
   // Unclip element
-  unclip: function () {
+  unclip () {
     return this.attr('clip-path', null)
   },
-  clipper: function () {
+
+  clipper () {
     return this.reference('clip-path')
   }
-
 })
index 43bafcb9c697385d21340a1abd13c88ef0eb561a..1e2befbe0550d20ed4dc6473e6c02a18d5e8fd25 100644 (file)
@@ -29,120 +29,99 @@ SVG.hsl()
 SVG.lab('rgb(100, 100, 100)')
 */
 
-// Module for color convertions
-SVG.Color = function (color, g, b) {
-  var match
-
-  // initialize defaults
-  this.r = 0
-  this.g = 0
-  this.b = 0
-
-  if (!color) return
-
-  // parse color
-  if (typeof color === 'string') {
-    if (SVG.regex.isRgb.test(color)) {
-      // get rgb values
-      match = SVG.regex.rgb.exec(color.replace(SVG.regex.whitespace, ''))
-
-      // parse numeric values
-      this.r = parseInt(match[1])
-      this.g = parseInt(match[2])
-      this.b = parseInt(match[3])
-    } else if (SVG.regex.isHex.test(color)) {
-      // get hex values
-      match = SVG.regex.hex.exec(fullHex(color))
-
-      // parse numeric values
-      this.r = parseInt(match[1], 16)
-      this.g = parseInt(match[2], 16)
-      this.b = parseInt(match[3], 16)
+import {isHex, isRgb, whitespace, rgb} from './regex.js'
+
+export default class Color {
+  constructor (color, g, b) {
+    let match
+
+    // initialize defaults
+    this.r = 0
+    this.g = 0
+    this.b = 0
+
+    if (!color) return
+
+    // parse color
+    if (typeof color === 'string') {
+      if (isRgb.test(color)) {
+        // get rgb values
+        match = rgb.exec(color.replace(whitespace, ''))
+
+        // parse numeric values
+        this.r = parseInt(match[1])
+        this.g = parseInt(match[2])
+        this.b = parseInt(match[3])
+      } else if (isHex.test(color)) {
+        // get hex values
+        match = hex.exec(fullHex(color))
+
+        // parse numeric values
+        this.r = parseInt(match[1], 16)
+        this.g = parseInt(match[2], 16)
+        this.b = parseInt(match[3], 16)
+      }
+    } else if (Array.isArray(color)) {
+      this.r = color[0]
+      this.g = color[1]
+      this.b = color[2]
+    } else if (typeof color === 'object') {
+      this.r = color.r
+      this.g = color.g
+      this.b = color.b
+    } else if (arguments.length === 3) {
+      this.r = color
+      this.g = g
+      this.b = b
     }
-  } else if (Array.isArray(color)) {
-    this.r = color[0]
-    this.g = color[1]
-    this.b = color[2]
-  } else if (typeof color === 'object') {
-    this.r = color.r
-    this.g = color.g
-    this.b = color.b
-  } else if (arguments.length === 3) {
-    this.r = color
-    this.g = g
-    this.b = b
   }
-}
 
-SVG.extend(SVG.Color, {
   // Default to hex conversion
-  toString: function () {
+  toString () {
     return this.toHex()
-  },
-  toArray: function () {
+  }
+
+  toArray () {
     return [this.r, this.g, this.b]
-  },
-  fromArray: function (a) {
-    return new SVG.Color(a)
-  },
+  }
+
   // Build hex value
-  toHex: function () {
+  toHex () {
     return '#' +
       compToHex(Math.round(this.r)) +
       compToHex(Math.round(this.g)) +
       compToHex(Math.round(this.b))
-  },
+  }
+
   // Build rgb value
-  toRgb: function () {
+  toRgb () {
     return 'rgb(' + [this.r, this.g, this.b].join() + ')'
-  },
+  }
+
   // Calculate true brightness
-  brightness: function () {
+  brightness () {
     return (this.r / 255 * 0.30) +
       (this.g / 255 * 0.59) +
       (this.b / 255 * 0.11)
-  },
-  // Make color morphable
-  morph: function (color) {
-    this.destination = new SVG.Color(color)
-
-    return this
-  },
-  // Get morphed color at given position
-  at: function (pos) {
-    // make sure a destination is defined
-    if (!this.destination) return this
-
-    // normalise pos
-    pos = pos < 0 ? 0 : pos > 1 ? 1 : pos
-
-    // generate morphed color
-    return new SVG.Color({
-      r: ~~(this.r + (this.destination.r - this.r) * pos),
-      g: ~~(this.g + (this.destination.g - this.g) * pos),
-      b: ~~(this.b + (this.destination.b - this.b) * pos)
-    })
   }
 
-})
-
-// Testers
+  // Testers
 
-// Test if given value is a color string
-SVG.Color.test = function (color) {
-  color += ''
-  return SVG.regex.isHex.test(color) ||
-    SVG.regex.isRgb.test(color)
-}
+  // Test if given value is a color string
+  static test (color) {
+    color += ''
+    return isHex.test(color) || isRgb.test(color)
+  }
 
-// Test if given value is a rgb object
-SVG.Color.isRgb = function (color) {
-  return color && typeof color.r === 'number' &&
-    typeof color.g === 'number' &&
-    typeof color.b === 'number'
-}
+  // Test if given value is a rgb object
+  static isRgb (color) {
+    return color && typeof color.r === 'number' &&
+      typeof color.g === 'number' &&
+      typeof color.b === 'number'
+  }
 
-// Test if given value is a color
-SVG.Color.isColor = function (color) {
-  return SVG.Color.isRgb(color) || SVG.Color.test(color)
+  // Test if given value is a color
+  static isColor (color) {
+    return this.isRgb(color) || this.test(color)
+  }
 }
index 8b324bd27079f80a9a3ea7e872373c286a1d335a..5d6dc436bdf6f6a7b5f76436d5b95204ac0e3ea8 100644 (file)
@@ -1,9 +1,2 @@
-SVG.Container = SVG.invent({
-  // Initialize node
-  create: function (node) {
-    SVG.Element.call(this, node)
-  },
-
-  // Inherit from
-  inherit: SVG.Parent
-})
+import Parent from './Parent.js'
+export default class Container extends Parent {}
index 842c7720dcca37a91f7096d4ff45f29bfe615e27..81f67219c6d23d6e974c356c5e926eeec59d6827 100644 (file)
@@ -1,7 +1,5 @@
 
-// c = {
-//   finished: Whether or not we are finished
-// }
+import {timeline} from './defaults.js'
 
 /***
 Base Class
@@ -18,75 +16,62 @@ function makeSetterGetter (k, f) {
   }
 }
 
-SVG.Stepper = SVG.invent({
-  create: function () {}
-})
+let easing = {
+  '-': function (pos) { return pos },
+  '<>': function (pos) { return -Math.cos(pos * Math.PI) / 2 + 0.5 },
+  '>': function (pos) { return Math.sin(pos * Math.PI / 2) },
+  '<': function (pos) { return -Math.cos(pos * Math.PI / 2) + 1 },
+  bezier: function (t0, x0, t1, x1) {
+    return function (t) {
+      // TODO: FINISH
+    }
+  }
+}
+
+
+export class Stepper {
+  done () { return false }
+}
 
 /***
 Easing Functions
 ================
 ***/
 
-SVG.Ease = SVG.invent({
-  inherit: SVG.Stepper,
-
-  create: function (fn) {
-    SVG.Stepper.call(this, fn)
-
-    this.ease = SVG.easing[fn || SVG.defaults.timeline.ease] || fn
-  },
-
-  extend: {
-
-    step: function (from, to, pos) {
-      if (typeof from !== 'number') {
-        return pos < 1 ? from : to
-      }
-      return from + (to - from) * this.ease(pos)
-    },
-
-    done: function (dt, c) {
-      return false
-    }
+export class Ease extends Stepper {
+  constructor (fn) {
+    super()
+    this.ease = easing[fn || timeline.ease] || fn
   }
-})
 
-SVG.easing = {
-  '-': function (pos) { return pos },
-  '<>': function (pos) { return -Math.cos(pos * Math.PI) / 2 + 0.5 },
-  '>': function (pos) { return Math.sin(pos * Math.PI / 2) },
-  '<': function (pos) { return -Math.cos(pos * Math.PI / 2) + 1 },
-  bezier: function (t0, x0, t1, x1) {
-    return function (t) {
-      // TODO: FINISH
+  step (from, to, pos) {
+    if (typeof from !== 'number') {
+      return pos < 1 ? from : to
     }
+    return from + (to - from) * this.ease(pos)
   }
 }
 
+
 /***
 Controller Types
 ================
 ***/
 
-SVG.Controller = SVG.invent({
-  inherit: SVG.Stepper,
-
-  create: function (fn) {
-    SVG.Stepper.call(this, fn)
+export class Controller extends Stepper {
+  constructor (fn) {
+    super()
     this.stepper = fn
-  },
-
-  extend: {
+  }
 
-    step: function (current, target, dt, c) {
-      return this.stepper(current, target, dt, c)
-    },
+  step (current, target, dt, c) {
+    return this.stepper(current, target, dt, c)
+  }
 
-    done: function (c) {
-      return c.done
-    }
+  done (c) {
+    return c.done
   }
-})
+}
 
 function recalculate () {
   // Apply the default parameters
@@ -105,89 +90,86 @@ function recalculate () {
   this.k = wn * wn
 }
 
-SVG.Spring = SVG.invent({
-  inherit: SVG.Controller,
-
-  create: function (duration, overshoot) {
+export class Spring extends Controller {
+  constructor (duration, overshoot) {
+    super()
     this.duration(duration || 500)
       .overshoot(overshoot || 0)
-  },
-
-  extend: {
-    step: function (current, target, dt, c) {
-      if (typeof current === 'string') return current
-      c.done = dt === Infinity
-      if (dt === Infinity) return target
-      if (dt === 0) return current
+  }
 
-      if (dt > 100) dt = 16
+  step (current, target, dt, c) {
+    if (typeof current === 'string') return current
+    c.done = dt === Infinity
+    if (dt === Infinity) return target
+    if (dt === 0) return current
 
-      dt /= 1000
+    if (dt > 100) dt = 16
 
-      // Get the previous velocity
-      var velocity = c.velocity || 0
+    dt /= 1000
 
-      // Apply the control to get the new position and store it
-      var acceleration = -this.d * velocity - this.k * (current - target)
-      var newPosition = current +
-        velocity * dt +
-        acceleration * dt * dt / 2
+    // Get the previous velocity
+    var velocity = c.velocity || 0
 
-      // Store the velocity
-      c.velocity = velocity + acceleration * dt
+    // Apply the control to get the new position and store it
+    var acceleration = -this.d * velocity - this.k * (current - target)
+    var newPosition = current +
+      velocity * dt +
+      acceleration * dt * dt / 2
 
-      // Figure out if we have converged, and if so, pass the value
-      c.done = Math.abs(target - newPosition) + Math.abs(velocity) < 0.002
-      return c.done ? target : newPosition
-    },
+    // Store the velocity
+    c.velocity = velocity + acceleration * dt
 
-    duration: makeSetterGetter('_duration', recalculate),
-    overshoot: makeSetterGetter('_overshoot', recalculate)
+    // Figure out if we have converged, and if so, pass the value
+    c.done = Math.abs(target - newPosition) + Math.abs(velocity) < 0.002
+    return c.done ? target : newPosition
   }
-})
+}
 
-SVG.PID = SVG.invent({
-  inherit: SVG.Controller,
+extend(Spring, {
+  duration: makeSetterGetter('_duration', recalculate),
+  overshoot: makeSetterGetter('_overshoot', recalculate)
+})
 
-  create: function (p, i, d, windup) {
-    SVG.Controller.call(this)
+export class PID extends Controller {
+  constructor (p, i, d, windup) {
+    super()
 
     p = p == null ? 0.1 : p
     i = i == null ? 0.01 : i
     d = d == null ? 0 : d
     windup = windup == null ? 1000 : windup
     this.p(p).i(i).d(d).windup(windup)
-  },
-
-  extend: {
-    step: function (current, target, dt, c) {
-      if (typeof current === 'string') return current
-      c.done = dt === Infinity
+  }
 
-      if (dt === Infinity) return target
-      if (dt === 0) return current
+  step (current, target, dt, c) {
+    if (typeof current === 'string') return current
+    c.done = dt === Infinity
 
-      var p = target - current
-      var i = (c.integral || 0) + p * dt
-      var d = (p - (c.error || 0)) / dt
-      var windup = this.windup
+    if (dt === Infinity) return target
+    if (dt === 0) return current
 
-      // antiwindup
-      if (windup !== false) {
-        i = Math.max(-windup, Math.min(i, windup))
-      }
+    var p = target - current
+    var i = (c.integral || 0) + p * dt
+    var d = (p - (c.error || 0)) / dt
+    var windup = this.windup
 
-      c.error = p
-      c.integral = i
+    // antiwindup
+    if (windup !== false) {
+      i = Math.max(-windup, Math.min(i, windup))
+    }
 
-      c.done = Math.abs(p) < 0.001
+    c.error = p
+    c.integral = i
 
-      return c.done ? target : current + (this.P * p + this.I * i + this.D * d)
-    },
+    c.done = Math.abs(p) < 0.001
 
-    windup: makeSetterGetter('windup'),
-    p: makeSetterGetter('P'),
-    i: makeSetterGetter('I'),
-    d: makeSetterGetter('D')
+    return c.done ? target : current + (this.P * p + this.I * i + this.D * d)
   }
+}
+
+extend(PID, {
+  windup: makeSetterGetter('windup'),
+  p: makeSetterGetter('P'),
+  i: makeSetterGetter('I'),
+  d: makeSetterGetter('D')
 })
index 3d6ebb9cedf4cccf83274012c1f66b1788b3b178..21b67032b053fca537e6fc280b39865f5256bb82 100644 (file)
@@ -1,7 +1,8 @@
-SVG.Defs = SVG.invent({
-  // Initialize node
-  create: 'defs',
+import Container from './Container.js'
+import {nodeOrNew} from './tools.js'
 
-  // Inherit from
-  inherit: SVG.Container
-})
+export default class Defs extends Container {
+  constructor (node) {
+    super(nodeOrNew('defs', node))
+  }
+}
index 423204fa07bf75e6d71b0987a8f61de1e8ff0c08..e4969965958bcbf6e8ff12ee98cabdc0da1965af 100644 (file)
@@ -1,70 +1,75 @@
-SVG.Doc = SVG.invent({
-  // Initialize node
-  create: function (node) {
-    SVG.Element.call(this, node || SVG.create('svg'))
+import Container from './Container.js'
+import Parent from './Parent.js'
+import {adopt, extend} from './tools.js'
+import {ns, xlink, xmlns, svgjs} from './namespaces.js'
 
-    // set svg element attributes and ensure defs node
-    this.namespace()
-  },
+export default class Doc extends Container {
+   constructor (node) {
+     super(nodeOrNew('svg', node))
+     this.namespace()
+   }
 
-  // Inherit from
-  inherit: SVG.Container,
+   isRoot () {
+     return !this.node.parentNode || !(this.node.parentNode instanceof window.SVGElement) || this.node.parentNode.nodeName === '#document'
+   }
 
-  // Add class methods
-  extend: {
-    isRoot: function () {
-      return !this.node.parentNode || !(this.node.parentNode instanceof window.SVGElement) || this.node.parentNode.nodeName === '#document'
-    },
-    // Check if this is a root svg. If not, call docs from this element
-    doc: function () {
-      if (this.isRoot()) return this
-      return SVG.Element.prototype.doc.call(this)
-    },
-    // Add namespaces
-    namespace: function () {
-      if (!this.isRoot()) return this.doc().namespace()
-      return this
-        .attr({ xmlns: SVG.ns, version: '1.1' })
-        .attr('xmlns:xlink', SVG.xlink, SVG.xmlns)
-        .attr('xmlns:svgjs', SVG.svgjs, SVG.xmlns)
-    },
-    // Creates and returns defs element
-    defs: function () {
-      if (!this.isRoot()) return this.doc().defs()
-      return SVG.adopt(this.node.getElementsByTagName('defs')[0]) || this.put(new SVG.Defs())
-    },
-    // custom parent method
-    parent: function (type) {
-      if (this.isRoot()) {
-        return this.node.parentNode.nodeName === '#document' ? null : this.node.parentNode
-      }
+   // Check if this is a root svg
+   // If not, call docs from this element
+   doc () {
+     if (this.isRoot()) return this
+     return super.doc()
+   }
 
-      return SVG.Element.prototype.parent.call(this, type)
-    },
-    // Removes the doc from the DOM
-    remove: function () {
-      if (!this.isRoot()) {
-        return SVG.Element.prototype.remove.call(this)
-      }
+   // Add namespaces
+   namespace () {
+     if (!this.isRoot()) return this.doc().namespace()
+     return this
+       .attr({ xmlns: ns, version: '1.1' })
+       .attr('xmlns:xlink', xlink, xmlns)
+       .attr('xmlns:svgjs', svgjs, xmlns)
+   }
 
-      if (this.parent()) {
-        this.parent().removeChild(this.node)
-      }
+   // Creates and returns defs element
+   defs () {
+     if (!this.isRoot()) return this.doc().defs()
+     return adopt(this.node.getElementsByTagName('defs')[0]) ||
+      this.put(new Defs())
+   }
 
-      return this
-    },
-    clear: function () {
-      // remove children
-      while (this.node.hasChildNodes()) {
-        this.node.removeChild(this.node.lastChild)
-      }
-      return this
-    }
-  },
-  construct: {
-    // Create nested svg document
-    nested: function () {
-      return this.put(new SVG.Doc())
-    }
+   // custom parent method
+   parent (type) {
+     if (this.isRoot()) {
+       return this.node.parentNode.nodeName === '#document' ? null : this.node.parentNode
+     }
+
+     return super.parent(type)
+   }
+
+   // Removes the doc from the DOM
+   remove () {
+     if (!this.isRoot()) {
+       return super.remove()
+     }
+
+     if (this.parent()) {
+       this.parent().removeChild(this.node)
+     }
+
+     return this
+   }
+
+   clear () {
+     // remove children
+     while (this.node.hasChildNodes()) {
+       this.node.removeChild(this.node.lastChild)
+     }
+     return this
+   }
+}
+
+addFactory(Container, {
+  // Create nested svg document
+  nested () {
+    return this.put(new Doc())
   }
 })
index f0d9e8e95b94ee58790d99b3b4ebeee49e15ea9f..76675638c72fb161e242d8dc77e5d7b32262f7b9 100644 (file)
@@ -1,10 +1,15 @@
-/* global proportionalSize, assignNewId, createElement, matches, is */
-
-SVG.Element = SVG.invent({
-  inherit: SVG.EventTarget,
-
-  // Initialize node
-  create: function (node) {
+import {proportionalSize, assignNewId, makeInstance, matches} from './helpers.js'
+import {eid} from './tools.js'
+import {delimiter} from './regex.js'
+import {ns} from './namespaces.js'
+import {adopt} from './tools.js'
+// import {Doc, EventTarget, Parent} from './classes.js'
+import EventTarget from './EventTarget.js'
+import Doc from './Doc.js'
+import Parent from './Parent.js'
+
+export default class Element extends EventTarget {
+  constructor (node) {
     // event listener
     this.events = {}
 
@@ -23,294 +28,275 @@ SVG.Element = SVG.invent({
         this.setData(JSON.parse(node.getAttribute('svgjs:data')) || {})
       }
     }
-  },
-
-  // Add class methods
-  extend: {
-    // Move over x-axis
-    x: function (x) {
-      return this.attr('x', x)
-    },
-
-    // Move over y-axis
-    y: function (y) {
-      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 = proportionalSize(this, width, height)
-
-      return this
-        .width(new SVG.Number(p.width))
-        .height(new SVG.Number(p.height))
-    },
-
-    // Clone element
-    clone: function (parent) {
-      // write dom data to the dom so the clone can pickup the data
-      this.writeDataToDom()
+  }
 
-      // clone element and assign new id
-      var clone = assignNewId(this.node.cloneNode(true))
+  // Move over x-axis
+  x (x) {
+    return this.attr('x', x)
+  }
 
-      // insert the clone in the given parent or after myself
-      if (parent) parent.add(clone)
-      else this.after(clone)
+  // Move over y-axis
+  y (y) {
+    return this.attr('y', y)
+  }
 
-      return clone
-    },
+  // Move by center over x-axis
+  cx (x) {
+    return x == null ? this.x() + this.width() / 2 : this.x(x - this.width() / 2)
+  }
 
-    // Remove element
-    remove: function () {
-      if (this.parent()) { this.parent().removeElement(this) }
+  // Move by center over y-axis
+  cy (y) {
+    return y == null
+      ? this.y() + this.height() / 2
+      : this.y(y - this.height() / 2)
+  }
 
-      return this
-    },
+  // Move element to given x and y values
+  move (x, y) {
+    return this.x(x).y(y)
+  }
 
-    // Replace element
-    replace: function (element) {
-      this.after(element).remove()
+  // Move element by its center
+  center (x, y) {
+    return this.cx(x).cy(y)
+  }
 
-      return element
-    },
+  // Set width of element
+  width (width) {
+    return this.attr('width', width)
+  }
 
-    // Add element to given container and return self
-    addTo: function (parent) {
-      return createElement(parent).put(this)
-    },
+  // Set height of element
+  height (height) {
+    return this.attr('height', height)
+  }
 
-    // Add element to given container and return container
-    putIn: function (parent) {
-      return createElement(parent).add(this)
-    },
+  // Set element size to given width and height
+  size (width, height) {
+    let p = proportionalSize(this, width, height)
 
-    // Get / set id
-    id: function (id) {
-      // generate new id if no id set
-      if (typeof id === 'undefined' && !this.node.id) {
-        this.node.id = SVG.eid(this.type)
-      }
+    return this
+      .width(new SVGNumber(p.width))
+      .height(new SVGNumber(p.height))
+  }
 
-      // dont't set directly width this.node.id to make `null` work correctly
-      return this.attr('id', id)
-    },
-
-    // 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.css('display', '')
-    },
-
-    // Hide element
-    hide: function () {
-      return this.css('display', 'none')
-    },
-
-    // Is element visible?
-    visible: function () {
-      return this.css('display') !== 'none'
-    },
-
-    // Return id on string conversion
-    toString: function () {
-      return this.id()
-    },
-
-    // Return array of classes on the node
-    classes: function () {
-      var attr = this.attr('class')
-      return attr == null ? [] : attr.trim().split(SVG.regex.delimiter)
-    },
-
-    // Return true if class exists on the node, false otherwise
-    hasClass: function (name) {
-      return this.classes().indexOf(name) !== -1
-    },
-
-    // Add class to the node
-    addClass: function (name) {
-      if (!this.hasClass(name)) {
-        var array = this.classes()
-        array.push(name)
-        this.attr('class', array.join(' '))
-      }
+  // Clone element
+  clone (parent) {
+    // write dom data to the dom so the clone can pickup the data
+    this.writeDataToDom()
 
-      return this
-    },
+    // clone element and assign new id
+    let clone = assignNewId(this.node.cloneNode(true))
 
-    // Remove class from the node
-    removeClass: function (name) {
-      if (this.hasClass(name)) {
-        this.attr('class', this.classes().filter(function (c) {
-          return c !== name
-        }).join(' '))
-      }
+    // insert the clone in the given parent or after myself
+    if (parent) parent.add(clone)
+    else this.after(clone)
 
-      return this
-    },
+    return clone
+  }
 
-    // Toggle the presence of a class on the node
-    toggleClass: function (name) {
-      return this.hasClass(name) ? this.removeClass(name) : this.addClass(name)
-    },
+  // Remove element
+  remove () {
+    if (this.parent()) { this.parent().removeElement(this) }
 
-    // Get referenced element form attribute value
-    reference: function (attr) {
-      return SVG.get(this.attr(attr))
-    },
+    return this
+  }
 
-    // Returns the parent element instance
-    parent: function (type) {
-      var parent = this
+  // Replace element
+  replace (element) {
+    this.after(element).remove()
 
-      // check for parent
-      if (!parent.node.parentNode) return null
+    return element
+  }
 
-      // get parent element
-      parent = SVG.adopt(parent.node.parentNode)
+  // Add element to given container and return self
+  addTo (parent) {
+    return makeInstance(parent).put(this)
+  }
 
-      if (!type) return parent
+  // Add element to given container and return container
+  putIn (parent) {
+    return makeInstance(parent).add(this)
+  }
 
-      // loop trough ancestors if type is given
-      while (parent && parent.node instanceof window.SVGElement) {
-        if (typeof type === 'string' ? parent.matches(type) : parent instanceof type) return parent
-        parent = SVG.adopt(parent.node.parentNode)
-      }
-    },
-
-    // Get parent document
-    doc: function () {
-      var p = this.parent(SVG.Doc)
-      return p && p.doc()
-    },
-
-    // Get defs
-    defs: function () {
-      return this.doc().defs()
-    },
-
-    // return array of all ancestors of given type up to the root svg
-    parents: function (type) {
-      var parents = []
-      var parent = this
-
-      do {
-        parent = parent.parent(type)
-        if (!parent || !parent.node) break
-
-        parents.push(parent)
-      } while (parent.parent)
-
-      return parents
-    },
-
-    // matches the element vs a css selector
-    matches: function (selector) {
-      return matches(this.node, selector)
-    },
-
-    // Returns the svg node to call native svg methods on it
-    native: function () {
-      return this.node
-    },
-
-    // Import raw svg
-    svg: function (svg) {
-      var well, len
-
-      // act as a setter if svg is given
-      if (svg && this instanceof SVG.Parent) {
-        // create temporary holder
-        well = document.createElementNS(SVG.ns, 'svg')
-        // dump raw svg
-        well.innerHTML = svg
-
-        // transplant nodes
-        for (len = well.children.length; len--;) {
-          this.node.appendChild(well.firstElementChild)
-        }
-
-      // otherwise act as a getter
-      } else {
-        // write svgjs data to the dom
-        this.writeDataToDom()
+  // Get / set id
+  id (id) {
+    // generate new id if no id set
+    if (typeof id === 'undefined' && !this.node.id) {
+      this.node.id = eid(this.type)
+    }
 
-        return this.node.outerHTML
-      }
+    // dont't set directly width this.node.id to make `null` work correctly
+    return this.attr('id', id)
+  }
 
-      return this
-    },
+  // Checks whether the given point inside the bounding box of the element
+  inside (x, y) {
+    let box = this.bbox()
 
-    // write svgjs data to the dom
-    writeDataToDom: function () {
-      // dump variables recursively
-      if (this.is(SVG.Parent)) {
-        this.each(function () {
-          this.writeDataToDom()
-        })
-      }
+    return x > box.x &&
+      y > box.y &&
+      x < box.x + box.width &&
+      y < box.y + box.height
+  }
+
+  // Return id on string conversion
+  toString () {
+    return this.id()
+  }
+
+  // Return array of classes on the node
+  classes () {
+    var attr = this.attr('class')
+    return attr == null ? [] : attr.trim().split(delimiter)
+  }
+
+  // Return true if class exists on the node, false otherwise
+  hasClass (name) {
+    return this.classes().indexOf(name) !== -1
+  }
+
+  // Add class to the node
+  addClass (name) {
+    if (!this.hasClass(name)) {
+      var array = this.classes()
+      array.push(name)
+      this.attr('class', array.join(' '))
+    }
+
+    return this
+  }
+
+  // Remove class from the node
+  removeClass (name) {
+    if (this.hasClass(name)) {
+      this.attr('class', this.classes().filter(function (c) {
+        return c !== name
+      }).join(' '))
+    }
+
+    return this
+  }
+
+  // Toggle the presence of a class on the node
+  toggleClass (name) {
+    return this.hasClass(name) ? this.removeClass(name) : this.addClass(name)
+  }
+
+  // FIXME: getIdFromReference
+  // Get referenced element form attribute value
+  reference (attr) {
+    return get(this.attr(attr))
+  }
+
+  // Returns the parent element instance
+  parent (type) {
+    var parent = this
 
-      // remove previously set data
-      this.node.removeAttribute('svgjs:data')
+    // check for parent
+    if (!parent.node.parentNode) return null
+
+    // get parent element
+    parent = adopt(parent.node.parentNode)
+
+    if (!type) return parent
+
+    // loop trough ancestors if type is given
+    while (parent && parent.node instanceof window.SVGElement) {
+      if (typeof type === 'string' ? parent.matches(type) : parent instanceof type) return parent
+      parent = adopt(parent.node.parentNode)
+    }
+  }
 
-      if (Object.keys(this.dom).length) {
-        this.node.setAttribute('svgjs:data', JSON.stringify(this.dom)) // see #428
+  // Get parent document
+  doc () {
+    let p = this.parent(Doc)
+    return p && p.doc()
+  }
+
+  // Get defs
+  defs () {
+    return this.doc().defs()
+  }
+
+  // return array of all ancestors of given type up to the root svg
+  parents (type) {
+    let parents = []
+    let parent = this
+
+    do {
+      parent = parent.parent(type)
+      if (!parent || !parent.node) break
+
+      parents.push(parent)
+    } while (parent.parent)
+
+    return parents
+  }
+
+  // matches the element vs a css selector
+  matches (selector) {
+    return matches(this.node, selector)
+  }
+
+  // Returns the svg node to call native svg methods on it
+  native () {
+    return this.node
+  }
+
+  // Import raw svg
+  svg (svg) {
+    var well, len
+
+    // act as a setter if svg is given
+    if (svg && this instanceof Parent) {
+      // create temporary holder
+      well = document.createElementNS(ns, 'svg')
+      // dump raw svg
+      well.innerHTML = svg
+
+      // transplant nodes
+      for (len = well.children.length; len--;) {
+        this.node.appendChild(well.firstElementChild)
       }
-      return this
-    },
-
-    // set given data to the elements data property
-    setData: function (o) {
-      this.dom = o
-      return this
-    },
-    is: function (obj) {
-      return is(this, obj)
-    },
-    getEventTarget: function () {
-      return this.node
+
+    // otherwise act as a getter
+    } else {
+      // write svgjs data to the dom
+      this.writeDataToDom()
+
+      return this.node.outerHTML
+    }
+
+    return this
+  }
+
+  // write svgjs data to the dom
+  writeDataToDom () {
+    // dump variables recursively
+    if (this.is(Parent)) {
+      this.each(function () {
+        this.writeDataToDom()
+      })
+    }
+
+    // remove previously set data
+    this.node.removeAttribute('svgjs:data')
+
+    if (Object.keys(this.dom).length) {
+      this.node.setAttribute('svgjs:data', JSON.stringify(this.dom)) // see #428
     }
+    return this
+  }
+
+  // set given data to the elements data property
+  setData (o) {
+    this.dom = o
+    return this
+  }
+
+  getEventTarget () {
+    return this.node
   }
-})
+}
index 8a8f0273c7fbf642364914a840c436571ff5e3d1..2a6fc517782ae80bfa0c429521426461eec851ef 100644 (file)
@@ -1,91 +1,17 @@
-/* global proportionalSize */
+import Parent from './Parent.js'
+import * as circled from './circled.js'
 
-SVG.Circle = SVG.invent({
-  // Initialize node
-  create: 'circle',
-
-  // Inherit from
-  inherit: SVG.Shape,
-
-  // Add parent method
-  construct: {
-    // Create circle element, based on ellipse
-    circle: function (size) {
-      return this.put(new SVG.Circle()).rx(new SVG.Number(size).divide(2)).move(0, 0)
-    }
-  }
-})
-
-SVG.extend([SVG.Circle, SVG.Timeline], {
-  // Radius x value
-  rx: function (rx) {
-    return this.attr('r', rx)
-  },
-  // Alias radius x value
-  ry: function (ry) {
-    return this.rx(ry)
-  }
-})
-
-SVG.Ellipse = SVG.invent({
-  // Initialize node
-  create: 'ellipse',
-
-  // Inherit from
-  inherit: SVG.Shape,
-
-  // Add parent method
-  construct: {
-    // Create an ellipse
-    ellipse: function (width, height) {
-      return this.put(new SVG.Ellipse()).size(width, height).move(0, 0)
-    }
+export default class Ellipse extends Shape {
+  constructor (node) {
+    super(nodeOrNew('ellipse', node))
   }
-})
-
-SVG.extend([SVG.Ellipse, SVG.Rect, SVG.Timeline], {
-  // Radius x value
-  rx: function (rx) {
-    return this.attr('rx', rx)
-  },
-  // Radius y value
-  ry: function (ry) {
-    return this.attr('ry', ry)
-  }
-})
+}
 
-// Add common method
-SVG.extend([SVG.Circle, SVG.Ellipse], {
-    // Move over x-axis
-  x: function (x) {
-    return x == null ? this.cx() - this.rx() : this.cx(x + this.rx())
-  },
-    // Move over y-axis
-  y: function (y) {
-    return y == null ? this.cy() - this.ry() : this.cy(y + this.ry())
-  },
-    // Move by center over x-axis
-  cx: function (x) {
-    return x == null ? this.attr('cx') : this.attr('cx', x)
-  },
-    // Move by center over y-axis
-  cy: function (y) {
-    return y == null ? this.attr('cy') : this.attr('cy', y)
-  },
-    // Set width of element
-  width: function (width) {
-    return width == null ? this.rx() * 2 : this.rx(new SVG.Number(width).divide(2))
-  },
-    // Set height of element
-  height: function (height) {
-    return height == null ? this.ry() * 2 : this.ry(new SVG.Number(height).divide(2))
-  },
-    // Custom size function
-  size: function (width, height) {
-    var p = proportionalSize(this, width, height)
+extend(Ellipse, circled)
 
-    return this
-        .rx(new SVG.Number(p.width).divide(2))
-        .ry(new SVG.Number(p.height).divide(2))
+addFactory(Container, {
+  // Create an ellipse
+  ellipse: function (width, height) {
+    return this.put(new Ellipse()).size(width, height).move(0, 0)
   }
 })
index fbe47811644092e9b6b9922fbc08077c3c4b2ad8..c762929612e3d834fff17854abd9a5c5d7102261 100644 (file)
@@ -1,23 +1,25 @@
-SVG.EventTarget = SVG.invent({
-  create: function () {},
-  extend: {
-    // Bind given event to listener
-    on: function (event, listener, binding, options) {
-      SVG.on(this, event, listener, binding, options)
-      return this
-    },
-    // Unbind event from listener
-    off: function (event, listener) {
-      SVG.off(this, event, listener)
-      return this
-    },
-    dispatch: function (event, data) {
-      return SVG.dispatch(this, event, data)
-    },
-    // Fire given event
-    fire: function (event, data) {
-      this.dispatch(event, data)
-      return this
-    }
+import {on, off, dispatch} from './event.js'
+
+export default class EventTarget {
+  // Bind given event to listener
+  on (event, listener, binding, options) {
+    on(this, event, listener, binding, options)
+    return this
   }
-})
+
+  // Unbind event from listener
+  off (event, listener) {
+    off(this, event, listener)
+    return this
+  }
+
+  dispatch (event, data) {
+    return dispatch(this, event, data)
+  }
+
+  // Fire given event
+  fire (event, data) {
+    this.dispatch(event, data)
+    return this
+  }
+}
index 0088a1ca8f71548713b07c8e93acc11073361014..2d60cfec24ac90c60b44dde83fc4d1b584b7d52e 100644 (file)
--- a/src/G.js
+++ b/src/G.js
@@ -1,19 +1,15 @@
-SVG.G = SVG.invent({
-  // Initialize node
-  create: 'g',
+import Container from './Container.js'
+import Parent from './Parent.js'
 
-  // Inherit from
-  inherit: SVG.Container,
-
-  // Add class methods
-  extend: {
-  },
+export default class G extends Container {
+  constructor (node) {
+    super(nodeorNew('group', node))
+  }
+}
 
-  // Add parent method
-  construct: {
-    // Create a group element
-    group: function () {
-      return this.put(new SVG.G())
-    }
+addFactory(Parent, {
+  // Create a group element
+  group: function () {
+    return this.put(new G())
   }
 })
index 45a4e08d813fbbff7d23a4bac4935c7125a516c7..da76666805c349e598b5fdf44edb4209e0f53a82 100644 (file)
-SVG.Gradient = SVG.invent({
-  // Initialize node
-  create: function (type) {
-    SVG.Element.call(this, typeof type === 'object' ? type : SVG.create(type + 'Gradient'))
-  },
+import Stop from './Stop.js'
+import * as gradiented from './gradiented.js'
+import {nodeOrNew, extend, addFactory} from './tools.js'
 
-  // Inherit from
-  inherit: SVG.Container,
+export default class Gradient extends Container {
+  constructor (type) {
+    super(nodeOrNew(type + 'Gradient', typeof type === 'string' ? null : type))
+  }
 
-  // Add class methods
-  extend: {
-    // Add a color stop
-    stop: function (offset, color, opacity) {
-      return this.put(new SVG.Stop()).update(offset, color, opacity)
-    },
-    // Update gradient
-    update: function (block) {
-      // remove all stops
-      this.clear()
+  // Add a color stop
+  stop (offset, color, opacity) {
+    return this.put(new Stop()).update(offset, color, opacity)
+  }
 
-      // invoke passed block
-      if (typeof block === 'function') {
-        block.call(this, this)
-      }
+  // Update gradient
+  update (block) {
+    // remove all stops
+    this.clear()
 
-      return this
-    },
-    // Return the fill id
-    url: function () {
-      return 'url(#' + this.id() + ')'
-    },
-    // Alias string convertion to fill
-    toString: function () {
-      return this.url()
-    },
-    // custom attr to handle transform
-    attr: function (a, b, c) {
-      if (a === 'transform') a = 'gradientTransform'
-      return SVG.Container.prototype.attr.call(this, a, b, c)
+    // invoke passed block
+    if (typeof block === 'function') {
+      block.call(this, this)
     }
-  },
 
-  // Add parent method
-  construct: {
-    // Create gradient element in defs
-    gradient: function (type, block) {
-      return this.defs().gradient(type, block)
-    }
+    return this
   }
-})
 
-// Add animatable methods to both gradient and fx module
-SVG.extend([SVG.Gradient, SVG.Timeline], {
-  // From position
-  from: function (x, y) {
-    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 === '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) })
+  // Return the fill id
+  url () {
+    return 'url(#' + this.id() + ')'
   }
-})
 
-// Base gradient generation
-SVG.extend(SVG.Defs, {
-  // define gradient
-  gradient: function (type, block) {
-    return this.put(new SVG.Gradient(type)).update(block)
+  // Alias string convertion to fill
+  toString () {
+    return this.url()
   }
 
-})
-
-SVG.Stop = SVG.invent({
-  // Initialize node
-  create: 'stop',
-
-  // Inherit from
-  inherit: SVG.Element,
+  // custom attr to handle transform
+  attr (a, b, c) {
+    if (a === 'transform') a = 'gradientTransform'
+    return super.attr(a, b, c)
+  }
+}
 
-  // Add class methods
-  extend: {
-    // add color stops
-    update: function (o) {
-      if (typeof o === 'number' || o instanceof SVG.Number) {
-        o = {
-          offset: arguments[0],
-          color: arguments[1],
-          opacity: arguments[2]
-        }
-      }
+extend(Gradient, gradiented)
 
-      // set attributes
-      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))
+addFactory(Parent, {
+  // Create gradient element in defs
+  gradient (type, block) {
+    return this.defs().gradient(type, block)
+  }
+})
 
-      return this
-    }
+// Base gradient generation
+addFactory(Defs, {
+  // define gradient
+  gradient: function (type, block) {
+    return this.put(new Gradient(type)).update(block)
   }
 })
index e04b731e05e9d6af8cec9534652f2123eda0ecac..4a12d3f1ccb9c4397423cd56681cab4d66e3a35d 100644 (file)
@@ -1,29 +1,27 @@
-/* global createElement */
+import {makeInstance} from './helpers.js'
+import EventTarget from './EventTarget.js'
 
-SVG.HtmlNode = SVG.invent({
-  inherit: SVG.EventTarget,
-  create: function (element) {
+export default class HtmlNode extends EventTarget {
+  constructor (element) {
     this.node = element
-  },
+  }
 
-  extend: {
-    add: function (element, i) {
-      element = createElement(element)
+  add (element, i) {
+    element = makeInstance(element)
 
-      if (element.node !== this.node.children[i]) {
-        this.node.insertBefore(element.node, this.node.children[i] || null)
-      }
+    if (element.node !== this.node.children[i]) {
+      this.node.insertBefore(element.node, this.node.children[i] || null)
+    }
 
-      return this
-    },
+    return this
+  }
 
-    put: function (element, i) {
-      this.add(element, i)
-      return element
-    },
+  put (element, i) {
+    this.add(element, i)
+    return element
+  }
 
-    getEventTarget: function () {
-      return this.node
-    }
+  getEventTarget () {
+    return this.node
   }
-})
+}
index f9395eb3bc2fa70bae1a798dd306e68a44fa2b2c..c70be1d50b10c4d14336878af2fea90c9b3c8d3b 100644 (file)
@@ -1,57 +1,58 @@
-SVG.Image = SVG.invent({
-  // Initialize node
-  create: 'image',
-
-  // Inherit from
-  inherit: SVG.Shape,
+import Shape from './Shape.js'
+import Container from './Container.js'
+import Pattern from './Pattern.js'
+import {on, off} from './event.js'
+import {nodeOrNew, addFactory} from './tools.js'
+import {xlink} from './namespaces.js'
+
+export default class Image extends Shape {
+  constructor (node) {
+    super(nodeOrNew('image', node))
+  }
 
-  // Add class methods
-  extend: {
-    // (re)load image
-    load: function (url, callback) {
-      if (!url) return this
+  // (re)load image
+  load (url, callback) {
+    if (!url) return this
 
-      var img = new window.Image()
+    var img = new window.Image()
 
-      SVG.on(img, 'load', function (e) {
-        var p = this.parent(SVG.Pattern)
+    on(img, 'load', function (e) {
+      var p = this.parent(Pattern)
 
-        // ensure image size
-        if (this.width() === 0 && this.height() === 0) {
-          this.size(img.width, img.height)
-        }
+      // ensure image size
+      if (this.width() === 0 && this.height() === 0) {
+        this.size(img.width, img.height)
+      }
 
-        if (p instanceof SVG.Pattern) {
-          // ensure pattern size if not set
-          if (p.width() === 0 && p.height() === 0) {
-            p.size(this.width(), this.height())
-          }
+      if (p instanceof Pattern) {
+        // ensure pattern size if not set
+        if (p.width() === 0 && p.height() === 0) {
+          p.size(this.width(), this.height())
         }
+      }
+
+      if (typeof callback === 'function') {
+        callback.call(this, {
+          width: img.width,
+          height: img.height,
+          ratio: img.width / img.height,
+          url: url
+        })
+      }
+    }, this)
+
+    on(img, 'load error', function () {
+      // dont forget to unbind memory leaking events
+      off(img)
+    })
+
+    return this.attr('href', (img.src = url), xlink)
+  }
+}
 
-        if (typeof callback === 'function') {
-          callback.call(this, {
-            width: img.width,
-            height: img.height,
-            ratio: img.width / img.height,
-            url: url
-          })
-        }
-      }, this)
-
-      SVG.on(img, 'load error', function () {
-        // dont forget to unbind memory leaking events
-        SVG.off(img)
-      })
-
-      return this.attr('href', (img.src = url), SVG.xlink)
-    }
-  },
-
-  // Add parent method
-  construct: {
-    // create image element, load image and set its size
-    image: function (source, callback) {
-      return this.put(new SVG.Image()).size(0, 0).load(source, callback)
-    }
+addFactory(Container, {
+  // create image element, load image and set its size
+  image (source, callback) {
+    return this.put(new Image()).size(0, 0).load(source, callback)
   }
 })
index da0c0cad01f1b415bf691d7b11994f8dd8722559..ddd00e9f5b861b92bd0870051ee40c0346034062 100644 (file)
@@ -1,57 +1,55 @@
-/* global proportionalSize */
+import {proportionalSize} from './helpers.js'
+import {nodeOrNew} from './tools.js'
+import {Shape, Container, PointArray} from './classes.js'
 
-SVG.Line = SVG.invent({
+export default class Line extends Shape {
   // Initialize node
-  create: 'line',
-
-  // Inherit from
-  inherit: SVG.Shape,
-
-  // Add class methods
-  extend: {
-    // Get array
-    array: function () {
-      return new SVG.PointArray([
-        [ this.attr('x1'), this.attr('y1') ],
-        [ this.attr('x2'), this.attr('y2') ]
-      ])
-    },
-
-    // Overwrite native plot() method
-    plot: function (x1, y1, x2, y2) {
-      if (x1 == null) {
-        return this.array()
-      } else if (typeof y1 !== 'undefined') {
-        x1 = { x1: x1, y1: y1, x2: x2, y2: y2 }
-      } else {
-        x1 = new SVG.PointArray(x1).toLine()
-      }
-
-      return this.attr(x1)
-    },
-
-    // Move by left top corner
-    move: function (x, y) {
-      return this.attr(this.array().move(x, y).toLine())
-    },
-
-    // Set element size to given width and height
-    size: function (width, height) {
-      var p = proportionalSize(this, width, height)
-      return this.attr(this.array().size(p.width, p.height).toLine())
-    }
-  },
-
-  // Add parent method
-  construct: {
-    // Create a line element
-    line: function (x1, y1, x2, y2) {
-      // make sure plot is called as a setter
-      // x1 is not necessarily a number, it can also be an array, a string and a SVG.PointArray
-      return SVG.Line.prototype.plot.apply(
-        this.put(new SVG.Line())
-      , x1 != null ? [x1, y1, x2, y2] : [0, 0, 0, 0]
-      )
+  constructor (node) {
+    super(nodeOrNew('line', node))
+  }
+
+  // Get array
+  array () {
+    return new PointArray([
+      [ this.attr('x1'), this.attr('y1') ],
+      [ this.attr('x2'), this.attr('y2') ]
+    ])
+  }
+
+  // Overwrite native plot() method
+  plot (x1, y1, x2, y2) {
+    if (x1 == null) {
+      return this.array()
+    } else if (typeof y1 !== 'undefined') {
+      x1 = { x1: x1, y1: y1, x2: x2, y2: y2 }
+    } else {
+      x1 = new PointArray(x1).toLine()
     }
+
+    return this.attr(x1)
+  }
+
+  // Move by left top corner
+  move (x, y) {
+    return this.attr(this.array().move(x, y).toLine())
+  }
+
+  // Set element size to given width and height
+  size (width, height) {
+    var p = proportionalSize(this, width, height)
+    return this.attr(this.array().size(p.width, p.height).toLine())
+  }
+
+}
+
+addFactory(Container, {
+  // Create a line element
+  line (...args) {
+    // make sure plot is called as a setter
+    // x1 is not necessarily a number, it can also be an array, a string and a PointArray
+    return Line.prototype.plot.apply(
+      this.put(new Line())
+    , args[0] != null ? args : [0, 0, 0, 0]
+    )
   }
 })
index 32f8e4eb7e3a8f4b6bcda7b403ba3f4757800bf5..298ac6fe7c9219b583f5ac59b62b2cf926401045 100644 (file)
@@ -1,67 +1,71 @@
-SVG.Marker = SVG.invent({
+import Container from './Container.js'
+import Defs from './Defs.js'
+import Line from './Line.js'
+import Polyline from './Polyline.js'
+import Polygon from './Polygon.js'
+import Path from './Path.js'
+
+export default class Marker extends Container {
   // Initialize node
-  create: 'marker',
+  constructor (node) {
+    super(nodeOrNew('marker', node))
+  }
+
+  // Set width of element
+  width (width) {
+    return this.attr('markerWidth', width)
+  }
+
+  // Set height of element
+  height (height) {
+    return this.attr('markerHeight', height)
+  }
 
-  // Inherit from
-  inherit: SVG.Container,
+  // Set marker refX and refY
+  ref (x, y) {
+    return this.attr('refX', x).attr('refY', y)
+  }
 
-  // Add class methods
-  extend: {
-    // Set width of element
-    width: function (width) {
-      return this.attr('markerWidth', width)
-    },
-    // Set height of element
-    height: function (height) {
-      return this.attr('markerHeight', height)
-    },
-    // Set marker refX and refY
-    ref: function (x, y) {
-      return this.attr('refX', x).attr('refY', y)
-    },
-    // Update marker
-    update: function (block) {
-      // remove all content
-      this.clear()
+  // Update marker
+  update (block) {
+    // remove all content
+    this.clear()
 
-      // invoke passed block
-      if (typeof block === 'function') { block.call(this, this) }
+    // invoke passed block
+    if (typeof block === 'function') { block.call(this, this) }
 
-      return this
-    },
-    // Return the fill id
-    toString: function () {
-      return 'url(#' + this.id() + ')'
-    }
-  },
+    return this
+  }
 
-  // Add parent method
-  construct: {
-    marker: function (width, height, block) {
-      // Create marker element in defs
-      return this.defs().marker(width, height, block)
-    }
+  // Return the fill id
+  toString () {
+    return 'url(#' + this.id() + ')'
   }
+}
 
+addFactory(Container, {
+  marker (width, height, block) {
+    // Create marker element in defs
+    return this.defs().marker(width, height, block)
+  }
 })
 
-SVG.extend(SVG.Defs, {
+extend(Defs, {
   // Create marker
-  marker: function (width, height, block) {
+  marker (width, height, block) {
     // Set default viewbox to match the width and height, set ref to cx and cy and set orient to auto
-    return this.put(new SVG.Marker())
+    return this.put(new Marker())
       .size(width, height)
       .ref(width / 2, height / 2)
       .viewbox(0, 0, width, height)
       .attr('orient', 'auto')
       .update(block)
   }
-
 })
 
-SVG.extend([SVG.Line, SVG.Polyline, SVG.Polygon, SVG.Path], {
+extend([Line, Polyline, Polygon, Path], {
   // Create and attach markers
-  marker: function (marker, width, height, block) {
+  marker (marker, width, height, block) {
     var attr = ['marker']
 
     // Build attribute name
@@ -69,7 +73,7 @@ SVG.extend([SVG.Line, SVG.Polyline, SVG.Polygon, SVG.Path], {
     attr = attr.join('-')
 
     // Set marker attribute
-    marker = arguments[1] instanceof SVG.Marker
+    marker = arguments[1] instanceof Marker
       ? arguments[1]
       : this.doc().marker(width, height, block)
 
index e40d80f41da45015d2418a3df833220460c2769f..bdd60863ef94c2c1f312528e2bbbe5eb1cba06ff 100644 (file)
@@ -1,51 +1,55 @@
-SVG.Mask = SVG.invent({
+import Container from './Container.js'
+import Element from './Element.js'
+import {nodeOrNew} from './tools.js'
+import find from './selector.js'
+
+export default class Mask extends Container {
   // Initialize node
-  create: 'mask',
-
-  // Inherit from
-  inherit: SVG.Container,
-
-  // Add class methods
-  extend: {
-    // Unmask all masked elements and remove itself
-    remove: function () {
-      // unmask all targets
-      this.targets().forEach(function (el) {
-        el.unmask()
-      })
-
-      // remove mask from parent
-      return SVG.Element.prototype.remove.call(this)
-    },
-
-    targets: function () {
-      return SVG.select('svg [mask*="' + this.id() + '"]')
-    }
-  },
+  constructor (node) {
+    super(nodeOrNew('mask', node))
+  }
+
+  // Unmask all masked elements and remove itself
+  remove () {
+    // unmask all targets
+    this.targets().forEach(function (el) {
+      el.unmask()
+    })
+
+    // remove mask from parent
+    return super.remove()
+  }
 
-  // Add parent method
-  construct: {
-    // Create masking element
-    mask: function () {
-      return this.defs().put(new SVG.Mask())
-    }
+  targets () {
+    return find('svg [mask*="' + this.id() + '"]')
+  }
+
+}
+
+addFactory(Container, {
+  mask () {
+    return this.defs().put(new Mask())
   }
 })
 
-SVG.extend(SVG.Element, {
+extend(Element, {
   // Distribute mask to svg element
-  maskWith: function (element) {
+  maskWith (element) {
     // use given mask or create a new one
-    var masker = element instanceof SVG.Mask ? element : this.parent().mask().add(element)
+    var masker = element instanceof Mask
+      ? element
+      : this.parent().mask().add(element)
 
     // apply mask
     return this.attr('mask', 'url("#' + masker.id() + '")')
   },
+
   // Unmask element
-  unmask: function () {
+  unmask () {
     return this.attr('mask', null)
   },
-  masker: function () {
+
+  masker () {
     return this.reference('mask')
   }
 })
index 666b898bbb83ae0e8d44ae857a4d9848a03c0ef4..5edbc5c888378dfc4d0a7c1eb3141c9add6f711d 100644 (file)
@@ -1,16 +1,20 @@
-/* global abcdef arrayToMatrix closeEnough formatTransforms isMatrixLike matrixMultiply */
+import {abcdef, arrayToMatrix, closeEnough, formatTransforms, isMatrixLike, matrixMultiply} from './helpers.js'
+import {Element, Point, Doc} from './classes.js'
+import {delimiter} from './regex.js'
+import {radians} from './utils.js'
+import parser from './parser.js'
 
-SVG.Matrix = SVG.invent({
+export default class Matrix {
   // Initialize
-  create: function (source) {
+  constructor (source) {
     var base = arrayToMatrix([1, 0, 0, 1, 0, 0])
 
     // ensure source as object
-    source = source instanceof SVG.Element ? source.matrixify()
-      : typeof source === 'string' ? arrayToMatrix(source.split(SVG.regex.delimiter).map(parseFloat))
+    source = source instanceof Element ? source.matrixify()
+      : typeof source === 'string' ? arrayToMatrix(source.split(delimiter).map(parseFloat))
       : Array.isArray(source) ? arrayToMatrix(source)
       : (typeof source === 'object' && isMatrixLike(source)) ? source
-      : (typeof source === 'object') ? new SVG.Matrix().transform(source)
+      : (typeof source === 'object') ? new Matrix().transform(source)
       : arguments.length === 6 ? arrayToMatrix([].slice.call(arguments))
       : base
 
@@ -21,439 +25,408 @@ SVG.Matrix = SVG.invent({
     this.d = source.d != null ? source.d : base.d
     this.e = source.e != null ? source.e : base.e
     this.f = source.f != null ? source.f : base.f
-  },
+  }
+
+
+  // Clones this matrix
+  clone () {
+    return new Matrix(this)
+  }
+
+  // Transform a matrix into another matrix by manipulating the space
+  transform (o) {
+    // Check if o is a matrix and then left multiply it directly
+    if (isMatrixLike(o)) {
+      var matrix = new Matrix(o)
+      return matrix.multiplyO(this)
+    }
+
+    // Get the proposed transformations and the current transformations
+    var t = formatTransforms(o)
+    var current = this
+    let { x: ox, y: oy } = new Point(t.ox, t.oy).transform(current)
+
+    // Construct the resulting matrix
+    var transformer = new Matrix()
+      .translateO(t.rx, t.ry)
+      .lmultiplyO(current)
+      .translateO(-ox, -oy)
+      .scaleO(t.scaleX, t.scaleY)
+      .skewO(t.skewX, t.skewY)
+      .shearO(t.shear)
+      .rotateO(t.theta)
+      .translateO(ox, oy)
+
+    // If we want the origin at a particular place, we force it there
+    if (isFinite(t.px) || isFinite(t.py)) {
+      const origin = new Point(ox, oy).transform(transformer)
+      // TODO: Replace t.px with isFinite(t.px)
+      const dx = t.px ? t.px - origin.x : 0
+      const dy = t.py ? t.py - origin.y : 0
+      transformer.translateO(dx, dy)
+    }
+
+    // Translate now after positioning
+    transformer.translateO(t.tx, t.ty)
+    return transformer
+  }
+
+  // Applies a matrix defined by its affine parameters
+  compose (o) {
+    if (o.origin) {
+      o.originX = o.origin[0]
+      o.originY = o.origin[1]
+    }
+    // Get the parameters
+    var ox = o.originX || 0
+    var oy = o.originY || 0
+    var sx = o.scaleX || 1
+    var sy = o.scaleY || 1
+    var lam = o.shear || 0
+    var theta = o.rotate || 0
+    var tx = o.translateX || 0
+    var ty = o.translateY || 0
+
+    // Apply the standard matrix
+    var result = new Matrix()
+      .translateO(-ox, -oy)
+      .scaleO(sx, sy)
+      .shearO(lam)
+      .rotateO(theta)
+      .translateO(tx, ty)
+      .lmultiplyO(this)
+      .translateO(ox, oy)
+    return result
+  }
+
+  // Decomposes this matrix into its affine parameters
+  decompose (cx = 0, cy = 0) {
+    // Get the parameters from the matrix
+    var a = this.a
+    var b = this.b
+    var c = this.c
+    var d = this.d
+    var e = this.e
+    var f = this.f
+
+    // Figure out if the winding direction is clockwise or counterclockwise
+    var determinant = a * d - b * c
+    var ccw = determinant > 0 ? 1 : -1
+
+    // Since we only shear in x, we can use the x basis to get the x scale
+    // and the rotation of the resulting matrix
+    var sx = ccw * Math.sqrt(a * a + b * b)
+    var thetaRad = Math.atan2(ccw * b, ccw * a)
+    var theta = 180 / Math.PI * thetaRad
+    var ct = Math.cos(thetaRad)
+    var st = Math.sin(thetaRad)
+
+    // We can then solve the y basis vector simultaneously to get the other
+    // two affine parameters directly from these parameters
+    var lam = (a * c + b * d) / determinant
+    var sy = ((c * sx) / (lam * a - b)) || ((d * sx) / (lam * b + a))
+
+    // Use the translations
+    let tx = e - cx + cx * ct * sx + cy * (lam * ct * sx - st * sy)
+    let ty = f - cy + cx * st * sx + cy * (lam * st * sx + ct * sy)
+
+    // Construct the decomposition and return it
+    return {
+      // Return the affine parameters
+      scaleX: sx,
+      scaleY: sy,
+      shear: lam,
+      rotate: theta,
+      translateX: tx,
+      translateY: ty,
+      originX: cx,
+      originY: cy,
+
+      // Return the matrix parameters
+      a: this.a,
+      b: this.b,
+      c: this.c,
+      d: this.d,
+      e: this.e,
+      f: this.f
+    }
+  }
+
+  // Left multiplies by the given matrix
+  multiply (matrix) {
+    return this.clone().multiplyO(matrix)
+  }
+
+  multiplyO (matrix) {
+    // Get the matrices
+    var l = this
+    var r = matrix instanceof Matrix
+      ? matrix
+      : new Matrix(matrix)
+
+    return matrixMultiply(l, r, this)
+  }
+
+  lmultiply (matrix) {
+    return this.clone().lmultiplyO(matrix)
+  }
+
+  lmultiplyO (matrix) {
+    var r = this
+    var l = matrix instanceof Matrix
+      ? matrix
+      : new Matrix(matrix)
+
+    return matrixMultiply(l, r, this)
+  }
+
+  // Inverses matrix
+  inverseO () {
+    // Get the current parameters out of the matrix
+    var a = this.a
+    var b = this.b
+    var c = this.c
+    var d = this.d
+    var e = this.e
+    var f = this.f
+
+    // Invert the 2x2 matrix in the top left
+    var det = a * d - b * c
+    if (!det) throw new Error('Cannot invert ' + this)
+
+    // Calculate the top 2x2 matrix
+    var na = d / det
+    var nb = -b / det
+    var nc = -c / det
+    var nd = a / det
+
+    // Apply the inverted matrix to the top right
+    var ne = -(na * e + nc * f)
+    var nf = -(nb * e + nd * f)
+
+    // Construct the inverted matrix
+    this.a = na
+    this.b = nb
+    this.c = nc
+    this.d = nd
+    this.e = ne
+    this.f = nf
+
+    return this
+  }
+
+  inverse () {
+    return this.clone().inverseO()
+  }
+
+  // Translate matrix
+  translate (x, y) {
+    return this.clone().translateO(x, y)
+  }
+
+  translateO (x, y) {
+    this.e += x || 0
+    this.f += y || 0
+    return this
+  }
+
+  // Scale matrix
+  scale (x, y, cx, cy) {
+    return this.clone().scaleO(...arguments)
+  }
+
+  scaleO (x, y = x, cx = 0, cy = 0) {
+    // Support uniform scaling
+    if (arguments.length === 3) {
+      cy = cx
+      cx = y
+      y = x
+    }
+
+    let {a, b, c, d, e, f} = this
+
+    this.a = a * x
+    this.b = b * y
+    this.c = c * x
+    this.d = d * y
+    this.e = e * x - cx * x + cx
+    this.f = f * y - cy * y + cy
+
+    return this
+  }
+
+  // Rotate matrix
+  rotate (r, cx, cy) {
+    return this.clone().rotateO(r, cx, cy)
+  }
+
+  rotateO (r, cx = 0, cy = 0) {
+    // Convert degrees to radians
+    r = radians(r)
+
+    let cos = Math.cos(r)
+    let sin = Math.sin(r)
+
+    let {a, b, c, d, e, f} = this
 
-  // Add methods
-  extend: {
-
-    // Clones this matrix
-    clone: function () {
-      return new SVG.Matrix(this)
-    },
-
-    // Transform a matrix into another matrix by manipulating the space
-    transform: function (o) {
-      // Check if o is a matrix and then left multiply it directly
-      if (isMatrixLike(o)) {
-        var matrix = new SVG.Matrix(o)
-        return matrix.multiplyO(this)
-      }
-
-      // Get the proposed transformations and the current transformations
-      var t = formatTransforms(o)
-      var current = this
-      let { x: ox, y: oy } = new SVG.Point(t.ox, t.oy).transform(current)
-
-      // Construct the resulting matrix
-      var transformer = new SVG.Matrix()
-        .translateO(t.rx, t.ry)
-        .lmultiplyO(current)
-        .translateO(-ox, -oy)
-        .scaleO(t.scaleX, t.scaleY)
-        .skewO(t.skewX, t.skewY)
-        .shearO(t.shear)
-        .rotateO(t.theta)
-        .translateO(ox, oy)
-
-      // If we want the origin at a particular place, we force it there
-      if (isFinite(t.px) || isFinite(t.py)) {
-        const origin = new SVG.Point(ox, oy).transform(transformer)
-        // TODO: Replace t.px with isFinite(t.px)
-        const dx = t.px ? t.px - origin.x : 0
-        const dy = t.py ? t.py - origin.y : 0
-        transformer.translateO(dx, dy)
-      }
-
-      // Translate now after positioning
-      transformer.translateO(t.tx, t.ty)
-      return transformer
-    },
-
-    // Applies a matrix defined by its affine parameters
-    compose: function (o) {
-      if (o.origin) {
-        o.originX = o.origin[0]
-        o.originY = o.origin[1]
-      }
-      // Get the parameters
-      var ox = o.originX || 0
-      var oy = o.originY || 0
-      var sx = o.scaleX || 1
-      var sy = o.scaleY || 1
-      var lam = o.shear || 0
-      var theta = o.rotate || 0
-      var tx = o.translateX || 0
-      var ty = o.translateY || 0
-
-      // Apply the standard matrix
-      var result = new SVG.Matrix()
-        .translateO(-ox, -oy)
-        .scaleO(sx, sy)
-        .shearO(lam)
-        .rotateO(theta)
-        .translateO(tx, ty)
-        .lmultiplyO(this)
-        .translateO(ox, oy)
-      return result
-    },
-
-    // Decomposes this matrix into its affine parameters
-    decompose: function (cx = 0, cy = 0) {
-      // Get the parameters from the matrix
-      var a = this.a
-      var b = this.b
-      var c = this.c
-      var d = this.d
-      var e = this.e
-      var f = this.f
-
-      // Figure out if the winding direction is clockwise or counterclockwise
-      var determinant = a * d - b * c
-      var ccw = determinant > 0 ? 1 : -1
-
-      // Since we only shear in x, we can use the x basis to get the x scale
-      // and the rotation of the resulting matrix
-      var sx = ccw * Math.sqrt(a * a + b * b)
-      var thetaRad = Math.atan2(ccw * b, ccw * a)
-      var theta = 180 / Math.PI * thetaRad
-      var ct = Math.cos(thetaRad)
-      var st = Math.sin(thetaRad)
-
-      // We can then solve the y basis vector simultaneously to get the other
-      // two affine parameters directly from these parameters
-      var lam = (a * c + b * d) / determinant
-      var sy = ((c * sx) / (lam * a - b)) || ((d * sx) / (lam * b + a))
-
-      // Use the translations
-      let tx = e - cx + cx * ct * sx + cy * (lam * ct * sx - st * sy)
-      let ty = f - cy + cx * st * sx + cy * (lam * st * sx + ct * sy)
-
-      // Construct the decomposition and return it
-      return {
-        // Return the affine parameters
-        scaleX: sx,
-        scaleY: sy,
-        shear: lam,
-        rotate: theta,
-        translateX: tx,
-        translateY: ty,
-        originX: cx,
-        originY: cy,
-
-        // Return the matrix parameters
-        a: this.a,
-        b: this.b,
-        c: this.c,
-        d: this.d,
-        e: this.e,
-        f: this.f
-      }
-    },
-
-    // Morph one matrix into another
-    morph: function (matrix) {
-      // Store new destination
-      this.destination = new SVG.Matrix(matrix)
-      return this
-    },
-
-    // Get morphed matrix at a given position
-    at: function (pos) {
-      // Make sure a destination is defined
-      if (!this.destination) return this
-
-      // Calculate morphed matrix at a given position
-      var matrix = new SVG.Matrix({
-        a: this.a + (this.destination.a - this.a) * pos,
-        b: this.b + (this.destination.b - this.b) * pos,
-        c: this.c + (this.destination.c - this.c) * pos,
-        d: this.d + (this.destination.d - this.d) * pos,
-        e: this.e + (this.destination.e - this.e) * pos,
-        f: this.f + (this.destination.f - this.f) * pos
-      })
-
-      return matrix
-    },
-
-    // Left multiplies by the given matrix
-    multiply: function (matrix) {
-      return this.clone().multiplyO(matrix)
-    },
-
-    multiplyO: function (matrix) {
-      // Get the matrices
-      var l = this
-      var r = matrix instanceof SVG.Matrix
-        ? matrix
-        : new SVG.Matrix(matrix)
-
-      return matrixMultiply(l, r, this)
-    },
-
-    lmultiply: function (matrix) {
-      return this.clone().lmultiplyO(matrix)
-    },
-
-    lmultiplyO: function (matrix) {
-      var r = this
-      var l = matrix instanceof SVG.Matrix
-        ? matrix
-        : new SVG.Matrix(matrix)
-
-      return matrixMultiply(l, r, this)
-    },
-
-    // Inverses matrix
-    inverseO: function () {
-      // Get the current parameters out of the matrix
-      var a = this.a
-      var b = this.b
-      var c = this.c
-      var d = this.d
-      var e = this.e
-      var f = this.f
-
-      // Invert the 2x2 matrix in the top left
-      var det = a * d - b * c
-      if (!det) throw new Error('Cannot invert ' + this)
-
-      // Calculate the top 2x2 matrix
-      var na = d / det
-      var nb = -b / det
-      var nc = -c / det
-      var nd = a / det
-
-      // Apply the inverted matrix to the top right
-      var ne = -(na * e + nc * f)
-      var nf = -(nb * e + nd * f)
-
-      // Construct the inverted matrix
-      this.a = na
-      this.b = nb
-      this.c = nc
-      this.d = nd
-      this.e = ne
-      this.f = nf
-
-      return this
-    },
-
-    inverse: function () {
-      return this.clone().inverseO()
-    },
-
-    // Translate matrix
-    translate: function (x, y) {
-      return this.clone().translateO(x, y)
-    },
-
-    translateO: function (x, y) {
-      this.e += x || 0
-      this.f += y || 0
-      return this
-    },
-
-    // Scale matrix
-    scale: function (x, y, cx, cy) {
-      return this.clone().scaleO(...arguments)
-    },
-
-    scaleO: function (x, y = x, cx = 0, cy = 0) {
-      // Support uniform scaling
-      if (arguments.length === 3) {
-        cy = cx
-        cx = y
-        y = x
-      }
-
-      let {a, b, c, d, e, f} = this
-
-      this.a = a * x
-      this.b = b * y
-      this.c = c * x
-      this.d = d * y
-      this.e = e * x - cx * x + cx
-      this.f = f * y - cy * y + cy
-
-      return this
-    },
-
-    // Rotate matrix
-    rotate: function (r, cx, cy) {
-      return this.clone().rotateO(r, cx, cy)
-    },
-
-    rotateO: function (r, cx = 0, cy = 0) {
-      // Convert degrees to radians
-      r = SVG.utils.radians(r)
-
-      let cos = Math.cos(r)
-      let sin = Math.sin(r)
-
-      let {a, b, c, d, e, f} = this
-
-      this.a = a * cos - b * sin
-      this.b = b * cos + a * sin
-      this.c = c * cos - d * sin
-      this.d = d * cos + c * sin
-      this.e = e * cos - f * sin + cy * sin - cx * cos + cx
-      this.f = f * cos + e * sin - cx * sin - cy * cos + cy
-
-      return this
-    },
-
-    // Flip matrix on x or y, at a given offset
-    flip: function (axis, around) {
-      return this.clone().flipO(axis, around)
-    },
-
-    flipO: function (axis, around) {
-      return axis === 'x' ? this.scaleO(-1, 1, around, 0)
-        : axis === 'y' ? this.scaleO(1, -1, 0, around)
-        : this.scaleO(-1, -1, axis, around || axis) // Define an x, y flip point
-    },
-
-    // Shear matrix
-    shear: function (a, cx, cy) {
-      return this.clone().shearO(a, cx, cy)
-    },
-
-    shearO: function (lx, cx = 0, cy = 0) {
-      let {a, b, c, d, e, f} = this
-
-      this.a = a + b * lx
-      this.c = c + d * lx
-      this.e = e + f * lx - cy * lx
-
-      return this
-    },
-
-    // Skew Matrix
-    skew: function (x, y, cx, cy) {
-      return this.clone().skewO(...arguments)
-    },
-
-    skewO: function (x, y = x, cx = 0, cy = 0) {
-      // support uniformal skew
-      if (arguments.length === 3) {
-        cy = cx
-        cx = y
-        y = x
-      }
-
-      // Convert degrees to radians
-      x = SVG.utils.radians(x)
-      y = SVG.utils.radians(y)
-
-      let lx = Math.tan(x)
-      let ly = Math.tan(y)
-
-      let {a, b, c, d, e, f} = this
-
-      this.a = a + b * lx
-      this.b = b + a * ly
-      this.c = c + d * lx
-      this.d = d + c * ly
-      this.e = e + f * lx - cy * lx
-      this.f = f + e * ly - cx * ly
-
-      return this
-    },
-
-    // SkewX
-    skewX: function (x, cx, cy) {
-      return this.skew(x, 0, cx, cy)
-    },
-
-    skewXO: function (x, cx, cy) {
-      return this.skewO(x, 0, cx, cy)
-    },
-
-    // SkewY
-    skewY: function (y, cx, cy) {
-      return this.skew(0, y, cx, cy)
-    },
-
-    skewYO: function (y, cx, cy) {
-      return this.skewO(0, y, cx, cy)
-    },
-
-    // Transform around a center point
-    aroundO: function (cx, cy, matrix) {
-      var dx = cx || 0
-      var dy = cy || 0
-      return this.translateO(-dx, -dy).lmultiplyO(matrix).translateO(dx, dy)
-    },
-
-    around: function (cx, cy, matrix) {
-      return this.clone().aroundO(cx, cy, matrix)
-    },
-
-    // Convert to native SVGMatrix
-    native: function () {
-      // create new matrix
-      var matrix = SVG.parser.nodes.svg.node.createSVGMatrix()
-
-      // update with current values
-      for (var i = abcdef.length - 1; i >= 0; i--) {
-        matrix[abcdef[i]] = this[abcdef[i]]
-      }
-
-      return matrix
-    },
-
-    // Check if two matrices are equal
-    equals: function (other) {
-      var comp = new SVG.Matrix(other)
-      return closeEnough(this.a, comp.a) && closeEnough(this.b, comp.b) &&
-        closeEnough(this.c, comp.c) && closeEnough(this.d, comp.d) &&
-        closeEnough(this.e, comp.e) && closeEnough(this.f, comp.f)
-    },
-
-    // Convert matrix to string
-    toString: function () {
-      return 'matrix(' + this.a + ',' + this.b + ',' + this.c + ',' + this.d + ',' + this.e + ',' + this.f + ')'
-    },
-
-    toArray: function () {
-      return [this.a, this.b, this.c, this.d, this.e, this.f]
-    },
-
-    valueOf: function () {
-      return {
-        a: this.a,
-        b: this.b,
-        c: this.c,
-        d: this.d,
-        e: this.e,
-        f: this.f
-      }
+    this.a = a * cos - b * sin
+    this.b = b * cos + a * sin
+    this.c = c * cos - d * sin
+    this.d = d * cos + c * sin
+    this.e = e * cos - f * sin + cy * sin - cx * cos + cx
+    this.f = f * cos + e * sin - cx * sin - cy * cos + cy
+
+    return this
+  }
+
+  // Flip matrix on x or y, at a given offset
+  flip (axis, around) {
+    return this.clone().flipO(axis, around)
+  }
+
+  flipO (axis, around) {
+    return axis === 'x' ? this.scaleO(-1, 1, around, 0)
+      : axis === 'y' ? this.scaleO(1, -1, 0, around)
+      : this.scaleO(-1, -1, axis, around || axis) // Define an x, y flip point
+  }
+
+  // Shear matrix
+  shear (a, cx, cy) {
+    return this.clone().shearO(a, cx, cy)
+  }
+
+  shearO (lx, cx = 0, cy = 0) {
+    let {a, b, c, d, e, f} = this
+
+    this.a = a + b * lx
+    this.c = c + d * lx
+    this.e = e + f * lx - cy * lx
+
+    return this
+  }
+
+  // Skew Matrix
+  skew (x, y, cx, cy) {
+    return this.clone().skewO(...arguments)
+  }
+
+  skewO (x, y = x, cx = 0, cy = 0) {
+    // support uniformal skew
+    if (arguments.length === 3) {
+      cy = cx
+      cx = y
+      y = x
+    }
+
+    // Convert degrees to radians
+    x = radians(x)
+    y = radians(y)
+
+    let lx = Math.tan(x)
+    let ly = Math.tan(y)
+
+    let {a, b, c, d, e, f} = this
+
+    this.a = a + b * lx
+    this.b = b + a * ly
+    this.c = c + d * lx
+    this.d = d + c * ly
+    this.e = e + f * lx - cy * lx
+    this.f = f + e * ly - cx * ly
+
+    return this
+  }
+
+  // SkewX
+  skewX (x, cx, cy) {
+    return this.skew(x, 0, cx, cy)
+  }
+
+  skewXO (x, cx, cy) {
+    return this.skewO(x, 0, cx, cy)
+  }
+
+  // SkewY
+  skewY (y, cx, cy) {
+    return this.skew(0, y, cx, cy)
+  }
+
+  skewYO (y, cx, cy) {
+    return this.skewO(0, y, cx, cy)
+  }
+
+  // Transform around a center point
+  aroundO (cx, cy, matrix) {
+    var dx = cx || 0
+    var dy = cy || 0
+    return this.translateO(-dx, -dy).lmultiplyO(matrix).translateO(dx, dy)
+  }
+
+  around (cx, cy, matrix) {
+    return this.clone().aroundO(cx, cy, matrix)
+  }
+
+  // Convert to native SVGMatrix
+  native () {
+    // create new matrix
+    var matrix = parser.nodes.node.createSVGMatrix()
+
+    // update with current values
+    for (var i = abcdef.length - 1; i >= 0; i--) {
+      matrix[abcdef[i]] = this[abcdef[i]]
     }
+
+    return matrix
+  }
+
+  // Check if two matrices are equal
+  equals (other) {
+    var comp = new Matrix(other)
+    return closeEnough(this.a, comp.a) && closeEnough(this.b, comp.b) &&
+      closeEnough(this.c, comp.c) && closeEnough(this.d, comp.d) &&
+      closeEnough(this.e, comp.e) && closeEnough(this.f, comp.f)
+  }
+
+  // Convert matrix to string
+  toString () {
+    return 'matrix(' + this.a + ',' + this.b + ',' + this.c + ',' + this.d + ',' + this.e + ',' + this.f + ')'
+  }
+
+  toArray () {
+    return [this.a, this.b, this.c, this.d, this.e, this.f]
+  }
+
+  valueOf () {
+    return {
+      a: this.a,
+      b: this.b,
+      c: this.c,
+      d: this.d,
+      e: this.e,
+      f: this.f
+    }
+  }
+}
+
+extend(Element, {
+  // Get current matrix
+  ctm () {
+    return new Matrix(this.node.getCTM())
   },
 
-  // Define parent
-  parent: SVG.Element,
-
-  // Add parent method
-  construct: {
-    // Get current matrix
-    ctm: function () {
-      return new SVG.Matrix(this.node.getCTM())
-    },
-    // Get current screen matrix
-    screenCTM: function () {
-      /* https://bugzilla.mozilla.org/show_bug.cgi?id=1344537
-         This is needed because FF does not return the transformation matrix
-         for the inner coordinate system when getScreenCTM() is called on nested svgs.
-         However all other Browsers do that */
-      if (this instanceof SVG.Doc && !this.isRoot()) {
-        var rect = this.rect(1, 1)
-        var m = rect.node.getScreenCTM()
-        rect.remove()
-        return new SVG.Matrix(m)
-      }
-      return new SVG.Matrix(this.node.getScreenCTM())
+  // Get current screen matrix
+  screenCTM () {
+    /* https://bugzilla.mozilla.org/show_bug.cgi?id=1344537
+       This is needed because FF does not return the transformation matrix
+       for the inner coordinate system when getScreenCTM() is called on nested svgs.
+       However all other Browsers do that */
+    if (this instanceof Doc && !this.isRoot()) {
+      var rect = this.rect(1, 1)
+      var m = rect.node.getScreenCTM()
+      rect.remove()
+      return new Matrix(m)
     }
+    return new Matrix(this.node.getScreenCTM())
   }
 })
 
@@ -461,12 +434,12 @@ SVG.Matrix = SVG.invent({
 // ['rotate'].forEach((method) => {
 //   let methodO = method + 'O'
 //   extensions[method] = function (...args) {
-//     return new SVG.Matrix(this)[methodO](...args)
+//     return new Matrix(this)[methodO](...args)
 //   }
 // })
 //
-// SVG.extend(SVG.Matrix, extensions)
+// extend(Matrix, extensions)
 
 // function matrixMultiplyParams (matrix, a, b, c, d, e, f) {
-//   return matrixMultiply({a, b, c, d, e, f}, matrix, matrix)
+//   return matrixMultiply({a, b, c, d, e, f} matrix, matrix)
 // }
index acb9e210e6bde4d8a39a7b8873ffb4d96fc02145..1cb437e55997d5509c4eca9db63e8c45625795a4 100644 (file)
+import {extend} from './tools.js'
+import {Color, SVGNumber, SVGArray, PathArray} from './classes.js'
 
-SVG.Morphable = SVG.invent({
-  create: function (stepper) {
+export default class Morphable {
+  constructor () {
     // FIXME: the default stepper does not know about easing
-    this._stepper = stepper || new SVG.Ease('-')
+    this._stepper = stepper || new Ease('-')
 
     this._from = null
     this._to = null
     this._type = null
     this._context = null
     this._morphObj = null
-  },
+  }
 
-  extend: {
+  from (val) {
+    if (val == null) {
+      return this._from
+    }
 
-    from: function (val) {
-      if (val == null) {
-        return this._from
-      }
+    this._from = this._set(val)
+    return this
+  }
 
-      this._from = this._set(val)
-      return this
-    },
+  to (val) {
+    if (val == null) {
+      return this._to
+    }
 
-    to: function (val) {
-      if (val == null) {
-        return this._to
-      }
+    this._to = this._set(val)
+    return this
+  }
 
-      this._to = this._set(val)
-      return this
-    },
+  type (type) {
+    // getter
+    if (type == null) {
+      return this._type
+    }
 
-    type: function (type) {
-      // getter
-      if (type == null) {
-        return this._type
-      }
+    // setter
+    this._type = type
+    return this
+  }
 
-      // setter
-      this._type = type
-      return this
-    },
-
-    _set: function (value) {
-      if (!this._type) {
-        var type = typeof value
-
-        if (type === 'number') {
-          this.type(SVG.Number)
-        } else if (type === 'string') {
-          if (SVG.Color.isColor(value)) {
-            this.type(SVG.Color)
-          } else if (SVG.regex.delimiter.test(value)) {
-            this.type(SVG.regex.pathLetters.test(value)
-              ? SVG.PathArray
-              : SVG.Array
-            )
-          } else if (SVG.regex.numberAndUnit.test(value)) {
-            this.type(SVG.Number)
-          } else {
-            this.type(SVG.Morphable.NonMorphable)
-          }
-        } else if (SVG.MorphableTypes.indexOf(value.constructor) > -1) {
-          this.type(value.constructor)
-        } else if (Array.isArray(value)) {
-          this.type(SVG.Array)
-        } else if (type === 'object') {
-          this.type(SVG.Morphable.ObjectBag)
+  _set (value) {
+    if (!this._type) {
+      var type = typeof value
+
+      if (type === 'number') {
+        this.type(SVGNumber)
+      } else if (type === 'string') {
+        if (Color.isColor(value)) {
+          this.type(Color)
+        } else if (regex.delimiter.test(value)) {
+          this.type(regex.pathLetters.test(value)
+            ? PathArray
+            : SVGArray
+          )
+        } else if (regex.numberAndUnit.test(value)) {
+          this.type(SVGNumber)
         } else {
-          this.type(SVG.Morphable.NonMorphable)
+          this.type(Morphable.NonMorphable)
         }
+      } else if (MorphableTypes.indexOf(value.constructor) > -1) {
+        this.type(value.constructor)
+      } else if (Array.isArray(value)) {
+        this.type(SVGArray)
+      } else if (type === 'object') {
+        this.type(Morphable.ObjectBag)
+      } else {
+        this.type(Morphable.NonMorphable)
       }
-
-      var result = (new this._type(value)).toArray()
-      this._morphObj = this._morphObj || new this._type()
-      this._context = this._context ||
-        Array.apply(null, Array(result.length)).map(Object)
-      return result
-    },
-
-    stepper: function (stepper) {
-      if (stepper == null) return this._stepper
-      this._stepper = stepper
-      return this
-    },
-
-    done: function () {
-      var complete = this._context
-        .map(this._stepper.done)
-        .reduce(function (last, curr) {
-          return last && curr
-        }, true)
-      return complete
-    },
-
-    at: function (pos) {
-      var _this = this
-
-      return this._morphObj.fromArray(
-        this._from.map(function (i, index) {
-          return _this._stepper.step(i, _this._to[index], pos, _this._context[index], _this._context)
-        })
-      )
     }
+
+    var result = (new this._type(value)).toArray()
+    this._morphObj = this._morphObj || new this._type()
+    this._context = this._context ||
+      Array.apply(null, Array(result.length)).map(Object)
+    return result
   }
-})
 
-SVG.Morphable.NonMorphable = SVG.invent({
-  create: function (val) {
+  stepper (stepper) {
+    if (stepper == null) return this._stepper
+    this._stepper = stepper
+    return this
+  }
+
+  done () {
+    var complete = this._context
+      .map(this._stepper.done)
+      .reduce(function (last, curr) {
+        return last && curr
+      }, true)
+    return complete
+  }
+
+  at (pos) {
+    var _this = this
+
+    return this._morphObj.fromArray(
+      this._from.map(function (i, index) {
+        return _this._stepper.step(i, _this._to[index], pos, _this._context[index], _this._context)
+      })
+    )
+  }
+}
+
+Morphable.NonMorphable = class {
+  constructor (val) {
     val = Array.isArray(val) ? val[0] : val
     this.value = val
-  },
+  }
 
-  extend: {
-    valueOf: function () {
-      return this.value
-    },
+  valueOf () {
+    return this.value
+  }
 
-    toArray: function () {
-      return [this.value]
-    }
+  toArray () {
+    return [this.value]
   }
-})
+}
 
-SVG.Morphable.TransformBag = SVG.invent({
-  create: function (obj) {
+Morphable.TransformBag = class {
+  constructor (obj) {
     if (Array.isArray(obj)) {
       obj = {
         scaleX: obj[0],
@@ -138,28 +135,26 @@ SVG.Morphable.TransformBag = SVG.invent({
       }
     }
 
-    Object.assign(this, SVG.Morphable.TransformBag.defaults, obj)
-  },
+    Object.assign(this, Morphable.TransformBag.defaults, obj)
+  }
 
-  extend: {
-    toArray: function () {
-      var v = this
-
-      return [
-        v.scaleX,
-        v.scaleY,
-        v.shear,
-        v.rotate,
-        v.translateX,
-        v.translateY,
-        v.originX,
-        v.originY
-      ]
-    }
+  toArray () {
+    var v = this
+
+    return [
+      v.scaleX,
+      v.scaleY,
+      v.shear,
+      v.rotate,
+      v.translateX,
+      v.translateY,
+      v.originX,
+      v.originY
+    ]
   }
-})
+}
 
-SVG.Morphable.TransformBag.defaults = {
+Morphable.TransformBag.defaults = {
   scaleX: 1,
   scaleY: 1,
   shear: 0,
@@ -170,8 +165,8 @@ SVG.Morphable.TransformBag.defaults = {
   originY: 0
 }
 
-SVG.Morphable.ObjectBag = SVG.invent({
-  create: function (objOrArr) {
+Morphable.ObjectBag = class {
+  constructor (objOrArr) {
     this.values = []
 
     if (Array.isArray(objOrArr)) {
@@ -184,47 +179,45 @@ SVG.Morphable.ObjectBag = SVG.invent({
     })
 
     this.values = entries.reduce((last, curr) => last.concat(curr), [])
-  },
+  }
 
-  extend: {
-    valueOf: function () {
-      var obj = {}
-      var arr = this.values
+  valueOf () {
+    var obj = {}
+    var arr = this.values
 
-      for (var i = 0, len = arr.length; i < len; i += 2) {
-        obj[arr[i]] = arr[i + 1]
-      }
+    for (var i = 0, len = arr.length; i < len; i += 2) {
+      obj[arr[i]] = arr[i + 1]
+    }
 
-      return obj
-    },
+    return obj
+  }
 
-    toArray: function () {
-      return this.values
-    }
+  toArray () {
+    return this.values
   }
-})
+}
 
-SVG.MorphableTypes = [
-  SVG.Number,
-  SVG.Color,
-  SVG.Box,
-  SVG.Matrix,
-  SVG.Array,
-  SVG.PointArray,
-  SVG.PathArray,
-  SVG.Morphable.NonMorphable,
-  SVG.Morphable.TransformBag,
-  SVG.Morphable.ObjectBag
+let morphableTypes = [
+  SVGNumber,
+  Color,
+  Box,
+  Matrix,
+  SVGArray,
+  PointArray,
+  PathArray,
+  Morphable.NonMorphable,
+  Morphable.TransformBag,
+  Morphable.ObjectBag
 ]
 
-SVG.extend(SVG.MorphableTypes, {
-  to: function (val, args) {
-    return new SVG.Morphable()
+extend(morphableTypes, {
+  to (val, args) {
+    return new Morphable()
       .type(this.constructor)
       .from(this.valueOf())
       .to(val, args)
   },
-  fromArray: function (arr) {
+  fromArray (arr) {
     this.constructor(arr)
     return this
   }
index 6bdad582f0b4d05997e1a28467151a67d3015057..ce22f803055583dc8c0d2fe35a872d2df2247d10 100644 (file)
@@ -1,92 +1,93 @@
-/* global createElement */
-
-SVG.Parent = SVG.invent({
-  // Initialize node
-  create: function (node) {
-    SVG.Element.call(this, node)
-  },
-
-  // Inherit from
-  inherit: SVG.Element,
-
-  // Add class methods
-  extend: {
-    // Returns all child elements
-    children: function () {
-      return SVG.utils.map(this.node.children, function (node) {
-        return SVG.adopt(node)
-      })
-    },
-    // Add given element at a position
-    add: function (element, i) {
-      element = createElement(element)
-
-      if (element.node !== this.node.children[i]) {
-        this.node.insertBefore(element.node, this.node.children[i] || null)
-      }
+import {makeInstance} from './helpers.js'
+import Element from './Element.js'
+import {adopt} from './tools.js'
+import {map} from './utils.js'
+
+export default class Parent extends Element {
+  // Returns all child elements
+  children () {
+    return map(this.node.children, function (node) {
+      return adopt(node)
+    })
+  }
+
+  // Add given element at a position
+  add (element, i) {
+    element = makeInstance(element)
+
+    if (element.node !== this.node.children[i]) {
+      this.node.insertBefore(element.node, this.node.children[i] || null)
+    }
+
+    return this
+  }
 
-      return this
-    },
-    // Basically does the same as `add()` but returns the added element instead
-    put: function (element, i) {
-      this.add(element, i)
-      return element.instance || element
-    },
-    // Checks if the given element is a child
-    has: function (element) {
-      return this.index(element) >= 0
-    },
-    // Gets index of given element
-    index: function (element) {
-      return [].slice.call(this.node.children).indexOf(element.node)
-    },
-    // Get a element at the given index
-    get: function (i) {
-      return SVG.adopt(this.node.children[i])
-    },
-    // Get first child
-    first: function () {
-      return this.get(0)
-    },
-    // Get the last child
-    last: function () {
-      return this.get(this.node.children.length - 1)
-    },
-    // Iterates over all children and invokes a given block
-    each: function (block, deep) {
-      var children = this.children()
-      var i, il
-
-      for (i = 0, il = children.length; i < il; i++) {
-        if (children[i] instanceof SVG.Element) {
-          block.apply(children[i], [i, children])
-        }
-
-        if (deep && (children[i] instanceof SVG.Parent)) {
-          children[i].each(block, deep)
-        }
+  // Basically does the same as `add()` but returns the added element instead
+  put (element, i) {
+    this.add(element, i)
+    return element.instance || element
+  }
+
+  // Checks if the given element is a child
+  has (element) {
+    return this.index(element) >= 0
+  }
+
+  // Gets index of given element
+  index (element) {
+    return [].slice.call(this.node.children).indexOf(element.node)
+  }
+
+  // Get a element at the given index
+  get (i) {
+    return adopt(this.node.children[i])
+  }
+
+  // Get first child
+  first () {
+    return this.get(0)
+  }
+
+  // Get the last child
+  last () {
+    return this.get(this.node.children.length - 1)
+  }
+
+  // Iterates over all children and invokes a given block
+  each (block, deep) {
+    var children = this.children()
+    var i, il
+
+    for (i = 0, il = children.length; i < il; i++) {
+      if (children[i] instanceof Element) {
+        block.apply(children[i], [i, children])
       }
 
-      return this
-    },
-    // Remove a given child
-    removeElement: function (element) {
-      this.node.removeChild(element.node)
-
-      return this
-    },
-    // Remove all elements in this container
-    clear: function () {
-      // remove children
-      while (this.node.hasChildNodes()) {
-        this.node.removeChild(this.node.lastChild)
+      if (deep && (children[i] instanceof Parent)) {
+        children[i].each(block, deep)
       }
+    }
 
-      // remove defs reference
-      delete this._defs
+    return this
+  }
 
-      return this
-    }
+  // Remove a given child
+  removeElement (element) {
+    this.node.removeChild(element.node)
+
+    return this
   }
 
-})
+  // Remove all elements in this container
+  clear () {
+    // remove children
+    while (this.node.hasChildNodes()) {
+      this.node.removeChild(this.node.lastChild)
+    }
+
+    // remove defs reference
+    delete this._defs
+
+    return this
+  }
+}
index db3929b199bfe57c254536baa74a4fdfeadd21d1..72269778d27eca442509f26154181baa4089b78a 100644 (file)
@@ -1,63 +1,71 @@
-/* global proportionalSize */
+import {proportionalSize} from './helpers.js'
+import {nodeOrNew} from './tools.js'
+import Shape from './Shape.js'
+import PathArray from './PathArray.js'
 
-SVG.Path = SVG.invent({
+export default class Path extends Shape {
   // Initialize node
-  create: 'path',
-
-  // Inherit from
-  inherit: SVG.Shape,
-
-  // Add class methods
-  extend: {
-    // Define morphable array
-    MorphArray: SVG.PathArray,
-    // Get array
-    array: function () {
-      return this._array || (this._array = new SVG.PathArray(this.attr('d')))
-    },
-    // Plot new path
-    plot: function (d) {
-      return (d == null) ? this.array()
-        : this.clear().attr('d', typeof d === 'string' ? d : (this._array = new SVG.PathArray(d)))
-    },
-    // Clear array cache
-    clear: function () {
-      delete this._array
-      return this
-    },
-    // Move by left top corner
-    move: function (x, y) {
-      return this.attr('d', this.array().move(x, y))
-    },
-    // Move by left top corner over x-axis
-    x: function (x) {
-      return x == null ? this.bbox().x : this.move(x, this.bbox().y)
-    },
-    // Move by left top corner over y-axis
-    y: function (y) {
-      return y == null ? this.bbox().y : this.move(this.bbox().x, y)
-    },
-    // Set element size to given width and height
-    size: function (width, height) {
-      var p = proportionalSize(this, width, height)
-      return this.attr('d', this.array().size(p.width, p.height))
-    },
-    // Set width of element
-    width: function (width) {
-      return width == null ? this.bbox().width : this.size(width, this.bbox().height)
-    },
-    // Set height of element
-    height: function (height) {
-      return height == null ? this.bbox().height : this.size(this.bbox().width, height)
-    }
-  },
+  constructor (node) {
+    super(nodeOrNew('path', node))
+  }
+
+  // Get array
+  array () {
+    return this._array || (this._array = new PathArray(this.attr('d')))
+  }
+
+  // Plot new path
+  plot (d) {
+    return (d == null) ? this.array()
+      : this.clear().attr('d', typeof d === 'string' ? d : (this._array = new PathArray(d)))
+  }
+
+  // Clear array cache
+  clear () {
+    delete this._array
+    return this
+  }
+
+  // Move by left top corner
+  move (x, y) {
+    return this.attr('d', this.array().move(x, y))
+  }
+
+  // Move by left top corner over x-axis
+  x (x) {
+    return x == null ? this.bbox().x : this.move(x, this.bbox().y)
+  }
+
+  // Move by left top corner over y-axis
+  y (y) {
+    return y == null ? this.bbox().y : this.move(this.bbox().x, y)
+  }
+
+  // Set element size to given width and height
+  size (width, height) {
+    var p = proportionalSize(this, width, height)
+    return this.attr('d', this.array().size(p.width, p.height))
+  }
+
+  // Set width of element
+  width (width) {
+    return width == null ? this.bbox().width : this.size(width, this.bbox().height)
+  }
+
+  // Set height of element
+  height (height) {
+    return height == null ? this.bbox().height : this.size(this.bbox().width, height)
+  }
+}
+
+// Define morphable array
+Path.prototype.MorphArray = PathArray
 
   // Add parent method
-  construct: {
-    // Create a wrapped path element
-    path: function (d) {
-      // make sure plot is called as a setter
-      return this.put(new SVG.Path()).plot(d || new SVG.PathArray())
-    }
+addFactory(Container, {
+  // Create a wrapped path element
+  path (d) {
+    // make sure plot is called as a setter
+    return this.put(new Path()).plot(d || new PathArray())
   }
 })
index 4432df3da969329c3a9e39dd5c60e4259303af16..24d8665b8ca96eccb87ddf75e4dbfe6210fca174 100644 (file)
@@ -1,6 +1,9 @@
-/* globals arrayToString, pathRegReplace */
+import {arrayToString, pathRegReplace} from './helpers.js'
+import parser from './parser.js'
+import {numbersWithDots, pathLetters, hyphen, delimiter, isPathLetter} from './regex.js'
+import Point from './Point.js'
 
-var pathHandlers = {
+let pathHandlers = {
   M: function (c, p, p0) {
     p.x = p0.x = c[0]
     p.y = p0.y = c[1]
@@ -52,7 +55,7 @@ var pathHandlers = {
   }
 }
 
-var mlhvqtcsaz = 'mlhvqtcsaz'.split('')
+let mlhvqtcsaz = 'mlhvqtcsaz'.split('')
 
 for (var i = 0, il = mlhvqtcsaz.length; i < il; ++i) {
   pathHandlers[mlhvqtcsaz[i]] = (function (i) {
@@ -73,27 +76,24 @@ for (var i = 0, il = mlhvqtcsaz.length; i < il; ++i) {
   })(mlhvqtcsaz[i].toUpperCase())
 }
 
-// Path points array
-SVG.PathArray = function (array, fallback) {
-  SVG.Array.call(this, array, fallback || [['M', 0, 0]])
-}
-
-// Inherit from SVG.Array
-SVG.PathArray.prototype = new SVG.Array()
-SVG.PathArray.prototype.constructor = SVG.PathArray
+export default class PathArray extends SVGArray {
+  constructor (array, fallback = [['M', 0, 0]]) {
+    super(array, fallback)
+  }
 
-SVG.extend(SVG.PathArray, {
   // Convert array to string
-  toString: function () {
+  toString () {
     return arrayToString(this.value)
-  },
-  toArray: function () {
+  }
+
+  toArray () {
     return this.value.reduce(function (prev, curr) {
       return [].concat.call(prev, curr)
     }, [])
-  },
+  }
+
   // Move path string
-  move: function (x, y) {
+  move (x, y) {
     // get bounding box of current situation
     var box = this.bbox()
 
@@ -131,9 +131,10 @@ SVG.extend(SVG.PathArray, {
     }
 
     return this
-  },
+  }
+
   // Resize path string
-  size: function (width, height) {
+  size (width, height) {
     // get bounding box of current situation
     var box = this.bbox()
     var i, l
@@ -171,12 +172,13 @@ SVG.extend(SVG.PathArray, {
     }
 
     return this
-  },
+  }
+
   // Test if the passed path array use the same path data commands as this path array
-  equalCommands: function (pathArray) {
+  equalCommands (pathArray) {
     var i, il, equalCommands
 
-    pathArray = new SVG.PathArray(pathArray)
+    pathArray = new PathArray(pathArray)
 
     equalCommands = this.value.length === pathArray.value.length
     for (i = 0, il = this.value.length; equalCommands && i < il; i++) {
@@ -184,10 +186,11 @@ SVG.extend(SVG.PathArray, {
     }
 
     return equalCommands
-  },
+  }
+
   // Make path array morphable
-  morph: function (pathArray) {
-    pathArray = new SVG.PathArray(pathArray)
+  morph (pathArray) {
+    pathArray = new PathArray(pathArray)
 
     if (this.equalCommands(pathArray)) {
       this.destination = pathArray
@@ -196,16 +199,17 @@ SVG.extend(SVG.PathArray, {
     }
 
     return this
-  },
+  }
+
   // Get morphed path array at given position
-  at: function (pos) {
+  at (pos) {
     // make sure a destination is defined
     if (!this.destination) return this
 
     var sourceArray = this.value
     var destinationArray = this.destination.value
     var array = []
-    var pathArray = new SVG.PathArray()
+    var pathArray = new PathArray()
     var i, il, j, jl
 
     // Animate has specified in the SVG spec
@@ -229,11 +233,12 @@ SVG.extend(SVG.PathArray, {
     // Directly modify the value of a path array, this is done this way for performance
     pathArray.value = array
     return pathArray
-  },
+  }
+
   // Absolutize and parse path to array
-  parse: function (array) {
+  parse (array) {
     // if it's already a patharray, no need to parse it
-    if (array instanceof SVG.PathArray) return array.valueOf()
+    if (array instanceof PathArray) return array.valueOf()
 
     // prepare for parsing
     var s
@@ -241,11 +246,11 @@ SVG.extend(SVG.PathArray, {
 
     if (typeof array === 'string') {
       array = array
-        .replace(SVG.regex.numbersWithDots, pathRegReplace) // convert 45.123.123 to 45.123 .123
-        .replace(SVG.regex.pathLetters, ' $& ') // put some room between letters and numbers
-        .replace(SVG.regex.hyphen, '$1 -')      // add space before hyphen
+        .replace(regex.numbersWithDots, pathRegReplace) // convert 45.123.123 to 45.123 .123
+        .replace(regex.pathLetters, ' $& ') // put some room between letters and numbers
+        .replace(regex.hyphen, '$1 -')      // add space before hyphen
         .trim()                                 // trim
-        .split(SVG.regex.delimiter)   // split into array
+        .split(regex.delimiter)   // split into array
     } else {
       array = array.reduce(function (prev, curr) {
         return [].concat.call(prev, curr)
@@ -254,14 +259,14 @@ SVG.extend(SVG.PathArray, {
 
     // array now is an array containing all parts of a path e.g. ['M', '0', '0', 'L', '30', '30' ...]
     var result = []
-    var p = new SVG.Point()
-    var p0 = new SVG.Point()
+    var p = new Point()
+    var p0 = new Point()
     var index = 0
     var len = array.length
 
     do {
       // Test if we have a path letter
-      if (SVG.regex.isPathLetter.test(array[index])) {
+      if (regex.isPathLetter.test(array[index])) {
         s = array[index]
         ++index
       // If last letter was a move command and we got no new, it defaults to [L]ine
@@ -279,11 +284,11 @@ SVG.extend(SVG.PathArray, {
     } while (len > index)
 
     return result
-  },
-  // Get bounding box of path
-  bbox: function () {
-    SVG.parser().path.setAttribute('d', this.toString())
-    return SVG.parser.nodes.path.getBBox()
   }
 
-})
+  // Get bounding box of path
+  bbox () {
+    parser().path.setAttribute('d', this.toString())
+    return parser.nodes.path.getBBox()
+  }
+}
index d4c41161e9cd4a9c964675515fc0dcf588335599..00f9de5a04eeb7206944381f2fd96986a774c55e 100644 (file)
@@ -1,53 +1,51 @@
-SVG.Pattern = SVG.invent({
-  // Initialize node
-  create: 'pattern',
-
-  // Inherit from
-  inherit: SVG.Container,
-
-  // Add class methods
-  extend: {
-    // Return the fill id
-    url: function () {
-      return 'url(#' + this.id() + ')'
-    },
-    // Update pattern by rebuilding
-    update: function (block) {
-      // remove content
-      this.clear()
+import {Container, Defs} from './classes.js'
+import {nodeOrNew} from './tools.js'
 
-      // invoke passed block
-      if (typeof block === 'function') {
-        block.call(this, this)
-      }
+export default class Pattern extends Container {
+  // Initialize node
+  constructor (node) {
+    super(nodeOrNew('pattern', node))
+  }
 
-      return this
-    },
-    // Alias string convertion to fill
-    toString: function () {
-      return this.url()
-    },
-    // custom attr to handle transform
-    attr: function (a, b, c) {
-      if (a === 'transform') a = 'patternTransform'
-      return SVG.Container.prototype.attr.call(this, a, b, c)
+  // Return the fill id
+  url () {
+    return 'url(#' + this.id() + ')'
+  }
+  // Update pattern by rebuilding
+  update (block) {
+    // remove content
+    this.clear()
+
+    // invoke passed block
+    if (typeof block === 'function') {
+      block.call(this, this)
     }
 
-  },
+    return this
+  }
+  // Alias string convertion to fill
+  toString () {
+    return this.url()
+  }
+  // custom attr to handle transform
+  attr (a, b, c) {
+    if (a === 'transform') a = 'patternTransform'
+    return super.attr(a, b, c)
+  }
+}
 
   // Add parent method
-  construct: {
-    // Create pattern element in defs
-    pattern: function (width, height, block) {
-      return this.defs().pattern(width, height, block)
-    }
+addFactory(Container, {
+  // Create pattern element in defs
+  pattern (width, height, block) {
+    return this.defs().pattern(width, height, block)
   }
 })
 
-SVG.extend(SVG.Defs, {
+extend(Defs, {
   // Define gradient
-  pattern: function (width, height, block) {
-    return this.put(new SVG.Pattern()).update(block).attr({
+  pattern (width, height, block) {
+    return this.put(new Pattern()).update(block).attr({
       x: 0,
       y: 0,
       width: width,
@@ -55,5 +53,4 @@ SVG.extend(SVG.Defs, {
       patternUnits: 'userSpaceOnUse'
     })
   }
-
 })
index 6c64ed6f2b89f21f7a518c283b632f7f4752d9f7..ff184734e508685467fed79ac5419f08b2224ce8 100644 (file)
@@ -1,8 +1,10 @@
+import parser from './parser.js'
+import Element from './Element.js'
 
-SVG.Point = SVG.invent({
+export default class Point {
   // Initialize
-  create: function (x, y, base) {
-    var source
+  constructor (x, y, base) {
+    let source
     base = base || {x: 0, y: 0}
 
     // ensure source as object
@@ -13,62 +15,38 @@ SVG.Point = SVG.invent({
     // merge source
     this.x = source.x == null ? base.x : source.x
     this.y = source.y == null ? base.y : source.y
-  },
-
-  // Add methods
-  extend: {
-    // Clone point
-    clone: function () {
-      return new SVG.Point(this)
-    },
-
-    // Morph one point into another
-    morph: function (x, y) {
-      // store new destination
-      this.destination = new SVG.Point(x, y)
-      return this
-    },
-
-    // Get morphed point at a given position
-    at: function (pos) {
-      // make sure a destination is defined
-      if (!this.destination) return this
+  }
 
-      // calculate morphed matrix at a given position
-      var point = new SVG.Point({
-        x: this.x + (this.destination.x - this.x) * pos,
-        y: this.y + (this.destination.y - this.y) * pos
-      })
-      return point
-    },
+  // Clone point
+  clone () {
+    return new Point(this)
+  }
 
-    // Convert to native SVGPoint
-    native: function () {
-      // create new point
-      var point = SVG.parser.nodes.svg.node.createSVGPoint()
+  // Convert to native SVGPoint
+  native () {
+    // create new point
+    var point = parser().svg.createSVGPoint()
 
-      // update with current values
-      point.x = this.x
-      point.y = this.y
-      return point
-    },
+    // update with current values
+    point.x = this.x
+    point.y = this.y
+    return point
+  }
 
-    // transform point with matrix
-    transform: function (m) {
-      // Perform the matrix multiplication
-      var x = m.a * this.x + m.c * this.y + m.e
-      var y = m.b * this.x + m.d * this.y + m.f
+  // transform point with matrix
+  transform (m) {
+    // Perform the matrix multiplication
+    var x = m.a * this.x + m.c * this.y + m.e
+    var y = m.b * this.x + m.d * this.y + m.f
 
-      // Return the required point
-      return new SVG.Point(x, y)
-    }
+    // Return the required point
+    return new Point(x, y)
   }
-})
-
-SVG.extend(SVG.Element, {
+}
 
+extend(Element, {
   // Get point
   point: function (x, y) {
-    return new SVG.Point(x, y).transform(this.screenCTM().inverse())
+    return new Point(x, y).transform(this.screenCTM().inverse())
   }
 })
index aa5f84a39c3a5c6e63254925a33ade6d61393dac..cadff805f081148b6a4817e5e0f758e592ef26f8 100644 (file)
@@ -1,42 +1,39 @@
+import SVGArray from './SVGArray.js'
+import {delimiter} from './regex.js'
 
-// Poly points array
-SVG.PointArray = function (array, fallback) {
-  SVG.Array.call(this, array, fallback || [[0, 0]])
-}
-
-// Inherit from SVG.Array
-SVG.PointArray.prototype = new SVG.Array()
-SVG.PointArray.prototype.constructor = SVG.PointArray
+export default class PointArray extends SVGArray {
+  constructor (array, fallback = [[0, 0]]) {
+    super(array, fallback)
+  }
 
-SVG.extend(SVG.PointArray, {
   // Convert array to string
-  toString: function () {
+  toString () {
     // convert to a poly point string
     for (var i = 0, il = this.value.length, array = []; i < il; i++) {
       array.push(this.value[i].join(','))
     }
 
     return array.join(' ')
-  },
+  }
 
-  toArray: function () {
+  toArray () {
     return this.value.reduce(function (prev, curr) {
       return [].concat.call(prev, curr)
     }, [])
-  },
+  }
 
   // Convert array to line object
-  toLine: function () {
+  toLine () {
     return {
       x1: this.value[0][0],
       y1: this.value[0][1],
       x2: this.value[1][0],
       y2: this.value[1][1]
     }
-  },
+  }
 
   // Get morphed array at given position
-  at: function (pos) {
+  at (pos) {
     // make sure a destination is defined
     if (!this.destination) return this
 
@@ -48,11 +45,11 @@ SVG.extend(SVG.PointArray, {
       ])
     }
 
-    return new SVG.PointArray(array)
-  },
+    return new PointArray(array)
+  }
 
   // Parse point string and flat array
-  parse: function (array) {
+  parse (array) {
     var points = []
 
     array = array.valueOf()
@@ -65,7 +62,7 @@ SVG.extend(SVG.PointArray, {
       }
     } else { // Else, it is considered as a string
       // parse points
-      array = array.trim().split(SVG.regex.delimiter).map(parseFloat)
+      array = array.trim().split(delimiter).map(parseFloat)
     }
 
     // validate points - https://svgwg.org/svg2-draft/shapes.html#DataTypePoints
@@ -78,10 +75,10 @@ SVG.extend(SVG.PointArray, {
     }
 
     return points
-  },
+  }
 
   // Move point string
-  move: function (x, y) {
+  move (x, y) {
     var box = this.bbox()
 
     // get relative offset
@@ -96,9 +93,10 @@ SVG.extend(SVG.PointArray, {
     }
 
     return this
-  },
+  }
+
   // Resize poly string
-  size: function (width, height) {
+  size (width, height) {
     var i
     var box = this.bbox()
 
@@ -109,10 +107,10 @@ SVG.extend(SVG.PointArray, {
     }
 
     return this
-  },
+  }
 
   // Get bounding box of points
-  bbox: function () {
+  bbox () {
     var maxX = -Infinity
     var maxY = -Infinity
     var minX = Infinity
@@ -125,4 +123,4 @@ SVG.extend(SVG.PointArray, {
     })
     return {x: minX, y: minY, width: maxX - minX, height: maxY - minY}
   }
-})
+}
index 96257765df038d45ddff191299b62bfde0768e6c..112d33b30a39bdab5960b70d81aa25f956698548 100644 (file)
@@ -1,67 +1,55 @@
-/* global proportionalSize */
+import {proportionalSize} from './helpers.js'
+import Shape from './Shape.js'
+import {nodeOrNew} from './tools.js'
+import * as pointed from './pointed.js'
+import PointArray from './PointArray.js'
 
-SVG.Polyline = SVG.invent({
+export default class Polygon extends Shape {
   // Initialize node
-  create: 'polyline',
-
-  // Inherit from
-  inherit: SVG.Shape,
-
-  // Add parent method
-  construct: {
-    // Create a wrapped polyline element
-    polyline: function (p) {
-      // make sure plot is called as a setter
-      return this.put(new SVG.Polyline()).plot(p || new SVG.PointArray())
-    }
+  constructor (node) {
+    super(nodeOrNew('polygon', node))
   }
-})
-
-SVG.Polygon = SVG.invent({
-  // Initialize node
-  create: 'polygon',
-
-  // Inherit from
-  inherit: SVG.Shape,
+}
 
-  // Add parent method
-  construct: {
-    // Create a wrapped polygon element
-    polygon: function (p) {
-      // make sure plot is called as a setter
-      return this.put(new SVG.Polygon()).plot(p || new SVG.PointArray())
-    }
+addFactory(Parent, {
+  // Create a wrapped polygon element
+  polygon (p) {
+    // make sure plot is called as a setter
+    return this.put(new Polygon()).plot(p || new PointArray())
   }
 })
 
-// Add polygon-specific functions
-SVG.extend([SVG.Polyline, SVG.Polygon], {
-  // Get array
-  array: function () {
-    return this._array || (this._array = new SVG.PointArray(this.attr('points')))
-  },
 
-  // Plot new path
-  plot: function (p) {
-    return (p == null) ? this.array()
-      : this.clear().attr('points', typeof p === 'string' ? p
-      : (this._array = new SVG.PointArray(p)))
-  },
-
-  // Clear array cache
-  clear: function () {
-    delete this._array
-    return this
-  },
-
-  // Move by left top corner
-  move: function (x, y) {
-    return this.attr('points', this.array().move(x, y))
-  },
-
-  // Set element size to given width and height
-  size: function (width, height) {
-    var p = proportionalSize(this, width, height)
-    return this.attr('points', this.array().size(p.width, p.height))
-  }
-})
+// // Add polygon-specific functions
+// extend([Polyline, Polygon], {
+//   // Get array
+//   array: function () {
+//     return this._array || (this._array = new PointArray(this.attr('points')))
+//   },
+//
+//   // Plot new path
+//   plot: function (p) {
+//     return (p == null) ? this.array()
+//       : this.clear().attr('points', typeof p === 'string' ? p
+//       : (this._array = new PointArray(p)))
+//   },
+//
+//   // Clear array cache
+//   clear: function () {
+//     delete this._array
+//     return this
+//   },
+//
+//   // Move by left top corner
+//   move: function (x, y) {
+//     return this.attr('points', this.array().move(x, y))
+//   },
+//
+//   // Set element size to given width and height
+//   size: function (width, height) {
+//     let p = proportionalSize(this, width, height)
+//     return this.attr('points', this.array().size(p.width, p.height))
+//   }
+// })
+//
+// extend([Polyline, Polygon], pointed)
diff --git a/src/Polyline.js b/src/Polyline.js
new file mode 100644 (file)
index 0000000..9c28438
--- /dev/null
@@ -0,0 +1,19 @@
+import Shape from './Shape.js'
+import {nodeOrNew} from './tools.js'
+import PointArray from './PointArray.js'
+
+export default class Polyline extends Shape {
+  // Initialize node
+  constructor (node) {
+    super(nodeOrNew('polyline', node))
+  }
+}
+
+// Add parent method
+addFactory (Parent, {
+  // Create a wrapped polyline element
+  polyline (p) {
+    // make sure plot is called as a setter
+    return this.put(new Polyline()).plot(p || new PointArray())
+  }
+})
index 621c88747835a509c893a9c021c81b61a799ee11..14b92b453c0109c3ccd4fa7cc04125c1a52edd6f 100644 (file)
@@ -1,61 +1,59 @@
-SVG.Queue = SVG.invent({
-  create: function () {
+export default class Queue {
+  constructor () {
     this._first = null
     this._last = null
-  },
-
-  extend: {
-    push: function (value) {
-      // An item stores an id and the provided value
-      var item = value.next ? value : { value: value, next: null, prev: null }
-
-      // Deal with the queue being empty or populated
-      if (this._last) {
-        item.prev = this._last
-        this._last.next = item
-        this._last = item
-      } else {
-        this._last = item
-        this._first = item
-      }
-
-      // Update the length and return the current item
-      return item
-    },
-
-    shift: function () {
-      // Check if we have a value
-      var remove = this._first
-      if (!remove) return null
-
-      // If we do, remove it and relink things
-      this._first = remove.next
-      if (this._first) this._first.prev = null
-      this._last = this._first ? this._last : null
-      return remove.value
-    },
-
-    // Shows us the first item in the list
-    first: function () {
-      return this._first && this._first.value
-    },
-
-    // Shows us the last item in the list
-    last: function () {
-      return this._last && this._last.value
-    },
-
-    // Removes the item that was returned from the push
-    remove: function (item) {
-      // Relink the previous item
-      if (item.prev) item.prev.next = item.next
-      if (item.next) item.next.prev = item.prev
-      if (item === this._last) this._last = item.prev
-      if (item === this._first) this._first = item.next
-
-      // Invalidate item
-      item.prev = null
-      item.next = null
+  }
+
+  push (value) {
+    // An item stores an id and the provided value
+    var item = value.next ? value : { value: value, next: null, prev: null }
+
+    // Deal with the queue being empty or populated
+    if (this._last) {
+      item.prev = this._last
+      this._last.next = item
+      this._last = item
+    } else {
+      this._last = item
+      this._first = item
     }
+
+    // Update the length and return the current item
+    return item
+  }
+
+  shift () {
+    // Check if we have a value
+    var remove = this._first
+    if (!remove) return null
+
+    // If we do, remove it and relink things
+    this._first = remove.next
+    if (this._first) this._first.prev = null
+    this._last = this._first ? this._last : null
+    return remove.value
+  }
+
+  // Shows us the first item in the list
+  first () {
+    return this._first && this._first.value
+  }
+
+  // Shows us the last item in the list
+  last () {
+    return this._last && this._last.value
+  }
+
+  // Removes the item that was returned from the push
+  remove (item) {
+    // Relink the previous item
+    if (item.prev) item.prev.next = item.next
+    if (item.next) item.next.prev = item.prev
+    if (item === this._last) this._last = item.prev
+    if (item === this._first) this._first = item.next
+
+    // Invalidate item
+    item.prev = null
+    item.next = null
   }
-})
+}
index 35a36780e949ce4efd4dbba2e64f8d8075e99d53..825adeb93aff80272401239b97b995b77cc5c393 100644 (file)
@@ -1,16 +1,16 @@
+import Shape from './Shape.js'
+import {nodeOrNew} from './tools.js'
 
-SVG.Rect = SVG.invent({
+export default class Rect extends Shape {
   // Initialize node
-  create: 'rect',
-
-  // Inherit from
-  inherit: SVG.Shape,
+  constructor (node) {
+    super(nodeOrNew('rect', node))
+  }
+}
 
-  // Add parent method
-  construct: {
-    // Create a rect element
-    rect: function (width, height) {
-      return this.put(new SVG.Rect()).size(width, height)
-    }
+addFactory(Parent, {
+  // Create a rect element
+  rect (width, height) {
+    return this.put(new Rect()).size(width, height)
   }
 })
index 97e04e245ec1a382633773ed05d26392b680b91f..c29c72c8792e53218ced1ba5c4e5f84ca367cb73 100644 (file)
@@ -1,27 +1,33 @@
-/* global isMatrixLike getOrigin */
-
-SVG.easing = {
-  '-': function (pos) { return pos },
-  '<>': function (pos) { return -Math.cos(pos * Math.PI) / 2 + 0.5 },
-  '>': function (pos) { return Math.sin(pos * Math.PI / 2) },
-  '<': function (pos) { return -Math.cos(pos * Math.PI / 2) + 1 }
-}
-
-SVG.Runner = SVG.invent({
-  parent: SVG.Element,
-
-  create: function (options) {
+import {isMatrixLike, getOrigin} from './helpers.js'
+import Matrix from './Matrix.js'
+import Morphable from './Morphable.js'
+import SVGNumber from './SVGNumber.js'
+import Element from './Element.js'
+import Timeline from './Timeline.js'
+import {Controller, Ease, Stepper} from './Controller.js'
+import {noop, timeline} from './defaults.js'
+
+// FIXME: What is this doing here?
+// easing = {
+//   '-': function (pos) { return pos },
+//   '<>': function (pos) { return -Math.cos(pos * Math.PI) / 2 + 0.5 },
+//   '>': function (pos) { return Math.sin(pos * Math.PI / 2) },
+//   '<': function (pos) { return -Math.cos(pos * Math.PI / 2) + 1 }
+// }
+
+export default class Runner extends EventTarget {
+  constructor (options) {
     // Store a unique id on the runner, so that we can identify it later
-    this.id = SVG.Runner.id++
+    this.id = Runner.id++
 
     // Ensure a default value
     options = options == null
-      ? SVG.defaults.timeline.duration
+      ? timeline.duration
       : options
 
     // Ensure that we get a controller
     options = typeof options === 'function'
-      ? new SVG.Controller(options)
+      ? new Controller(options)
       : options
 
     // Declare all of the variables
@@ -32,8 +38,8 @@ SVG.Runner = SVG.invent({
 
     // Work out the stepper and the duration
     this._duration = typeof options === 'number' && options
-    this._isDeclarative = options instanceof SVG.Controller
-    this._stepper = this._isDeclarative ? options : new SVG.Ease()
+    this._isDeclarative = options instanceof Controller
+    this._stepper = this._isDeclarative ? options : new Ease()
 
     // We copy the current values from the timeline because they can change
     this._history = {}
@@ -44,7 +50,7 @@ SVG.Runner = SVG.invent({
     this._last = 0
 
     // Save transforms applied to this runner
-    this.transforms = new SVG.Matrix()
+    this.transforms = new Matrix()
     this.transformId = 1
 
     // Looping variables
@@ -54,419 +60,415 @@ SVG.Runner = SVG.invent({
     this._swing = false
     this._wait = 0
     this._times = 1
-  },
+  }
 
-  construct: {
+  /*
+  Runner Definitions
+  ==================
+  These methods help us define the runtime behaviour of the Runner or they
+  help us make new runners from the current runner
+  */
+
+  element (element) {
+    if (element == null) return this._element
+    this._element = element
+    element._prepareRunner()
+    return this
+  }
 
-    animate: function (duration, delay, when) {
-      var o = SVG.Runner.sanitise(duration, delay, when)
-      var timeline = this.timeline()
-      return new SVG.Runner(o.duration)
-        .loop(o)
-        .element(this)
-        .timeline(timeline)
-        .schedule(delay, when)
-    },
-
-    delay: function (by, when) {
-      return this.animate(0, by, when)
-    }
-  },
+  timeline (timeline) {
+    // check explicitly for undefined so we can set the timeline to null
+    if (typeof timeline === 'undefined') return this._timeline
+    this._timeline = timeline
+    return this
+  }
 
-  extend: {
+  animate (duration, delay, when) {
+    var o = Runner.sanitise(duration, delay, when)
+    var runner = new Runner(o.duration)
+    if (this._timeline) runner.timeline(this._timeline)
+    if (this._element) runner.element(this._element)
+    return runner.loop(o).schedule(delay, when)
+  }
 
-    /*
-    Runner Definitions
-    ==================
-    These methods help us define the runtime behaviour of the Runner or they
-    help us make new runners from the current runner
-    */
+  schedule (timeline, delay, when) {
+    // The user doesn't need to pass a timeline if we already have one
+    if (!(timeline instanceof Timeline)) {
+      when = delay
+      delay = timeline
+      timeline = this.timeline()
+    }
 
-    element: function (element) {
-      if (element == null) return this._element
-      this._element = element
-      element._prepareRunner()
-      return this
-    },
+    // If there is no timeline, yell at the user...
+    if (!timeline) {
+      throw Error('Runner cannot be scheduled without timeline')
+    }
 
-    timeline: function (timeline) {
-      // check explicitly for undefined so we can set the timeline to null
-      if (typeof timeline === 'undefined') return this._timeline
-      this._timeline = timeline
-      return this
-    },
-
-    animate: function (duration, delay, when) {
-      var o = SVG.Runner.sanitise(duration, delay, when)
-      var runner = new SVG.Runner(o.duration)
-      if (this._timeline) runner.timeline(this._timeline)
-      if (this._element) runner.element(this._element)
-      return runner.loop(o).schedule(delay, when)
-    },
-
-    schedule: function (timeline, delay, when) {
-      // The user doesn't need to pass a timeline if we already have one
-      if (!(timeline instanceof SVG.Timeline)) {
-        when = delay
-        delay = timeline
-        timeline = this.timeline()
-      }
+    // Schedule the runner on the timeline provided
+    timeline.schedule(this, delay, when)
+    return this
+  }
 
-      // If there is no timeline, yell at the user...
-      if (!timeline) {
-        throw Error('Runner cannot be scheduled without timeline')
-      }
+  unschedule () {
+    var timeline = this.timeline()
+    timeline && timeline.unschedule(this)
+    return this
+  }
 
-      // Schedule the runner on the timeline provided
-      timeline.schedule(this, delay, when)
-      return this
-    },
+  loop (times, swing, wait) {
+    // Deal with the user passing in an object
+    if (typeof times === 'object') {
+      swing = times.swing
+      wait = times.wait
+      times = times.times
+    }
 
-    unschedule: function () {
-      var timeline = this.timeline()
-      timeline && timeline.unschedule(this)
-      return this
-    },
-
-    loop: function (times, swing, wait) {
-      // Deal with the user passing in an object
-      if (typeof times === 'object') {
-        swing = times.swing
-        wait = times.wait
-        times = times.times
-      }
+    // Sanitise the values and store them
+    this._times = times || Infinity
+    this._swing = swing || false
+    this._wait = wait || 0
+    return this
+  }
 
-      // Sanitise the values and store them
-      this._times = times || Infinity
-      this._swing = swing || false
-      this._wait = wait || 0
-      return this
-    },
+  delay (delay) {
+    return this.animate(0, delay)
+  }
 
-    delay: function (delay) {
-      return this.animate(0, delay)
-    },
+  /*
+  Basic Functionality
+  ===================
+  These methods allow us to attach basic functions to the runner directly
+  */
+
+  queue (initFn, runFn, isTransform) {
+    this._queue.push({
+      initialiser: initFn || noop,
+      runner: runFn || noop,
+      isTransform: isTransform,
+      initialised: false,
+      finished: false
+    })
+    var timeline = this.timeline()
+    timeline && this.timeline()._continue()
+    return this
+  }
 
-    /*
-    Basic Functionality
-    ===================
-    These methods allow us to attach basic functions to the runner directly
-    */
+  during (fn) {
+    return this.queue(null, fn)
+  }
 
-    queue: function (initFn, runFn, isTransform) {
-      this._queue.push({
-        initialiser: initFn || SVG.void,
-        runner: runFn || SVG.void,
-        isTransform: isTransform,
-        initialised: false,
-        finished: false
-      })
-      var timeline = this.timeline()
-      timeline && this.timeline()._continue()
-      return this
-    },
+  after (fn) {
+    return this.on('finish', fn)
+  }
 
-    during: function (fn) {
-      return this.queue(null, fn)
-    },
+  /*
+  Runner animation methods
+  ========================
+  Control how the animation plays
+  */
 
-    after (fn) {
-      return this.on('finish', fn)
-    },
+  time (time) {
+    if (time == null) {
+      return this._time
+    }
+    let dt = time - this._time
+    this.step(dt)
+    return this
+  }
 
-    /*
-    Runner animation methods
-    ========================
-    Control how the animation plays
-    */
+  duration () {
+    return this._times * (this._wait + this._duration) - this._wait
+  }
 
-    time: function (time) {
-      if (time == null) {
-        return this._time
-      }
-      let dt = time - this._time
-      this.step(dt)
-      return this
-    },
-
-    duration: function () {
-      return this._times * (this._wait + this._duration) - this._wait
-    },
-
-    loops: function (p) {
-      var loopDuration = this._duration + this._wait
-      if (p == null) {
-        var loopsDone = Math.floor(this._time / loopDuration)
-        var relativeTime = (this._time - loopsDone * loopDuration)
-        var position = relativeTime / this._duration
-        return Math.min(loopsDone + position, this._times)
-      }
-      var whole = Math.floor(p)
-      var partial = p % 1
-      var time = loopDuration * whole + this._duration * partial
-      return this.time(time)
-    },
-
-    position: function (p) {
-      // Get all of the variables we need
-      var x = this._time
-      var d = this._duration
-      var w = this._wait
-      var t = this._times
-      var s = this._swing
-      var r = this._reverse
-      var position
-
-      if (p == null) {
-        /*
-        This function converts a time to a position in the range [0, 1]
-        The full explanation can be found in this desmos demonstration
-          https://www.desmos.com/calculator/u4fbavgche
-        The logic is slightly simplified here because we can use booleans
-        */
-
-        // Figure out the value without thinking about the start or end time
-        const f = function (x) {
-          var swinging = s * Math.floor(x % (2 * (w + d)) / (w + d))
-          var backwards = (swinging && !r) || (!swinging && r)
-          var uncliped = Math.pow(-1, backwards) * (x % (w + d)) / d + backwards
-          var clipped = Math.max(Math.min(uncliped, 1), 0)
-          return clipped
-        }
+  loops (p) {
+    var loopDuration = this._duration + this._wait
+    if (p == null) {
+      var loopsDone = Math.floor(this._time / loopDuration)
+      var relativeTime = (this._time - loopsDone * loopDuration)
+      var position = relativeTime / this._duration
+      return Math.min(loopsDone + position, this._times)
+    }
+    var whole = Math.floor(p)
+    var partial = p % 1
+    var time = loopDuration * whole + this._duration * partial
+    return this.time(time)
+  }
 
-        // Figure out the value by incorporating the start time
-        var endTime = t * (w + d) - w
-        position = x <= 0 ? Math.round(f(1e-5))
-          : x < endTime ? f(x)
-          : Math.round(f(endTime - 1e-5))
-        return position
+  position (p) {
+    // Get all of the variables we need
+    var x = this._time
+    var d = this._duration
+    var w = this._wait
+    var t = this._times
+    var s = this._swing
+    var r = this._reverse
+    var position
+
+    if (p == null) {
+      /*
+      This function converts a time to a position in the range [0, 1]
+      The full explanation can be found in this desmos demonstration
+        https://www.desmos.com/calculator/u4fbavgche
+      The logic is slightly simplified here because we can use booleans
+      */
+
+      // Figure out the value without thinking about the start or end time
+      const f = function (x) {
+        var swinging = s * Math.floor(x % (2 * (w + d)) / (w + d))
+        var backwards = (swinging && !r) || (!swinging && r)
+        var uncliped = Math.pow(-1, backwards) * (x % (w + d)) / d + backwards
+        var clipped = Math.max(Math.min(uncliped, 1), 0)
+        return clipped
       }
 
-      // Work out the loops done and add the position to the loops done
-      var loopsDone = Math.floor(this.loops())
-      var swingForward = s && (loopsDone % 2 === 0)
-      var forwards = (swingForward && !r) || (r && swingForward)
-      position = loopsDone + (forwards ? p : 1 - p)
-      return this.loops(position)
-    },
-
-    progress: function (p) {
-      if (p == null) {
-        return Math.min(1, this._time / this.duration())
-      }
-      return this.time(p * this.duration())
-    },
-
-    step: function (dt) {
-      // If we are inactive, this stepper just gets skipped
-      if (!this.enabled) return this
-
-      // Update the time and get the new position
-      dt = dt == null ? 16 : dt
-      this._time += dt
-      var position = this.position()
-
-      // Figure out if we need to run the stepper in this frame
-      var running = this._lastPosition !== position && this._time >= 0
-      this._lastPosition = position
-
-      // Figure out if we just started
-      var duration = this.duration()
-      var justStarted = this._lastTime < 0 && this._time > 0
-      var justFinished = this._lastTime < this._time && this.time > duration
-      this._lastTime = this._time
-      if (justStarted) {
-        // this.fire('start', this)
-      }
+      // Figure out the value by incorporating the start time
+      var endTime = t * (w + d) - w
+      position = x <= 0 ? Math.round(f(1e-5))
+        : x < endTime ? f(x)
+        : Math.round(f(endTime - 1e-5))
+      return position
+    }
 
-      // Work out if the runner is finished set the done flag here so animations
-      // know, that they are running in the last step (this is good for
-      // transformations which can be merged)
-      var declarative = this._isDeclarative
-      this.done = !declarative && !justFinished && this._time >= duration
+    // Work out the loops done and add the position to the loops done
+    var loopsDone = Math.floor(this.loops())
+    var swingForward = s && (loopsDone % 2 === 0)
+    var forwards = (swingForward && !r) || (r && swingForward)
+    position = loopsDone + (forwards ? p : 1 - p)
+    return this.loops(position)
+  }
 
-      // Call initialise and the run function
-      if (running || declarative) {
-        this._initialise(running)
+  progress (p) {
+    if (p == null) {
+      return Math.min(1, this._time / this.duration())
+    }
+    return this.time(p * this.duration())
+  }
 
-        // clear the transforms on this runner so they dont get added again and again
-        this.transforms = new SVG.Matrix()
-        var converged = this._run(declarative ? dt : position)
-        // this.fire('step', this)
-      }
-      // correct the done flag here
-      // declaritive animations itself know when they converged
-      this.done = this.done || (converged && declarative)
-      // if (this.done) {
-      //   this.fire('finish', this)
-      // }
-      return this
-    },
+  step (dt) {
+    // If we are inactive, this stepper just gets skipped
+    if (!this.enabled) return this
+
+    // Update the time and get the new position
+    dt = dt == null ? 16 : dt
+    this._time += dt
+    var position = this.position()
+
+    // Figure out if we need to run the stepper in this frame
+    var running = this._lastPosition !== position && this._time >= 0
+    this._lastPosition = position
+
+    // Figure out if we just started
+    var duration = this.duration()
+    var justStarted = this._lastTime < 0 && this._time > 0
+    var justFinished = this._lastTime < this._time && this.time > duration
+    this._lastTime = this._time
+    if (justStarted) {
+      // this.fire('start', this)
+    }
 
-    finish: function () {
-      return this.step(Infinity)
-    },
+    // Work out if the runner is finished set the done flag here so animations
+    // know, that they are running in the last step (this is good for
+    // transformations which can be merged)
+    var declarative = this._isDeclarative
+    this.done = !declarative && !justFinished && this._time >= duration
 
-    reverse: function (reverse) {
-      this._reverse = reverse == null ? !this._reverse : reverse
-      return this
-    },
+    // Call initialise and the run function
+    if (running || declarative) {
+      this._initialise(running)
 
-    ease: function (fn) {
-      this._stepper = new SVG.Ease(fn)
-      return this
-    },
+      // clear the transforms on this runner so they dont get added again and again
+      this.transforms = new Matrix()
+      var converged = this._run(declarative ? dt : position)
+      // this.fire('step', this)
+    }
+    // correct the done flag here
+    // declaritive animations itself know when they converged
+    this.done = this.done || (converged && declarative)
+    // if (this.done) {
+    //   this.fire('finish', this)
+    // }
+    return this
+  }
 
-    active: function (enabled) {
-      if (enabled == null) return this.enabled
-      this.enabled = enabled
-      return this
-    },
+  finish () {
+    return this.step(Infinity)
+  }
 
-    /*
-    Private Methods
-    ===============
-    Methods that shouldn't be used externally
-    */
+  reverse (reverse) {
+    this._reverse = reverse == null ? !this._reverse : reverse
+    return this
+  }
 
-    // Save a morpher to the morpher list so that we can retarget it later
-    _rememberMorpher: function (method, morpher) {
-      this._history[method] = {
-        morpher: morpher,
-        caller: this._queue[this._queue.length - 1]
-      }
-    },
-
-    // Try to set the target for a morpher if the morpher exists, otherwise
-    // do nothing and return false
-    _tryRetarget: function (method, target) {
-      if (this._history[method]) {
-        // if the last method wasnt even initialised, throw it away
-        if (!this._history[method].caller.initialised) {
-          let index = this._queue.indexOf(this._history[method].caller)
-          this._queue.splice(index, 1)
-          return false
-        }
+  ease (fn) {
+    this._stepper = new Ease(fn)
+    return this
+  }
 
-        // for the case of transformations, we use the special retarget function
-        // which has access to the outer scope
-        if (this._history[method].caller.isTransform) {
-          this._history[method].caller.isTransform(target)
-        // for everything else a simple morpher change is sufficient
-        } else {
-          this._history[method].morpher.to(target)
-        }
+  active (enabled) {
+    if (enabled == null) return this.enabled
+    this.enabled = enabled
+    return this
+  }
 
-        this._history[method].caller.finished = false
-        var timeline = this.timeline()
-        timeline && timeline._continue()
-        return true
-      }
-      return false
-    },
-
-    // Run each initialise function in the runner if required
-    _initialise: function (running) {
-      // If we aren't running, we shouldn't initialise when not declarative
-      if (!running && !this._isDeclarative) return
-
-      // Loop through all of the initialisers
-      for (var i = 0, len = this._queue.length; i < len; ++i) {
-        // Get the current initialiser
-        var current = this._queue[i]
-
-        // Determine whether we need to initialise
-        var needsIt = this._isDeclarative || (!current.initialised && running)
-        running = !current.finished
-
-        // Call the initialiser if we need to
-        if (needsIt && running) {
-          current.initialiser.call(this)
-          current.initialised = true
-        }
+  /*
+  Private Methods
+  ===============
+  Methods that shouldn't be used externally
+  */
+
+  // Save a morpher to the morpher list so that we can retarget it later
+  _rememberMorpher (method, morpher) {
+    this._history[method] = {
+      morpher: morpher,
+      caller: this._queue[this._queue.length - 1]
+    }
+  }
+
+  // Try to set the target for a morpher if the morpher exists, otherwise
+  // do nothing and return false
+  _tryRetarget (method, target) {
+    if (this._history[method]) {
+      // if the last method wasnt even initialised, throw it away
+      if (!this._history[method].caller.initialised) {
+        let index = this._queue.indexOf(this._history[method].caller)
+        this._queue.splice(index, 1)
+        return false
       }
-    },
-
-    // Run each run function for the position or dt given
-    _run: function (positionOrDt) {
-      // Run all of the _queue directly
-      var allfinished = true
-      for (var i = 0, len = this._queue.length; i < len; ++i) {
-        // Get the current function to run
-        var current = this._queue[i]
-
-        // Run the function if its not finished, we keep track of the finished
-        // flag for the sake of declarative _queue
-        var converged = current.runner.call(this, positionOrDt)
-        current.finished = current.finished || (converged === true)
-        allfinished = allfinished && current.finished
+
+      // for the case of transformations, we use the special retarget function
+      // which has access to the outer scope
+      if (this._history[method].caller.isTransform) {
+        this._history[method].caller.isTransform(target)
+      // for everything else a simple morpher change is sufficient
+      } else {
+        this._history[method].morpher.to(target)
       }
 
-      // We report when all of the constructors are finished
-      return allfinished
-    },
+      this._history[method].caller.finished = false
+      var timeline = this.timeline()
+      timeline && timeline._continue()
+      return true
+    }
+    return false
+  }
+
+  // Run each initialise function in the runner if required
+  _initialise (running) {
+    // If we aren't running, we shouldn't initialise when not declarative
+    if (!running && !this._isDeclarative) return
 
-    addTransform: function (transform, index) {
-      this.transforms.lmultiplyO(transform)
-      return this
-    },
+    // Loop through all of the initialisers
+    for (var i = 0, len = this._queue.length; i < len; ++i) {
+      // Get the current initialiser
+      var current = this._queue[i]
 
-    clearTransform: function () {
-      this.transforms = new SVG.Matrix()
-      return this
+      // Determine whether we need to initialise
+      var needsIt = this._isDeclarative || (!current.initialised && running)
+      running = !current.finished
+
+      // Call the initialiser if we need to
+      if (needsIt && running) {
+        current.initialiser.call(this)
+        current.initialised = true
+      }
     }
   }
-})
 
-SVG.Runner.id = 0
-
-SVG.Runner.sanitise = function (duration, delay, when) {
-  // Initialise the default parameters
-  var times = 1
-  var swing = false
-  var wait = 0
-  duration = duration || SVG.defaults.timeline.duration
-  delay = delay || SVG.defaults.timeline.delay
-  when = when || 'last'
-
-  // If we have an object, unpack the values
-  if (typeof duration === 'object' && !(duration instanceof SVG.Stepper)) {
-    delay = duration.delay || delay
-    when = duration.when || when
-    swing = duration.swing || swing
-    times = duration.times || times
-    wait = duration.wait || wait
-    duration = duration.duration || SVG.defaults.timeline.duration
-  }
-
-  return {
-    duration: duration,
-    delay: delay,
-    swing: swing,
-    times: times,
-    wait: wait,
-    when: when
+  // Run each run function for the position or dt given
+  _run (positionOrDt) {
+    // Run all of the _queue directly
+    var allfinished = true
+    for (var i = 0, len = this._queue.length; i < len; ++i) {
+      // Get the current function to run
+      var current = this._queue[i]
+
+      // Run the function if its not finished, we keep track of the finished
+      // flag for the sake of declarative _queue
+      var converged = current.runner.call(this, positionOrDt)
+      current.finished = current.finished || (converged === true)
+      allfinished = allfinished && current.finished
+    }
+
+    // We report when all of the constructors are finished
+    return allfinished
+  }
+
+  addTransform (transform, index) {
+    this.transforms.lmultiplyO(transform)
+    return this
+  }
+
+  clearTransform () {
+    this.transforms = new Matrix()
+    return this
+  }
+
+  static sanitise (duration, delay, when) {
+    // Initialise the default parameters
+    var times = 1
+    var swing = false
+    var wait = 0
+    duration = duration || timeline.duration
+    delay = delay || timeline.delay
+    when = when || 'last'
+
+    // If we have an object, unpack the values
+    if (typeof duration === 'object' && !(duration instanceof Stepper)) {
+      delay = duration.delay || delay
+      when = duration.when || when
+      swing = duration.swing || swing
+      times = duration.times || times
+      wait = duration.wait || wait
+      duration = duration.duration || timeline.duration
+    }
+
+    return {
+      duration: duration,
+      delay: delay,
+      swing: swing,
+      times: times,
+      wait: wait,
+      when: when
+    }
   }
 }
 
-SVG.FakeRunner = class {
-  constructor (transforms = new SVG.Matrix(), id = -1, done = true) {
+Runner.id = 0
+
+extend(Element, {
+  animate (duration, delay, when) {
+    var o = Runner.sanitise(duration, delay, when)
+    var timeline = this.timeline()
+    return new Runner(o.duration)
+      .loop(o)
+      .element(this)
+      .timeline(timeline)
+      .schedule(delay, when)
+  },
+
+  delay (by, when) {
+    return this.animate(0, by, when)
+  }
+})
+
+class FakeRunner{
+  constructor (transforms = new Matrix(), id = -1, done = true) {
     this.transforms = transforms
     this.id = id
     this.done = done
   }
 }
 
-SVG.extend([SVG.Runner, SVG.FakeRunner], {
+extend([Runner, FakeRunner], {
   mergeWith (runner) {
-    return new SVG.FakeRunner(
+    return new FakeRunner(
       runner.transforms.lmultiply(this.transforms),
       runner.id
     )
   }
 })
 
-// SVG.FakeRunner.emptyRunner = new SVG.FakeRunner()
+// FakeRunner.emptyRunner = new FakeRunner()
 
 const lmultiply = (last, curr) => last.lmultiplyO(curr)
 const getRunnerTransform = (runner) => runner.transforms
@@ -476,7 +478,7 @@ function mergeTransforms () {
   let runners = this._transformationRunners.runners
   let netTransform = runners
     .map(getRunnerTransform)
-    .reduce(lmultiply, new SVG.Matrix())
+    .reduce(lmultiply, new Matrix())
 
   this.transform(netTransform)
 
@@ -550,17 +552,17 @@ class RunnerArray {
   clearBefore (id) {
     let deleteCnt = this.ids.indexOf(id + 1) || 1
     this.ids.splice(0, deleteCnt, 0)
-    this.runners.splice(0, deleteCnt, new SVG.FakeRunner())
+    this.runners.splice(0, deleteCnt, new FakeRunner())
     return this
   }
 }
 
-SVG.extend(SVG.Element, {
+extend(Element, {
   // this function searches for all runners on the element and deletes the ones
   // which run before the current one. This is because absolute transformations
   // overwfrite anything anyway so there is no need to waste time computing
   // other runners
-  _clearTransformRunnersBefore: function (currentRunner) {
+  _clearTransformRunnersBefore (currentRunner) {
     this._transformationRunners.clearBefore(currentRunner.id)
   },
 
@@ -571,36 +573,36 @@ SVG.extend(SVG.Element, {
       // taken into account
       .filter((runner) => runner.id <= current.id)
       .map(getRunnerTransform)
-      .reduce(lmultiply, new SVG.Matrix())
+      .reduce(lmultiply, new Matrix())
   },
 
-  addRunner: function (runner) {
+  addRunner (runner) {
     this._transformationRunners.add(runner)
 
-    SVG.Animator.transform_frame(
+    Animator.transform_frame(
       mergeTransforms.bind(this), this._frameId
     )
   },
 
-  _prepareRunner: function () {
+  _prepareRunner () {
     if (this._frameId == null) {
       this._transformationRunners = new RunnerArray()
-        .add(new SVG.FakeRunner(new SVG.Matrix(this)))
+        .add(new FakeRunner(new Matrix(this)))
 
-      this._frameId = SVG.Element.frameId++
+      this._frameId = Element.frameId++
     }
   }
 })
 
-SVG.Element.frameId = 0
+Element.frameId = 0
 
-SVG.extend(SVG.Runner, {
-  attr: function (a, v) {
+extend(Runner, {
+  attr (a, v) {
     return this.styleAttr('attr', a, v)
   },
 
   // Add animatable styles
-  css: function (s, v) {
+  css (s, v) {
     return this.styleAttr('css', s, v)
   },
 
@@ -612,7 +614,7 @@ SVG.extend(SVG.Runner, {
       }
     }
 
-    var morpher = new SVG.Morphable(this._stepper).to(val)
+    var morpher = new Morphable(this._stepper).to(val)
 
     this.queue(function () {
       morpher = morpher.from(this.element()[type](name))
@@ -624,8 +626,8 @@ SVG.extend(SVG.Runner, {
     return this
   },
 
-  zoom: function (level, point) {
-    var morpher = new SVG.Morphable(this._stepper).to(new SVG.Number(level))
+  zoom (level, point) {
+    var morpher = new Morphable(this._stepper).to(new SVGNumber(level))
 
     this.queue(function () {
       morpher = morpher.from(this.zoom())
@@ -654,7 +656,7 @@ SVG.extend(SVG.Runner, {
   //   - Note F(1) = T
   // 4. Now you get the delta matrix as a result: D = F * inv(M)
 
-  transform: function (transforms, relative, affine) {
+  transform (transforms, relative, affine) {
     // If we have a declarative function, we should retarget it if possible
     relative = transforms.relative || relative
     if (this._isDeclarative && !relative && this._tryRetarget('transform', transforms)) {
@@ -668,8 +670,8 @@ SVG.extend(SVG.Runner, {
       : (affine != null ? affine : !isMatrix)
 
     // Create a morepher and set its type
-    const morpher = new SVG.Morphable()
-      .type(affine ? SVG.Morphable.TransformBag : SVG.Matrix)
+    const morpher = new Morphable()
+      .type(affine ? Morphable.TransformBag : Matrix)
       .stepper(this._stepper)
 
     let origin
@@ -683,7 +685,7 @@ SVG.extend(SVG.Runner, {
       element = element || this.element()
       origin = origin || getOrigin(transforms, element)
 
-      startTransform = new SVG.Matrix(relative ? undefined : element)
+      startTransform = new Matrix(relative ? undefined : element)
 
       // add the runner to the element so it can merge transformations
       element.addRunner(this)
@@ -699,9 +701,9 @@ SVG.extend(SVG.Runner, {
       // on this runner. We are absolute. We dont need these!
       if (!relative) this.clearTransform()
 
-      let {x, y} = new SVG.Point(origin).transform(element._currentTransform(this))
+      let {x, y} = new Point(origin).transform(element._currentTransform(this))
 
-      let target = new SVG.Matrix({...transforms, origin: [x, y]})
+      let target = new Matrix({...transforms, origin: [x, y]})
       let start = this._isDeclarative && current
         ? current
         : startTransform
@@ -724,7 +726,7 @@ SVG.extend(SVG.Runner, {
 
       if (relative) {
         // we have to be careful here not to overwrite the rotation
-        // with the rotate method of SVG.Matrix
+        // with the rotate method of Matrix
         if (!isMatrix) {
           target.rotate = transforms.rotate || 0
         }
@@ -738,7 +740,7 @@ SVG.extend(SVG.Runner, {
 
       let affineParameters = morpher.at(pos)
       currentAngle = affineParameters.rotate
-      current = new SVG.Matrix(affineParameters)
+      current = new Matrix(affineParameters)
 
       this.addTransform(current)
       return morpher.done()
@@ -763,31 +765,31 @@ SVG.extend(SVG.Runner, {
   },
 
   // Animatable x-axis
-  x: function (x, relative) {
+  x (x, relative) {
     return this._queueNumber('x', x)
   },
 
   // Animatable y-axis
-  y: function (y) {
+  y (y) {
     return this._queueNumber('y', y)
   },
 
-  dx: function (x) {
+  dx (x) {
     return this._queueNumberDelta('dx', x)
   },
 
-  dy: function (y) {
+  dy (y) {
     return this._queueNumberDelta('dy', y)
   },
 
-  _queueNumberDelta: function (method, to) {
-    to = new SVG.Number(to)
+  _queueNumberDelta (method, to) {
+    to = new SVGNumber(to)
 
     // Try to change the target if we have this method already registerd
     if (this._tryRetargetDelta(method, to)) return this
 
     // Make a morpher and queue the animation
-    var morpher = new SVG.Morphable(this._stepper).to(to)
+    var morpher = new Morphable(this._stepper).to(to)
     this.queue(function () {
       var from = this.element()[method]()
       morpher.from(from)
@@ -802,12 +804,12 @@ SVG.extend(SVG.Runner, {
     return this
   },
 
-  _queueObject: function (method, to) {
+  _queueObject (method, to) {
     // Try to change the target if we have this method already registerd
     if (this._tryRetarget(method, to)) return this
 
     // Make a morpher and queue the animation
-    var morpher = new SVG.Morphable(this._stepper).to(to)
+    var morpher = new Morphable(this._stepper).to(to)
     this.queue(function () {
       morpher.from(this.element()[method]())
     }, function (pos) {
@@ -820,32 +822,32 @@ SVG.extend(SVG.Runner, {
     return this
   },
 
-  _queueNumber: function (method, value) {
-    return this._queueObject(method, new SVG.Number(value))
+  _queueNumber (method, value) {
+    return this._queueObject(method, new SVGNumber(value))
   },
 
   // Animatable center x-axis
-  cx: function (x) {
+  cx (x) {
     return this._queueNumber('cx', x)
   },
 
   // Animatable center y-axis
-  cy: function (y) {
+  cy (y) {
     return this._queueNumber('cy', y)
   },
 
   // Add animatable move
-  move: function (x, y) {
+  move (x, y) {
     return this.x(x).y(y)
   },
 
   // Add animatable center
-  center: function (x, y) {
+  center (x, y) {
     return this.cx(x).cy(y)
   },
 
   // Add animatable size
-  size: function (width, height) {
+  size (width, height) {
     // animate bbox based size for all other elements
     var box
 
@@ -867,17 +869,17 @@ SVG.extend(SVG.Runner, {
   },
 
   // Add animatable width
-  width: function (width) {
+  width (width) {
     return this._queueNumber('width', width)
   },
 
   // Add animatable height
-  height: function (height) {
+  height (height) {
     return this._queueNumber('height', height)
   },
 
   // Add animatable plot
-  plot: function (a, b, c, d) {
+  plot (a, b, c, d) {
     // Lines can be plotted with 4 arguments
     if (arguments.length === 4) {
       return this.plot([a, b, c, d])
@@ -901,16 +903,16 @@ SVG.extend(SVG.Runner, {
   },
 
   // Add leading method
-  leading: function (value) {
+  leading (value) {
     return this._queueNumber('leading', value)
   },
 
   // Add animatable viewbox
-  viewbox: function (x, y, width, height) {
-    return this._queueObject('viewbox', new SVG.Box(x, y, width, height))
+  viewbox (x, y, width, height) {
+    return this._queueObject('viewbox', new Box(x, y, width, height))
   },
 
-  update: function (o) {
+  update (o) {
     if (typeof o !== 'object') {
       return this.update({
         offset: arguments[0],
index aa43d5cc96fa92707f65bad6be2f9b41e8f81429..e7881df86fe29be714b05855d24c894a2f5e9ede 100644 (file)
@@ -1,92 +1,45 @@
 /* global arrayClone */
-
-// Module for array conversion
-SVG.Array = function (array, fallback) {
-  array = (array || []).valueOf()
-
-  // if array is empty and fallback is provided, use fallback
-  if (array.length === 0 && fallback) {
-    array = fallback.valueOf()
+import {delimiter} from './regex.js'
+import ArrayPolyfill from './ArrayPolyfill.js'
+
+let BaseArray = (function() {
+  try {
+    let b = class extends Array {}
+    return Array
+  } catch (e) {
+    return ArrayPolyfill
   }
+})()
 
-  // parse array
-  this.value = this.parse(array)
-}
-
-SVG.extend(SVG.Array, {
-  // Make array morphable
-  morph: function (array) {
-    this.destination = this.parse(array)
-
-    // normalize length of arrays
-    if (this.value.length !== this.destination.length) {
-      var lastValue = this.value[this.value.length - 1]
-      var lastDestination = this.destination[this.destination.length - 1]
-
-      while (this.value.length > this.destination.length) {
-        this.destination.push(lastDestination)
-      }
-      while (this.value.length < this.destination.length) {
-        this.value.push(lastValue)
-      }
-    }
+export default class SVGArray extends BaseArray {
+  constructor (array, fallback) {
+    super()
+    this.push(...this.parse(array || fallback))
+  }
 
-    return this
-  },
-  // Clean up any duplicate points
-  settle: function () {
-    // find all unique values
-    for (var i = 0, il = this.value.length, seen = []; i < il; i++) {
-      if (seen.indexOf(this.value[i]) === -1) {
-        seen.push(this.value[i])
-      }
-    }
+  toArray () {
+    return Array.prototype.slice(this)
+  }
 
-    // set new value
-    this.value = seen
-    return seen
-  },
-  // Get morphed array at given position
-  at: function (pos) {
-    // make sure a destination is defined
-    if (!this.destination) return this
+  toString () {
+    this.join(' ')
+  }
 
-    // generate morphed array
-    for (var i = 0, il = this.value.length, array = []; i < il; i++) {
-      array.push(this.value[i] + (this.destination[i] - this.value[i]) * pos)
-    }
+  valueOf () {
+    return this.toArray()
+  }
 
-    return new SVG.Array(array)
-  },
-  toArray: function () {
-    return this.value
-  },
-  // Convert array to string
-  toString: function () {
-    return this.value.join(' ')
-  },
-  // Real value
-  valueOf: function () {
-    return this.value
-  },
   // Parse whitespace separated string
-  parse: function (array) {
+  parse (array) {
     array = array.valueOf()
 
     // if already is an array, no need to parse it
     if (Array.isArray(array)) return array
 
-    return array.trim().split(SVG.regex.delimiter).map(parseFloat)
-  },
-  // Reverse array
-  reverse: function () {
-    this.value.reverse()
+    return array.trim().split(delimiter).map(parseFloat)
+  }
 
-    return this
-  },
-  clone: function () {
-    var clone = new this.constructor()
-    clone.value = arrayClone(this.value)
-    return clone
+  clone () {
+    return new this.constructor(this)
   }
-})
+}
index 2135b61245285adecf65a0e8b945de6cfa1b880d..cb1fd2835084a2f8dab0c107c0e276e6292b25bc 100644 (file)
@@ -1,8 +1,9 @@
+import {numberAndUnit} from './regex.js'
 
 // Module for unit convertions
-SVG.Number = SVG.invent({
+export default class SVGNumber {
   // Initialize
-  create: function (value, unit) {
+  constructor (value, unit) {
     unit = Array.isArray(value) ? value[1] : unit
     value = Array.isArray(value) ? value[0] : value
 
@@ -15,7 +16,7 @@ SVG.Number = SVG.invent({
       // ensure a valid numeric value
       this.value = isNaN(value) ? 0 : !isFinite(value) ? (value < 0 ? -3.4e+38 : +3.4e+38) : value
     } else if (typeof value === 'string') {
-      unit = value.match(SVG.regex.numberAndUnit)
+      unit = value.match(numberAndUnit)
 
       if (unit) {
         // make value numeric
@@ -30,70 +31,54 @@ SVG.Number = SVG.invent({
         this.unit = unit[5]
       }
     } else {
-      if (value instanceof SVG.Number) {
+      if (value instanceof SVGNumber) {
         this.value = value.valueOf()
         this.unit = value.unit
       }
     }
-  },
-  // Add methods
-  extend: {
-    // Stringalize
-    toString: function () {
-      return (this.unit === '%' ? ~~(this.value * 1e8) / 1e6
-        : this.unit === 's' ? this.value / 1e3
-        : this.value
-      ) + this.unit
-    },
-    toJSON: function () {
-      return this.toString()
-    },   // Convert to primitive
-    toArray: function () {
-      return [this.value, this.unit]
-    },
-    valueOf: function () {
-      return this.value
-    },
-    // Add number
-    plus: function (number) {
-      number = new SVG.Number(number)
-      return new SVG.Number(this + number, this.unit || number.unit)
-    },
-    // Subtract number
-    minus: function (number) {
-      number = new SVG.Number(number)
-      return new SVG.Number(this - number, this.unit || number.unit)
-    },
-    // Multiply number
-    times: function (number) {
-      number = new SVG.Number(number)
-      return new SVG.Number(this * number, this.unit || number.unit)
-    },
-    // Divide number
-    divide: function (number) {
-      number = new SVG.Number(number)
-      return new SVG.Number(this / number, this.unit || number.unit)
-    },
-    // Make number morphable
-    morph: function (number) {
-      this.destination = new SVG.Number(number)
+  }
 
-      if (number.relative) {
-        this.destination.value += this.value
-      }
+  toString () {
+    return (this.unit === '%' ? ~~(this.value * 1e8) / 1e6
+      : this.unit === 's' ? this.value / 1e3
+      : this.value
+    ) + this.unit
+  }
+
+  toJSON () {
+    return this.toString()
+  }
 
-      return this
-    },
-    // Get morphed number at given position
-    at: function (pos) {
-      // Make sure a destination is defined
-      if (!this.destination) return this
 
-      // Generate new morphed number
-      return new SVG.Number(this.destination)
-          .minus(this)
-          .times(pos)
-          .plus(this)
-    }
+  toArray () {
+    return [this.value, this.unit]
+  }
+
+  valueOf () {
+    return this.value
+  }
+
+  // Add number
+  plus (number) {
+    number = new SVGNumber(number)
+    return new SVGNumber(this + number, this.unit || number.unit)
+  }
+
+  // Subtract number
+  minus (number) {
+    number = new SVGNumber(number)
+    return new SVGNumber(this - number, this.unit || number.unit)
+  }
+
+  // Multiply number
+  times (number) {
+    number = new SVGNumber(number)
+    return new SVGNumber(this * number, this.unit || number.unit)
+  }
+
+  // Divide number
+  divide (number) {
+    number = new SVGNumber(number)
+    return new SVGNumber(this / number, this.unit || number.unit)
   }
-})
+}
index cb150983bffea12c68becbc75c071fe22adcf5be..d73ffb6ba6c25fe9db900eb547d719c5c007b791 100644 (file)
@@ -1,10 +1,3 @@
+import Element from './Element.js'
 
-SVG.Shape = SVG.invent({
-  // Initialize node
-  create: function (node) {
-    SVG.Element.call(this, node)
-  },
-
-  // Inherit from
-  inherit: SVG.Element
-})
+export default class Shape extends Element { }
index ca6760799ea93038f477cd257d3b6ffef699dd21..98d10ef17141c6c01311cd575c45c20a225788a7 100644 (file)
@@ -1,15 +1,16 @@
+import Container from './Container.js'
+import {nodeOrNew} from './tools.js'
 
-SVG.Symbol = SVG.invent({
+export default class Symbol extends Container {
   // Initialize node
-  create: 'symbol',
-
-  // Inherit from
-  inherit: SVG.Container,
+  constructor (node) {
+    super(nodeOrNew('symbol', node))
+  }
+}
 
-  construct: {
-    // create symbol
-    symbol: function () {
-      return this.put(new SVG.Symbol())
-    }
+addFactory(Container, {
+  // create symbol
+  symbol () {
+    return this.put(new Symbol())
   }
 })
index 8a50df97ce5bdd06787f5637430a6c5d7e9e3712..3d9f074bc89f927ba484763c91e2184a2cb4197e 100644 (file)
-SVG.Text = SVG.invent({
+import Parent from './Parent.js'
+import SVGNumber from './SVGNumber.js'
+import {nodeOrNew, adopt} from './tools.js'
+import {attrs} from './defaults.js'
+
+export default class Text extends Parent {
   // Initialize node
-  create: function (node) {
-    SVG.Element.call(this, node || SVG.create('text'))
-    this.dom.leading = new SVG.Number(1.3)    // store leading value for rebuilding
+  constructor (node) {
+    super(nodeOrNew('text', node))
+
+    this.dom.leading = new SVGNumber(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
+    this._build = false                       // disable build mode for adding multiple lines
 
     // set default font
-    this.attr('font-family', SVG.defaults.attrs['font-family'])
-  },
+    this.attr('font-family', attrs['font-family'])
+  }
 
-  // Inherit from
-  inherit: SVG.Parent,
+  // Move over x-axis
+  x (x) {
+    // act as getter
+    if (x == null) {
+      return this.attr('x')
+    }
 
-  // Add class methods
-  extend: {
-    // Move over x-axis
-    x: function (x) {
-      // act as getter
-      if (x == null) {
-        return this.attr('x')
-      }
+    return this.attr('x', x)
+  }
 
-      return this.attr('x', x)
-    },
-    // Move over y-axis
-    y: function (y) {
-      var oy = this.attr('y')
-      var o = typeof oy === 'number' ? oy - this.bbox().y : 0
+  // Move over y-axis
+  y (y) {
+    var oy = this.attr('y')
+    var o = typeof oy === 'number' ? oy - this.bbox().y : 0
 
-      // act as getter
-      if (y == null) {
-        return typeof oy === 'number' ? oy - o : oy
-      }
+    // act as getter
+    if (y == null) {
+      return typeof oy === 'number' ? oy - o : oy
+    }
 
-      return this.attr('y', typeof y === 'number' ? y + o : y)
-    },
-    // Move center over x-axis
-    cx: function (x) {
-      return x == null ? this.bbox().cx : this.x(x - this.bbox().width / 2)
-    },
-    // Move center over y-axis
-    cy: function (y) {
-      return y == null ? this.bbox().cy : this.y(y - this.bbox().height / 2)
-    },
-    // Set the text content
-    text: function (text) {
-      // act as getter
-      if (text === undefined) {
-        var children = this.node.childNodes
-        var firstLine = 0
-        text = ''
-
-        for (var i = 0, len = children.length; i < len; ++i) {
-          // skip textPaths - they are no lines
-          if (children[i].nodeName === 'textPath') {
-            if (i === 0) firstLine = 1
-            continue
-          }
+    return this.attr('y', typeof y === 'number' ? y + o : y)
+  }
 
-          // add newline if its not the first child and newLined is set to true
-          if (i !== firstLine && children[i].nodeType !== 3 && SVG.adopt(children[i]).dom.newLined === true) {
-            text += '\n'
-          }
+  // Move center over x-axis
+  cx (x) {
+    return x == null ? this.bbox().cx : this.x(x - this.bbox().width / 2)
+  }
+
+  // Move center over y-axis
+  cy (y) {
+    return y == null ? this.bbox().cy : this.y(y - this.bbox().height / 2)
+  }
 
-          // add content of this node
-          text += children[i].textContent
+  // Set the text content
+  text (text) {
+    // act as getter
+    if (text === undefined) {
+      var children = this.node.childNodes
+      var firstLine = 0
+      text = ''
+
+      for (var i = 0, len = children.length; i < len; ++i) {
+        // skip textPaths - they are no lines
+        if (children[i].nodeName === 'textPath') {
+          if (i === 0) firstLine = 1
+          continue
         }
 
-        return text
+        // add newline if its not the first child and newLined is set to true
+        if (i !== firstLine && children[i].nodeType !== 3 && adopt(children[i]).dom.newLined === true) {
+          text += '\n'
+        }
+
+        // add content of this node
+        text += children[i].textContent
       }
 
-      // remove existing content
-      this.clear().build(true)
+      return text
+    }
 
-      if (typeof text === 'function') {
-        // call block
-        text.call(this, this)
-      } else {
-        // store text and make sure text is not blank
-        text = text.split('\n')
+    // remove existing content
+    this.clear().build(true)
 
-        // build new lines
-        for (var j = 0, jl = text.length; j < jl; j++) {
-          this.tspan(text[j]).newLine()
-        }
-      }
+    if (typeof text === 'function') {
+      // call block
+      text.call(this, this)
+    } else {
+      // store text and make sure text is not blank
+      text = text.split('\n')
 
-      // disable build mode and rebuild lines
-      return this.build(false).rebuild()
-    },
-    // Set / get leading
-    leading: function (value) {
-      // act as getter
-      if (value == null) {
-        return this.dom.leading
+      // build new lines
+      for (var j = 0, jl = text.length; j < jl; j++) {
+        this.tspan(text[j]).newLine()
       }
+    }
 
-      // act as setter
-      this.dom.leading = new SVG.Number(value)
+    // disable build mode and rebuild lines
+    return this.build(false).rebuild()
+  }
 
-      return this.rebuild()
-    },
-    // Rebuild appearance type
-    rebuild: function (rebuild) {
-      // store new rebuild flag if given
-      if (typeof rebuild === 'boolean') {
-        this._rebuild = rebuild
-      }
+  // Set / get leading
+  leading (value) {
+    // act as getter
+    if (value == null) {
+      return this.dom.leading
+    }
 
-      // define position of all lines
-      if (this._rebuild) {
-        var self = this
-        var blankLineOffset = 0
-        var dy = this.dom.leading * new SVG.Number(this.attr('font-size'))
-
-        this.each(function () {
-          if (this.dom.newLined) {
-            this.attr('x', self.attr('x'))
-
-            if (this.text() === '\n') {
-              blankLineOffset += dy
-            } else {
-              this.attr('dy', dy + blankLineOffset)
-              blankLineOffset = 0
-            }
-          }
-        })
+    // act as setter
+    this.dom.leading = new SVGNumber(value)
 
-        this.fire('rebuild')
-      }
+    return this.rebuild()
+  }
 
-      return this
-    },
-    // Enable / disable build mode
-    build: function (build) {
-      this._build = !!build
-      return this
-    },
-    // overwrite method from parent to set data properly
-    setData: function (o) {
-      this.dom = o
-      this.dom.leading = new SVG.Number(o.leading || 1.3)
-      return this
+  // Rebuild appearance type
+  rebuild (rebuild) {
+    // store new rebuild flag if given
+    if (typeof rebuild === 'boolean') {
+      this._rebuild = rebuild
     }
-  },
 
-  // Add parent method
-  construct: {
-    // Create text element
-    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)
+    // define position of all lines
+    if (this._rebuild) {
+      var self = this
+      var blankLineOffset = 0
+      var dy = this.dom.leading * new SVGNumber(this.attr('font-size'))
+
+      this.each(function () {
+        if (this.dom.newLined) {
+          this.attr('x', self.attr('x'))
+
+          if (this.text() === '\n') {
+            blankLineOffset += dy
+          } else {
+            this.attr('dy', dy + blankLineOffset)
+            blankLineOffset = 0
+          }
+        }
+      })
+
+      this.fire('rebuild')
     }
+
+    return this
+  }
+
+  // Enable / disable build mode
+  build (build) {
+    this._build = !!build
+    return this
+  }
+
+  // overwrite method from parent to set data properly
+  setData (o) {
+    this.dom = o
+    this.dom.leading = new SVGNumber(o.leading || 1.3)
+    return this
   }
+}
 
+
+addFactory(Parent, {
+  // Create text element
+  text (text) {
+    return this.put(new Text()).text(text)
+  },
+
+  // Create plain text element
+  plain (text) {
+    return this.put(new Text()).plain(text)
+  }
 })
 
-SVG.Tspan = SVG.invent({
+
+class Tspan extends Parent {
   // Initialize node
-  create: 'tspan',
-
-  // Inherit from
-  inherit: SVG.Parent,
-
-  // Add class methods
-  extend: {
-    // Set text content
-    text: function (text) {
-      if (text == null) return this.node.textContent + (this.dom.newLined ? '\n' : '')
-
-      typeof text === 'function' ? text.call(this, this) : this.plain(text)
-
-      return this
-    },
-    // Shortcut dx
-    dx: function (dx) {
-      return this.attr('dx', dx)
-    },
-    // Shortcut dy
-    dy: function (dy) {
-      return this.attr('dy', dy)
-    },
-    // Create new line
-    newLine: function () {
-      // fetch text parent
-      var t = this.parent(SVG.Text)
-
-      // mark new line
-      this.dom.newLined = true
-
-      // apply new position
-      return this.dy(t.dom.leading * t.attr('font-size')).attr('x', t.x())
-    }
+  constructor (node) {
+    super(nodeOrNew('tspan', node))
   }
-})
 
-SVG.extend([SVG.Text, SVG.Tspan], {
+  // Set text content
+  text (text) {
+    if (text == null) return this.node.textContent + (this.dom.newLined ? '\n' : '')
+
+    typeof text === 'function' ? text.call(this, this) : this.plain(text)
+
+    return this
+  }
+
+  // Shortcut dx
+  dx (dx) {
+    return this.attr('dx', dx)
+  }
+
+  // Shortcut dy
+  dy (dy) {
+    return this.attr('dy', dy)
+  }
+
+  // Create new line
+  newLine () {
+    // fetch text parent
+    var t = this.parent(Text)
+
+    // mark new line
+    this.dom.newLined = true
+
+    // apply new position
+    return this.dy(t.dom.leading * t.attr('font-size')).attr('x', t.x())
+  }
+}
+
+extend([Text, Tspan], {
   // Create plain text node
   plain: function (text) {
     // clear if build mode is disabled
@@ -212,9 +220,10 @@ SVG.extend([SVG.Text, SVG.Tspan], {
 
     return this
   },
+
   // Create a tspan
   tspan: function (text) {
-    var tspan = new SVG.Tspan()
+    var tspan = new Tspan()
 
     // clear if build mode is disabled
     if (!this._build) {
@@ -226,6 +235,7 @@ SVG.extend([SVG.Text, SVG.Tspan], {
 
     return tspan.text(text)
   },
+
   // FIXME: Does this also work for textpath?
   // Get length of text element
   length: function () {
index 561f147102782e793872746f757e77e06bf10dce..cd1757efe46d424b04f06dfb7e861b480a1523f5 100644 (file)
@@ -1,77 +1,80 @@
-SVG.TextPath = SVG.invent({
+import {Path, Text, PathArray} from './classes.js'
+import {nodeOrNew} from './tools.js'
+import {xlink} from './namespaces.js'
+
+export default class TextPath extends Text {
   // Initialize node
-  create: 'textPath',
-
-  // Inherit from
-  inherit: SVG.Text,
-
-  // Define parent class
-  parent: SVG.Parent,
-
-  // Add parent method
-  extend: {
-    MorphArray: SVG.PathArray,
-    // return the array of the path track element
-    array: function () {
-      var track = this.track()
-
-      return track ? track.array() : null
-    },
-    // Plot path if any
-    plot: function (d) {
-      var track = this.track()
-      var pathArray = null
-
-      if (track) {
-        pathArray = track.plot(d)
-      }
-
-      return (d == null) ? pathArray : this
-    },
-    // Get the path element
-    track: function () {
-      return this.reference('href')
-    }
-  },
-  construct: {
-    textPath: function (text, path) {
-      return this.defs().path(path).text(text).addTo(this)
+  constructor (node) {
+    super(nodeOrNew('textPath', node))
+  }
+
+  // return the array of the path track element
+  array () {
+    var track = this.track()
+
+    return track ? track.array() : null
+  }
+
+  // Plot path if any
+  plot (d) {
+    var track = this.track()
+    var pathArray = null
+
+    if (track) {
+      pathArray = track.plot(d)
     }
+
+    return (d == null) ? pathArray : this
+  }
+
+  // Get the path element
+  track () {
+    return this.reference('href')
+  }
+}
+
+addFactory(Parent, {
+  textPath (text, path) {
+    return this.defs().path(path).text(text).addTo(this)
   }
 })
 
-SVG.extend([SVG.Text], {
+
+extend([Text], {
     // Create path for text to run on
   path: function (track) {
-    var path = new SVG.TextPath()
+    var path = new TextPath()
 
     // if d is a path, reuse it
-    if (!(track instanceof SVG.Path)) {
+    if (!(track instanceof Path)) {
       // create path element
       track = this.doc().defs().path(track)
     }
 
     // link textPath to path and add content
-    path.attr('href', '#' + track, SVG.xlink)
+    path.attr('href', '#' + track, xlink)
 
     // add textPath element as child node and return textPath
     return this.put(path)
   },
-  // Todo: make this plural?
+
+  // FIXME: make this plural?
   // Get the textPath children
   textPath: function () {
     return this.select('textPath')
   }
 })
 
-SVG.extend([SVG.Path], {
+extend([Path], {
   // creates a textPath from this path
   text: function (text) {
-    if (text instanceof SVG.Text) {
+    if (text instanceof Text) {
       var txt = text.text()
       return text.clear().path(this).text(txt)
     }
-    return this.parent().put(new SVG.Text()).path(this).text(text)
+    return this.parent().put(new Text()).path(this).text(text)
   }
-  // TODO: Maybe add `targets` to get all textPaths associated with this path
+  // FIXME: Maybe add `targets` to get all textPaths associated with this path
 })
+
+TextPath.prototype.MorphArray = PathArray
index 0bf8ac5ed79e67ec8f8f1bb661d31422bf92a80a..01a8e2203a7626ab78f22c91789fb8f37c0f769b 100644 (file)
@@ -1,11 +1,5 @@
-
-// Must Change ....
-SVG.easing = {
-  '-': function (pos) { return pos },
-  '<>': function (pos) { return -Math.cos(pos * Math.PI) / 2 + 0.5 },
-  '>': function (pos) { return Math.sin(pos * Math.PI / 2) },
-  '<': function (pos) { return -Math.cos(pos * Math.PI / 2) + 1 }
-}
+import EventTarget from './EventTarget.js'
+import Animator from './Animator.js'
 
 var time = window.performance || Date
 
@@ -16,16 +10,14 @@ var makeSchedule = function (runnerInfo) {
   return {start: start, duration: duration, end: end, runner: runnerInfo.runner}
 }
 
-SVG.Timeline = SVG.invent({
-  inherit: SVG.EventTarget,
-
+export default class Timeline extends EventTarget {
   // Construct a new timeline on the given element
-  create: function () {
+  constructor () {
     this._timeSource = function () {
       return time.now()
     }
 
-    this._dispatcher = document.createElement('div')
+    this._dispatcher = document.makeInstance('div')
 
     // Store the timing variables
     this._startTime = 0
@@ -43,240 +35,235 @@ SVG.Timeline = SVG.invent({
     this._time = 0
     this._lastSourceTime = 0
     this._lastStepTime = 0
-  },
-
-  extend: {
+  }
 
-    getEventTarget () {
-      return this._dispatcher
-    },
+  getEventTarget () {
+    return this._dispatcher
+  }
 
-    /**
-     *
-     */
+  /**
+   *
+   */
 
-    // schedules a runner on the timeline
-    schedule (runner, delay, when) {
-      if (runner == null) {
-        return this._runners.map(makeSchedule).sort(function (a, b) {
-          return (a.start - b.start) || (a.duration - b.duration)
-        })
-      }
+  // schedules a runner on the timeline
+  schedule (runner, delay, when) {
+    if (runner == null) {
+      return this._runners.map(makeSchedule).sort(function (a, b) {
+        return (a.start - b.start) || (a.duration - b.duration)
+      })
+    }
 
-      if (!this.active()) {
-        this._step()
-        if (when == null) {
-          when = 'now'
-        }
+    if (!this.active()) {
+      this._step()
+      if (when == null) {
+        when = 'now'
       }
+    }
 
-      // The start time for the next animation can either be given explicitly,
-      // derived from the current timeline time or it can be relative to the
-      // last start time to chain animations direclty
-      var absoluteStartTime = 0
-      delay = delay || 0
-
-      // Work out when to start the animation
-      if (when == null || when === 'last' || when === 'after') {
-        // Take the last time and increment
-        absoluteStartTime = this._startTime
-      } else if (when === 'absolute' || when === 'start') {
-        absoluteStartTime = delay
+    // The start time for the next animation can either be given explicitly,
+    // derived from the current timeline time or it can be relative to the
+    // last start time to chain animations direclty
+    var absoluteStartTime = 0
+    delay = delay || 0
+
+    // Work out when to start the animation
+    if (when == null || when === 'last' || when === 'after') {
+      // Take the last time and increment
+      absoluteStartTime = this._startTime
+    } else if (when === 'absolute' || when === 'start') {
+      absoluteStartTime = delay
+      delay = 0
+    } else if (when === 'now') {
+      absoluteStartTime = this._time
+    } else if (when === 'relative') {
+      let runnerInfo = this._runners[runner.id]
+      if (runnerInfo) {
+        absoluteStartTime = runnerInfo.start + delay
         delay = 0
-      } else if (when === 'now') {
-        absoluteStartTime = this._time
-      } else if (when === 'relative') {
-        let runnerInfo = this._runners[runner.id]
-        if (runnerInfo) {
-          absoluteStartTime = runnerInfo.start + delay
-          delay = 0
-        }
-      } else {
-        throw new Error('Invalid value for the "when" parameter')
       }
+    } else {
+      throw new Error('Invalid value for the "when" parameter')
+    }
 
-      // Manage runner
-      runner.unschedule()
-      runner.timeline(this)
-      runner.time(-delay)
+    // Manage runner
+    runner.unschedule()
+    runner.timeline(this)
+    runner.time(-delay)
 
-      // Save startTime for next runner
-      this._startTime = absoluteStartTime + runner.duration() + delay
+    // Save startTime for next runner
+    this._startTime = absoluteStartTime + runner.duration() + delay
 
-      // Save runnerInfo
-      this._runners[runner.id] = {
-        persist: this.persist(),
-        runner: runner,
-        start: absoluteStartTime
-      }
+    // Save runnerInfo
+    this._runners[runner.id] = {
+      persist: this.persist(),
+      runner: runner,
+      start: absoluteStartTime
+    }
 
-      // Save order and continue
-      this._order.push(runner.id)
-      this._continue()
-      return this
-    },
-
-    // Remove the runner from this timeline
-    unschedule (runner) {
-      var index = this._order.indexOf(runner.id)
-      if (index < 0) return this
-
-      delete this._runners[runner.id]
-      this._order.splice(index, 1)
-      runner.timeline(null)
-      return this
-    },
-
-    play () {
-      // Now make sure we are not paused and continue the animation
-      this._paused = false
-      return this._continue()
-    },
-
-    pause () {
-      // Cancel the next animation frame and pause
-      this._nextFrame = null
-      this._paused = true
-      return this
-    },
-
-    stop () {
-      // Cancel the next animation frame and go to start
-      this.seek(-this._time)
-      return this.pause()
-    },
-
-    finish () {
-      this.seek(Infinity)
-      return this.pause()
-    },
-
-    speed (speed) {
-      if (speed == null) return this._speed
-      this._speed = speed
-      return this
-    },
-
-    reverse (yes) {
-      var currentSpeed = this.speed()
-      if (yes == null) return this.speed(-currentSpeed)
-
-      var positive = Math.abs(currentSpeed)
-      return this.speed(yes ? positive : -positive)
-    },
-
-    seek (dt) {
-      this._time += dt
-      return this._continue()
-    },
-
-    time (time) {
-      if (time == null) return this._time
-      this._time = time
-      return this
-    },
-
-    persist (dtOrForever) {
-      if (dtOrForever == null) return this._persist
-      this._persist = dtOrForever
-      return this
-    },
-
-    source (fn) {
-      if (fn == null) return this._timeSource
-      this._timeSource = fn
-      return this
-    },
-
-    _step () {
-      // If the timeline is paused, just do nothing
-      if (this._paused) return
-
-      // Get the time delta from the last time and update the time
-      // TODO: Deal with window.blur window.focus to pause animations
-      var time = this._timeSource()
-      var dtSource = time - this._lastSourceTime
-      var dtTime = this._speed * dtSource + (this._time - this._lastStepTime)
-      this._lastSourceTime = time
-
-      // Update the time
-      this._time += dtTime
-      this._lastStepTime = this._time
-      // this.fire('time', this._time)
-
-      // Run all of the runners directly
-      var runnersLeft = false
-      for (var i = 0, len = this._order.length; i < len; i++) {
-        // Get and run the current runner and ignore it if its inactive
-        var runnerInfo = this._runners[this._order[i]]
-        var runner = runnerInfo.runner
-        let dt = dtTime
-
-        // Make sure that we give the actual difference
-        // between runner start time and now
-        let dtToStart = this._time - runnerInfo.start
-
-        // Dont run runner if not started yet
-        if (dtToStart < 0) {
-          runnersLeft = true
-          continue
-        } else if (dtToStart < dt) {
-          // Adjust dt to make sure that animation is on point
-          dt = dtToStart
-        }
+    // Save order and continue
+    this._order.push(runner.id)
+    this._continue()
+    return this
+  }
 
-        if (!runner.active()) continue
-
-        // If this runner is still going, signal that we need another animation
-        // frame, otherwise, remove the completed runner
-        var finished = runner.step(dt).done
-        if (!finished) {
-          runnersLeft = true
-          // continue
-        } else if (runnerInfo.persist !== true) {
-          // runner is finished. And runner might get removed
-
-          // TODO: Figure out end time of runner
-          var endTime = runner.duration() - runner.time() + this._time
-
-          if (endTime + this._persist < this._time) {
-            // Delete runner and correct index
-            delete this._runners[this._order[i]]
-            this._order.splice(i--, 1) && --len
-            runner.timeline(null)
-          }
-        }
-      }
+  // Remove the runner from this timeline
+  unschedule (runner) {
+    var index = this._order.indexOf(runner.id)
+    if (index < 0) return this
+
+    delete this._runners[runner.id]
+    this._order.splice(index, 1)
+    runner.timeline(null)
+    return this
+  }
 
-      // Get the next animation frame to keep the simulation going
-      if (runnersLeft) {
-        this._nextFrame = SVG.Animator.frame(this._step.bind(this))
-      } else {
-        this._nextFrame = null
+  play () {
+    // Now make sure we are not paused and continue the animation
+    this._paused = false
+    return this._continue()
+  }
+
+  pause () {
+    // Cancel the next animation frame and pause
+    this._nextFrame = null
+    this._paused = true
+    return this
+  }
+
+  stop () {
+    // Cancel the next animation frame and go to start
+    this.seek(-this._time)
+    return this.pause()
+  }
+
+  finish () {
+    this.seek(Infinity)
+    return this.pause()
+  }
+
+  speed (speed) {
+    if (speed == null) return this._speed
+    this._speed = speed
+    return this
+  }
+
+  reverse (yes) {
+    var currentSpeed = this.speed()
+    if (yes == null) return this.speed(-currentSpeed)
+
+    var positive = Math.abs(currentSpeed)
+    return this.speed(yes ? positive : -positive)
+  }
+
+  seek (dt) {
+    this._time += dt
+    return this._continue()
+  }
+
+  time (time) {
+    if (time == null) return this._time
+    this._time = time
+    return this
+  }
+
+  persist (dtOrForever) {
+    if (dtOrForever == null) return this._persist
+    this._persist = dtOrForever
+    return this
+  }
+
+  source (fn) {
+    if (fn == null) return this._timeSource
+    this._timeSource = fn
+    return this
+  }
+
+  _step () {
+    // If the timeline is paused, just do nothing
+    if (this._paused) return
+
+    // Get the time delta from the last time and update the time
+    // TODO: Deal with window.blur window.focus to pause animations
+    var time = this._timeSource()
+    var dtSource = time - this._lastSourceTime
+    var dtTime = this._speed * dtSource + (this._time - this._lastStepTime)
+    this._lastSourceTime = time
+
+    // Update the time
+    this._time += dtTime
+    this._lastStepTime = this._time
+    // this.fire('time', this._time)
+
+    // Run all of the runners directly
+    var runnersLeft = false
+    for (var i = 0, len = this._order.length; i < len; i++) {
+      // Get and run the current runner and ignore it if its inactive
+      var runnerInfo = this._runners[this._order[i]]
+      var runner = runnerInfo.runner
+      let dt = dtTime
+
+      // Make sure that we give the actual difference
+      // between runner start time and now
+      let dtToStart = this._time - runnerInfo.start
+
+      // Dont run runner if not started yet
+      if (dtToStart < 0) {
+        runnersLeft = true
+        continue
+      } else if (dtToStart < dt) {
+        // Adjust dt to make sure that animation is on point
+        dt = dtToStart
       }
-      return this
-    },
-
-    // Checks if we are running and continues the animation
-    _continue () {
-      if (this._paused) return this
-      if (!this._nextFrame) {
-        this._nextFrame = SVG.Animator.frame(this._step.bind(this))
+
+      if (!runner.active()) continue
+
+      // If this runner is still going, signal that we need another animation
+      // frame, otherwise, remove the completed runner
+      var finished = runner.step(dt).done
+      if (!finished) {
+        runnersLeft = true
+        // continue
+      } else if (runnerInfo.persist !== true) {
+        // runner is finished. And runner might get removed
+
+        // TODO: Figure out end time of runner
+        var endTime = runner.duration() - runner.time() + this._time
+
+        if (endTime + this._persist < this._time) {
+          // Delete runner and correct index
+          delete this._runners[this._order[i]]
+          this._order.splice(i--, 1) && --len
+          runner.timeline(null)
+        }
       }
-      return this
-    },
+    }
 
-    active () {
-      return !!this._nextFrame
+    // Get the next animation frame to keep the simulation going
+    if (runnersLeft) {
+      this._nextFrame = Animator.frame(this._step.bind(this))
+    } else {
+      this._nextFrame = null
     }
-  },
-
-  // These methods will be added to all SVG.Element objects
-  parent: SVG.Element,
-  construct: {
-    timeline: function () {
-      this._timeline = (this._timeline || new SVG.Timeline())
-      return this._timeline
+    return this
+  }
+
+  // Checks if we are running and continues the animation
+  _continue () {
+    if (this._paused) return this
+    if (!this._nextFrame) {
+      this._nextFrame = Animator.frame(this._step.bind(this))
     }
+    return this
+  }
+
+  active () {
+    return !!this._nextFrame
+  }
+}
+
+extend(Element, {
+  timeline: function () {
+    this._timeline = (this._timeline || new Timeline())
+    return this._timeline
   }
 })
index a90814301b94ce25ac5af8d38225252d36637578..b6d5e26f24350e89301686f2b29d43a6fdd59f1f 100644 (file)
@@ -1,97 +1,96 @@
-// ### This module adds backward / forward functionality to elements.
-
-//
-SVG.extend(SVG.Element, {
-  // Get all siblings, including myself
-  siblings: function () {
-    return this.parent().children()
-  },
-
-  // Get the curent position siblings
-  position: function () {
-    return this.parent().index(this)
-  },
-
-  // Get the next element (will return null if there is none)
-  next: function () {
-    return this.siblings()[this.position() + 1]
-  },
-
-  // Get the next element (will return null if there is none)
-  prev: function () {
-    return this.siblings()[this.position() - 1]
-  },
-
-  // Send given element one step forward
-  forward: function () {
-    var i = this.position() + 1
-    var p = this.parent()
+import Doc from './Doc.js'
 
-    // move node one step forward
-    p.removeElement(this).add(this, i)
+// ### This module adds backward / forward functionality to elements.
 
-    // make sure defs node is always at the top
-    if (p instanceof SVG.Doc) {
-      p.node.appendChild(p.defs().node)
-    }
+// Get all siblings, including myself
+export function siblings () {
+  return this.parent().children()
+}
+
+// Get the curent position siblings
+export function position () {
+  return this.parent().index(this)
+}
+
+// Get the next element (will return null if there is none)
+export function next () {
+  return this.siblings()[this.position() + 1]
+}
+
+// Get the next element (will return null if there is none)
+export function prev () {
+  return this.siblings()[this.position() - 1]
+}
+
+// Send given element one step forward
+export function forward () {
+  var i = this.position() + 1
+  var p = this.parent()
+
+  // move node one step forward
+  p.removeElement(this).add(this, i)
+
+  // make sure defs node is always at the top
+  if (p instanceof Doc) {
+    p.node.appendChild(p.defs().node)
+  }
 
-    return this
-  },
+  return this
+}
 
-  // Send given element one step backward
-  backward: function () {
-    var i = this.position()
+// Send given element one step backward
+export function backward () {
+  var i = this.position()
 
-    if (i > 0) {
-      this.parent().removeElement(this).add(this, i - 1)
-    }
+  if (i > 0) {
+    this.parent().removeElement(this).add(this, i - 1)
+  }
 
-    return this
-  },
+  return this
+}
 
-  // Send given element all the way to the front
-  front: function () {
-    var p = this.parent()
+// Send given element all the way to the front
+export function front () {
+  var p = this.parent()
 
-    // Move node forward
-    p.node.appendChild(this.node)
+  // Move node forward
+  p.node.appendChild(this.node)
 
-    // Make sure defs node is always at the top
-    if (p instanceof SVG.Doc) {
-      p.node.appendChild(p.defs().node)
-    }
+  // Make sure defs node is always at the top
+  if (p instanceof Doc) {
+    p.node.appendChild(p.defs().node)
+  }
 
-    return this
-  },
+  return this
+}
 
-  // Send given element all the way to the back
-  back: function () {
-    if (this.position() > 0) {
-      this.parent().removeElement(this).add(this, 0)
-    }
+// Send given element all the way to the back
+export function back () {
+  if (this.position() > 0) {
+    this.parent().removeElement(this).add(this, 0)
+  }
 
-    return this
-  },
+  return this
+}
 
-  // Inserts a given element before the targeted element
-  before: function (element) {
-    element.remove()
+// Inserts a given element before the targeted element
+export function before (element) {
+  element.remove()
 
-    var i = this.position()
+  var i = this.position()
 
-    this.parent().add(element, i)
+  this.parent().add(element, i)
 
-    return this
-  },
+  return this
+}
 
-  // Insters a given element after the targeted element
-  after: function (element) {
-    element.remove()
+// Inserts a given element after the targeted element
+export function after (element) {
+  element.remove()
 
-    var i = this.position()
+  var i = this.position()
 
-    this.parent().add(element, i + 1)
+  this.parent().add(element, i + 1)
 
-    return this
-  }
-})
+  return this
+}
index 19c7525d4abf1245ba47488a55476842ea782bd3..a0c95b4a56d7c717103acbdf7a568bc7ae004960 100644 (file)
@@ -1,72 +1,78 @@
-SVG.extend(SVG.Element, {
-  // Set svg element attribute
-  attr: function (a, v, n) {
-    // act as full getter
-    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.isNumber.test(v[n].nodeValue)
-          ? 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 if the first and only argument is not an object
-      v = this.node.getAttribute(a)
-      return v == null ? SVG.defaults.attrs[a]
-        : SVG.regex.isNumber.test(v) ? parseFloat(v)
-        : v
-    } else {
-      // convert image fill and stroke to patterns
-      if (a === 'fill' || a === 'stroke') {
-        if (SVG.regex.isImage.test(v)) {
-          v = this.doc().defs().image(v)
-        }
+import {isNumer, isImage} from './regex.js'
+import {attrs as defaults} from './defaults.js'
+import {Color, SVGArray, Image} from './classes.js'
 
-        if (v instanceof SVG.Image) {
-          v = this.doc().defs().pattern(0, 0, function () {
-            this.add(v)
-          })
-        }
-      }
+// Set svg element attribute
+export default function attr (attr, val, ns) {
+  // act as full getter
+  if (attr == null) {
+    // get an object of attributes
+    attr = {}
+    val = this.node.attributes
 
-      // ensure correct numeric values (also accepts NaN and Infinity)
-      if (typeof v === 'number') {
-        v = new SVG.Number(v)
-      } else if (SVG.Color.isColor(v)) {
-        // ensure full hex color
-        v = new SVG.Color(v)
-      } else if (Array.isArray(v)) {
-        // parse array values
-        v = new SVG.Array(v)
+    for (let node of val) {
+      attr[node.nodeName] = isNumer.test(node.nodeValue)
+        ? parseFloat(node.nodeValue)
+        : node.nodeValue
+    }
+
+    return attr
+  } else if (Array.isArray(attr)) {
+    // FIXME: implement
+  } else if (typeof attr === 'object') {
+    // apply every attribute individually if an object is passed
+    for (val in a) this.attr(val, attr[val])
+  }else if (val === null) {
+      // remove value
+    this.node.removeAttribute(attr)
+  } else if (val == null) {
+    // act as a getter if the first and only argument is not an object
+    val = this.node.getAttribute(attr)
+    return val == null ? defaults[attr] // FIXME: do we need to return defaults?
+      : isNumber.test(val) ? parseFloat(val)
+      : val
+  } else {
+    // convert image fill and stroke to patterns
+    if (attr === 'fill' || attr === 'stroke') {
+      if (isImage.test(v)) {
+        val = this.doc().defs().image(val)
       }
 
-      // if the passed attribute is leading...
-      if (a === 'leading') {
-        // ... call the leading method instead
-        if (this.leading) {
-          this.leading(v)
-        }
-      } else {
-        // set given attribute on node
-        typeof n === 'string' ? this.node.setAttributeNS(n, a, v.toString())
-          : this.node.setAttribute(a, v.toString())
+      if (val instanceof Image) {
+        val = this.doc().defs().pattern(0, 0, function () {
+          this.add(val)
+        })
       }
+    }
 
-      // rebuild if required
-      if (this.rebuild && (a === 'font-size' || a === 'x')) {
-        this.rebuild(a, v)
+    // ensure correct numeric values (also accepts NaN and Infinity)
+    if (typeof val === 'number') {
+      val = new SVGNumber(val)
+    } else if (isColor(val)) {
+      // ensure full hex color
+      val = new Color(val)
+    } else if (Array.isArray(val)) {
+      // parse array values
+      val = new SVGArray(val)
+    }
+
+    // if the passed attribute is leading...
+    if (attr === 'leading') {
+      // ... call the leading method instead
+      if (this.leading) {
+        this.leading(val)
       }
+    } else {
+      // set given attribute on node
+      typeof ns === 'string' ? this.node.setAttributeNS(ns, attr, val.toString())
+        : this.node.setAttribute(attr, val.toString())
     }
 
-    return this
+    // rebuild if required
+    if (this.rebuild && (attr === 'font-size' || attr === 'x')) {
+      this.rebuild()
+    }
   }
-})
+
+  return this
+}
diff --git a/src/circled.js b/src/circled.js
new file mode 100644 (file)
index 0000000..70fafef
--- /dev/null
@@ -0,0 +1,64 @@
+// FIXME: import this to runner
+import {proportionalSize} from './helpers.js'
+import SVGNumber from './SVGNumber.js'
+
+// Radius x value
+export function rx (rx) {
+  return this.attr('rx', rx)
+}
+
+// Radius y value
+export function ry (ry) {
+  return this.attr('ry', ry)
+}
+
+// Move over x-axis
+export function x (x) {
+  return x == null
+    ? this.cx() - this.rx()
+    : this.cx(x + this.rx())
+}
+
+// Move over y-axis
+export function y (y) {
+  return y == null
+    ? this.cy() - this.ry()
+    : this.cy(y + this.ry())
+}
+
+// Move by center over x-axis
+export function cx (x) {
+  return x == null
+    ? this.attr('cx')
+    : this.attr('cx', x)
+}
+
+// Move by center over y-axis
+export function cy (y) {
+  return y == null
+    ? this.attr('cy')
+    : this.attr('cy', y)
+}
+
+// Set width of element
+export function width (width) {
+  return width == null
+    ? this.rx() * 2
+    : this.rx(new SVGNumber(width).divide(2))
+}
+
+// Set height of element
+export function height (height) {
+  return height == null
+    ? this.ry() * 2
+    : this.ry(new SVGNumber(height).divide(2))
+}
+
+// Custom size function
+export function size (width, height) {
+  var p = proportionalSize(this, width, height)
+
+  return this
+    .rx(new SVGNumber(p.width).divide(2))
+    .ry(new SVGNumber(p.height).divide(2))
+}
diff --git a/src/classes.js b/src/classes.js
new file mode 100644 (file)
index 0000000..df65151
--- /dev/null
@@ -0,0 +1,87 @@
+export {default as EventTarget} from './EventTarget.js'
+export {default as Element} from './Element.js'
+export {default as HtmlNode} from './HtmlNode.js'
+export {default as Parent} from './Parent.js'
+export {default as Container} from './Container.js'
+export {default as Doc} from './Doc.js'
+export {default as Defs} from './Defs.js'
+export {default as G} from './G.js'
+export {default as Animator} from './Animator.js'
+export {default as Shape} from './Shape.js'
+export {default as Bare} from './Bare.js'
+export {default as Circle} from './Circle.js'
+export {default as ClipPath} from './ClipPath.js'
+export {default as A} from './A.js'
+export {default as Ellipse} from './Ellipse.js'
+export {default as Stop} from './Stop.js'
+export {default as Gradient} from './Gradient.js'
+export {default as Image} from './Image.js'
+export {default as Line} from './Line.js'
+export {default as Marker} from './Marker.js'
+export {default as Mask} from './Mask.js'
+export {default as Path} from './Path.js'
+export {default as Pattern} from './Pattern.js'
+export {default as Polygon} from './Polygon.js'
+export {default as Polyline} from './Polyline.js'
+export {default as Rect} from './Rect.js'
+export {default as Symbol} from './Symbol.js'
+export {default as Text} from './Text.js'
+export {default as TextPath} from './TextPath.js'
+export {default as Use} from './Use.js'
+export {default as SVGNumber} from './SVGNumber.js'
+export {default as SVGArray} from './SVGArray.js'
+export {default as PathArray} from './PathArray.js'
+export {default as PointArray} from './PointArray.js'
+export {default as Matrix} from './Matrix.js'
+export {default as Point} from './Point.js'
+export {default as Box} from './Box.js'
+export {default as Color} from './Color.js'
+export {default as Morphable} from './Morphable.js'
+export {default as Queue} from './Queue.js'
+export {default as Runner} from './Runner.js'
+export {default as Timeline} from './Timeline.js'
+export {Controller, Ease, PID, Spring} from './Controller.js'
+
+// export {default as Animator} from './Animator.js'
+// export {default as SVGArray} from './SVGArray.js'
+// export {default as Bare} from './Bare.js'
+// export {default as Box} from './Box.js'
+// export {default as Circle} from './Circle.js'
+// export {default as ClipPath} from './ClipPath.js'
+// export {default as Color} from './Color.js'
+// export {default as Container} from './Container.js'
+// export {Controller, Ease, PID, Spring} from './Controller.js'
+// export {default as Defs} from './Defs.js'
+// export {default as Doc} from './Doc.js'
+// export {default as Element} from './Element.js'
+// export {default as Ellipse} from './Ellipse.js'
+// export {default as EventTarget} from './EventTarget.js'
+// export {default as Gradient} from './Gradient.js'
+// export {default as G} from './G.js'
+// export {default as HtmlNode} from './HtmlNode.js'
+// export {default as A} from './A.js'
+// export {default as Image} from './Image.js'
+// export {default as Line} from './Line.js'
+// export {default as Marker} from './Marker.js'
+// export {default as Mask} from './Mask.js'
+// export {default as Matrix} from './Matrix.js'
+// export {default as Morphable} from './Morphable.js'
+// export {default as SVGNumber} from './SVGNumber.js'
+// export {default as Parent} from './Parent.js'
+// export {default as Path} from './Path.js'
+// export {default as PathArray} from './PathArray.js'
+// export {default as Pattern} from './Pattern.js'
+// export {default as Point} from './Point.js'
+// export {default as PointArray} from './PointArray.js'
+// export {default as Polygon} from './Polygon.js'
+// export {default as Polyline} from './Polyline.js'
+// export {default as Queue} from './Queue.js'
+// export {default as Rect} from './Rect.js'
+// export {default as Runner} from './Runner.js'
+// export {default as Shape} from './Shape.js'
+// export {default as Stop} from './Stop.js'
+// export {default as Symbol} from './Symbol.js'
+// export {default as Text} from './Text.js'
+// export {default as TextPath} from './TextPath.js'
+// export {default as Timeline} from './Timeline.js'
+// export {default as Use} from './Use.js'
index c549bd5f50404fb3346cd1ed64ad3f465901f2e4..e5b079475a5e8f2f111e06200395f31b22d20d11 100644 (file)
@@ -1,14 +1,19 @@
-/* global camelCase */
+import {camelCase} from './helpers.js'
+import Element from './Element.js'
+import {extend} from './tools.js'
+import {isBlank} from './regex.js'
 
-SVG.extend(SVG.Element, {
+extend(Element, {
   // Dynamic style generator
-  css: function (s, v) {
-    var ret = {}
-    var t, i
+  css (style, val) {
+    let ret = {}
+    let i
     if (arguments.length === 0) {
       // get full style as object
-      this.node.style.cssText.split(/\s*;\s*/).filter(function (el) { return !!el.length }).forEach(function (el) {
-        t = el.split(/\s*:\s*/)
+      this.node.style.cssText.split(/\s*;\s*/)
+        .filter(function (el) { return !!el.length })
+        .forEach(function (el) {
+        let t = el.split(/\s*:\s*/)
         ret[t[0]] = t[1]
       })
       return ret
@@ -16,32 +21,50 @@ SVG.extend(SVG.Element, {
 
     if (arguments.length < 2) {
       // get style properties in the array
-      if (Array.isArray(s)) {
-        for (i = s.length; i--;) {
-          ret[camelCase(s[i])] = this.node.style[camelCase(s[i])]
+      if (Array.isArray(style)) {
+        for (let name of style) {
+          let cased = camelCase(name)
+          ret[cased] = this.node.style(cased)
         }
         return ret
       }
 
       // get style for property
-      if (typeof s === 'string') {
-        return this.node.style[camelCase(s)]
+      if (typeof style === 'string') {
+        return this.node.style[camelCase(style)]
       }
 
       // set styles in object
-      if (typeof s === 'object') {
-        for (i in s) {
+      if (typeof style === 'object') {
+        for (name in style) {
           // set empty string if null/undefined/'' was given
-          this.node.style[camelCase(i)] = (s[i] == null || SVG.regex.isBlank.test(s[i])) ? '' : s[i]
+          this.node.style[camelCase(name)] =
+            (style[name] == null || isBlank.test(style[name])) ? '' : style[name]
         }
       }
     }
 
     // set style for property
     if (arguments.length === 2) {
-      this.node.style[camelCase(s)] = (v == null || SVG.regex.isBlank.test(v)) ? '' : v
+      this.node.style[camelCase(style)] =
+        (val == null || isBlank.test(val)) ? '' : val
     }
 
     return this
+  },
+
+  // Show element
+  show () {
+    return this.css('display', '')
+  },
+
+  // Hide element
+  hide () {
+    return this.css('display', 'none')
+  },
+
+  // Is element visible?
+  visible () {
+    return this.css('display') !== 'none'
   }
 })
index f7fcd558a5b3ff2138a0be472aa23904ffbb1056..530986d99ec2402cb511346ce5df766c88361d52 100644 (file)
@@ -1,7 +1,9 @@
+import Element from './Element.js'
+import {extend} from './tools.js'
 
-SVG.extend(SVG.Element, {
+extend(Element, {
   // Store data values on svg nodes
-  data: function (a, v, r) {
+  data (a, v, r) {
     if (typeof a === 'object') {
       for (v in a) {
         this.data(v, a[v])
diff --git a/src/defaults.js b/src/defaults.js
new file mode 100644 (file)
index 0000000..0d496bc
--- /dev/null
@@ -0,0 +1,48 @@
+
+export function noop () {}
+
+// Default animation values
+export let timeline = {
+  duration: 400,
+  ease: '>',
+  delay: 0
+}
+
+// Default attribute values
+export let attrs = {
+
+  // fill and stroke
+  'fill-opacity': 1,
+  'stroke-opacity': 1,
+  'stroke-width': 0,
+  'stroke-linejoin': 'miter',
+  'stroke-linecap': 'butt',
+  fill: '#000000',
+  stroke: '#000000',
+  opacity: 1,
+
+  // position
+  x: 0,
+  y: 0,
+  cx: 0,
+  cy: 0,
+
+  // size
+  width: 0,
+  height: 0,
+
+  // radius
+  r: 0,
+  rx: 0,
+  ry: 0,
+
+  // gradient
+  offset: 0,
+  'stop-opacity': 1,
+  'stop-color': '#000000',
+
+  // text
+  'font-size': 16,
+  'font-family': 'Helvetica, Arial, sans-serif',
+  'text-anchor': 'start'
+}
index 4f1660970f1b7c7cc4e94ab567a80532963bf6ec..8d54782f6f77f421f480bdfa556fd2e0cc94b6c8 100644 (file)
@@ -1,38 +1,42 @@
-// Add events to elements
-;[ 'click',
-  'dblclick',
-  'mousedown',
-  'mouseup',
-  'mouseover',
-  'mouseout',
-  'mousemove',
-  'mouseenter',
-  'mouseleave',
-  'touchstart',
-  'touchmove',
-  'touchleave',
-  'touchend',
-  'touchcancel' ].forEach(function (event) {
-    // add event to SVG.Element
-    SVG.Element.prototype[event] = function (f) {
-      if (f === null) {
-        SVG.off(this, event)
-      } else {
-        SVG.on(this, event, f)
-      }
-      return this
-    }
-  })
-
-SVG.listenerId = 0
+import EventTarget from './EventTarget.js'
+import Element from './Element.js'
+import {delimiter} from './regex.js'
+
+// // Add events to elements
+// ;[ 'click',
+//   'dblclick',
+//   'mousedown',
+//   'mouseup',
+//   'mouseover',
+//   'mouseout',
+//   'mousemove',
+//   'mouseenter',
+//   'mouseleave',
+//   'touchstart',
+//   'touchmove',
+//   'touchleave',
+//   'touchend',
+//   'touchcancel' ].forEach(function (event) {
+//     // add event to Element
+//     Element.prototype[event] = function (f) {
+//       if (f === null) {
+//         off(this, event)
+//       } else {
+//         on(this, event, f)
+//       }
+//       return this
+//     }
+//   })
+
+let listenerId = 0
 
 // Add event binder in the SVG namespace
-SVG.on = function (node, events, listener, binding, options) {
+export function on (node, events, listener, binding, options) {
   var l = listener.bind(binding || node)
-  var n = node instanceof SVG.EventTarget ? node.getEventTarget() : node
+  var n = node instanceof EventTarget ? node.getEventTarget() : node
 
   // events can be an array of events or a string of events
-  events = Array.isArray(events) ? events : events.split(SVG.regex.delimiter)
+  events = Array.isArray(events) ? events : events.split(delimiter)
 
   // ensure instance object for nodes which are not adopted
   n.instance = n.instance || {events: {}}
@@ -42,7 +46,7 @@ SVG.on = function (node, events, listener, binding, options) {
 
   // add id to listener
   if (!listener._svgjsListenerId) {
-    listener._svgjsListenerId = ++SVG.listenerId
+    listener._svgjsListenerId = ++listenerId
   }
 
   events.forEach(function (event) {
@@ -62,8 +66,8 @@ SVG.on = function (node, events, listener, binding, options) {
 }
 
 // Add event unbinder in the SVG namespace
-SVG.off = function (node, events, listener, options) {
-  var n = node instanceof SVG.EventTarget ? node.getEventTarget() : node
+export function off (node, events, listener, options) {
+  var n = node instanceof EventTarget ? node.getEventTarget() : node
   if (!n.instance) return
 
   // listener can be a function or a number
@@ -76,7 +80,7 @@ SVG.off = function (node, events, listener, options) {
   var bag = n.instance.events
 
   // events can be an array of events or a string or undefined
-  events = Array.isArray(events) ? events : (events || '').split(SVG.regex.delimiter)
+  events = Array.isArray(events) ? events : (events || '').split(delimiter)
 
   events.forEach(function (event) {
     var ev = event && event.split('.')[0]
@@ -94,7 +98,7 @@ SVG.off = function (node, events, listener, options) {
     } else if (ev && ns) {
       // remove all listeners for a namespaced event
       if (bag[ev] && bag[ev][ns]) {
-        for (l in bag[ev][ns]) { SVG.off(n, [ev, ns].join('.'), l) }
+        for (l in bag[ev][ns]) { off(n, [ev, ns].join('.'), l) }
 
         delete bag[ev][ns]
       }
@@ -102,27 +106,27 @@ SVG.off = function (node, events, listener, options) {
       // remove all listeners for a specific namespace
       for (event in bag) {
         for (namespace in bag[event]) {
-          if (ns === namespace) { SVG.off(n, [event, ns].join('.')) }
+          if (ns === namespace) { off(n, [event, ns].join('.')) }
         }
       }
     } else if (ev) {
       // remove all listeners for the event
       if (bag[ev]) {
-        for (namespace in bag[ev]) { SVG.off(n, [ev, namespace].join('.')) }
+        for (namespace in bag[ev]) { off(n, [ev, namespace].join('.')) }
 
         delete bag[ev]
       }
     } else {
       // remove all listeners on a given node
-      for (event in bag) { SVG.off(n, event) }
+      for (event in bag) { off(n, event) }
 
       n.instance.events = {}
     }
   })
 }
 
-SVG.dispatch = function (node, event, data) {
-  var n = node instanceof SVG.EventTarget ? node.getEventTarget() : node
+export function dispatch (node, event, data) {
+  var n = node instanceof EventTarget ? node.getEventTarget() : node
 
   // Dispatch event
   if (event instanceof window.Event) {
index 19eebd7a9be8e28b9a6f67e94c950cef85d20102..34a21bb102e5673d348741a67f68778383af927b 100644 (file)
@@ -1,38 +1,42 @@
-SVG.extend(SVG.Parent, {
-  flatten: function (parent) {
-    // flattens is only possible for nested svgs and groups
-    if (!(this instanceof SVG.G || this instanceof SVG.Doc)) {
-      return this
-    }
+import {Doc, G, Parent, Defs} from './classes.js'
 
-    parent = parent || (this instanceof SVG.Doc && this.isRoot() ? this : this.parent(SVG.Parent))
+export function flatten (parent) {
+  // flatten is only possible for svgs and groups
+  if (!(this instanceof G || this instanceof Doc)) {
+    return this
+  }
+
+  parent = parent ||
+    (this instanceof Doc && this.isRoot()
+      ? this
+      : this.parent(Parent))
+
+  this.each(function () {
+    if (this instanceof Defs) return this
+    if (this instanceof Parent) return this.flatten(parent)
+    return this.toParent(parent)
+  })
 
-    this.each(function () {
-      if (this instanceof SVG.Defs) return this
-      if (this instanceof SVG.Parent) return this.flatten(parent)
-      return this.toParent(parent)
-    })
+  // we need this so that Doc does not get removed
+  this.node.firstElementChild || this.remove()
 
-    // we need this so that SVG.Doc does not get removed
-    this.node.firstElementChild || this.remove()
+  return this
+}
 
+export function ungroup (parent) {
+  // ungroup is only possible for nested svgs and groups
+  if (!(this instanceof G || (this instanceof Doc && !this.isRoot()))) {
     return this
-  },
-  ungroup: function (parent) {
-    // ungroup is only possible for nested svgs and groups
-    if (!(this instanceof SVG.G || (this instanceof SVG.Doc && !this.isRoot()))) {
-      return this
-    }
+  }
 
-    parent = parent || this.parent(SVG.Parent)
+  parent = parent || this.parent(Parent)
 
-    this.each(function () {
-      return this.toParent(parent)
-    })
+  this.each(function () {
+    return this.toParent(parent)
+  })
 
-    // we need this so that SVG.Doc does not get removed
-    this.remove()
+  // we need this so that Doc does not get removed
+  this.remove()
 
-    return this
-  }
-})
+  return this
+}
diff --git a/src/gradiented.js b/src/gradiented.js
new file mode 100644 (file)
index 0000000..da2bc41
--- /dev/null
@@ -0,0 +1,14 @@
+// FIXME: add to runner
+import SVGNumber from './SVGNumber.js'
+
+export function from (x, y) {
+  return (this._element || this).type === 'radialGradient'
+    ? this.attr({ fx: new SVGNumber(x), fy: new SVGNumber(y) })
+    : this.attr({ x1: new SVGNumber(x), y1: new SVGNumber(y) })
+}
+
+export function to (x, y) {
+  return (this._element || this).type === 'radialGradient'
+    ? this.attr({ cx: new SVGNumber(x), cy: new SVGNumber(y) })
+    : this.attr({ x2: new SVGNumber(x), y2: new SVGNumber(y) })
+}
index c2073cf4aed5bda143c55c35be5f31bc6252e1c6..b4bddf9eef5f802ef7c83efc40332fdc2cf46ce6 100644 (file)
@@ -1,33 +1,35 @@
-/* eslint no-unused-vars: 0 */
+import {Doc, Point, Element} from './classes.js'
+import {adopt, eid, makeNode} from './tools.js'
+import {dots, reference} from './regex.js'
 
-function createElement (element, makeNested) {
-  if (element instanceof SVG.Element) return element
+export function makeInstance (element, makeNested) {
+  if (element instanceof Element) return element
 
   if (typeof element === 'object') {
-    return SVG.adopt(element)
+    return adopt(element)
   }
 
   if (element == null) {
-    return new SVG.Doc()
+    return new Doc()
   }
 
   if (typeof element === 'string' && element.charAt(0) !== '<') {
-    return SVG.adopt(document.querySelector(element))
+    return adopt(document.querySelector(element))
   }
 
-  var node = SVG.create('svg')
+  var node = makeNode('svg')
   node.innerHTML = element
 
-  element = SVG.adopt(node.firstElementChild)
+  element = adopt(node.firstElementChild)
 
   return element
 }
 
-function isNulledBox (box) {
+export function isNulledBox (box) {
   return !box.w && !box.h && !box.x && !box.y
 }
 
-function domContains (node) {
+export function domContains (node) {
   return (document.documentElement.contains || function (node) {
     // This is IE - it does not support contains() for top-level SVGs
     while (node.parentNode) {
@@ -37,12 +39,12 @@ function domContains (node) {
   }).call(document.documentElement, node)
 }
 
-function pathRegReplace (a, b, c, d) {
-  return c + d.replace(SVG.regex.dots, ' .')
+export function pathRegReplace (a, b, c, d) {
+  return c + d.replace(dots, ' .')
 }
 
 // creates deep clone of array
-function arrayClone (arr) {
+export function arrayClone (arr) {
   var clone = arr.slice(0)
   for (var i = clone.length; i--;) {
     if (Array.isArray(clone[i])) {
@@ -52,30 +54,25 @@ function arrayClone (arr) {
   return clone
 }
 
-// tests if a given element is instance of an object
-function is (el, obj) {
-  return el instanceof obj
-}
-
 // tests if a given selector matches an element
-function matches (el, selector) {
+export function matches (el, selector) {
   return (el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector).call(el, selector)
 }
 
 // Convert dash-separated-string to camelCase
-function camelCase (s) {
+export function camelCase (s) {
   return s.toLowerCase().replace(/-(.)/g, function (m, g) {
     return g.toUpperCase()
   })
 }
 
 // Capitalize first letter of a string
-function capitalize (s) {
+export function capitalize (s) {
   return s.charAt(0).toUpperCase() + s.slice(1)
 }
 
 // Ensure to six-based hex
-function fullHex (hex) {
+export function fullHex (hex) {
   return hex.length === 4
     ? [ '#',
       hex.substring(1, 2), hex.substring(1, 2),
@@ -86,13 +83,13 @@ function fullHex (hex) {
 }
 
 // Component to hex value
-function compToHex (comp) {
+export function compToHex (comp) {
   var hex = comp.toString(16)
   return hex.length === 1 ? '0' + hex : hex
 }
 
 // Calculate proportional width and height values when necessary
-function proportionalSize (element, width, height) {
+export function proportionalSize (element, width, height) {
   if (width == null || height == null) {
     var box = element.bbox()
 
@@ -110,18 +107,18 @@ function proportionalSize (element, width, height) {
 }
 
 // Map matrix array to object
-function arrayToMatrix (a) {
+export function arrayToMatrix (a) {
   return { a: a[0], b: a[1], c: a[2], d: a[3], e: a[4], f: a[5] }
 }
 
 // Add centre point to transform object
-function ensureCentre (o, target) {
+export function ensureCentre (o, target) {
   o.cx = o.cx == null ? target.bbox().cx : o.cx
   o.cy = o.cy == null ? target.bbox().cy : o.cy
 }
 
 // PathArray Helpers
-function arrayToString (a) {
+export function arrayToString (a) {
   for (var i = 0, il = a.length, s = ''; i < il; i++) {
     s += a[i][0]
 
@@ -158,21 +155,21 @@ function arrayToString (a) {
 }
 
 // Deep new id assignment
-function assignNewId (node) {
+export function assignNewId (node) {
   // do the same for SVG child nodes as well
   for (var i = node.children.length - 1; i >= 0; i--) {
     assignNewId(node.children[i])
   }
 
   if (node.id) {
-    return SVG.adopt(node).id(SVG.eid(node.nodeName))
+    return adopt(node).id(eid(node.nodeName))
   }
 
-  return SVG.adopt(node)
+  return adopt(node)
 }
 
 // Add more bounding box properties
-function fullBox (b) {
+export function fullBox (b) {
   if (b.x == null) {
     b.x = 0
     b.y = 0
@@ -191,20 +188,20 @@ function fullBox (b) {
 }
 
 // Get id from reference string
-function idFromReference (url) {
-  var m = (url || '').toString().match(SVG.regex.reference)
+export function idFromReference (url) {
+  var m = (url || '').toString().match(reference)
 
   if (m) return m[1]
 }
 
 // Create matrix array for looping
-var abcdef = 'abcdef'.split('')
+export let abcdef = 'abcdef'.split('')
 
-function closeEnough (a, b, threshold) {
+export function closeEnough (a, b, threshold) {
   return Math.abs(b - a) < (threshold || 1e-6)
 }
 
-function isMatrixLike (o) {
+export function isMatrixLike (o) {
   return (
     o.a != null ||
     o.b != null ||
@@ -216,7 +213,7 @@ function isMatrixLike (o) {
 }
 
 // TODO: Refactor this to a static function of matrix.js
-function formatTransforms (o) {
+export function formatTransforms (o) {
   // Get all of the parameters required to form the matrix
   var flipBoth = o.flip === 'both' || o.flip === true
   var flipX = o.flip && (flipBoth || o.flip === 'x') ? -1 : 1
@@ -239,16 +236,16 @@ function formatTransforms (o) {
     : flipY
   var shear = o.shear || 0
   var theta = o.rotate || o.theta || 0
-  var origin = new SVG.Point(o.origin || o.around || o.ox || o.originX, o.oy || o.originY)
+  var origin = new Point(o.origin || o.around || o.ox || o.originX, o.oy || o.originY)
   var ox = origin.x
   var oy = origin.y
-  var position = new SVG.Point(o.position || o.px || o.positionX, o.py || o.positionY)
+  var position = new Point(o.position || o.px || o.positionX, o.py || o.positionY)
   var px = position.x
   var py = position.y
-  var translate = new SVG.Point(o.translate || o.tx || o.translateX, o.ty || o.translateY)
+  var translate = new Point(o.translate || o.tx || o.translateX, o.ty || o.translateY)
   var tx = translate.x
   var ty = translate.y
-  var relative = new SVG.Point(o.relative || o.rx || o.relativeX, o.ry || o.relativeY)
+  var relative = new Point(o.relative || o.rx || o.relativeX, o.ry || o.relativeY)
   var rx = relative.x
   var ry = relative.y
 
@@ -259,7 +256,7 @@ function formatTransforms (o) {
 }
 
 // left matrix, right matrix, target matrix which is overwritten
-function matrixMultiply (l, r, o) {
+export function matrixMultiply (l, r, o) {
   // Work out the product directly
   var a = l.a * r.a + l.c * r.b
   var b = l.b * r.a + l.d * r.b
@@ -279,7 +276,7 @@ function matrixMultiply (l, r, o) {
   return o
 }
 
-function getOrigin (o, element) {
+export function getOrigin (o, element) {
   // Allow origin or around as the names
   let origin = o.origin // o.around == null ? o.origin : o.around
   let ox, oy
index 57dfa029679e90b92992a46c8b260b16c98ce15b..bc13196d79d588597065843faa5baea1655e6cdf 100644 (file)
@@ -1,7 +1,8 @@
+import Element from './Element.js'
 
-SVG.extend(SVG.Element, {
+extend(Element, {
   // Remember arbitrary data
-  remember: function (k, v) {
+  remember (k, v) {
     // remember every item in an object individually
     if (typeof arguments[0] === 'object') {
       for (var key in k) {
@@ -19,7 +20,7 @@ SVG.extend(SVG.Element, {
   },
 
   // Erase a given memory
-  forget: function () {
+  forget () {
     if (arguments.length === 0) {
       this._memory = {}
     } else {
@@ -28,10 +29,10 @@ SVG.extend(SVG.Element, {
       }
     }
     return this
-  },
+  }
 
   // Initialize or return local memory object
-  memory: function () {
+  memory () {
     return this._memory || (this._memory = {})
   }
 })
diff --git a/src/namespaces.js b/src/namespaces.js
new file mode 100644 (file)
index 0000000..3791298
--- /dev/null
@@ -0,0 +1,5 @@
+// Default namespaces
+export let ns = 'http://www.w3.org/2000/svg'
+export let xmlns = 'http://www.w3.org/2000/xmlns/'
+export let xlink = 'http://www.w3.org/1999/xlink'
+export let svgjs = 'http://svgjs.com/svgjs'
index 84c8d776da67f5e965a8d74e71782f8911c47a60..c51ad7123e5c0edbfc11c619f9220400422f70e9 100644 (file)
@@ -1,17 +1,16 @@
+import Doc from './Doc.js'
 
-SVG.parser = function () {
-  var b
-
-  if (!SVG.parser.nodes.svg.node.parentNode) {
-    b = document.body || document.documentElement
-    SVG.parser.nodes.svg.addTo(b)
+let parser = function () {
+  if (!parser.nodes.svg.node.parentNode) {
+    let b = document.body || document.documentElement
+    parser.nodes.svg.addTo(b)
   }
 
-  return SVG.parser.nodes
+  return parser.nodes
 }
 
-SVG.parser.nodes = {
-  svg: SVG().size(2, 0).css({
+parser.nodes = {
+  svg: new Doc().size(2, 0).css({
     opacity: 0,
     position: 'absolute',
     left: '-100%',
@@ -20,4 +19,6 @@ SVG.parser.nodes = {
   })
 }
 
-SVG.parser.nodes.path = SVG.parser.nodes.svg.path().node
+parser.nodes.path = parser.nodes.svg.path().node
+
+export default parser
index 6493964ea678e8c2194c6d2474166c90f8cf023f..11df4f332c6962d893f3898f6e827f338d760625 100644 (file)
@@ -1,25 +1,25 @@
-// unify all point to point elements
-SVG.extend([SVG.Line, SVG.Polyline, SVG.Polygon], {
-  // Define morphable array
-  MorphArray: SVG.PointArray,
-  // Move by left top corner over x-axis
-  x: function (x) {
-    return x == null ? this.bbox().x : this.move(x, this.bbox().y)
-  },
-  // Move by left top corner over y-axis
-  y: function (y) {
-    return y == null ? this.bbox().y : this.move(this.bbox().x, y)
-  },
-  // Set width of element
-  width: function (width) {
-    var b = this.bbox()
+import PointArray from './PointArray.js'
 
-    return width == null ? b.width : this.size(width, b.height)
-  },
-  // Set height of element
-  height: function (height) {
-    var b = this.bbox()
+export let MorphArray =  PointArray
 
-    return height == null ? b.height : this.size(b.width, height)
-  }
-})
+// Move by left top corner over x-axis
+export function x (x) {
+  return x == null ? this.bbox().x : this.move(x, this.bbox().y)
+}
+
+// Move by left top corner over y-axis
+export function y (y) {
+  return y == null ? this.bbox().y : this.move(this.bbox().x, y)
+}
+
+// Set width of element
+export function width (width) {
+  let b = this.bbox()
+  return width == null ? b.width : this.size(width, b.height)
+}
+
+// Set height of element
+export function height (height) {
+  let b = this.bbox()
+  return height == null ? b.height : this.size(b.width, height)
+}
index 5a3e3ebfc4d719f10a1f5dac1fa029a9ae160389..5477b81aaaabfe7ec1b63b807bf34d3d2097d9bd 100644 (file)
@@ -1,61 +1,58 @@
-// Storage for regular expressions
-SVG.regex = {
-  // Parse unit value
-  numberAndUnit: /^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i,
+// Parse unit value
+export let numberAndUnit = /^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i
 
-  // Parse hex value
-  hex: /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,
+// Parse hex value
+export let hex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i
 
-  // Parse rgb value
-  rgb: /rgb\((\d+),(\d+),(\d+)\)/,
+// Parse rgb value
+export let rgb = /rgb\((\d+),(\d+),(\d+)\)/
 
-  // Parse reference id
-  reference: /#([a-z0-9\-_]+)/i,
+// Parse reference id
+export let reference = /#([a-z0-9\-_]+)/i
 
-  // splits a transformation chain
-  transforms: /\)\s*,?\s*/,
+// splits a transformation chain
+export let transforms = /\)\s*,?\s*/
 
-  // Whitespace
-  whitespace: /\s/g,
+// Whitespace
+export let whitespace = /\s/g
 
-  // Test hex value
-  isHex: /^#[a-f0-9]{3,6}$/i,
+// Test hex value
+export let isHex = /^#[a-f0-9]{3,6}$/i
 
-  // Test rgb value
-  isRgb: /^rgb\(/,
+// Test rgb value
+export let isRgb = /^rgb\(/
 
-  // Test css declaration
-  isCss: /[^:]+:[^;]+;?/,
+// Test css declaration
+export let isCss = /[^:]+:[^;]+;?/
 
-  // Test for blank string
-  isBlank: /^(\s+)?$/,
+// Test for blank string
+export let isBlank = /^(\s+)?$/
 
-  // Test for numeric string
-  isNumber: /^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,
+// Test for numeric string
+export let isNumber = /^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i
 
-  // Test for percent value
-  isPercent: /^-?[\d.]+%$/,
+// Test for percent value
+export let isPercent = /^-?[\d.]+%$/
 
-  // Test for image url
-  isImage: /\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i,
+// Test for image url
+export let isImage = /\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i
 
-  // split at whitespace and comma
-  delimiter: /[\s,]+/,
+// split at whitespace and comma
+export let delimiter = /[\s,]+/
 
-  // The following regex are used to parse the d attribute of a path
+// The following regex are used to parse the d attribute of a path
 
-  // Matches all hyphens which are not after an exponent
-  hyphen: /([^e])-/gi,
+// Matches all hyphens which are not after an exponent
+export let hyphen = /([^e])-/gi
 
-  // Replaces and tests for all path letters
-  pathLetters: /[MLHVCSQTAZ]/gi,
+// Replaces and tests for all path letters
+export let pathLetters = /[MLHVCSQTAZ]/gi
 
-  // yes we need this one, too
-  isPathLetter: /[MLHVCSQTAZ]/i,
+// yes we need this one, too
+export let isPathLetter = /[MLHVCSQTAZ]/i
 
-  // matches 0.154.23.45
-  numbersWithDots: /((\d?\.\d+(?:e[+-]?\d+)?)((?:\.\d+(?:e[+-]?\d+)?)+))+/gi,
+// matches 0.154.23.45
+export let numbersWithDots = /((\d?\.\d+(?:e[+-]?\d+)?)((?:\.\d+(?:e[+-]?\d+)?)+))+/gi
 
-  // matches .
-  dots: /\./g
-}
+// matches .
+export let dots = /\./g
index b4ea05f2e204f9fee5b02bf8bf70ac62a27fc40a..a148b56227c310b8526e215a8836976809bb0428 100644 (file)
@@ -1,31 +1,46 @@
-/* global idFromReference */
+import {idFromReference} from './helpers.js'
+import {map} from './utils.js'
+import {adopt} from './tools.js'
 
-// Method for getting an element by id
-SVG.get = function (id) {
-  var node = document.getElementById(idFromReference(id) || id)
-  return SVG.adopt(node)
-}
-
-// Select elements by query string
-SVG.select = function (query, parent) {
-  return SVG.utils.map((parent || document).querySelectorAll(query), function (node) {
-    return SVG.adopt(node)
-  })
-}
+// // Method for getting an element by id
+// SVG.get = function (id) {
+//   var node = document.getElementById(idFromReference(id) || id)
+//   return SVG.adopt(node)
+// }
+//
+// // Select elements by query string
+// SVG.select = function (query, parent) {
+//   return SVG.utils.map((parent || document).querySelectorAll(query), function (node) {
+//     return SVG.adopt(node)
+//   })
+// }
+//
+// 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.$$ = function (query, parent) {
-  return SVG.utils.map((parent || document).querySelectorAll(query), function (node) {
-    return SVG.adopt(node)
+export default function find (query, parent) {
+  return utils.map((parent || document).querySelectorAll(query), function (node) {
+    return adopt(node)
   })
 }
 
-SVG.$ = function (query, parent) {
-  return SVG.adopt((parent || document).querySelector(query))
-}
-
-SVG.extend(SVG.Parent, {
+export let mixings = {
   // Scoped select method
   select: function (query) {
-    return SVG.select(query, this.node)
+    return find(query, this.node)
   }
-})
+}
+
+// extend(SVG.Parent, {
+//   // Scoped select method
+//   select: function (query) {
+//     return SVG.select(query, this.node)
+//   }
+// })
diff --git a/src/stop.js b/src/stop.js
new file mode 100644 (file)
index 0000000..6bce999
--- /dev/null
@@ -0,0 +1,27 @@
+import Element from './Element.js'
+import SVGNumber from './SVGNumber.js'
+import {nodeOrNew} from './tools.js'
+
+export default class Stop extends Element {
+  constructor (node) {
+    super(nodeOrNew('stop', node))
+  }
+
+  // add color stops
+  update (o) {
+    if (typeof o === 'number' || o instanceof SVGNumber) {
+      o = {
+        offset: arguments[0],
+        color: arguments[1],
+        opacity: arguments[2]
+      }
+    }
+
+    // set attributes
+    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 SVGNumber(o.offset))
+
+    return this
+  }
+}
index ad991afa17cae7cfb28c792712352e61fec9c784..e33fb10d1b4435371e571c7c92d7adc39d282cec 100644 (file)
@@ -1,3 +1,5 @@
+import {Color, Element, Runner} from './classes.js'
+
 // Define list of available attributes for stroke and fill
 var sugar = {
   stroke: ['color', 'width', 'opacity', 'linecap', 'linejoin', 'miterlimit', 'dasharray', 'dashoffset'],
@@ -16,7 +18,7 @@ var sugar = {
     if (typeof o === 'undefined') {
       return this
     }
-    if (typeof o === 'string' || SVG.Color.isRgb(o) || (o && typeof o.fill === 'function')) {
+    if (typeof o === 'string' || Color.isRgb(o) || (o && typeof o.fill === 'function')) {
       this.attr(m, o)
     } else {
       // set all attributes from sugar.fill and sugar.stroke list
@@ -30,19 +32,19 @@ var sugar = {
     return this
   }
 
-  SVG.extend([SVG.Element, SVG.Timeline], extension)
+  extend([Element, Runner], extension)
 })
 
-SVG.extend([SVG.Element, SVG.Timeline], {
+extend([Element, Runner], {
   // Let the user set the matrix directly
   matrix: function (mat, b, c, d, e, f) {
     // Act as a getter
     if (mat == null) {
-      return new SVG.Matrix(this)
+      return new Matrix(this)
     }
 
     // Act as a setter, the user can pass a matrix or a set of numbers
-    return this.attr('transform', new SVG.Matrix(mat, b, c, d, e, f))
+    return this.attr('transform', new Matrix(mat, b, c, d, e, f))
   },
 
   // Map rotation to transform
@@ -98,12 +100,12 @@ SVG.extend([SVG.Element, SVG.Timeline], {
 
   // Relative move over x axis
   dx: function (x) {
-    return this.x(new SVG.Number(x).plus(this instanceof SVG.Timeline ? 0 : this.x()), true)
+    return this.x(new SVGNumber(x).plus(this instanceof Runner ? 0 : this.x()), true)
   },
 
   // Relative move over y axis
   dy: function (y) {
-    return this.y(new SVG.Number(y).plus(this instanceof SVG.Timeline ? 0 : this.y()), true)
+    return this.y(new SVGNumber(y).plus(this instanceof Runner ? 0 : this.y()), true)
   },
 
   // Relative move over x and y axes
@@ -112,28 +114,28 @@ SVG.extend([SVG.Element, SVG.Timeline], {
   }
 })
 
-SVG.extend([SVG.Rect, SVG.Ellipse, SVG.Circle, SVG.Gradient, SVG.Timeline], {
+extend([Rect, Ellipse, Circle, Gradient, Runner], {
   // Add x and y radius
   radius: function (x, y) {
     var type = (this._target || this).type
     return type === 'radialGradient' || type === 'radialGradient'
-      ? this.attr('r', new SVG.Number(x))
+      ? this.attr('r', new SVGNumber(x))
       : this.rx(x).ry(y == null ? x : y)
   }
 })
 
-SVG.extend(SVG.Path, {
+extend(Path, {
   // Get path length
   length: function () {
     return this.node.getTotalLength()
   },
   // Get point at length
   pointAt: function (length) {
-    return new SVG.Point(this.node.getPointAtLength(length))
+    return new Point(this.node.getPointAtLength(length))
   }
 })
 
-SVG.extend([SVG.Parent, SVG.Text, SVG.Tspan, SVG.Timeline], {
+extend([Parent, Text, Tspan, Runner], {
   // Set font
   font: function (a, v) {
     if (typeof a === 'object') {
index bf02df01b0da5cd85d3f8e9317a460ea03e710d4..6f8fd2dedc4a4104ab28b8f0427d42f657bf94c6 100644 (file)
-/* global createElement, capitalize */
-/* eslint-disable new-cap */
+import {makeInstance} from './helpers.js'
+import * as Classes from './classes.js'
+import * as tools from './tools.js'
 
 // The main wrapping element
-var SVG = window.SVG = function (element) {
-  if (SVG.supported) {
-    element = createElement(element)
-    return element
-  }
+export default function SVG (element) {
+  return makeInstance(element)
 }
 
-// Svg must be supported if we reached this stage
-SVG.supported = true
-
-// Default namespaces
-SVG.ns = 'http://www.w3.org/2000/svg'
-SVG.xmlns = 'http://www.w3.org/2000/xmlns/'
-SVG.xlink = 'http://www.w3.org/1999/xlink'
-SVG.svgjs = 'http://svgjs.com/svgjs'
-
-// Element id sequence
-SVG.did = 1000
-
-// Get next named element id
-SVG.eid = function (name) {
-  return 'Svgjs' + capitalize(name) + (SVG.did++)
-}
-
-// Method for element creation
-SVG.create = function (name) {
-  // create element
-  return document.createElementNS(this.ns, name)
-}
-
-// Method for extending objects
-SVG.extend = function (modules, methods) {
-  var key, i
-
-  modules = Array.isArray(modules) ? modules : [modules]
-
-  for (i = modules.length - 1; i >= 0; i--) {
-    if (modules[i]) {
-      for (key in methods) {
-        modules[i].prototype[key] = methods[key]
-      }
-    }
-  }
-}
-
-// Invent new element
-SVG.invent = function (config) {
-  // Create element initializer
-  var initializer = typeof config.create === 'function' ? config.create
-    : function (node) {
-      config.inherit.call(this, node || SVG.create(config.create))
-    }
-
-  // Inherit prototype
-  if (config.inherit) {
-    initializer.prototype = new config.inherit()
-    initializer.prototype.constructor = initializer
-  }
-
-  // Extend with methods
-  if (config.extend) {
-    SVG.extend(initializer, config.extend)
-  }
-
-  // Attach construct method to parent
-  if (config.construct) { SVG.extend(config.parent || SVG.Container, config.construct) }
-
-  return initializer
-}
-
-// Adopt existing svg elements
-SVG.adopt = function (node) {
-  // check for presence of node
-  if (!node) return null
-
-  // make sure a node isn't already adopted
-  if (node.instance instanceof SVG.Element) return node.instance
-
-  if (!(node instanceof window.SVGElement)) {
-    return new SVG.HtmlNode(node)
-  }
-
-  // initialize variables
-  var element
-
-  // adopt with element-specific settings
-  if (node.nodeName === 'svg') {
-    element = new SVG.Doc(node)
-  } else if (node.nodeName === 'linearGradient' || node.nodeName === 'radialGradient') {
-    element = new SVG.Gradient(node)
-  } else if (SVG[capitalize(node.nodeName)]) {
-    element = new SVG[capitalize(node.nodeName)](node)
-  } else {
-    element = new SVG.Parent(node)
-  }
-
-  return element
-}
+Object.assign(SVG, Classes)
+Object.assign(SVG, tools)
diff --git a/src/tools.js b/src/tools.js
new file mode 100644 (file)
index 0000000..e77d653
--- /dev/null
@@ -0,0 +1,94 @@
+import {ns} from './namespaces.js'
+import {Container, Element, HtmlNode, Doc, Gradient, Parent} from './classes.js'
+
+// Element id sequence
+let did = 1000
+
+// Get next named element id
+export function eid (name) {
+  return 'Svgjs' + capitalize(name) + (did++)
+}
+
+export function nodeOrNew (name, node) {
+  return node || makeNode(name)
+}
+
+// Method for element creation
+export function makeNode (name) {
+  // create element
+  return document.createElementNS(ns, name)
+}
+
+// Method for extending objects
+export function extend (modules, methods) {
+  var key, i
+
+  modules = Array.isArray(modules) ? modules : [modules]
+
+  for (i = modules.length - 1; i >= 0; i--) {
+    if (modules[i]) {
+      for (key in methods) {
+        modules[i].prototype[key] = methods[key]
+      }
+    }
+  }
+}
+
+// FIXME: enhanced constructors here
+export function addFactory (modules, methods) {
+  extend(modules, methods)
+}
+
+// Invent new element
+export function invent (config) {
+  // Create element initializer
+  var initializer = typeof config.create === 'function' ? config.create
+    : function (node) {
+      config.inherit.call(this, node || makeNode(config.create))
+    }
+
+  // Inherit prototype
+  if (config.inherit) {
+    initializer.prototype = new config.inherit()
+    initializer.prototype.constructor = initializer
+  }
+
+  // Extend with methods
+  if (config.extend) {
+    extend(initializer, config.extend)
+  }
+
+  // Attach construct method to parent
+  if (config.construct) { extend(config.parent || Container, config.construct) }
+
+  return initializer
+}
+
+// Adopt existing svg elements
+export function adopt (node) {
+  // check for presence of node
+  if (!node) return null
+
+  // make sure a node isn't already adopted
+  if (node.instance instanceof Element) return node.instance
+
+  if (!(node instanceof window.SVGElement)) {
+    return new HtmlNode(node)
+  }
+
+  // initialize variables
+  var element
+
+  // adopt with element-specific settings
+  if (node.nodeName === 'svg') {
+    element = new Doc(node)
+  } else if (node.nodeName === 'linearGradient' || node.nodeName === 'radialGradient') {
+    element = new Gradient(node)
+  } else if (SVG[capitalize(node.nodeName)]) {
+    element = new SVG[capitalize(node.nodeName)](node)
+  } else {
+    element = new Parent(node)
+  }
+
+  return element
+}
index 96c0aec524fbfa7fd0e606f59e07af776a377623..d6516a2a43959aef162a61eec11ce1cc93784888 100644 (file)
@@ -1,70 +1,67 @@
-/* global arrayToMatrix getOrigin isMatrixLike */
+import {arrayToMatrix, getOrigin, isMatrixLike} from './helpers.js'
+import Matrix from './Matrix.js'
+import {delimiter, transforms} from './regex.js'
 
-SVG.extend(SVG.Element, {
-  // Reset all transformations
-  untransform: function () {
-    return this.attr('transform', null)
-  },
+// Reset all transformations
+export function untransform () {
+  return this.attr('transform', null)
+}
 
-  // merge the whole transformation chain into one matrix and returns it
-  matrixify: function () {
-    var matrix = (this.attr('transform') || '')
-      // split transformations
-      .split(SVG.regex.transforms).slice(0, -1).map(function (str) {
-        // generate key => value pairs
-        var kv = str.trim().split('(')
-        return [kv[0],
-          kv[1].split(SVG.regex.delimiter)
-            .map(function (str) { return parseFloat(str) })
-        ]
-      })
-      .reverse()
-      // merge every transformation into one matrix
-      .reduce(function (matrix, transform) {
-        if (transform[0] === 'matrix') {
-          return matrix.lmultiply(arrayToMatrix(transform[1]))
-        }
-        return matrix[transform[0]].apply(matrix, transform[1])
-      }, new SVG.Matrix())
+// merge the whole transformation chain into one matrix and returns it
+export function matrixify () {
+  var matrix = (this.attr('transform') || '')
+    // split transformations
+    .split(transforms).slice(0, -1).map(function (str) {
+      // generate key => value pairs
+      var kv = str.trim().split('(')
+      return [kv[0],
+        kv[1].split(delimiter)
+          .map(function (str) { return parseFloat(str) })
+      ]
+    })
+    .reverse()
+    // merge every transformation into one matrix
+    .reduce(function (matrix, transform) {
+      if (transform[0] === 'matrix') {
+        return matrix.lmultiply(arrayToMatrix(transform[1]))
+      }
+      return matrix[transform[0]].apply(matrix, transform[1])
+    }, new Matrix())
 
-    return matrix
-  },
+  return matrix
+}
 
-  // add an element to another parent without changing the visual representation on the screen
-  toParent: function (parent) {
-    if (this === parent) return this
-    var ctm = this.screenCTM()
-    var pCtm = parent.screenCTM().inverse()
+// add an element to another parent without changing the visual representation on the screen
+export function toParent (parent) {
+  if (this === parent) return this
+  var ctm = this.screenCTM()
+  var pCtm = parent.screenCTM().inverse()
 
-    this.addTo(parent).untransform().transform(pCtm.multiply(ctm))
+  this.addTo(parent).untransform().transform(pCtm.multiply(ctm))
 
-    return this
-  },
+  return this
+}
 
-  // same as above with parent equals root-svg
-  toDoc: function () {
-    return this.toParent(this.doc())
-  }
-})
-
-SVG.extend(SVG.Element, {
-
-  // Add transformations
-  transform: function (o, relative) {
-    // Act as a getter if no object was passed
-    if (o == null || typeof o === 'string') {
-      var decomposed = new SVG.Matrix(this).decompose()
-      return decomposed[o] || decomposed
-    }
+// same as above with parent equals root-svg
+export function toDoc () {
+  return this.toParent(this.doc())
+}
 
-    if (!isMatrixLike(o)) {
-      // Set the origin according to the defined transform
-      o = {...o, origin: getOrigin(o, this)}
-    }
+// Add transformations
+export function transform (o, relative) {
+  // Act as a getter if no object was passed
+  if (o == null || typeof o === 'string') {
+    var decomposed = new Matrix(this).decompose()
+    return decomposed[o] || decomposed
+  }
 
-    // The user can pass a boolean, an SVG.Element or an SVG.Matrix or nothing
-    var cleanRelative = relative === true ? this : (relative || false)
-    var result = new SVG.Matrix(cleanRelative).transform(o)
-    return this.attr('transform', result)
+  if (!isMatrixLike(o)) {
+    // Set the origin according to the defined transform
+    o = {...o, origin: getOrigin(o, this)}
   }
-})
+
+  // The user can pass a boolean, an Element or an Matrix or nothing
+  var cleanRelative = relative === true ? this : (relative || false)
+  var result = new Matrix(cleanRelative).transform(o)
+  return this.attr('transform', result)
+}
index 2b8e65e2fe644b72d0b03e99f5f273949936005e..9cf1711b8a9ab393b6a52611b7dd2dd3efc9ed59 100644 (file)
@@ -1,25 +1,21 @@
+import {Shape, Container} from './classes.js'
+import {xlink} from './namespaces.js'
 
-SVG.Use = SVG.invent({
-  // Initialize node
-  create: 'use',
-
-  // Inherit from
-  inherit: SVG.Shape,
+export default class Use extends Shape {
+  constructor (node) {
+    super(nodeOrNew('use', node))
+  }
 
-  // Add class methods
-  extend: {
-    // Use element as a reference
-    element: function (element, file) {
-      // Set lined element
-      return this.attr('href', (file || '') + '#' + element, SVG.xlink)
-    }
-  },
+  // Use element as a reference
+  element (element, file) {
+    // Set lined element
+    return this.attr('href', (file || '') + '#' + element, xlink)
+  }
+}
 
-  // Add parent method
-  construct: {
-    // Create a use element
-    use: function (element, file) {
-      return this.put(new SVG.Use()).element(element, file)
-    }
+addFactory(Container, {
+  // Create a use element
+  use: function (element, file) {
+    return this.put(new Use()).element(element, file)
   }
 })
diff --git a/src/utils.js b/src/utils.js
new file mode 100644 (file)
index 0000000..c7407de
--- /dev/null
@@ -0,0 +1,40 @@
+
+// Map function
+export function map (array, block) {
+  var i
+  var il = array.length
+  var result = []
+
+  for (i = 0; i < il; i++) {
+    result.push(block(array[i]))
+  }
+
+  return result
+}
+
+// Filter function
+export function filter (array, block) {
+  var i
+  var il = array.length
+  var result = []
+
+  for (i = 0; i < il; i++) {
+    if (block(array[i])) { result.push(array[i]) }
+  }
+
+  return result
+}
+
+// Degrees to radians
+export function radians (d) {
+  return d % 360 * Math.PI / 180
+}
+
+// Radians to degrees
+export function degrees (r) {
+  return r * 180 / Math.PI % 360
+}
+
+export function filterSVGElements (nodes) {
+  return this.filter(nodes, function (el) { return el instanceof window.SVGElement })
+}