Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 642ddba

Browse files
add new promise-based toImage and downloadImage to Plotly
1 parent 1903061 commit 642ddba

File tree

10 files changed

+546
-93
lines changed

10 files changed

+546
-93
lines changed

.eslintrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
"no-floating-decimal": [2],
3939
"space-infix-ops": [0, {"int32Hint": false}],
4040
"quotes": [2, "single"],
41-
"dot-notation": [2, {"allowKeywords": false}],
41+
"dot-notation": [2],
4242
"operator-linebreak": [2, "after"],
4343
"eqeqeq": [2],
4444
"new-cap": [0],

src/components/modebar/buttons.js

Lines changed: 8 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
var Plotly = require('../../plotly');
1313
var Lib = require('../../lib');
1414
var setCursor = require('../../lib/setcursor');
15-
var Snapshot = require('../../snapshot');
15+
var downloadImage = require('../../snapshot/download');
1616
var Icons = require('../../../build/ploticon');
1717

1818

@@ -49,49 +49,15 @@ modeBarButtons.toImage = {
4949
title: 'Download plot as a png',
5050
icon: Icons.camera,
5151
click: function(gd) {
52-
var format = 'png';
53-
54-
if(Lib.isIE()) {
55-
Lib.notifier('Snapshotting is unavailable in Internet Explorer. ' +
56-
'Consider exporting your images using the Plotly Cloud', 'long');
57-
return;
58-
}
59-
60-
if(gd._snapshotInProgress) {
61-
Lib.notifier('Snapshotting is still in progress - please hold', 'long');
62-
return;
63-
}
64-
65-
gd._snapshotInProgress = true;
6652
Lib.notifier('Taking snapshot - this may take a few seconds', 'long');
6753

68-
var ev = Snapshot.toImage(gd, {format: format});
69-
70-
var filename = gd.fn || 'newplot';
71-
filename += '.' + format;
72-
73-
ev.once('success', function(result) {
74-
gd._snapshotInProgress = false;
75-
76-
var downloadLink = document.createElement('a');
77-
downloadLink.href = result;
78-
downloadLink.download = filename; // only supported by FF and Chrome
79-
80-
document.body.appendChild(downloadLink);
81-
downloadLink.click();
82-
document.body.removeChild(downloadLink);
83-
84-
ev.clean();
85-
});
86-
87-
ev.once('error', function(err) {
88-
gd._snapshotInProgress = false;
89-
90-
Lib.notifier('Sorry there was a problem downloading your ' + format, 'long');
91-
console.error(err);
92-
93-
ev.clean();
94-
});
54+
downloadImage(gd)
55+
.then(function(filename) {
56+
Lib.notifier('Snapshot succeeded - ' + filename, 'long');
57+
})
58+
.catch(function() {
59+
Lib.notifier('Sorry there was a problem downloading your snapshot', 'long');
60+
});
9561
}
9662
};
9763

src/core.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ exports.moveTraces = Plotly.moveTraces;
3131
exports.purge = Plotly.purge;
3232
exports.setPlotConfig = require('./plot_api/set_plot_config');
3333
exports.register = Plotly.register;
34+
exports.toImage = require('./plot_api/to_image');
35+
exports.downloadImage = require('./snapshot/download');
3436

3537
// plot icons
3638
exports.Icons = require('../build/ploticon');

src/plot_api/to_image.js

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/**
2+
* Copyright 2012-2016, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
var Plotly = require('../plotly');
12+
13+
var isNumeric = require('fast-isnumeric');
14+
15+
/**
16+
* @param {object} gd figure Object
17+
* @param {object} opts option object
18+
* @param opts.format 'jpeg' | 'png' | 'webp' | 'svg'
19+
* @param opts.width width of snapshot in px
20+
* @param opts.height height of snapshot in px
21+
*/
22+
function toImage(gd, opts) {
23+
var Snapshot = require('../snapshot');
24+
25+
var promise = new Promise(function(resolve, reject) {
26+
// check for undefined opts
27+
opts = opts || {};
28+
// default to png
29+
opts.format = opts.format || 'png';
30+
31+
var isSizeGood = function(size) {
32+
// undefined and null are valid options
33+
if(size === undefined || size === null) {
34+
return true;
35+
}
36+
37+
if(isNumeric(size) && size > 1) {
38+
return true;
39+
}
40+
};
41+
42+
if(!isSizeGood(opts.width) || !isSizeGood(opts.height)) {
43+
reject(new Error('Height and width should be pixel values.'));
44+
}
45+
46+
// first clone the GD so we can operate in a clean environment
47+
var clone = Snapshot.clone(gd, {format: 'png', height: opts.height, width: opts.width});
48+
var clonedGd = clone.td;
49+
50+
// put the cloned div somewhere off screen before attaching to DOM
51+
clonedGd.style.position = 'absolute';
52+
clonedGd.style.left = '-5000px';
53+
document.body.appendChild(clonedGd);
54+
55+
function wait() {
56+
var delay = Snapshot.getDelay(clonedGd._fullLayout);
57+
58+
return new Promise(function(resolve, reject) {
59+
setTimeout(function() {
60+
var svg = Snapshot.toSVG(clonedGd);
61+
62+
var canvasContainer = window.document.createElement('div');
63+
var canvas = window.document.createElement('canvas');
64+
65+
// window.document.body.appendChild(canvasContainer);
66+
canvasContainer.appendChild(canvas);
67+
68+
canvasContainer.id = Plotly.Lib.randstr();
69+
canvas.id = Plotly.Lib.randstr();
70+
71+
Snapshot.svgToImg({
72+
format: opts.format,
73+
width: clonedGd._fullLayout.width,
74+
height: clonedGd._fullLayout.height,
75+
canvas: canvas,
76+
svg: svg,
77+
// ask svgToImg to return a Promise
78+
// rather than EventEmitter
79+
// leave EventEmitter for backward
80+
// compatibility
81+
promise: true
82+
}).then(function(url) {
83+
if(clonedGd) clonedGd.remove();
84+
resolve(url);
85+
}).catch(function(err) {
86+
reject(err);
87+
});
88+
}, delay);
89+
});
90+
}
91+
92+
var redrawFunc = Snapshot.getRedrawFunc(clonedGd);
93+
94+
Plotly.plot(clonedGd, clone.data, clone.layout, clone.config)
95+
// TODO: the following is Plotly.Plots.redrawText but without the waiting.
96+
// we shouldn't need to do this, but in *occasional* cases we do. Figure
97+
// out why and take it out.
98+
99+
// not sure the above TODO makes sense anymore since
100+
// we have converted to promises
101+
.then(redrawFunc)
102+
.then(wait)
103+
.then(function(url) { resolve(url); })
104+
.catch(function(err) {
105+
reject(err);
106+
});
107+
});
108+
109+
return promise;
110+
}
111+
112+
module.exports = toImage;

