Joint JS Plus demo with custom HTML and Navigator

by Roman Bruckner

HTML

<script src="https://resources.jointjs.com/docs/rappid/v4.0/js/lib/joint-plus.min.js"></script>
<link rel="stylesheet" href="https://resources.jointjs.com/docs/rappid/v4.0/css/lib/joint-plus.min.css">
<div id="paper"></div>
<div class="toolbar">
  <span id="zoom-out" class="toolbar-button">Zoom Out</span>
  <span id="zoom-in" class="toolbar-button">Zoom In</span>
  <span id="reset" class="toolbar-button">Reset</span>
</div>
<div id="navigator"></div>

CSS

html, body {
    margin: 0;
    padding: 0;
    height: 100%;
}
body {
    display: flex;
    justify-content: center;
    align-items: center;
    overflow-y: hidden;
}
#paper {
    border: 1px solid #E2E2E2;
    background-color: #F3F7F6;
    position: absolute;
    inset: 0;
}
#navigator {
  right: 4px;
  bottom: 4px;
  position: absolute;
}
/* JointJS HTML Element */
.html-element {
    box-sizing: border-box;
    font-family: sans-serif;
    box-shadow: 4px 4px 4px -1px rgba(0,0,0,0.18);
    padding: 8px 16px;
    background-color: #FCFCFC;
}
.html-element:after {
    content: ' ';
    background: #6C6C6C;
    height: 8px;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
}
.html-element:before {
    content: ' ';
    position: absolute;
    top: 24px;
    right: 16px;
    width: 20px;
    height: 20px;
    background-position: 50% 50%;
    background-repeat: no-repeat;
    background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0Ij48cGF0aCBkPSJNMCAwaDI0djI0SDBWMHoiIGZpbGw9Im5vbmUiLz48cGF0aCBkPSJNMTEuOTkgMkM2LjQ3IDIgMiA2LjQ4IDIgMTJzNC40NyAxMCA5Ljk5IDEwQzE3LjUyIDIyIDIyIDE3LjUyIDIyIDEyUzE3LjUyIDIgMTEuOTkgMnpNMTIgMjBjLTQuNDIgMC04LTMuNTgtOC04czMuNTgtOCA4LTggOCAzLjU4IDggOC0zLjU4IDgtOCA4em0uNS0xM0gxMXY2bDUuMjUgMy4xNS43NS0xLjIzLTQuNS0yLjY3eiIvPjwvc3ZnPg==);
}
.html-element[data-state="done"]:after {
    background:#4666E5;
}
.html-element[data-state="done"]:before {
    background-image:...

Babel + JSX

const {
  util,
  dia,
  ui,
  shapes
} = joint;

const Element = dia.Element;
const ElementView = dia.ElementView;

const HTMLElement = Element.define('HTMLElement', {
  size: {
    width: 250,
    height: 228
  },
  fields: {
    header: 'Task',
    name: '',
    resource: '',
    state: ''
  },
  attrs: {
    placeholder: {
      width: 'calc(w)',
      height: 'calc(h)',
      fill: 'transparent',
      stroke: '#D4D4D4'
    }
  }
}, {

  htmlMarkup: util.svg `
            <foreignObject>
                <div @selector="htmlRoot" @group-selector="field" xmlns="http://www.w3.org/1999/xhtml"
                    class="html-element"
                    style="position: absolute; pointer-events: auto; user-select: none; box-sizing: border-box;"
                    data-attribute="state"
                >
                    <label @group-selector="field" class="html-element-header" data-attribute="header"></label>
                    <label class="html-element-label">Name
                        <input @group-selector="field" class="html-element-field" data-attribute="name" placeholder="Name" style="pointer-events: auto;" />
                    </label>
                    <label class="html-element-label">Resource
                        <select @group-selector="field" class="html-element-field" data-attribute="resource" style="pointer-events: auto;">
                            <option value="" disabled="true">Resource</option>
                            <option value="john">John</option>
                            <option value="mary">Mary</option>
                            <option value="bob">Bob</option>
                        </select>
                    </label>
                </div>
            </foreignObject>
        `,

  markup: util.svg `
            <rect @selector="placeholder" />
        `,
});

// A link model used in the example
var Link = joint.shapes.standard.Link.define('Link', {
  z: 1,
});

// Custom view for JointJS HTML element...