forked from zalando/tech-radar
-
Notifications
You must be signed in to change notification settings - Fork 3
/
svg-crowbar-export.js
132 lines (105 loc) · 4.59 KB
/
svg-crowbar-export.js
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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
129
130
131
132
var svg_crowbar = function (svg_el, options){
// TODO: should probably do some checking to make sure that svg_el is
// actually a <svg> and throw a friendly error otherwise
// get options passed to svg_crowbar
var filename = options.filename || "download.png";
var width = options.width; // TODO: add fallback value based on svg attributes
var height = options.height; // TODO: add fallback value based on svg attributes
var crowbar_el = options.crowbar_el; // TODO: element for preparing the canvas element
// apply the stylesheet to the svg to be sure to capture all of the stylings
applyStylesheets(svg_el)
// grab the html from the svg and encode the svg in a data url
var html = svg_el.outerHTML;
var imgsrc = "data:image/svg+xml;base64," + window.btoa(unescape(encodeURIComponent(html)));
// create a canvas element that has the right dimensions
crowbar_el.innerHTML = (
'<canvas width="' + width + '" height="' + height + '"></canvas>'
)
var ua = navigator.userAgent.toLowerCase();
// if (ua.indexOf('safari') != -1) {
// if (ua.indexOf('chrome') > -1) {
// } else {
// crowbar_el.innerHTML = (
// '<canvas width="' + 1300 + '" height="' + 1000 + '"></canvas>'
// )
// }
// }
var canvas = crowbar_el.querySelector("canvas");
// var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
var image = new Image;
image.src = imgsrc;
image.onload = function() {
// draw the image in the context of the canvas and then get the
// image data from the canvas
//
// TODO: the resulting canvas image is a little on the grainy side.
// up until this point the image is lossless, so it definitely has
// something to do with the imgsrc getting lost when embedding in
// the canvas. this appears to be a problem with just about
// anything i've seen
context.drawImage(image, 0, 0);
var canvasdata = canvas.toDataURL("image/png", context);
var a = window.document.createElement("a");
a.download = filename;
a.href = canvasdata;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
canvasdata = null;
};
// this is adapted (barely) from svg-crowbar
// https://github.com/NYTimes/svg-crowbar/blob/gh-pages/svg-crowbar-2.js#L211-L250
function applyStylesheets(svgEl) {
// use an empty svg to compute the browser applied stylesheets
var emptySvg = window.document.createElementNS("http://www.w3.org/2000/svg", 'svg');
window.document.body.appendChild(emptySvg);
var emptySvgDeclarationComputed = getComputedStyle(emptySvg);
emptySvg.parentNode.removeChild(emptySvg);
// traverse the element tree and explicitly set all stylesheet values
// on an element. this is ripped from svg-crowbar
var allElements = traverse(svgEl);
var i = allElements.length;
while (i--){
explicitlySetStyle(allElements[i], emptySvgDeclarationComputed);
}
}
function explicitlySetStyle (element, emptySvgDeclarationComputed) {
var cSSStyleDeclarationComputed = getComputedStyle(element);
var i, len, key, value;
var computedStyleStr = "";
for (i=0, len=cSSStyleDeclarationComputed.length; i<len; i++) {
key=cSSStyleDeclarationComputed[i];
value=cSSStyleDeclarationComputed.getPropertyValue(key);
if (value!==emptySvgDeclarationComputed.getPropertyValue(key)) {
computedStyleStr+=key+":"+value+";";
}
}
element.setAttribute('style', computedStyleStr);
}
// traverse an svg and append all of the elements to the tree array. This
// ignores some elements that can appear in <svg> elements but whose
// children's styles should not be tweaked
function traverse(obj){
var tree = [];
var ignoreElements = {
'script': undefined,
'defs': undefined,
};
tree.push(obj);
visit(obj);
function visit(node) {
if (node && node.hasChildNodes() && !(node.nodeName.toLowerCase() in ignoreElements)) {
var child = node.firstChild;
while (child) {
if (child.nodeType === 1) {
tree.push(child);
visit(child);
}
child = child.nextSibling;
}
}
}
return tree;
}
}