JointJS + SVGPanZoom

by Roman Bruckner

HTML

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<html>

  <head>
    <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jointjs/3.1.1/joint.css" />
  </head>

  <body>
    <!-- content -->
    <div id="paper" style="border: 1px solid black;"></div>

    <!-- dependencies -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.4.0/backbone.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jointjs/3.1.1/joint.js"></script>

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/svg-pan-zoom.min.js"></script>

  </body>

</html>

JavaScript

const graph = new joint.dia.Graph();
const paper = new joint.dia.Paper({
  el: document.getElementById('paper'),
  width: 800,
  height: 600,
  model: graph,
  gridSize: 10,
  drawGrid: true
});

const shapeA = new joint.shapes.standard.Rectangle({
    attrs: { label: { text: 'Rect' }}
});
const shapeB = new joint.shapes.standard.Ellipse({
    attrs: { label: { text: 'Ellipse' }}
});
shapeA.position(50,100);
shapeB.position(200,100);
shapeA.resize(50, 50);
shapeB.resize(50, 50);
shapeA.addTo(graph);
shapeB.addTo(graph);

const panZoom = svgPanZoom(paper.svg, {
    viewportSelector: paper.layers,
    zoomEnabled: true,
    panEnabled: false,
    controlIconsEnabled: true,
    maxZoom: 2,
    minZoom: 0.1,
    onUpdatedCTM: (function() {
      let currentMatrix = paper.matrix();
    	return function onUpdatedCTM(matrix) {
         const { a, d, e, f } = matrix;
         const { a: ca, d: cd, e: ce, f: cf } = currentMatrix;         
         const translateChanged = (e !== ce || f !== cf)
         if (translateChanged) {
	         paper.trigger('translate', e - ce, f - cf);
         }
         const scaleChanged = (a !== ca || d !== cd);         
         if (scaleChanged) {
	         paper.trigger('scale', a, d, e, f);
         }
         currentMatrix = matrix;
      }
    })()
});
  
paper.on('blank:pointerdown', function() {
  panZoom.enablePan();
});
  
paper.on('blank:pointerup', function() {
  panZoom.disablePan();
});