JointJS Advanced Performance Tips

1. Faster Paper 2. Faster Custom Element View

HTML

<script src="https://code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.2.3/backbone-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jointjs/0.9.7/joint.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jointjs/0.9.7/joint.css">
<!-- JointJS Fiddle -->
<div id="paper"></div>
<button id="start">Start</button>
<div id="fps"></div>

CSS

body {
   background-color: white;
   color: #3c4260;
 }
 
 #start, #fps {
   position: fixed;
   top: 15px;
   left: 15px;
 }

#paper {
  display: inline-block;
  border: 2px solid #3c4260;
}
 .rect-outer {
   fill: blue;
   stroke: none;
 }

JavaScript

'use strict';

joint.dia.FastPaper = joint.dia.Paper.extend({

  sortViews: _.noop,

  beforeRenderViews: function() {

    this.documentFragment = document.createDocumentFragment();
  },

  renderView: function(cell) {

    var view = this._views[cell.id] = this.createViewForModel(cell);

    // Keep the document fragment sorted. First goes links and then elements. L-L-L-L-L-E-E-E-E-E-E
    // Note that built-in JointJS `z` index will be completely ignored.
    // Links stays always under elements.
    if (cell.isLink()) {
      this.documentFragment.insertBefore(view.el, this.documentFragment.firstChild);
    } else {
      this.documentFragment.appendChild(view.el);
    }

    view.paper = this;
    view.render();

    return view;
  },

  asyncBatchAdded: function() {

    if (this.documentFragment.childNodes.length) {
      // Insert the document fragment after last link. i.e. If the viewport is sorted having
      // L1-L2-L3-E1-E2-E3 and the fragment contains L4-E4 we want the viewport stay sorted.
      // -> L1-L2-L3-L4-E4-E1-E2-E3
      this.viewport.insertBefore(this.documentFragment, this.viewport.querySelector('.element'));
      this.documentFragment = document.createDocumentFragment();
    }
  }
});

joint.shapes.basic.ConveyorElement = joint.dia.Element.extend({

  PADDING: 2,

  defaults: joint.util.deepSupplement({

    type: 'basic.ConveyorElement',
    hasPallet: false

  }, joint.dia.Element.prototype.defaults),

  addPallet: function() {

    this.set('hasPallet', true);
  },

  removePallet: function() {

    this.set('hasPallet', false);
  },

  hasPallet: function() {

    return !!this.get('hasPallet');
  },

  switchPallet: function() {

    if (this.hasPallet()) {
      this.removePallet();
    } else {
      this.addPallet();
    }
  },

  getOuterRectBBox: function() {

    var size = this.get('size');
    var bbox = {
      x: 0,
      y: 0,
      width: size.width,
      height: size.height
    };

    return bbox;
  },

 ...