Elements

In the first part of the tutorial, we saw a working example of a simple JointJS application:

In the previous section, we created a graph and learned how to modify the appearance of the paper:

In this section, we will learn how to create graph elements and how to change their appearance. This is an introduction to elements as they appear in the Hello, World! application; more advanced topics are covered later in the tutorial series. We will continue with the code we modified in the previous section:

<!DOCTYPE html>
<html>
<body>
    <!-- content -->
    <div id="myholder"></div>

    <!-- dependencies -->
    <script src="node_modules/@joint/core/dist/joint.js"></script>

    <!-- code -->
    <script type="text/javascript">

        var namespace = joint.shapes;

        var graph = new joint.dia.Graph({}, { cellNamespace: namespace });

        var paper = new joint.dia.Paper({
            el: document.getElementById('myholder'),
            model: graph,
            width: 600,
            height: 100,
            gridSize: 10,
            drawGrid: true,
            background: {
                color: 'rgba(0, 255, 0, 0.3)'
            },
            cellViewNamespace: namespace
        });

        var rect = new joint.shapes.standard.Rectangle();
        rect.position(100, 30);
        rect.resize(100, 40);
        rect.attr({
            body: {
                fill: 'blue'
            },
            label: {
                text: 'Hello',
                fill: 'white'
            }
        });
        rect.addTo(graph);

        var rect2 = rect.clone();
        rect2.translate(300, 0);
        rect2.attr('label/text', 'World!');
        rect2.addTo(graph);

        var link = new joint.shapes.standard.Link();
        link.source(rect);
        link.target(rect2);
        link.addTo(graph);

    </script>
</body>
</html>

The code illustrates the basic idea of working with elements:

In our case, the two elements are instances of joint.shapes.standard.Rectangle. The standard shape library contains many more ready-made element definitions (e.g. Ellipse, Embedded Image, Cylinder...) that can be used in your document. Moreover, advanced users may supply their own element definitions instead, by extending the basic joint.dia.Element class.

Our demo showcases some of the most important Element methods:

Element Styling

Visually, the most important function is the one that changes element styling:

When element.attr() is called with one object as argument, the keys of the object are selectors that correspond to SVGElements of the shape's markup; each of those can have one or more attributes defined alongside the value to be set. If you only need to change one value, you can also call element.attr() with two arguments; the first is the path of the attribute in the form 'selector/attribute' and the second is the value to be assigned.

If you are completely new to SVG, you may want to have a look at, for example, the Fills and Strokes tutorial on MDN. JointJS is able to handle all standard SVG attributes, however, please note that we strongly encourage everyone to use camelCase versions of attribute names for consistency and in order to avoid the need for quotation marks in attribute name keys. In addition, JointJS provides an extensive set of non-standard special JointJS attributes; these allow you to specify attributes relatively to other shape selectors, among other things. Special attributes are discussed in detail later in the tutorial.

The joint.shapes.standard.Rectangle shape used in our example has two selectors defined: body (the <rect> SVGElement itself), and label (the <text> SVGElement inside the shape). Other element shapes have their own selector names (although consistency was preserved where applicable, e.g. with body); please refer to the joint.shapes.standard documentation for detailed information.

In the case of the rect element, we can see that the body selector is assigned a fill color attribute, while the label selector also has its text content set to 'Hello' (via a JointJS special attribute).

rect.attr({
    body: { // selector for the <rect> SVGElement
        fill: 'blue'
    },
    label: { // selector for the <text> SVGElement
        text: 'Hello',
        fill: 'white'
    }
});

In the case of the rect2 element, we are assigning the value 'World!' to 'label/text'. Here label is the selector for the <text> SVGElement; text is the attribute we want to modify.

rect2.attr('label/text', 'World!');

Note that this is equivalent to calling:

rect2.attr('label', {
    text: 'World!'
});

The same effect can also be achieved by passing a single object argument to rect2.attr():

rect2.attr({
    label: {
        text: 'World!'
    }
});

