jointjs
Version:
JavaScript diagramming library
353 lines (257 loc) • 38.7 kB
HTML
<html>
<head>
<link rel="canonical" href="http://www.jointjs.com/" />
<meta name="description" content="Create interactive diagrams in JavaScript easily. JointJS plugins for ERD, Org chart, FSA, UML, PN, DEVS, LDM diagrams are ready to use." />
<meta name="keywords" content="JointJS, JavaScript, diagrams, diagramming library, UML, charts" />
<link href="http://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
<link rel="stylesheet" href="css/tutorial.css" />
<link rel="stylesheet" href="../node_modules/prismjs/themes/prism.css">
<!-- Dependencies: -->
<script src="../node_modules/jquery/dist/jquery.js"></script>
<script src="../node_modules/lodash/lodash.js"></script>
<script src="../node_modules/backbone/backbone.js"></script>
<link rel="stylesheet" type="text/css" href="../build/joint.min.css" />
<script type="text/javascript" src="../build/joint.min.js"></script>
<title>JointJS - JavaScript diagramming library - Getting started.</title>
</head>
<body class="language-javascript tutorial-page">
<script>
SVGElement.prototype.getTransformToElement = SVGElement.prototype.getTransformToElement || function (toElement) {
return toElement.getScreenCTM().inverse().multiply(this.getScreenCTM());
};
</script>
<div id="links-patterns" class="tutorial">
<h2>Links and patterns</h2>
<p><b>TL;DR</b>: Jump right into the <a href="#pipes-demo" target="_self">demo</a> below.</p>
<p>This tutorial shows another way how to style JointJS links, especially if only changing the stroke color and
width of your links is not sufficient to meet your requirements.
What gives us more flexibility is <b>SVG gradients</b> and <b>SVG patterns</b>. SVG gradients as filling for
strokes would be fine enough if we were using only straight links with no vertices.
This is because the gradients are applied on the link SVG path as a whole. Therefore, applying the gradient
on the link SVG path stroke would give different parts of the links different colors depending on how the
link is
broken and where it is positioned. This gives us an unpredictable result that we most likely don't want.
Meet SVG patterns!
<div>
<svg width="600" height="200" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="path-pattern" patternUnits="userSpaceOnUse" x="0" y="0" width="160" height="160">
<image id="logo"
xlink:href="data:image/png;base64,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"
width="160" height="160"/>
</pattern>
</defs>
<path stroke="black" stroke-width="20" d="M 10 20 L 80 130 150 20" fill="none"/>
<use transform="translate(200,0)" xlink:href="#logo"/>
<path transform="translate(400,0)" stroke="url(#path-pattern)" stroke-width="20"
d="M 10 20 L 80 130 150 20" fill="none"/>
<text x="160" y="80" font-size="40" fill="black">+</text>
<text x="380" y="80" font-size="40" fill="black">=</text>
</svg>
</div>
<p>The idea is simple. We create and render a link. We create an
<a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Canvas" target="_blank">HTML 5 canvas element</a> of the size of
the bounding box of the link. We draw onto the canvas anything we'd like the link to look like. We generate
a <a href="http://en.wikipedia.org/wiki/Data_URI_scheme" target="_blank">Data URI image</a> from the canvas
and tell the link to use this image as an SVG pattern for the link stroke. And we repeat all this every time
the link gets changed.</p>
<h3 id="linkview">About the LinkView</h3>
<p>A link view is responsible for rendering and updating a link, it manipulates the DOM elements and it is the
right place to implement a link interaction or customize the link appearance.</p>
<p>Each time we change a link attribute, source or target, we add a vertex or we move an element that is
connected to the link - the link has to be updated.
Normally, the <a href="/docs/jointjs/v1.0/joint.html#dia.LinkView" target="_top">joint.dia.LinkView</a> takes care of this.
It inherits from the <a href="http://backbonejs.org/#View" target="_blank">Backbone.View</a> and extends it
by new methods and properties. We're going to introduce some of them.
<br>
<br>The <code>linkView.render()</code> method creates SVG elements from the defined link markup and appends
them to the DOM.
It's usually called only once when link is created. Also, it calls update() internally.
<br>The <code>linkView.update()</code> method applies all the attributes to the DOM elements, finds the
route, positions the link tools and arrowheads and so on. It is called everytime the link is changed.
<br>The <code>linkView.remove()</code> cleans up SVG elements from the DOM and removes event handlers.
Called once the view is removed.
<br>The <code>linkView.sourcePoint</code> and <code>linkView.targetPoint</code> are cached coordinates of a
point where the link connects to an element or point.
<br>The <code>linkView.route</code> is a cached array of points calculated from the vertices by a
<a href="/docs/jointjs/v1.0/joint.html#dia.Link" target="_blank">router</a>.
<br>The <code>linkView.paper</code> is a reference to the paper the view is rendered into.
</p>
<p>The <code>joint.dia.LinkView</code> can be extended and used, for example, in the following way:</p>
<pre><code class="language-javascript">joint.dia.LinkView.extend({
render: function() {
// call parent's render
joint.dia.LinkView.prototype.render.apply(this, arguments);
// here we create and append the pattern into the paper SVG <defs> element
// and tell the link to use it
// it is a good convetion to return `this` to enable chaining
return this;
},
remove: function() {
// call parent's remove first
joint.dia.LinkView.prototype.remove.apply(this, arguments);
// here we remove the pattern from the paper SVG <defs> element
return this;
},
update: function() {
// call parent's update first
joint.dia.LinkView.prototype.update.apply(this, arguments);
// here we generate an image and set it as a pattern
return this;
}
});</code></pre>
<h3 id="render">Creating a pattern</h3>
<p>First of all we have to create an SVG pattern with an image element inside and append it to the DOM
(specifically into the paper <a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs" target="_blank">SVG
<code><defs></code> element</a> - this is a good place in SVG documents where referenced elements
are defined).
The perfect place for this is the <code>linkView.render()</code> method.
Here we can also cache some important elements we will be using during the updates in order to minimize DOM
traversal.</p>
<pre><code class="language-javascript">render: function() {
joint.dia.LinkView.prototype.render.apply(this, arguments);
// make sure that pattern doesn't already exist
if (!this.pattern) {
// create the pattern and the image element
this.pattern = V('<pattern id="pattern-' + this.id + '" patternUnits="userSpaceOnUse"><image/></pattern>');
// cache the image element for a quicker access
this.patternImage = this.pattern.findOne('image');
// append the pattern to the paper's defs
V(this.paper.svg).defs().append(this.pattern);
}
// tell the '.connection' path to use the pattern
var connection = V(this.el).findOne('.connection').attr({
stroke: 'url(#pattern-' + this.id + ')'
});
// cache the stroke width
this.strokeWidth = connection.attr('stroke-width') || 1;
return this;
}</code></pre>
<p>Note that we're using the <a href="/docs/jointjs/v1.0/vectorizer.html" target="_top">built-in Vectorizer library</a> for creating SVG.</p>
<h3 id="update">Using the pattern</h3>
<p>Once we are able to get the link's bounding box (the one without transformations), we can create an HTML 5
canvas of the size of the bounding box of the link.
We know the points which the link goes through (<code>sourcePoint</code>, <code>targetPoint</code> and
<code>route</code>) so the next thing is to transform them into the link coordinate system (the coordinates
of the link top-left corner are obtained from its bounding box).
<br>For example if we have a bounding box <code>{ x: 100, y: 30, width: 200, height: 200 }</code> and a
vertex with coordinates <code>{ x: 150, y: 150 }</code> the position of that vertex on the canvas is <code>{
x: 50, y: 120 }</code>.
Now we have all we need to be able to draw our pattern into the canvas (more info on how to draw into the
canvas can be found <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial"
target="_blank">here</a>).</p>
When we finish with drawing we set the pattern's coordinates and the dimensions to reflect the link bounding
box.
We set the <code>xlink:href</code> attribute of the image element inside the pattern to the data URI containing
a representation of the image in the PNG format (we can obtain it from the canvas by calling <code>canvas.toDataURL('image/png')</code>).
<pre><code class="language-javascript">update: function() {
joint.dia.LinkView.prototype.update.apply(this, arguments);
var strokeWidth = this.strokeWidth;
// we get the bounding box of the linkView without the transformations
// and expand it to all 4 sides by the stroke width
// (making sure there is always enough room for drawing,
// even if the bounding box was tiny.
// Note that the bounding box doesn't include the stroke.)
var bbox = g.rect(V(this.el).bbox(true)).moveAndExpand({
x: - strokeWidth,
y: - strokeWidth,
width: 2 * strokeWidth,
height: 2 * strokeWidth
});
// create an array of all the points the link goes through
// (route doesn't contain the connection points)
var points = [].concat(this.sourcePoint, this.route, this.targetPoint);
// transform all the points to the link coordinate system
points = _.map(points, function(point) {
return g.point(point.x - bbox.x, point.y - bbox.y);
});
// create a canvas of the size same as the link bounding box
var canvas = document.createElement('canvas');
canvas.width = bbox.width;
canvas.height = bbox.height;
var ctx = canvas.getContext('2d');
ctx.lineWidth = strokeWidth;
// iterate over the points and draw the link's new look into the canvas
for (var i = 0, pointsCount = points.length - 1; i < pointsCount; i++) {
var from = points[i];
var to = point[i + 1];
// draw something into the canvas
// e.g a line from 'from.x','from.y' to 'to.x','to.y'
}
// generate data URI from the canvas
var dataUri = canvas.toDataURL('image/png');
// set the pattern's size to the size of the link bounding box
this.pattern.attr(bbox);
// update the pattern image and the dimensions
this.patternImage.attr({
width: bbox.width,
height: bbox.height,
'xlink:href': dataUri
});
return this;
}</code></pre>
<h3 id="remove">Removing the pattern</h3>
<p>It's a good practice to clean up when the link gets removed from the paper. We don't want to leave
unreferenced pattern elements in the DOM.</p>
<pre><code class="language-javascript">remove: function() {
joint.dia.LinkView.prototype.remove.apply(this, arguments);
// remove the pattern from the DOM
this.pattern.remove();
}</code></pre>
<h3 id="workaround">Pure vertical and horizontal lines</h3>
<p>There is one more thing we have to deal with.
According to the SVG specification it is not possible to apply patterns on elements with no width or no
height.</p>
<blockquote>
<q>Keyword objectBoundingBox should not be used when the geometry of the
applicable element has no width or no height, such as the case of a
horizontal or vertical line, even when the line has actual thickness when
viewed due to having a non-zero stroke width since stroke width is ignored
for bounding box calculations. When the geometry of the applicable element
has no width or height and objectBoundingBox is specified, then the given
effect (e.g., a gradient or a filter) will be ignored.</q>
</blockquote>
<p>That means, in our case, that we can't use patterns for drawing pure vertical and pure horizontal links.</p>
<pre><code class="language-markup"><!-- pure vertical path (height 0)-->
<path d="M 0 0 L 300 0"/>
<!-- pure horizontal path (width 0)-->
<path d="M 100 0 100 50 100 100"/></code></pre>
<p>To overcome this issue, we can offset one of the path points by a small number.</p>
<pre><code class="language-markup"><!-- vertical path (height 0.01) -->
<path d="M 0 0 L 300 0.01"/>
<!-- horizontal path (width 0.01)-->
<path d="M 100 0 100 50 100.01 100"/></code></pre>
<p>The best place where to deal with this is the link connector (connectors are responsible for generating the
link path by constructing its <code>d</code> attribute).
Here we take <code>joint.connectors.normal</code>, change the method name to <code>normalDimFix</code> and
add a very small number to x and y coordinates of the last point of the resulting path.</p>
<pre><code class="language-javascript">joint.connectors.normalDimFix = function(sourcePoint, targetPoint, vertices) {
var dimensionFix = 1e-3;
var d = ['M', sourcePoint.x, sourcePoint.y];
_.each(vertices, function(vertex) { d.push(vertex.x, vertex.y); });
d.push(targetPoint.x + dimensionFix, targetPoint.y + dimensionFix);
return d.join(' ');
};</code></pre>
<h3 id="pipes-demo">The pipes demo</h3>
<p>Let's combine all this together and create a link which looks like a pipe.
The demo below contains all that we described so far, plus it is adding some new features.
<br>The LinkView draws into the canvas and updates the pattern asynchronously (using
<a href="/docs/jointjs/v1.0/joint.html#util.nextFrame" target="_top">joint.util.nextFrame</a>).
<br>It automatically creates a gradient with a directions perpendicular to the path direction for each link
segment. This way you can style your link from the 'border' to 'border' and draw an image like the one
below.</p>
<img src="data:image/png;base64,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"
width="316" height="67"/>
<br>It also separates the drawing function from the <code>update()</code> into a new linkView method <code>drawPattern()</code>.<br/>
<div id="paper-pipes"></div>
<p>The <a href="js/pipes.js">source code</a> to the demo.</p>
<script type="text/javascript" src="js/pipes.js"></script>
<pre data-src="js/pipes.js" style="height: 4880px"></pre>
</div>
<script src="../node_modules/prismjs/prism.js"></script>
</body>
</html>