How to build a snipping tool in WebViewer

Here is a quick example of how to build a snipping tool where a user can make a selection and the selection will be downloaded as a PNG:

import React, { useRef, useEffect } from 'react';
import WebViewer from '@pdftron/webviewer';
import './App.css';

const App = () => {
  const viewer = useRef(null);

  // if using a class, equivalent of componentDidMount 
  useEffect(() => {
    WebViewer(
      {
        path: '/webviewer/lib',
        initialDoc: '/files/PDFTRON_about.pdf',
      },
      viewer.current,
    ).then((instance) => {
      const { docViewer, Annotations, Tools, iframeWindow, annotManager } = instance;
      
      const createSnipTool = function() {
        const SnipTool = function() {
          Tools.RectangleCreateTool.apply(this, arguments);
          this.defaults.StrokeColor = new Annotations.Color('#F69A00');
          this.defaults.StrokeThickness = 2;
        }
      
        SnipTool.prototype = new Tools.RectangleCreateTool();
        
        return new SnipTool(docViewer);
      };

      const customSnipTool = createSnipTool();

      instance.registerTool({
        toolName: 'SnipTool',
        toolObject: customSnipTool,
        buttonImage: '/cut-solid.svg',
        buttonName: 'snipToolButton',
        tooltip: 'Snipping Tool'
      });

      instance.setHeaderItems(header => {
        header.push({
          type: 'toolButton',
          toolName: 'SnipTool',
        });
      });

      const downloadURI = (uri, name) => {
        const link = document.createElement("a");
        link.download = name;
        link.href = uri;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
      }

      customSnipTool.on('annotationAdded', (annotation) => {
        const pageIndex = annotation.PageNumber;
        // get the canvas for the page
        const pageContainer = iframeWindow.document.getElementById('pageContainer' + pageIndex);
        const pageCanvas = pageContainer.querySelector('.canvas' + pageIndex);
    
        const topOffset = parseFloat(pageCanvas.style.top) || 0;
        const leftOffset = parseFloat(pageCanvas.style.left) || 0;
        const zoom = docViewer.getZoom();
    
        const x = annotation.X * zoom - leftOffset;
        const y = annotation.Y * zoom - topOffset;
        const width = annotation.Width * zoom;
        const height = annotation.Height * zoom;
    
        const copyCanvas = document.createElement('canvas');
        copyCanvas.width = width;
        copyCanvas.height = height;
        const ctx = copyCanvas.getContext('2d');
        // copy the image data from the page to a new canvas so we can get the data URL
        ctx.drawImage(pageCanvas, x, y, width, height, 0, 0, width, height);
        downloadURI(copyCanvas.toDataURL(), "snippet.png");
    
        annotManager.deleteAnnotation(annotation);
      });

    });
  }, []);

  return (
    <div className="App">
      <div className="header">React sample</div>
      <div className="webviewer" ref={viewer}></div>
    </div>
  );
};

export default App;