0

I tried asking this in a different way but it was marked as a duplicate, probably because my title was not specific enough.

I'm trying to trigger a download of an SVG file from within the SVG file, using a link and clicking the link with javascript.

I know that I cannot use HTMLElement.click() as the <a> is an SVG element, and instead I should use dispatchEvent().

But what I don't know is what I need to have in my onclick function in order to download the file.

This is a working (manual) version of what I want to achieve - when the circle is clicked, a Save As dialog opens with Original-Name-edited.svg as the file name, and when I click OK it correctly saves the SVG to my computer:

<svg xmlns="http://www.w3.org/2000/svg"
     viewBox="0 0 100 100">

  <a>
    <circle cx="50" cy="50" r="25" fill="red"/>
  </a>

  <script>
  // <![CDATA[
    const thisSvg = new XMLSerializer().serializeToString(document.getElementsByTagName('svg')[0])
    const link = document.getElementsByTagName('a')[0]
    const fileName = document.baseURI.replace(/(.*\/)([^\/]*)(\.svg)/, '$2-edited$3')
    const data = 'data:image/svg+xml;base64,' + btoa(thisSvg)
    link.setAttribute('download', fileName)
    link.setAttribute('href', data)
  // ]]>
  </script>

</svg>

When I create a function to run on click using dispatchEvent as outlined in this answer I can trigger an alert() or console.log(), so it feels like I'm on the right track, but I just can't get it to have the same effect as clicking on the link using the manual method.

  <a onclick="downloadSvg()">
    <circle cx="50" cy="50" r="25" fill="red"/>
  </a>
  
  <script>
  // <![CDATA[
    const thisSvg = new XMLSerializer().serializeToString(document.getElementsByTagName('svg')[0])
    const fileName = document.baseURI.replace(/(.*\/)([^\/]*)(\.svg)/, '$2-edited$3')
    const data = 'data:image/svg+xml;base64,' + btoa(thisSvg)

    // the function is called but this does not work
    const downloadSvg = () => {
      window.location.download = fileName
      window.location.href = data
    }

    link.dispatchEvent(new Event('click'))
  // ]]>
  </script>

</svg>
  • why not just use a HTML anchor element? – Robert Longson Feb 07 '21 at 23:28
  • Because this is intended to be part of a script which converts an SVG animated with an anime.js timeline to one animated with css animations, which can then be used as a stand-alone looping `img` in places where inline /js-animated svg isn't possible. Everything happens within the svg, it's not in an html page. I tried using an html `a` element within a `foreignobject` but that was even more difficult with little documentation available to help me. – cameralibre Feb 08 '21 at 00:27

0 Answers0