src/snapshot/download.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* Copyright 2012-2016, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
10+
'use strict';
11+
12+
var toImage = require('../plot_api/to_image');
13+
var Lib = require('../lib'); // for isIE
14+
var fileSaver = require('./filesaver');
15+
16+
/**
17+
* @param {object} gd figure Object
18+
* @param {object} opts option object
19+
* @param opts.format 'jpeg' | 'png' | 'webp' | 'svg'
20+
* @param opts.width width of snapshot in px
21+
* @param opts.height height of snapshot in px
22+
* @param opts.filename name of file excluding extension
23+
*/
24+
function downloadImage(gd, opts) {
25+
26+
// check for undefined opts
27+
opts = opts || {};
28+
29+
// default to png
30+
opts.format = opts.format || 'png';
31+
32+
return new Promise(function(resolve,reject) {
33+
if(gd._snapshotInProgress) {
34+
reject(new Error('Snapshotting already in progress.'));
35+
}
36+
37+
// see comments within svgtoimg for additional
38+
// discussion of problems with IE
39+
// can now draw to canvas, but CORS tainted canvas
40+
// does not allow toDataURL
41+
// svg format will work though
42+
if(Lib.isIE() && opts.format !== 'svg') {
43+
reject(new Error('Sorry IE does not support downloading from canvas.'));
44+
}
45+
46+
gd._snapshotInProgress = true;
47+
var promise = toImage(gd, opts);
48+
49+
var filename = opts.filename || gd.fn || 'newplot';
50+
filename += '.' + opts.format;
51+
52+
promise.then(function(result) {
53+
gd._snapshotInProgress = false;
54+
return fileSaver(result,filename);
55+
}).then(function(name) {
56+
resolve(name);
57+
}).catch(function(err) {
58+
gd._snapshotInProgress = false;
59+
reject(err);
60+
});
61+
});
62+
}
63+
64+
module.exports = downloadImage;

src/snapshot/filesaver.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* Copyright 2012-2016, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
/*
10+
* substantial portions of this code from FileSaver.js
11+
* https://github.com/eligrey/FileSaver.js
12+
* License: https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
13+
* FileSaver.js
14+
* A saveAs() FileSaver implementation.
15+
* 1.1.20160328
16+
*
17+
* By Eli Grey, http://eligrey.com
18+
* License: MIT
19+
* See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
20+
*/
21+
22+
'use strict';
23+
24+
var fileSaver = function(url, name) {
25+
var saveLink = document.createElement('a');
26+
var canUseSaveLink = 'download' in saveLink;
27+
var isSafari = /Version\/[\d\.]+.*Safari/.test(navigator.userAgent);
28+
var promise = new Promise(function(resolve, reject) {
29+
// IE <10 is explicitly unsupported
30+
if(typeof navigator !== 'undefined' && /MSIE [1-9]\./.test(navigator.userAgent)) {
31+
reject(new Error('IE < 10 unsupported'));
32+
}
33+
34+
// First try a.download, then web filesystem, then object URLs
35+
if(isSafari) {
36+
// Safari doesn't allow downloading of blob urls
37+
document.location.href = 'data:attachment/file' + url.slice(url.search(/[,;]/));
38+
resolve(name);
39+
}
40+
41+
if(!name) {
42+
name = 'download';
43+
}
44+
45+
if(canUseSaveLink) {
46+
saveLink.href = url;
47+
saveLink.download = name;
48+
document.body.appendChild(saveLink);
49+
saveLink.click();
50+
document.body.removeChild(saveLink);
51+
resolve(name);
52+
}
53+
54+
// IE 10+ (native saveAs)
55+
if(typeof navigator !== 'undefined' && navigator.msSaveOrOpenBlob) {
56+
navigator.msSaveOrOpenBlob(url, name);
57+
resolve(name);
58+
}
59+
60+
reject(new Error('download error'));
61+
});
62+
63+
return promise;
64+
};
65+
66+
module.exports = fileSaver;

src/snapshot/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ var Snapshot = {
3636
clone: require('./cloneplot'),
3737
toSVG: require('./tosvg'),
3838
svgToImg: require('./svgtoimg'),
39-
toImage: require('./toimage')
39+
toImage: require('./toimage'),
40+
downloadImage: require('./download')
4041
};
4142

4243
module.exports = Snapshot;

0 commit comments

Comments
 (0)