## Creating custom elements

JointJS has built-in elements for basic shapes. These shapes are all in the `joint.shapes.basic` namespace and consist of `joint.shapes.basic.Rect`, `joint.shapes.basic.Circle`, `joint.shapes.basic.Text` and `joint.shapes.basic.Image`. Additionally, JointJS has plugins that contain shapes and links for elements of some well-known diagrams. Though there is plenty of shapes to choose from, you might be missing one and want to create your own.

Creating new shapes is quite simple though you need some basic knowledge of SVG elements. The most important SVG elements you should know about are `rect`, `text`, `circle`, `ellipse`, `image` and `path`. Their thorough description together with examples can be found e.g. on MDN. Combining these, you can make basically any 2D shape you like.

As it was mentioned, custom elements are created by combining SVG tags. Many times, it is useful to position one element relatively to another. Imagine a basic situation where you want to have a rectangle element and a text element that should always be in the center of the rectangle. Unfortunately, SVG does not provide a facility to do that. Therefore, JointJS introduces special attributes that are helpful for positioning elements relatively to each other. For an example, let's explore how the `joint.shapes.basic.Rect` element is defined:

    joint.shapes.basic.Rect = joint.shapes.basic.Generic.extend({
        markup: '<g class="rotatable"><g class="scalable"><rect/></g><text/></g>',

        defaults: joint.util.deepSupplement({
            type: 'basic.Rect',
            attrs: {
                'rect': { fill: 'white', stroke: 'black', 'follow-scale': true, width: 80, height: 40 },
                'text': { 'font-size': 14, 'ref-x': .5, 'ref-y': .5, ref: 'rect', 'y-alignment': 'middle', 'x-alignment': 'middle' }
            }
        }, joint.shapes.basic.Generic.prototype.defaults)
    });

As you can see, the SVG tags are stored in a property `markup`. This property contains an SVG template for the `joint.shapes.basic.Rect` element. There are two important SVG groups in the markup that JointJS understands. The first one is the one with the class `"rotatable"`. All elements in this group will get rotated when the joint.dia.Element.rotate() method is called. The other group is `"scalable"`. All elements in this group will get scaled when the joint.dia.Element.resize() method is called.

All the positioning and presentation definitions are then stored as usual in the `attrs` object. Notice the special attributes `ref-x`, `ref-y`, `ref`, `x-alignment` and `y-alignment`. `ref-x` and `ref-y` determine the position of the `text` SVG element relative to an element referenced to by the selector stored in the `ref` attribute. In our case, the `text` element is positioned 50% in the x-axis and 50% in the y-axis relative to the `rect` element, i.e. in the center of the rectangle. `x-alignment === 'middle'` and `y-alignment === 'middle'` causes the text to center itself around its x-axis and y-axis. If we didn't do that, only the left-corner of the text element would be in the center of the rectangle but not the whole text.

Notice that in this case, we don't want the text to scale, only the rectangle (that's why the text is not inside the "scalable" group in the markup). But because we set the relative positioning attributes on the text, the text will move in order to put itself to the center of the rectangle even though the center moved due to the scale operation on the rectangle. Isn't this nice?

SVG + JointJS relative positioning attributes make it easy to create custom elements in a declarative fashion. It just needs a little bit of practice and try-fail loops.

Browse through the menu on the left to see some common techniques that you might find useful in your applications.