Add Padding to Embedded SVGs for svg-pan-zoom Controls Using JavaScript

A while ago, my current project added support for zooming and panning SVG images. We were able to accomplish this pretty quickly by using the svg-pan-zoom library, which allowed us to easily add UI for pan and zoom controls on top of SVGs.

However, after seeing how the control icons appeared over some of our images, it was apparent that we had some overlap issues that we needed to resolve. We wanted to keep the same control icons, but ensure that they would never overlap the actual image during the initial load. To accomplish this, we planned to add in a small bit of padding to accommodate the space the tools take up.

Basic Method for Adding Pan/Zoom Controls

Before we get into modifying the SVGs, let’s go over our basic setup using the svg-pan-zoom library. We use an Embed element to include the SVGs on the page. When using this method, we need to wait for the embedded SVG to load before we can apply the panning and zooming controls.

Thankfully, there are a lot of functions available to help make this pretty easy. The code looks like this:


const SvgPanZoom = require("svg-pan-zoom");

export function addPanZoomToolsToEmbeddedSvgs() {
  // Collect all the embed elements from the document
  const allEmbeds = document.embeds;
  for (let i = 0; i < allEmbeds.length; i++) {
    const embedEl = allEmbeds[i];
    embedEl.addEventListener("load", function(event) {
      // After the embed element is done loading, apply the pan and zoom tools with the control icons
      SvgPanZoom(embedEl, {
        controlIconsEnabled: true
      });
    });
  }
}

First, we can grab all of the Embed elements using the embeds property of the Document. Then, for each of those elements, we add a new listener for the load event. When the load event is called, we apply the svg-pan-zoom library to the element.

In this case, we were only planning to use the Embed elements for the SVGs, so we can call the svg-pan-zoom function no matter what. Further down, this will be a bit more sophisticated and better support cases where there may be other Embed elements on the page.

Updated Method for Adding Pan/Zoom Controls

At this point, we have zooming and panning functionality, but we still need to add in that extra space for the controls. Again, lucky for us, there are functions that can easily support this!

Our new version of the load event listener looks like this:


const SvgPanZoom = require("svg-pan-zoom");

export function addPanZoomToolsToEmbeddedSvgs() {
  // Collect all the embed elements from the document
  const allEmbeds = document.embeds;
  for (let i = 0; i < allEmbeds.length; i++) {
    const embedEl = allEmbeds[i];
    embedEl.addEventListener("load", function(event) {
      // After the embed element is done loading, try and find an embedded SVG
      const svgDocument = embedEl.getSVGDocument();
            if (svgDocument) {
        const svgEl = svgDocument.querySelector("svg");
        if (svgEl) {
          // For any embedded SVG, add 75px of padding to accomidate the SVG pan/zoom tool UI
          // and update the viewBox to ensure the original SVG image is left-aligned
          const boundingRect = svgEl.getBoundingClientRect();
          const newWidth = boundingRect.width + 75;
          svgEl.setAttribute("width", newWidth.toString());
          svgEl.setAttribute(
            "viewBox",
            `0 0 ${newWidth} ${boundingRect.height}`
          );

          // After the width is updated, apply the SVG pan zoom tools
          SvgPanZoom(embedEl, {
            controlIconsEnabled: true,
            minZoom: 1,
            mouseWheelZoomEnabled: false
          });
        }
      }
    });
  }
}

The event listener is certainly a little more sophisticated in this example. Now, before we apply the svg-pan-zoom tools, we do the following:

  • Try to grab the XMLDocument for the embedded SVG using the .getSVGDocument() function. More information on that can be found in this MDN documentation.
  • Try to find the actual SVG element in that XMLDocument.
  • For any SVG we do find, we add 75 pixels to the width to make room for the controls and adjust the viewBox to ensure the image is left-aligned in relation to the control icons.

Once the SVG has been modified, we still apply the svg-pan-zoom controls as before. However, now we know that the controls will not overlap our image, and we will not be trying to apply them in cases where we don't actually have an SVG.

Alternate Options

This method of modifying the SVGs provided a pretty convenient way for us to get the control icons to appear as we wanted. We knew we didn't want to sink a lot of time into changing things.

If we had more time, however, we could have considered something like creating custom controls, which svg-pan-zoom does support. Or, we could have even explored other libraries. Given enough time, we could have even written our own panning and zooming tool.

There are many different ways to solve issues like this, and thankfully, we found a convenient and effective approach for our needs.