Example

Now let us use element.attr() to change the look of our elements:

<!DOCTYPE html>
<html>
<body>
    <!-- content -->
    <div id="myholder"></div>

    <!-- dependencies -->
    <script src="node_modules/@joint/core/dist/joint.js"></script>

    <!-- code -->
    <script type="text/javascript">

        var namespace = joint.shapes;

        var graph = new joint.dia.Graph({}, { cellNamespace: namespace });

        var paper = new joint.dia.Paper({
            el: document.getElementById('myholder'),
            model: graph,
            width: 600,
            height: 300, // height had to be increased
            gridSize: 10,
            drawGrid: true,
            background: {
                color: 'rgba(0, 255, 0, 0.3)'
            },
            cellViewNamespace: namespace
        });

        var rect = new joint.shapes.standard.Rectangle();
        rect.position(100, 30);
        rect.resize(100, 40);
        rect.attr({
            body: {
                fill: 'blue'
            },
            label: {
                text: 'Hello',
                fill: 'white'
            }
        });
        rect.addTo(graph);

        var rect2 = new joint.shapes.standard.Rectangle();
        rect2.position(400, 30);
        rect2.resize(100, 40);
        rect2.attr({
            body: {
                fill: '#2C3E50',
                rx: 5,
                ry: 5,
                strokeWidth: 2
            },
            label: {
                text: 'World!',
                fill: '#3498DB',
                fontSize: 18,
                fontWeight: 'bold',
                fontVariant: 'small-caps'
            }
        });
        rect2.addTo(graph);

        var link = new joint.shapes.standard.Link();
        link.source(rect);
        link.target(rect2);
        link.addTo(graph);

        var rect3 = new joint.shapes.standard.Rectangle();
        rect3.position(100, 130);
        rect3.resize(100, 40);
        rect3.attr({
            body: {
                fill: '#E74C3C',
                rx: 20,
                ry: 20,
                strokeWidth: 0
            },
            label: {
                text: 'Hello',
                fill: '#ECF0F1',
                fontSize: 11,
                fontVariant: 'small-caps'
            }
        });
        rect3.addTo(graph);

        var rect4 = new joint.shapes.standard.Rectangle();
        rect4.position(400, 130);
        rect4.resize(100, 40);
        rect4.attr({
            body: {
                fill: '#8E44AD',
                strokeWidth: 0
            },
            label: {
                text: 'World!',
                fill: 'white',
                fontSize: 13
            }
        });
        rect4.addTo(graph);

        var link2 = new joint.shapes.standard.Link();
        link2.source(rect3);
        link2.target(rect4);
        link2.addTo(graph);

        var rect5 = new joint.shapes.standard.Rectangle();
        rect5.position(100, 230);
        rect5.resize(100, 40);
        rect5.attr({
            body: {
                fill: '#2ECC71',
                strokeDasharray: '10,2'
            },
            label: {
                text: 'Hello',
                fill: 'black',
                fontSize: 13
            }
        });
        rect5.addTo(graph);

        var rect6 = new joint.shapes.standard.Rectangle();
        rect6.position(400, 230);
        rect6.resize(100, 40);
        rect6.attr({
            body: {
                fill: '#F39C12',
                rx: 20,
                ry: 20,
                strokeDasharray: '1,1'
            },
            label: {
                text: 'World!',
                fill: 'gray',
                fontSize: 18,
                fontWeight: 'bold',
                fontVariant: 'small-caps',
                textShadow: '1px 1px 1px black'
            }
        });
        rect6.addTo(graph);

        var link3 = new joint.shapes.standard.Link();
        link3.source(rect5);
        link3.target(rect6);
        link3.addTo(graph);

    </script>
</body>
</html>

JointJS source code: elements.js

The Filters and Gradients tutorial illustrates some more advanced methods of SVG styling when applied to elements.

We now know how to change the appearance of our elements.

The next step is to learn how to work with links.