Extending

Due to the Object Oriented nature of SVG.js, objects/prototypes can be extended on any level. The invent() and extend()methods provide a convenient way to implement your own functionality.


SVG.invent()

Creating your own custom elements with SVG.js is a piece of cake thanks to the SVG.invent function. For the sake of this example, lets "invent" a shape. We want a rect with rounded corners that are always proportional to the height of the element. The new shape lives in the SVG namespace and is called Rounded. Here is how we achieve that.

SVG.Rounded = SVG.invent({
  // Define the type of element that should be created
  create: 'rect'

  // Specify from which existing class this shape inherits
, inherit: SVG.Shape

  // Add custom methods to invented shape
, extend: {
    // Create method to proportionally scale the rounded corners
    size: function(width, height) {
      return this.attr({
        width:  width
      , height: height
      , rx:     height / 5
      , ry:     height / 5
      })
    }
  }

  // Add method to parent elements
, construct: {
    // Create a rounded element
    rounded: function(width, height) {
      return this.put(new SVG.Rounded).size(width, height)
    }

  }
})

To create the element in your drawing:

var rounded = draw.rounded(200, 100)

That's it, the invention is now ready to be used!

Accepted values

The SVG.invent() function always expects an object. The object can have the following configuration values.

- create

required

Can be either a string with the node name (e.g. rect, ellipse, ...) or a custom initializer function.

- inherit

optional but recommended
defaults to SVG.Element

The desired SVG.js class to inherit from (e.g. SVG.Shape, SVG.Element, SVG.Container, SVG.Rect, ...).

- extend

optional

An object with the methods that should be applied to the element's prototype.

- construct

optional

An object with the methods to create the element on the parent element.

- parent

optional
defaults to SVG.Container

An SVG.js parent class on which the methods in the passed construct object should be available.

Usage notes

It should be emphasised that in the configuration object passed to SVG.invent():

  • construct does not supply constructors, but rather methods that are likely to call constructors;
  • create specifies the constructor for the type you are defining, and is not analogous to Object.create().

When defining specialised svg elements (such as SVG.Rounded in the example above), the function specified by create needs to do all the work of adding the element to the DOM for the svg document and connecting the DOM node to the SVG.js interface. All this is done automatically when the value of create is a string identifying an element type. If needed, see the source for a sense of how to do it explicitly.

Though the defaults are geared toward creating svg elements for the SVG.js framework, SVG.invent() can be used as a generalised function for defining types in Javascript. When used in this more general way, the function supplied as a value for create should be written as an ordinary JS constructor. (Indeed, the function is simply returned as the constructor for your newly defined type.)

Svg.js uses the SVG.invent() function to create all internal elements. A look at the source will show how this function is used in various ways.


SVG.extend()

SVG.js has a modular structure. It is very easy to add your own methods at different levels. Let's say we want to add a method to all shape types then we would add our method to SVG.Shape:

SVG.extend(SVG.Shape, {
  paintRed: function() {
    return this.fill('red')
  }
})

Now all shapes will have the paintRed() method available. Say we want to have the paintRed() method on an ellipse apply a slightly different colour:

SVG.extend(SVG.Ellipse, {
  paintRed: function() {
    return this.fill('orangered')
  }
})

The complete inheritance stack for SVG.Ellipse is:

SVG.Element > SVG.Shape > SVG.Ellipse

The SVG document can be extended by using:

SVG.extend(SVG.Doc, {
  paintAllPink: function() {
    this.each(function() {
      this.fill('pink')
    })
  }
})

You can also extend multiple elements at once:

SVG.extend(SVG.Ellipse, SVG.Path, SVG.Polygon, {
  paintRed: function() {
    return this.fill('orangered')
  }
})
Fork me on GitHub