bramp / js-sequence-diagrams

Draws simple SVG sequence diagrams from textual representation of the diagram
https://bramp.github.io/js-sequence-diagrams/
BSD 2-Clause "Simplified" License
7.8k stars 1.08k forks source link

Export as image #47

Open ratonlarvor opened 11 years ago

ratonlarvor commented 11 years ago

Would it be possible to export the result as PNG image like the svg export ?

yesnault commented 10 years ago

+1

alexandre-mbm commented 10 years ago

:+1:

bramp commented 10 years ago

Saving as PNG is a little tricky. As the SVG is generated client side, the browser has to save the SVG as a PNG. A year ago when I last tried, I had mixed success getting this to work. I will revisit.

winfinit commented 9 years ago

simplest way to get a PNG, is to port SVG to canvas, and then from canvas element get data image, and assign that to either img or a

i found an issue with this approach, and that is probably you had a mixed success, raphael.js doesn't produce valid SVG at times, if xlink namespaces are used, and in this case xlink:href is used quite a lot when relationships/signals are created.

hopefully next version of raphael will resolve that, there is a pull request to fix this particular issue.

question is weather js-sequence-diagram wants to pull as part of the project all of the dependencies that are used to create PNG (similar how raphael.js and others are pulled), or do we just want to address this as part of the documentation?

example uses canvg.js and patched version of raphael.js

below example can be previewed with all of the proper dependencies here on jsfiddle

<!DOCTYPE html>
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!-->
<html class="no-js">
<!--<![endif]-->
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">

        <script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/rgbcolor.js"></script>
        <script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/StackBlur.js"></script>
        <script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/canvg.js"></script>
        <script src="jquery.min.js"></script>
        <script src="lodash.min.js"></script>
        <script src="raphael-min.js"></script>
        <script src="../build/sequence-diagram-min.js"></script>

    </head>
    <body>

        <table border="1">
            <thead>
                <th>SVG</th>
                <th>PNG</th>
                <th>Anchor</th>
            </thead>
            <tbody>
                <tr>
                    <td><div id="svgWrapper"></div></td>
                    <td><img id="myPNG"></img></td>
                    <td><a id="uriToPNG"></a></td>
                </tr>
            </tbody>
        </table>

        <script>
            $(document).ready(function() {
                // set svgWrapper content to blank
                $("#svgWrapper").html('');
                var diagram = Diagram.parse( 
                        "Title: Sample Diagram\nA->B: message"
                );
                // draw SVG inside element with id of svgWrapper
                diagram.drawSVG('svgWrapper', {
                    theme : 'hand'
                });

                // select container that is wraping SVG
                var container = $('#svgWrapper');
                // tring selected SVG
                var content = container.html().trim();
                // create canvas element
                var canvas = document.createElement("canvas");
                // transform and add SVG content to canvas
                canvg(canvas, content);

                // get data for image in the canvas
                var theImage = canvas.toDataURL('image/png');

                // add to anchor a href of produced data
                $('#uriToPNG').attr({
                    'href' : theImage,
                    'download' : "image.png",
                }).text("click here to download (chrome,firefox, opera)");

                // add PNG to img element
                $('#myPNG').attr('src', theImage);

            });

        </script>
    </body>
</html>
ComFreek commented 9 years ago

There is an even simpler approach:

  1. Extract the SVG source code from the <svg> element. svg.outerHTML works (at least in Chrome).
  2. Load the source code (as a data URI) into an <image> element.
    At this stage you can already right-click and select "Save image" in Chrome.
  3. Load the image data using canvas2dContext.drawImage(img, 0, 0) into a canvas.
  4. Save the canvas data as a PNG using canvas.toDataURL("image/png").

jsFiddle demo: http://jsfiddle.net/0ktjqm9t/3/ (directly visiting http://jsfiddle.net/0ktjqm9t/3/show will show the data URI in the address bar in Chrome)

Caveats:

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

<!-- Supplying some more attributes I found on MDN seems reasonable to me -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ...>
winfinit commented 9 years ago

that example producing a broken image for me actually in safari.

ComFreek commented 9 years ago

@winfinit It definitely needs investigating. What is the browser compatibility like in your solution? I can't find information on that topic on canvg's Google Code website.

winfinit commented 9 years ago

@ComFreek it looks like opera, safari (ios+osx), chrome are working, so browsers that support SVG. i just ran provided jsfiddle through browserstack, and it seems that everything rendered as expected.

ComFreek commented 9 years ago

That sounds nice!

Unfortunately - as I just tried - it doesn't work in IE 11 on Win 8.1:

File: show
HTML1503: Unexpected start tag.
File: show, Line: 93, Column: 9
HTML1512: Unmatched end tag.
File: show, Line: 100, Column: 33
SCRIPT5022: SyntaxError
File: canvg.js, Line: 145, Column: 5

The line from canvg.js:

else if (window.DOMParser)
{
    var parser = new DOMParser();
    return parser.parseFromString(xml, 'text/xml');
}

It seems that the SVG is ill-formed.

tiagoboldt commented 7 years ago

Ping! Has anyone reconsidered this?

vin-ni commented 6 years ago

I'm using this as an image src (new XMLSerializer).serializeToString(svg)

Works everywhere except ios safari. The functions returns wrong results.

vin-ni commented 6 years ago

Actually what I found is bugging: <svg xmlns="http://www.w3.org/2000/svg" class="sequence simple" width="990.539px" height="401.203px" y="0" systemLanguage="" externalResourcesRequired="false" requiredFeatures="" transform="" preserveAspectRatio="xMidYMid meet" requiredExtensions="" viewBox="0 0 0 0" x="0">

It works if its: <svg xmlns="http://www.w3.org/2000/svg" class="sequence simple" width="990.539px" height="401.203px">

vin-ni commented 6 years ago

The solution I found to display the generated SVG responsively via a element cross device.

After the svg is rendered I call:

// diagramDom is the element holding the svg
var svg = diagramDom.getElementsByTagName('svg')[0];
var img = document.createElement("IMG");
 img.src = "";
setImageToSVG(img, svg);
diagramDom.appendChild(img);

function setImageToSVG(img, svg) {
    //function to clean svg so it also works on iOs Safari
    svg.removeAttribute("x");
    svg.removeAttribute("y");
    svg.removeAttribute("systemLanguage");
    svg.removeAttribute("externalResourcesRequired");
    svg.removeAttribute("requiredFeatures");
    svg.removeAttribute("transform");
    svg.removeAttribute("preserveAspectRatio");
    svg.removeAttribute("requiredExtensions");
    svg.removeAttribute("viewBox");

    var xml = (new XMLSerializer).serializeToString(svg);

    let string = `data:image/svg+xml;charset=utf-8,${xml}`;
    img.src = string;
}