0

So I have currently tried converting an SVG to an image with a data uri, and it works for simple SVGs, however I am using mermaid js for complex charts and graphs which contains internal css and other elements, here is an example:

<div class="mermaid" data-processed="true"><svg id="mermaidChart1" width="100%" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 1112 268" style="max-width:1112px;"><style type="text/css" title="mermaid-svg-internal-css">/*  */
#mermaidChart1 .node { fill:#ffa; stroke:#666; stroke-width:3px; }
#mermaidChart1 .node text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaidChart1 .edgeLabel text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
#mermaidChart1 .cluster rect  { rx:4px; fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary, time, mark, audio, video { margin: 0px; padding: 0px; border: 0px; outline: 0px; font-size: 100%; vertical-align: baseline; background: transparent; }
#markdown-preview .mermaid .label { color: rgb(51, 51, 51); }
#markdown-preview .node rect, #markdown-preview .node circle, #markdown-preview .node polygon { fill: rgb(238, 238, 238); stroke: rgb(51, 51, 51); stroke-width: 1px; }
#markdown-preview .edgePath .path { stroke: rgb(51, 51, 51); }
#markdown-preview .cluster rect { fill: rgb(255, 255, 222) !important; rx: 4px !important; stroke: rgb(170, 170, 51) !important; stroke-width: 1px !important; }
#markdown-preview .cluster text { fill: rgb(51, 51, 51); }
#markdown-preview text { font-family: 'Roboto Slab', verdana, arial; font-size: 14px; }
/*  */
</style><g><g class="output"><g class="clusters"><g class="cluster" id="subGraph2" transform="translate(969,124)" style="opacity: 1;"><g class="label"><g transform="translate(-49.5,-12)"><foreignObject width="99" height="24"><div style="display: inline-block; white-space: nowrap;">subGraph2</div></foreignObject></g></g><rect width="206" height="208" x="-103" y="-104"></rect><text x="0" y="-90" fill="black" stroke="none" id="mermaidChart1Text" style="text-anchor: middle;"> Effects</text></g><g class="cluster" id="subGraph1" transform="translate(581.5,124)" style="opacity: 1;"><g class="label"><g transform="translate(-48,-12)"><foreignObject width="96" height="24"><div style="display: inline-block; white-space: nowrap;">subGraph1</div></foreignObject></g></g><rect width="469" height="208" x="-234.5" y="-104"></rect><text x="0" y="-90" fill="black" stroke="none" id="mermaidChart1Text" style="text-anchor: middle;"> Combat Scenario</text></g><g class="cluster" id="subGraph0" transform="translate(158.5,124)" style="opacity: 1;"><g class="label"><g transform="translate(-49.5,-12)"><foreignObject width="99" height="24"><div style="display: inline-block; white-space: nowrap;">subGraph0</div></foreignObject></g></g><rect width="277" height="208" x="-138.5" y="-104"></rect><text x="0" y="-90" fill="black" stroke="none" id="mermaidChart1Text" style="text-anchor: middle;"> Weapon &amp; Target</text></g></g><g class="edgePaths"><g class="edgePath" style="opacity: 1;"><path class="path" d="M257,77L297,77L322,77L347,77L403.9148936170213,102" marker-end="url(#arrowhead125)" style="fill:none"></path><defs><marker id="arrowhead125" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M272,171L297,171L322,171L347,171L403.9148936170213,146" marker-end="url(#arrowhead126)" style="stroke: #333; fill:none;stroke-width:2px;stroke-dasharray:3;"></path><defs><marker id="arrowhead126" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M504.0851063829787,102L561,77L595,77" marker-end="url(#arrowhead127)" style="fill:none"></path><defs><marker id="arrowhead127" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M504.0851063829787,146L561,171L586,171" marker-end="url(#arrowhead128)" style="fill:none"></path><defs><marker id="arrowhead128" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M782,77L816,77L841,77L866,77L891,77" marker-end="url(#arrowhead129)" style="fill:none"></path><defs><marker id="arrowhead129" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M791,171L816,171L841,171L866,171L908.5,171" marker-end="url(#arrowhead130)" style="fill:none"></path><defs><marker id="arrowhead130" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node" id="Damage" transform="translate(688.5,77)" style="opacity: 1;"><rect rx="5" ry="5" x="-93.5" y="-22" width="187" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-83.5,-12)"><foreignObject width="167" height="24"><div style="display: inline-block; white-space: nowrap;">DamageCalculator</div></foreignObject></g></g></g><g class="node" id="Output" transform="translate(969,77)" style="opacity: 1;"><rect rx="5" ry="5" x="-78" y="-22" width="156" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-68,-12)"><foreignObject width="136" height="24"><div style="display: inline-block; white-space: nowrap;">Bonus Damage</div></foreignObject></g></g></g><g class="node" id="Visual" transform="translate(688.5,171)" style="opacity: 1;"><rect rx="5" ry="5" x="-102.5" y="-22" width="205" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-92.5,-12)"><foreignObject width="185" height="24"><div style="display: inline-block; white-space: nowrap;">VisualEffectHandler</div></foreignObject></g></g></g><g class="node" id="Output2" transform="translate(969,171)" style="opacity: 1;"><rect rx="5" ry="5" x="-60.5" y="-22" width="121" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-50.5,-12)"><foreignObject width="101" height="24"><div style="display: inline-block; white-space: nowrap;">Set On Fire</div></foreignObject></g></g></g><g class="node" id="CombatHandler" transform="translate(454,124)" style="opacity: 1;"><rect rx="5" ry="5" x="-82" y="-22" width="164" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-72,-12)"><foreignObject width="144" height="24"><div style="display: inline-block; white-space: nowrap;">CombatHandler</div></foreignObject></g></g></g><g class="node" id="Tags" transform="translate(158.5,77)" style="opacity: 1;"><rect rx="5" ry="5" x="-98.5" y="-22" width="197" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-88.5,-12)"><foreignObject width="177" height="24"><div style="display: inline-block; white-space: nowrap;">silver, magic, sharp</div></foreignObject></g></g></g><g class="node" id="Optional" transform="translate(158.5,171)" style="opacity: 1;"><rect rx="5" ry="5" x="-113.5" y="-22" width="227" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-103.5,-12)"><foreignObject width="207" height="24"><div style="display: inline-block; white-space: nowrap;">werewolf, undead, frail</div></foreignObject></g></g></g></g></g></g></svg></div>

Now the problem is when I target svg tags and do the xml serialization like so:

var svgToDataUri = function(svgElement){

        console.log("converting svg to datauri");

        // Create canvas for converting image to data URL
        var image = document.createElement("img");
        var parent = svgElement.parentElement;
        image.style.width = svgElement.width + "px";
        image.style.height = svgElement.height + "px";

        // get svg data
        var xml = new XMLSerializer().serializeToString(svgElement);

        // make it base64
        var svg64 = btoa(xml);
        var image64 = 'data:image/svg+xml;base64,' + svg64;

        // Get data URL encoding of image
        image.setAttribute("src", image64);
        parent.insertBefore(image, svgElement);
        parent.removeChild(svgElement);
    };

The output image is missing bits and also does not seem to be styled correctly, even though it is basically replacing the existing content so should have all same styles on the page, so do I need to do anything special when outputting more complex svg elements to images or should this work? (tried it in FF, Chrome)

Here is an example of the actual output and desired output:

Example of broken SVG as image

So as you can see it just blacks out sections and some lines are not visible, the one below looks how I would expect it to look.

Grofit
  • 17,693
  • 24
  • 96
  • 176
  • Could you add some snapshot of what you get ? Running your code I can't repro on FF. Are you sure you don't have any external rules applied on the in doc svg? Also, as a test, could you try [this code](https://github.com/Kaiido/SVG2Bitmap/) on your svg ? – Kaiido Jan 20 '16 at 15:54
  • Hey just leaving office, will try again tomorrow and let you know, updated with an image of what happens. – Grofit Jan 20 '16 at 18:18
  • @Kaiido I have tried your lib as I would rather just re-use existing logic. I get the same output as above, but have noticed that mathjax does not get processed correctly. Have raised an issue for you. – Grofit Jan 21 '16 at 11:34

1 Answers1

1
  • #markdown-preview doesn't occur as an id of any element of your svg - or of the posted html for that matter. This means it won't render as you expect as original svg (see second attached image below).
  • Probably the html originally surrounding the div does contain an element with that id.
  • Quick fix: give the outer group in the svg the markdown-preview id: replace </style><g><g class="output"> with </style><g id="markdown-preview"><g class="output"> (see attached and HTML snippet image below)
  • Permanent fix: file an issue with the software that rendered the svg.

results

I've uncommented the parent.removeChild(svgElement); in your code so I could see both the img (first in each) and the original svg (second).

Fixed:

Fixed HTML

The original HTML:

Original HTML

The code I used to reproduce 'fixed'

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script type="text/javascript" defer>
            var svgToDataUri = function(svgElement){

                    console.log("converting svg to datauri");

                    // Create canvas for converting image to data URL
                    var image = document.createElement("img");
                    var parent = svgElement.parentElement;
                    image.style.width = svgElement.width + "px";
                    image.style.height = svgElement.height + "px";

                    // get svg data
                    var xml = new XMLSerializer().serializeToString(svgElement);

                    // make it base64
                    var svg64 = btoa(xml);
                    var image64 = 'data:image/svg+xml;base64,' + svg64;

                    // Get data URL encoding of image
                    image.setAttribute("src", image64);
                    parent.insertBefore(image, svgElement);
                    // parent.removeChild(svgElement);
                };

        </script>

    </head>
    <body>

        <div class="mermaid" data-processed="true"><svg id="mermaidChart1" width="100%" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 1112 268" style="max-width:1112px;"><style type="text/css" title="mermaid-svg-internal-css">/*  */
        #mermaidChart1 .node { fill:#ffa; stroke:#666; stroke-width:3px; }
        #mermaidChart1 .node text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
        #mermaidChart1 .edgeLabel text  { fill:#000; stroke:none; font-weight:300; font-family:"Helvetica Neue",Helvetica,Arial,sans-serf; font-size:14px; }
        #mermaidChart1 .cluster rect  { rx:4px; fill: rgb(255, 255, 222); rx: 4px; stroke: rgb(170, 170, 51); stroke-width: 1px; }
        html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary, time, mark, audio, video { margin: 0px; padding: 0px; border: 0px; outline: 0px; font-size: 100%; vertical-align: baseline; background: transparent; }
        #markdown-preview .mermaid .label { color: rgb(51, 51, 51); }
        #markdown-preview .node rect, #markdown-preview .node circle, #markdown-preview .node polygon { fill: rgb(238, 238, 238); stroke: rgb(51, 51, 51); stroke-width: 1px; }
        #markdown-preview .edgePath .path { stroke: rgb(51, 51, 51); }
        #markdown-preview .cluster rect { fill: rgb(255, 255, 222) !important; rx: 4px !important; stroke: rgb(170, 170, 51) !important; stroke-width: 1px !important; }
        #markdown-preview .cluster text { fill: rgb(51, 51, 51); }
        #markdown-preview text { font-family: 'Roboto Slab', verdana, arial; font-size: 14px; }
        /*  */
        </style><g id="markdown-preview"><g class="output"><g class="clusters"><g class="cluster" id="subGraph2" transform="translate(969,124)" style="opacity: 1;"><g class="label"><g transform="translate(-49.5,-12)"><foreignObject width="99" height="24"><div style="display: inline-block; white-space: nowrap;">subGraph2</div></foreignObject></g></g><rect width="206" height="208" x="-103" y="-104"></rect><text x="0" y="-90" fill="black" stroke="none" id="mermaidChart1Text" style="text-anchor: middle;"> Effects</text></g><g class="cluster" id="subGraph1" transform="translate(581.5,124)" style="opacity: 1;"><g class="label"><g transform="translate(-48,-12)"><foreignObject width="96" height="24"><div style="display: inline-block; white-space: nowrap;">subGraph1</div></foreignObject></g></g><rect width="469" height="208" x="-234.5" y="-104"></rect><text x="0" y="-90" fill="black" stroke="none" id="mermaidChart1Text" style="text-anchor: middle;"> Combat Scenario</text></g><g class="cluster" id="subGraph0" transform="translate(158.5,124)" style="opacity: 1;"><g class="label"><g transform="translate(-49.5,-12)"><foreignObject width="99" height="24"><div style="display: inline-block; white-space: nowrap;">subGraph0</div></foreignObject></g></g><rect width="277" height="208" x="-138.5" y="-104"></rect><text x="0" y="-90" fill="black" stroke="none" id="mermaidChart1Text" style="text-anchor: middle;"> Weapon &amp; Target</text></g></g><g class="edgePaths"><g class="edgePath" style="opacity: 1;"><path class="path" d="M257,77L297,77L322,77L347,77L403.9148936170213,102" marker-end="url(#arrowhead125)" style="fill:none"></path><defs><marker id="arrowhead125" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M272,171L297,171L322,171L347,171L403.9148936170213,146" marker-end="url(#arrowhead126)" style="stroke: #333; fill:none;stroke-width:2px;stroke-dasharray:3;"></path><defs><marker id="arrowhead126" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M504.0851063829787,102L561,77L595,77" marker-end="url(#arrowhead127)" style="fill:none"></path><defs><marker id="arrowhead127" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M504.0851063829787,146L561,171L586,171" marker-end="url(#arrowhead128)" style="fill:none"></path><defs><marker id="arrowhead128" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M782,77L816,77L841,77L866,77L891,77" marker-end="url(#arrowhead129)" style="fill:none"></path><defs><marker id="arrowhead129" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g><g class="edgePath" style="opacity: 1;"><path class="path" d="M791,171L816,171L841,171L866,171L908.5,171" marker-end="url(#arrowhead130)" style="fill:none"></path><defs><marker id="arrowhead130" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" style="fill: #333"></path></marker></defs></g></g><g class="edgeLabels"><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g><g class="edgeLabel" transform="" style="opacity: 1;"><g transform="translate(0,0)" class="label"><foreignObject width="0" height="0"><div style="display: inline-block; white-space: nowrap;"><span style="background:#e8e8e8"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node" id="Damage" transform="translate(688.5,77)" style="opacity: 1;"><rect rx="5" ry="5" x="-93.5" y="-22" width="187" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-83.5,-12)"><foreignObject width="167" height="24"><div style="display: inline-block; white-space: nowrap;">DamageCalculator</div></foreignObject></g></g></g><g class="node" id="Output" transform="translate(969,77)" style="opacity: 1;"><rect rx="5" ry="5" x="-78" y="-22" width="156" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-68,-12)"><foreignObject width="136" height="24"><div style="display: inline-block; white-space: nowrap;">Bonus Damage</div></foreignObject></g></g></g><g class="node" id="Visual" transform="translate(688.5,171)" style="opacity: 1;"><rect rx="5" ry="5" x="-102.5" y="-22" width="205" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-92.5,-12)"><foreignObject width="185" height="24"><div style="display: inline-block; white-space: nowrap;">VisualEffectHandler</div></foreignObject></g></g></g><g class="node" id="Output2" transform="translate(969,171)" style="opacity: 1;"><rect rx="5" ry="5" x="-60.5" y="-22" width="121" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-50.5,-12)"><foreignObject width="101" height="24"><div style="display: inline-block; white-space: nowrap;">Set On Fire</div></foreignObject></g></g></g><g class="node" id="CombatHandler" transform="translate(454,124)" style="opacity: 1;"><rect rx="5" ry="5" x="-82" y="-22" width="164" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-72,-12)"><foreignObject width="144" height="24"><div style="display: inline-block; white-space: nowrap;">CombatHandler</div></foreignObject></g></g></g><g class="node" id="Tags" transform="translate(158.5,77)" style="opacity: 1;"><rect rx="5" ry="5" x="-98.5" y="-22" width="197" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-88.5,-12)"><foreignObject width="177" height="24"><div style="display: inline-block; white-space: nowrap;">silver, magic, sharp</div></foreignObject></g></g></g><g class="node" id="Optional" transform="translate(158.5,171)" style="opacity: 1;"><rect rx="5" ry="5" x="-113.5" y="-22" width="227" height="44"></rect><g class="label" transform="translate(0,0)"><g transform="translate(-103.5,-12)"><foreignObject width="207" height="24"><div style="display: inline-block; white-space: nowrap;">werewolf, undead, frail</div></foreignObject></g></g></g></g></g></g></svg></div>

        <script>
            svgToDataUri(document.getElementById("mermaidChart1"));
        </script>
    </body>
</html>

B.t.w. here's some things I learned the hard way to do while developing mscgen_js, but you might already know and left out just to simplify your sample code:

  • add a charset to the data uri, so text will render correctly even when it's not ASCII (provided fonts are available) data:image/svg+xml;charset=utf-8;base64,
  • for similar reasons, when dumping the generated uri in links/ url bars encodeURIComponent and unescape it before feeding it to the btoa
  • (... and think of a strategy for hitting browse max uri length in case you ever run on IE)
Sander
  • 622
  • 6
  • 12
  • For the max uri length, a first way is to not base64 encode the string, it doesn't add anything good but 30% more characters. A simple dataURI with `'data:image/svg+xml; charset=utf8, '` as a header has more compatibility than the b64 version. Also, `encodeURIComponent('serializedMarkup')` should be enough, no need to `encodeURIComponent`+`unescape`+`btoa`. Finally, do you have some numbers about this IE max-length hit ? I only did tested Chrome (approx. 90 000 000 chars) and Firefox (approx. 205 963 544 chars in FF) on my machine, and I even was wondering if it has to do with the hardware. – Kaiido Jan 21 '16 at 04:26
  • Thank you so much for the information, will give it a go now. As you mention the `#markdown-preview` is the parent container of all this stuff, although mermaid is auto generating that css so I assume it uses the parent containers ID for some reason. Will give this a whirl and give you the answer if it works. – Grofit Jan 21 '16 at 08:04
  • Doing what you mention does make sense but does not fix it in the real scenario, you are correct in that there is a parent element which has the id `markdown-preview` which is a fairly high level div in the page. Thing is when the SVG is moved to an image with embedded SVG content, the structure is pretty much the same as the img replaces the svg node (as far as the DOM is concerned) so it is still contained within a `markdown-preview` container, but as you see the styles still break. Problem is I have multiple svg elements on the page so I cannot just add the id constraint into the svg. – Grofit Jan 21 '16 at 09:07
  • I guess the crux of my query here is does the CSS behave differently when embedded like it is? i.e will it only style things WITHIN the image? so it ignores anything outside of it? so although it is contained within a `#markdown-preview` in the DOM, inside the `img` element there is no element with that ID, so does this change how the CSS is processed? i.e it acts like an iframe and does not bleed out into the rest of the page etc. – Grofit Jan 21 '16 at 09:10
  • @Grofit it acts worth than in an iframe. No external content is loaded from an `` tag's content, and no external content can access it either. You have to make your content self-sufficient and include everything within the dataURI. – Kaiido Jan 21 '16 at 14:23
  • ah ok, this may be where things are falling down, as even if I try and hack it by setting an internal id it still seems to do some odd stuff on more complex charts etc, gantt charts dont even display its just a black blob. I mean without detracting the problem I need solving is extracting SVGs which looks fine on the page then converting them into an image and replacing them, so it may be that I need to look at alternative ways to do this, or do more magic to extract styles out of the svg and put them outside of it. – Grofit Jan 21 '16 at 14:36
  • @Grofit, you can then tweak [SVG2Bitmap.js](https://github.com/Kaiido/SVG2Bitmap/blob/master/SVG2Bitmap.js), it could actually be seen just as this : it gets any external resources needed in the svg, and append it inside, so it can be "self-sufficient". Btw, I may add a `toSVGString` during the week-end. – Kaiido Jan 21 '16 at 14:56
  • about scope: what @Kaiido says. The tool that generated the svg & page should be fixed to prevent this from happening. – Sander Jan 21 '16 at 19:29
  • @Kaiido: [Maximum URL length is 2,083 characters in Internet Explorer](https://support.microsoft.com/en-us/kb/208427). About not having to base64 it: true. Only necessary for binary stuff - was doing that out of habit about unescape: that is indeed not necessary (anymore?). And `unescape` is deprecated now. `encodeURIComponent` remains necessary. – Sander Jan 21 '16 at 20:00
  • I may be wrong but that seems to apply to IE<6 which didn't supported dataURI nor svg btw. – Kaiido Jan 21 '16 at 23:13
  • Last I tested the limit still applied up till IE10. Don't know about Edge. Also see the first answer of [what-is-the-maximum-length-of-a-url-in-different-browsers](http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers?rq=1) – Sander Jan 22 '16 at 20:53
  • @Sander this question is about http protocol. For dataURI (which is what interests us here), you can get much more and since IE9 : https://jsfiddle.net/ej5thLzb/ 2.5M characters, perfectly loaded in a VM. – Kaiido Jan 24 '16 at 07:14