diff --git a/superset/assets/javascripts/components/ExportSlice.js b/superset/assets/javascripts/components/ExportSlice.js
new file mode 100644
index 0000000000000..6df0f577452bd
--- /dev/null
+++ b/superset/assets/javascripts/components/ExportSlice.js
@@ -0,0 +1,31 @@
+/* eslint camelcase: 0 */
+
+export function hasSvg(slice) {
+ return !['table', 'filter_box'].includes(slice.form_data.viz_type);
+}
+
+export function exportSlice(slice, format) {
+ if (format === 'png') {
+ const tmp = document.getElementById('con_' + slice.slice_id);
+ const svg = tmp.getElementsByTagName('svg')[0];
+ const svg_xml = (new XMLSerializer()).serializeToString(svg);
+ const data_uri = 'data:image/svg+xml;base64,' + window.btoa(svg_xml);
+
+ const image = new Image();
+ image.src = data_uri;
+ image.onload = function () {
+ const canvas = document.createElement('canvas');
+ canvas.width = image.width;
+ canvas.height = image.height;
+
+ const context = canvas.getContext('2d');
+ context.clearRect(0, 0, image.width, image.height);
+ context.drawImage(image, 0, 0);
+
+ const a = document.createElement('a');
+ a.download = slice.slice_name;
+ a.href = canvas.toDataURL('image/png');
+ a.click();
+ };
+ }
+}
diff --git a/superset/assets/javascripts/dashboard/components/SliceCell.jsx b/superset/assets/javascripts/dashboard/components/SliceCell.jsx
index 0a179034825bf..49d52220e94af 100644
--- a/superset/assets/javascripts/dashboard/components/SliceCell.jsx
+++ b/superset/assets/javascripts/dashboard/components/SliceCell.jsx
@@ -4,6 +4,8 @@ import PropTypes from 'prop-types';
import { getExploreUrl } from '../../explore/exploreUtils';
+import { exportSlice, hasSvg } from '../../components/ExportSlice';
+
const propTypes = {
slice: PropTypes.object.isRequired,
removeSlice: PropTypes.func.isRequired,
@@ -50,6 +52,15 @@ function SliceCell({ expandedSlices, removeSlice, slice }) {
>
+ { exportSlice(slice, 'png'); }}
+ title="Export PNG"
+ data-toggle="tooltip"
+ style={{ display: hasSvg(slice) ? 'inline' : 'none' }}
+ >
+
+
diff --git a/superset/assets/spec/javascripts/dashboard/SliceCell_spec.jsx b/superset/assets/spec/javascripts/dashboard/SliceCell_spec.jsx
index 8dbf661d20788..c9b1f266e1452 100644
--- a/superset/assets/spec/javascripts/dashboard/SliceCell_spec.jsx
+++ b/superset/assets/spec/javascripts/dashboard/SliceCell_spec.jsx
@@ -17,8 +17,8 @@ describe('SliceCell', () => {
React.isValidElement(),
).to.equal(true);
});
- it('renders six links', () => {
+ it('renders seven links', () => {
const wrapper = mount();
- expect(wrapper.find('a')).to.have.length(6);
+ expect(wrapper.find('a')).to.have.length(7);
});
});