0

I have a basic static site which utilizes the free JointJS library to draw interactive diagrams.

The JointJS library seems to draw the diagrams as SVG, and I'm able to successfully export them as SVG files, but I can't seem to figure out how to successfully export them as PNG files.

The below code block works fine to export as a SVG file.

function saveSvg (svgEl, name) {
  /*
  Download the diagram as a SVG file
  */
  // Serialize the SVG HTML data
  let svgData = new XMLSerializer().serializeToString(svgEl)
  // Clean the HTML tootltips out of the SVG data
  svgData = svgData.replace(/data-bs-title=".*?"/gm, '')
  // Build the base64 SVG image data
  const image64 = 'data:image/svg+xml;base64,' + window.btoa(svgData)
  // Create a download URL for the SVG file
  const img = document.createElement('img')
  // Set the source for the image to the base64 image data
  img.src = image64
  // Create a link for the download
  const downloadLink = document.createElement('a')
  // Set the URL for the download link
  downloadLink.href = image64
  // Set the file name
  downloadLink.download = name
  // Add the download link to the document
  document.body.appendChild(downloadLink)
  // Simulate a click on the link
  downloadLink.click()
  // Remove the link from the document
  document.body.removeChild(downloadLink)
}

But when I try to write it out to a canvas, then use canvas.toDataURL() to create the PNG base64, it always ends up in a blank PNG file.

If I manually create a basic SVG and then run that SVG through the same process, it works fine.

What am I missing here?

John Kerns
  • 89
  • 1
  • 2

1 Answers1

0

Your example does not include the canvas part. Is that on purpose? But with the code provided there is one issue. You need to wait for the image to get loaded, so the last part of the code need to be in the callback function of the load event. This example is not really working -- I think that the function click() is blocked by the browser (a separate issue).

If you need a similar example that includes a canvas element you can find one in this answer.

const svgEl = document.getElementById('svg01');

saveSvg(svgEl, "test.svg");

function saveSvg (svgEl, name) {
  /*
  Download the diagram as a SVG file
  */
  // Serialize the SVG HTML data
  let svgData = new XMLSerializer().serializeToString(svgEl);
  // Clean the HTML tootltips out of the SVG data
  svgData = svgData.replace(/data-bs-title=".*?"/gm, '');
  // Build the base64 SVG image data
  const image64 = 'data:image/svg+xml;base64,' + window.btoa(svgData);
  
  // Create a download URL for the SVG file
  const img = document.createElement('img');
  
  // wait for the SVG to be loaded
  img.addEventListener('load', e => {
    // Create a link for the download
    const downloadLink = document.createElement('a');
    // Set the URL for the download link
    downloadLink.href = e.target.src;
    // Set the file name
    downloadLink.download = name;
    // Add the download link to the document
    document.body.appendChild(downloadLink);
    // Simulate a click on the link
    downloadLink.click();
    // Remove the link from the document
    document.body.removeChild(downloadLink);
  });
  // Set the source for the image to the base64 image data
  img.src = image64;
}
<div>
  <svg id="svg01" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10" width="30" height="30">
    <circle r="4" cx="4" cy="4" fill="red" />
    <rect x="4" y="4" width="6" height="6" fill="navy"/>
  </svg>
</div>
<canvas id="canvas"></canvas>
<div>
<img id="img01"/>
</div>
chrwahl
  • 8,675
  • 2
  • 20
  • 30