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.position()
- sets the position of the origin of the element (the top-left corner), relative to the paper's
coordinate system (taking into account paper scaling and other transformations).element.resize()
- sets the dimensions of the element.element.clone()
- clones an existing element, including its position, dimensions, and attributes (attributes are
explained in more detail below).element.translate()
- moves the element by the specified distance along the two coordinate axes.
There are methods to
scale and
rotate elements, too.element.addTo()
- adds the element to a graph so it can be rendered.
Visually, the most important function is the one that changes element styling:
element.attr()
- programmatically assigns SVG attributes directly to the SVGElements of the shape's markup.
(CSS styles may still be used on top of the styling defined here, and they will have precedence over
these attributes.)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!'
}
});
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.