Commit 9d1e206582d8a9d1ac2227f40630d534e87988a2
1 parent
1d74f62f
Exists in
master
Fix an issue with PNG downloads.
Showing
3 changed files
with
134 additions
and
125 deletions
Show diff stats
flaskr/static/js/vendor/simg.js
1 | 1 | /*jshint nonstandard:true */ |
2 | -(function(root){ | |
3 | - var previousSimg = root.Simg; | |
4 | - var Simg = root.Simg = function(svg){ | |
5 | - this.svg = svg; | |
6 | - }; | |
7 | - | |
8 | - Simg.noConflict = function(){ | |
9 | - root.Simg = previousSimg; | |
10 | - return this; | |
11 | - }; | |
12 | - | |
13 | - Simg.getBase64Image = function(img) { | |
14 | - // From: http://stackoverflow.com/questions/934012/get-image-data-in-javascript | |
15 | - var canvas = document.createElement("canvas"); | |
16 | - canvas.width = img.width; | |
17 | - canvas.height = img.height; | |
18 | - | |
19 | - var ctx = canvas.getContext("2d"); | |
20 | - ctx.drawImage(img, 0, 0); | |
21 | - var dataURL = canvas.toDataURL("image/png"); | |
22 | - | |
23 | - return dataURL.replace(/^data:image\/(png|jpg);base64,/, ""); | |
24 | - }; | |
25 | - | |
26 | - Simg.prototype = { | |
27 | - // Return SVG text. | |
28 | - toString: function(svg){ | |
29 | - if (!svg){ | |
30 | - throw new Error('.toString: No SVG found.'); | |
31 | - } | |
32 | - | |
33 | - [ | |
34 | - ['version', 1.1], | |
35 | - ['xmlns', "http://www.w3.org/2000/svg"], | |
36 | - ].forEach(function(item){ | |
37 | - svg.setAttribute(item[0], item[1]); | |
38 | - }); | |
39 | - return svg.parentNode.innerHTML; | |
40 | - }, | |
41 | - | |
42 | - // Return canvas with this SVG drawn inside. | |
43 | - toCanvas: function(cb){ | |
44 | - this.toSvgImage(function(img){ | |
45 | - var canvas = document.createElement('canvas'); | |
46 | - var context = canvas.getContext("2d"); | |
47 | - | |
2 | +(function (root) { | |
3 | + var previousSimg = root.Simg; | |
4 | + var Simg = root.Simg = function (svg) { | |
5 | + this.svg = svg; | |
6 | + }; | |
7 | + | |
8 | + Simg.noConflict = function () { | |
9 | + root.Simg = previousSimg; | |
10 | + return this; | |
11 | + }; | |
12 | + | |
13 | + Simg.getBase64Image = function (img) { | |
14 | + // From: http://stackoverflow.com/questions/934012/get-image-data-in-javascript | |
15 | + var canvas = document.createElement("canvas"); | |
48 | 16 | canvas.width = img.width; |
49 | 17 | canvas.height = img.height; |
50 | 18 | |
51 | - context.drawImage(img, 0, 0); | |
52 | - cb(canvas); | |
53 | - }); | |
54 | - }, | |
55 | - | |
56 | - toSvgImage: function(cb){ | |
57 | - var str = this.toString(this.svg); | |
58 | - var img = document.createElement('img'); | |
59 | - | |
60 | - if (cb){ | |
61 | - img.onload = function(){ | |
62 | - cb(img); | |
63 | - }; | |
64 | - } | |
65 | - | |
66 | - // Make the new img's source an SVG image. | |
67 | - img.setAttribute('src', 'data:image/svg+xml;base64,'+ btoa(unescape(encodeURIComponent(str)))); | |
68 | - }, | |
69 | - | |
70 | - // Returns callback to new img from SVG. | |
71 | - // Call with no arguments to return svg image element. | |
72 | - // Call with callback to return png image element. | |
73 | - toImg: function(cb){ | |
74 | - this.toCanvas(function(canvas){ | |
75 | - var canvasData = canvas.toDataURL("image/png"); | |
76 | - var img = document.createElement('img'); | |
77 | - | |
78 | - img.onload = function(){ | |
79 | - cb(img); | |
80 | - }; | |
81 | - | |
82 | - // Make pngImg's source the canvas data. | |
83 | - img.setAttribute('src', canvasData); | |
84 | - }); | |
85 | - }, | |
86 | - | |
87 | - // Replace SVG with PNG img. | |
88 | - replace: function(cb){ | |
89 | - var self = this; | |
90 | - this.toImg(function(img){ | |
91 | - var parentNode = self.svg.parentNode; | |
92 | - parentNode.replaceChild(img, self.svg); | |
93 | - if (cb){ | |
94 | - cb(); | |
95 | - } | |
96 | - }); | |
97 | - }, | |
98 | - | |
99 | - // Converts canvas to binary blob. | |
100 | - toBinaryBlob: function(cb){ | |
101 | - this.toCanvas(function(canvas){ | |
102 | - var dataUrl = canvas.toDataURL().replace(/^data:image\/(png|jpg);base64,/, ""); | |
103 | - var byteString = atob(escape(dataUrl)); | |
104 | - // write the bytes of the string to an ArrayBuffer | |
105 | - var ab = new ArrayBuffer(byteString.length); | |
106 | - var ia = new Uint8Array(ab); | |
107 | - for (var i = 0; i < byteString.length; i++) { | |
108 | - ia[i] = byteString.charCodeAt(i); | |
19 | + var ctx = canvas.getContext("2d"); | |
20 | + ctx.drawImage(img, 0, 0); | |
21 | + var dataURL = canvas.toDataURL("image/png"); | |
22 | + | |
23 | + return dataURL.replace(/^data:image\/(png|jpg);base64,/, ""); | |
24 | + }; | |
25 | + | |
26 | + Simg.prototype = { | |
27 | + // Return SVG text. | |
28 | + toString: function (svg) { | |
29 | + if (!svg) { | |
30 | + throw new Error('.toString: No SVG found.'); | |
31 | + } | |
32 | + | |
33 | + [ | |
34 | + ['version', 1.1], | |
35 | + ['xmlns', "http://www.w3.org/2000/svg"], | |
36 | + ].forEach(function (item) { | |
37 | + svg.setAttribute(item[0], item[1]); | |
38 | + }); | |
39 | + return svg.parentNode.innerHTML; | |
40 | + }, | |
41 | + | |
42 | + // Return canvas with this SVG drawn inside. | |
43 | + toCanvas: function (cb) { | |
44 | + this.toSvgImage(function (img) { | |
45 | + var canvas = document.createElement('canvas'); | |
46 | + var context = canvas.getContext("2d"); | |
47 | + | |
48 | + canvas.width = img.width; | |
49 | + canvas.height = img.height; | |
50 | + | |
51 | + context.drawImage(img, 0, 0); | |
52 | + cb(canvas); | |
53 | + }); | |
54 | + }, | |
55 | + | |
56 | + toSvgImage: function (cb) { | |
57 | + var str = this.toString(this.svg); | |
58 | + var img = document.createElement('img'); | |
59 | + | |
60 | + if (cb) { | |
61 | + img.onload = function () { | |
62 | + cb(img); | |
63 | + }; | |
64 | + } | |
65 | + | |
66 | + // Make the new img's source an SVG image. | |
67 | + img.setAttribute('src', 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(str)))); | |
68 | + | |
69 | + //document.getElementById("png_buffer").appendChild(img); | |
70 | + }, | |
71 | + | |
72 | + // Returns callback to new img from SVG. | |
73 | + // Call with no arguments to return svg image element. | |
74 | + // Call with callback to return png image element. | |
75 | + toImg: function (cb) { | |
76 | + this.toCanvas(function (canvas) { | |
77 | + var canvasData = canvas.toDataURL("image/png"); | |
78 | + var img = document.createElement('img'); | |
79 | + //document.getElementById("png_buffer").appendChild(img); | |
80 | + img.onload = function () { | |
81 | + cb(img); | |
82 | + }; | |
83 | + | |
84 | + // Make pngImg's source the canvas data. | |
85 | + img.setAttribute('src', canvasData); | |
86 | + }); | |
87 | + }, | |
88 | + | |
89 | + // Replace SVG with PNG img. | |
90 | + replace: function (cb) { | |
91 | + var self = this; | |
92 | + this.toImg(function (img) { | |
93 | + var parentNode = self.svg.parentNode; | |
94 | + parentNode.replaceChild(img, self.svg); | |
95 | + if (cb) { | |
96 | + cb(); | |
97 | + } | |
98 | + }); | |
99 | + }, | |
100 | + | |
101 | + // Converts canvas to binary blob. | |
102 | + toBinaryBlob: function (cb) { | |
103 | + this.toCanvas(function (canvas) { | |
104 | + var dataUrl = canvas.toDataURL().replace(/^data:image\/(png|jpg);base64,/, ""); | |
105 | + var byteString = atob(escape(dataUrl)); | |
106 | + // write the bytes of the string to an ArrayBuffer | |
107 | + var ab = new ArrayBuffer(byteString.length); | |
108 | + var ia = new Uint8Array(ab); | |
109 | + for (var i = 0; i < byteString.length; i++) { | |
110 | + ia[i] = byteString.charCodeAt(i); | |
111 | + } | |
112 | + var dataView = new DataView(ab); | |
113 | + var blob = new Blob([dataView], {type: "image/png"}); | |
114 | + cb(blob); | |
115 | + }); | |
116 | + }, | |
117 | + | |
118 | + // Trigger download of image. | |
119 | + download: function (filename) { | |
120 | + if (!filename) { | |
121 | + filename = 'chart'; | |
122 | + } | |
123 | + this.toImg(function (img) { | |
124 | + var a = document.createElement("a"); | |
125 | + a.download = filename + ".png"; | |
126 | + a.href = img.getAttribute('src'); | |
127 | + //document.getElementById("png_buffer").appendChild(a); | |
128 | + a.click(); | |
129 | + }); | |
109 | 130 | } |
110 | - var dataView = new DataView(ab); | |
111 | - var blob = new Blob([dataView], {type: "image/png"}); | |
112 | - cb(blob); | |
113 | - }); | |
114 | - }, | |
115 | - | |
116 | - // Trigger download of image. | |
117 | - download: function(filename){ | |
118 | - if (!filename){ | |
119 | - filename = 'chart'; | |
120 | - } | |
121 | - this.toImg(function(img){ | |
122 | - var a = document.createElement("a"); | |
123 | - a.download = filename + ".png"; | |
124 | - a.href = img.getAttribute('src'); | |
125 | - a.click(); | |
126 | - }); | |
127 | - } | |
128 | - }; | |
131 | + }; | |
129 | 132 | })(this); | ... | ... |
flaskr/static/public/js/common.js
flaskr/templates/estimation.html
... | ... | @@ -100,8 +100,9 @@ |
100 | 100 | {# <h4>Total CO<sub>2</sub> footprint (in kilograms-equivalent) of each city</h4>#} |
101 | 101 | {# <div id="cities_footprints_d3viz" class="plot-container"></div>#} |
102 | 102 | <hr> |
103 | + <div id="cities_footprints_spinner" class="lds-ripple text-center"><div></div><div></div><div></div></div> | |
104 | + {# This MUST stay empty (because Simg uses svg.getparentnode.innerhtml) #} | |
103 | 105 | <div id="cities_footprints_d3viz_lollipop" class="plot-container"> |
104 | - <div id="cities_footprints_spinner" class="lds-ripple text-center"><div></div><div></div><div></div></div> | |
105 | 106 | </div> |
106 | 107 | {# <br>#} |
107 | 108 | {# <p>A Legend here</p>#} |
... | ... | @@ -203,6 +204,9 @@ |
203 | 204 | {{ content.estimation.footer | markdown | safe }} |
204 | 205 | </div> |
205 | 206 | |
207 | +{# Buffer to drop the PNG image into to hack firefox into downloading the PNG #} | |
208 | +<div id="png_buffer"></div> | |
209 | + | |
206 | 210 | {% endif %}{# not estimation.has_failed() #} |
207 | 211 | {% endblock %} |
208 | 212 | |
... | ... | @@ -560,7 +564,7 @@ jQuery(document).ready(function($){ |
560 | 564 | $(vizid+" svg .value-text").css("opacity", 1); |
561 | 565 | // May not work everywhere, but… |
562 | 566 | var simg = new Simg($(vizid + " svg")[0]); |
563 | - simg.download(); | |
567 | + simg.download("travel_carbon_footprint_{{ estimation.public_id }}"); | |
564 | 568 | // Hide the values |
565 | 569 | $(vizid+" svg .value-text").css("opacity", 0); |
566 | 570 | return false; | ... | ... |