JointJS+ Popup

ui.Popup

ui.Popup is a UI widget for displaying contextual information (or even other diagrams) below a certain target element (HTML or SVG). There can always be only one popup opened at a time. This is automatically handled by the ui.Popup component which simplifies the process and makes sure you don't have to keep track of opened popups yourself. This component is very similar to the ui.ContextToolbar component (in fact, it inherits from it) with the only difference that ui.Popup does not contain a set of buttons but an arbitrary HTML (which might even contain another diagram).

Installation

Include joint.ui.popup.js and joint.ui.popup.css files and the joint.ui.contextToolbar.js and joint.ui.contextToolbar.css dependencies to your HTML:

<link rel="stylesheet" type="text/css" href="joint.ui.contextToolbar.css">
<link rel="stylesheet" type="text/css" href="joint.ui.popup.css">
<script src="joint.ui.contextToolbar.js"></script>
<script src="joint.ui.popup.js"></script>

Usage

Create an object of joint.ui.Popup type, specify content and call the render() method in order to open the popup.

const element = new joint.shapes.standard.Rectangle({
    position: { x: 10, y: 10 },
    size: { width: 80, height: 50 },
    attrs: { label: { text: 'Rect' }}
});

const elementView = element.findView(paper);

new joint.ui.Popup({
    content: '<b>I am a ui.Popup</b>',
    target: elementView.el
}).render();

A common usage is to open the popup on click on a certain element (either HTML or SVG) and display either an image or another diagram:

paper.on('element:pointerdown', (elementView) => {
    const popup = new joint.ui.Popup({
        content: '<img width="100" style="float: left" src="/images/docs/popup/amsterdam1.jpg" />',
        target: elementView.el
    });
    popup.render();
});

paper.on('element:pointerdown', (elementView, evt) => {
    evt.preventDefault();
    const popup = new joint.ui.Popup({
        content: 'I am a ui.Popup!',
        target: elementView.el,
        anchor: 'bottom-left',
        position: 'right',
        arrowPosition: 'none'
    });
    popup.render();
});

paper.on('element:pointerdown', (elementView) => {
    const popup = new joint.ui.Popup({
        content: function(el) {
            const graph = new joint.dia.Graph;
            const paper = new joint.dia.Paper({
                width: 200,
                height: 100,
                gridSize: 1,
                model: graph
            });
            el.appendChild(paper.el);
            const r1 = new joint.shapes.standard.Rectangle({ position: { x: 10, y: 10 }, size: { width: 50, height: 30 }, attrs: { body: { fill: '#FE854F' }, label: { text: 'r1' }}});
            const r2 = new joint.shapes.standard.Rectangle({ position: { x: 90, y: 40 }, size: { width: 50, height: 30 }, attrs: { body: { fill: '#7C68FC' }, label: { text: 'r2' }}});
            const l = new joint.shapes.standard.Link({ source: { id: r1.id }, target: { id: r2.id }});
            graph.addCells([r1, r2, l]);
        },
        target: elementView.el
    }).render();
});

paper.on('element:pointerdown', (elementView) => {
    const popup = new joint.ui.Popup({
        events: {
            'click .btn-cancel': 'remove',
            'click .btn-change': function() {
                const strokeWidth = parseInt(document.querySelector('.inp-stroke-width').value, 10);
                const fill = document.querySelector('.inp-fill').value;
                elementView.model.attr({
                    body: { fill: fill, strokeWidth: strokeWidth }
                });
            }
        },
        content: [
            '<div>',
            'Fill: <input class="inp-fill" type="color" value="#FEB663"> <br><br>',
            'Stroke width: <input class="inp-stroke-width" type="number" value="5"> <br><br>',
            '<button class="btn-cancel">Cancel</button>',
            '<button class="btn-change">Change</button>',
            '</div>'
        ].join(''),
        target: elementView.el
    });

    popup.render();
});

Appearance

You can alter arrow appearance by customizing css variables inside the .joint-popup class. Available variables are --arrow-width, --arrow-mask-width, --arrow-color, --arrow-mask-color.

Configuration

The following table lists options that you can pass to the ui.Popup constructor function:

content The content of the popup. It can be a text or an arbitrary HTML as a string, or an HTML element.

It can also be specified as a function with el (the parent HTML element of the Popup) exposed as a parameter. The parameter can be used, for example, to dynamically calculate a return string or HTML element to be used as the content of the popup, as specified above.

Alternatively, instead of returning a value, the function may append HTML elements directly to el (e.g. by calling el.appendChild(paper.el); using a JointJS paper element). This approach enables appending of JointJS diagrams directly into the ui.Popup element.
target The target element (either HTML or SVG).
padding The gap between the target element an the popup. Default is 20.
position The name of the position on the target element to which the popup is attached. The default is 'bottom'.
anchor The name of the position on the popup, where it is attached to the target. The default is 'top'. The arrow is rendered with this position by default. If the anchor is 'center' the arrow is not rendered.
arrowPosition The optional name of the position on the popup, where the arrow is rendered. The default is anchor position. Use 'none' if you want the arrow not to be rendered. Accepts all position names except 'center'.
autoClose Determines if the popup should be closed if the user clicked outside of the area of the popup. Default is true.
scale Optional parameter that sets the scale of the context toolbar.

API

render() Render the popup onto the screen.
remove() Remove the popup. Usually, you don't have to call this method as the popup is closed automatically if the user clicked outside of the area of the popup (unless you set the autoClose option to false).
on(event, handler [, context]) Register a handler function that will be called whenever event is triggered. The optional context is an object that will be the context of the handler function (the this).
joint.ui.Popup.close() This is a static method that closes any poup that is currently open.
joint.ui.Popup.update() This is a static method that updates the position of the opened popup (if any). Call this method if you target element changes its position while you still want to keep the popup opened.

Events

close Triggered when the popup gets closed.