Minimap
JointJS+ provides an Navigator plugin that enables the ability to display a smaller view into a larger diagram.
Installation
Access Navigator via the ui namespace, and simply create an instance. Append the navigator DOM element to any container,
and call the render() method.
import { ui } from '@joint/plus';
const nav = new ui.Navigator({
paperScroller,
width: 300,
height: 200,
padding: 10,
zoomOptions: { max: 2, min: 0.2 }
});
document.getElementById('navigator').appendChild(nav.el);
nav.render();
There is also a UMD version available
Include joint.ui.navigator.js and joint.ui.navigator.css in your HTML:
<link rel="stylesheet" type="text/css" href="joint.ui.navigator.css">
<script src="joint.js"></script>
<script src="joint.ui.navigator.js"></script>
Access Navigator through the joint.ui namespace:
const nav = new joint.ui.Navigator({
paperScroller,
width: 300,
height: 200,
padding: 10,
zoomOptions: { max: 2, min: 0.2 }
});
document.getElementById('navigator').appendChild(nav.el);
nav.render();
How does Navigator work?
Navigator is a UI widget that displays a smaller view into a larger diagram. It's a quick way for users to navigate in
diagrams with a pannable and resizable rectangle. The navigator requires a ui.PaperScroller
object as a parameter.
Navigator example
The following example creates an instance of Navigator, appends it to the DOM, and calls the render() method on it.
The required paperScroller is also provided as an option. Users can pan and zoom via the rectangle in the minimap.
Changing attributes such as position is also reflected in the minimap.
The navigator viewport initially shows only the content of the paper thanks to the useContentBBox option, and it adjusts dynamically as the user pans around thanks to the dynamicZoom option.
The navigator draws the graph in a paper of its own, and that paper does not inherit the options of the main paper. The
router and the connector are passed to it with paperOptions; without them the
links would be drawn as plain straight lines in the minimap.
Lightweight minimap
The navigator renders its own paper (targetPaper) over the very same graph as the
main paper, and by default it uses the very same cell views. Every shape, label, port and link is therefore rendered twice.
None of that detail is legible at minimap scale, so on large diagrams it is worth rendering a simplified version instead.
The paperOptions option is passed to the navigator's paper. There are two levers:
elementView- a customdia.ElementViewwhose root node is the shape itself. SettagNameto'rect'(or'path'), skip the markup rendering entirely, and only handle the@updateand@transformflags.cellVisibility()- returnfalsefor links, and their views are never created. The callback receives the cell only whenviewManagementis enabled; without it the paper runs in the legacy mode and passes the cell view instead.
const MinimapElementView = dia.ElementView.extend({
tagName: 'rect',
initFlag: ['@update', '@transform'],
presentationAttributes: {
position: ['@transform'],
angle: ['@transform'],
size: ['@update'],
attrs: ['@update']
},
confirmUpdate: function(flags) {
if (this.hasFlag(flags, '@update')) this.update();
if (this.hasFlag(flags, '@transform')) this.updateTransformation();
return 0;
},
update: function() {
const { width, height } = this.model.size();
this.vel.attr({ width, height, fill: STATUS_COLORS[this.model.attr('root/dataStatus')] });
}
});
const nav = new ui.Navigator({
paperScroller,
useContentBBox: { useModelGeometry: true },
paperOptions: {
async: true,
viewManagement: true,
elementView: MinimapElementView,
cellVisibility: (cell) => !cell.isLink()
}
});
Note the useContentBBox option set to { useModelGeometry: true }. The
navigator then takes the size of the content from the graph rather than measuring the rendered content in the DOM. The
measurement is run every time the paper finishes rendering, so reading the size from the models is noticeably cheaper on
large diagrams.
If you keep the links in the minimap, remember that their endpoints are computed from the element views of the minimap's own
paper. A simplified view may not have the same bounding box as the shape on the main paper (or may render nothing at all), so
pass defaultAnchor: { name: 'center', args: { useModelGeometry: true }} and
defaultConnectionPoint: { name: 'bbox', args: { useModelGeometry: true }} in paperOptions to have the endpoints computed
from the models as well.