Skip to main content
Version: 4.3

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:

index.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:

index.js
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.

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 custom dia.ElementView whose root node is the shape itself. Set tagName to 'rect' (or 'path'), skip the markup rendering entirely, and only handle the @update and @transform flags.
  • cellVisibility() - return false for links, and their views are never created. The callback receives the cell only when viewManagement is 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.

note

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.

Stay in the know

Be where thousands of diagramming enthusiasts meet

Star us on GitHub