GSAP Draggable SVG with zoom and panning

Tiny demo creating a draggable, zoomable SVG element

In the HTML, we need a parent/wrapper element which will act as the bounds for our draggable SVG element:

<div id="container" style="width: 800px; height: 400px;">
  <svg id="svg"><!-- rest of the svg code --></svg>
</div>

Next, initialize the Draggable with GSAP:

import gsap from 'gsap';
import Draggable from 'gsap/Draggable';

const draggable = Draggable.create('#svg', {
    type: 'x,y',
    bounds: '#container',
    inertia: true,
    throwResistance: 300,
    throwProps: true,
    allowEventDefault: true,
  })[0];

An important aspect to get it to be “smooth” and not display a blank viewBox when zooming in/out or resetting the zoom, is to also update the bounds of the SVG element while it’s zooming (onUpdate):

function zoom() {
  const zoomLevel = 2;
  gsap.to('#svg',
    { 
      scale: zoomLevel,
      transformOrigin: 'center center',
      onUpdate: () => {
        draggable.applyBounds('#container');
        draggable.update();
    },
  });
}

Full demo & working code available here: