Blame view

app/main/static/js/svg_to_png.js 4.45 KB
5e6f4e07   hitier   Set Rokotyan Solu...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
var download_png = function () {
    // This callback is supposed to be called on the click event of a button child of the div containing the svg.
    // We then get the parent of this btn to guess the chart's title, width and heigth
    var chart_div = this.parentNode;
    var chart_title = chart_div.id;
    width = chart_div.offsetWidth;
    height = chart_div.offsetHeight;

    // Then we can access the svg contained in that parent
    svg = chart_div.getElementsByTagName('svg')[0]

    // Export to string and save
    var svgString = getSVGString(svg);
    svgString2Image(svgString, 2 * width, 2 * height, 'png', save); // passes Blob and filesize String to the callback

    function save(dataBlob, filesize) {
        saveAs(dataBlob, chart_title); // FileSaver.js function
    }
}


// Below are the functions that handle actual exporting:
// getSVGString ( svgNode ) and svgString2Image( svgString, width, height, format, callback )
function getSVGString(svgNode) {
    svgNode.setAttribute('xlink', 'http://www.w3.org/1999/xlink');
    var cssStyleText = getCSSStyles(svgNode);
    appendCSS(cssStyleText, svgNode);

    var serializer = new XMLSerializer();
    var svgString = serializer.serializeToString(svgNode);
    svgString = svgString.replace(/(\w+)?:?xlink=/g, 'xmlns:xlink='); // Fix root xlink without namespace
    svgString = svgString.replace(/NS\d+:href/g, 'xlink:href'); // Safari NS namespace fix

    return svgString;

    function getCSSStyles(parentElement) {
        var selectorTextArr = [];

        // Add Parent element Id and Classes to the list
        selectorTextArr.push('#' + parentElement.id);
b87db710   hitier   Fix css extractio...
41
42
        for (var c = 0; c < parentElement.classList.length; c++){
            if (!contains('.' + parentElement.classList[c], selectorTextArr)){
5e6f4e07   hitier   Set Rokotyan Solu...
43
                selectorTextArr.push('.' + parentElement.classList[c]);
b87db710   hitier   Fix css extractio...
44
45
            }
        }
5e6f4e07   hitier   Set Rokotyan Solu...
46
47
48
49
50
51
52
53
54

        // Add Children element Ids and Classes to the list
        var nodes = parentElement.getElementsByTagName("*");
        for (var i = 0; i < nodes.length; i++) {
            var id = nodes[i].id;
            if (!contains('#' + id, selectorTextArr))
                selectorTextArr.push('#' + id);

            var classes = nodes[i].classList;
b87db710   hitier   Fix css extractio...
55
            for (var c = 0; c < classes.length; c++){
5e6f4e07   hitier   Set Rokotyan Solu...
56
57
                if (!contains('.' + classes[c], selectorTextArr))
                    selectorTextArr.push('.' + classes[c]);
b87db710   hitier   Fix css extractio...
58
            }
5e6f4e07   hitier   Set Rokotyan Solu...
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
        }

        // Extract CSS Rules
        var extractedCSSText = "";
        for (var i = 0; i < document.styleSheets.length; i++) {
            var s = document.styleSheets[i];

            try {
                if (!s.cssRules) continue;
            } catch (e) {
                if (e.name !== 'SecurityError') throw e; // for Firefox
                continue;
            }

            var cssRules = s.cssRules;
            for (var r = 0; r < cssRules.length; r++) {
b87db710   hitier   Fix css extractio...
75
76
77
78
79
80
81
                var cssRule = cssRules[r]
                if (typeof cssRule.selectorText === 'undefined') {
                    continue;
                }
                var classFromSelector = '.'+cssRule.selectorText.split('.')[1]
                if (contains(classFromSelector, selectorTextArr))
                    extractedCSSText += cssRule.cssText;
5e6f4e07   hitier   Set Rokotyan Solu...
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
            }
        }


        return extractedCSSText;

        function contains(str, arr) {
            return arr.indexOf(str) === -1 ? false : true;
        }

    }

    function appendCSS(cssText, element) {
        var styleElement = document.createElement("style");
        styleElement.setAttribute("type", "text/css");
        styleElement.innerHTML = cssText;
        var refNode = element.hasChildNodes() ? element.children[0] : null;
        element.insertBefore(styleElement, refNode);
    }
}

function svgString2Image(svgString, width, height, format, callback) {
    var format = format ? format : 'png';

    var imgsrc = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svgString))); // Convert SVG string to data URL

    var canvas = document.createElement("canvas");
    var context = canvas.getContext("2d");

    canvas.width = width;
    canvas.height = height;

    var image = new Image();
    image.onload = function () {
        context.clearRect(0, 0, width, height);
        context.drawImage(image, 0, 0, width, height);

        canvas.toBlob(function (blob) {
            var filesize = Math.round(blob.length / 1024) + ' KB';
            if (callback) callback(blob, filesize);
        });


    };

    image.src = imgsrc;
}