diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js
index f7fb3e83880..ba3caf2bf63 100644
--- a/src/plot_api/plot_api.js
+++ b/src/plot_api/plot_api.js
@@ -25,6 +25,7 @@ var Polar = require('../plots/polar');
var initInteractions = require('../plots/cartesian/graph_interact');
var Drawing = require('../components/drawing');
+var Color = require('../components/color');
var ErrorBars = require('../components/errorbars');
var xmlnsNamespaces = require('../constants/xmlns_namespaces');
var svgTextUtils = require('../lib/svg_text_utils');
@@ -390,10 +391,17 @@ Plotly.plot = function(gd, data, layout, config) {
});
};
+function setBackground(gd, bgColor) {
+ try {
+ gd._fullLayout._paper.style('background', bgColor);
+ } catch(e) {
+ Lib.error(e);
+ }
+}
function opaqueSetBackground(gd, bgColor) {
- gd._fullLayout._paperdiv.style('background', 'white');
- Plotly.defaultConfig.setBackground(gd, bgColor);
+ var blend = Color.combine(bgColor, 'white');
+ setBackground(gd, blend);
}
function setPlotContext(gd, config) {
@@ -410,8 +418,9 @@ function setPlotContext(gd, config) {
if(key in context) {
if(key === 'setBackground' && config[key] === 'opaque') {
context[key] = opaqueSetBackground;
+ } else {
+ context[key] = config[key];
}
- else context[key] = config[key];
}
}
@@ -460,6 +469,11 @@ function setPlotContext(gd, config) {
if(context.displayModeBar === 'hover' && !hasHover) {
context.displayModeBar = true;
}
+
+ // default and fallback for setBackground
+ if(context.setBackground === 'transparent' || typeof context.setBackground !== 'function') {
+ context.setBackground = setBackground;
+ }
}
function plotPolar(gd, data, layout) {
diff --git a/src/plot_api/plot_config.js b/src/plot_api/plot_config.js
index c19d0d3ebc8..27f4735a24e 100644
--- a/src/plot_api/plot_config.js
+++ b/src/plot_api/plot_config.js
@@ -8,8 +8,6 @@
'use strict';
-/* eslint-disable no-console */
-
/**
* This will be transferred over to gd and overridden by
* config args to Plotly.plot.
@@ -108,9 +106,11 @@ module.exports = {
// increase the pixel ratio for Gl plot images
plotGlPixelRatio: 2,
- // function to add the background color to a different container
- // or 'opaque' to ensure there's white behind it
- setBackground: defaultSetBackground,
+ // background setting function
+ // 'transparent' sets the background `layout.paper_color`
+ // 'opaque' blends bg color with white ensuring an opaque background
+ // or any other custom function of gd
+ setBackground: 'transparent',
// URL to topojson files used in geo charts
topojsonURL: 'https://cdn.plot.ly/',
@@ -128,16 +128,3 @@ module.exports = {
// specification needed
globalTransforms: []
};
-
-// where and how the background gets set can be overridden by context
-// so we define the default (plotly.js) behavior here
-function defaultSetBackground(gd, bgColor) {
- try {
- gd._fullLayout._paper.style('background', bgColor);
- }
- catch(e) {
- if(module.exports.logging > 0) {
- console.error(e);
- }
- }
-}
diff --git a/src/plot_api/to_image.js b/src/plot_api/to_image.js
index 6ebcf75b367..4ce0821aaaa 100644
--- a/src/plot_api/to_image.js
+++ b/src/plot_api/to_image.js
@@ -8,101 +8,191 @@
'use strict';
-var isNumeric = require('fast-isnumeric');
-
var Plotly = require('../plotly');
var Lib = require('../lib');
var helpers = require('../snapshot/helpers');
-var clonePlot = require('../snapshot/cloneplot');
var toSVG = require('../snapshot/tosvg');
var svgToImg = require('../snapshot/svgtoimg');
-/**
- * @param {object} gd figure Object
- * @param {object} opts option object
- * @param opts.format 'jpeg' | 'png' | 'webp' | 'svg'
- * @param opts.width width of snapshot in px
- * @param opts.height height of snapshot in px
+var getGraphDiv = require('./helpers').getGraphDiv;
+
+var attrs = {
+ format: {
+ valType: 'enumerated',
+ values: ['png', 'jpeg', 'webp', 'svg'],
+ dflt: 'png',
+ description: 'Sets the format of exported image.'
+ },
+ width: {
+ valType: 'number',
+ min: 1,
+ description: [
+ 'Sets the exported image width.',
+ 'Defaults to the value found in `layout.width`'
+ ].join(' ')
+ },
+ height: {
+ valType: 'number',
+ min: 1,
+ description: [
+ 'Sets the exported image height.',
+ 'Defaults to the value found in `layout.height`'
+ ].join(' ')
+ },
+ setBackground: {
+ valType: 'any',
+ dflt: false,
+ description: [
+ 'Sets the image background mode.',
+ 'By default, the image background is determined by `layout.paper_bgcolor`,',
+ 'the *transparent* mode.',
+ 'One might consider setting `setBackground` to *opaque*',
+ 'when exporting a *jpeg* image as JPEGs do not support opacity.'
+ ].join(' ')
+ },
+ imageDataOnly: {
+ valType: 'boolean',
+ dflt: false,
+ description: [
+ 'Determines whether or not the return value is prefixed by',
+ 'the image format\'s corresponding \'data:image;\' spec.'
+ ].join(' ')
+ }
+};
+
+var IMAGE_URL_PREFIX = /^data:image\/\w+;base64,/;
+
+/** Plotly.toImage
+ *
+ * @param {object | string | HTML div} gd
+ * can either be a data/layout/config object
+ * or an existing graph
+ * or an id to an existing graph
+ * @param {object} opts (see above)
+ * @return {promise}
*/
function toImage(gd, opts) {
+ opts = opts || {};
+
+ var data;
+ var layout;
+ var config;
+
+ if(Lib.isPlainObject(gd)) {
+ data = gd.data || [];
+ layout = gd.layout || {};
+ config = gd.config || {};
+ } else {
+ gd = getGraphDiv(gd);
+ data = Lib.extendDeep([], gd.data);
+ layout = Lib.extendDeep({}, gd.layout);
+ config = gd._context;
+ }
+
+ function isImpliedOrValid(attr) {
+ return !(attr in opts) || Lib.validate(opts[attr], attrs[attr]);
+ }
+
+ if(!isImpliedOrValid('width') || !isImpliedOrValid('height')) {
+ throw new Error('Height and width should be pixel values.');
+ }
+
+ if(!isImpliedOrValid('format')) {
+ throw new Error('Image format is not jpeg, png, svg or webp.');
+ }
+
+ var fullOpts = {};
+
+ function coerce(attr, dflt) {
+ return Lib.coerce(opts, fullOpts, attrs, attr, dflt);
+ }
+
+ var format = coerce('format');
+ var width = coerce('width');
+ var height = coerce('height');
+ var setBackground = coerce('setBackground');
+ var imageDataOnly = coerce('imageDataOnly');
+
+ // put the cloned div somewhere off screen before attaching to DOM
+ var clonedGd = document.createElement('div');
+ clonedGd.style.position = 'absolute';
+ clonedGd.style.left = '-5000px';
+ document.body.appendChild(clonedGd);
+
+ // extend layout with image options
+ var layoutImage = Lib.extendFlat({}, layout);
+ if(width) layoutImage.width = width;
+ if(height) layoutImage.height = height;
+
+ // extend config for static plot
+ var configImage = Lib.extendFlat({}, config, {
+ staticPlot: true,
+ plotGlPixelRatio: config.plotGlPixelRatio || 2,
+ setBackground: setBackground
+ });
- var promise = new Promise(function(resolve, reject) {
- // check for undefined opts
- opts = opts || {};
- // default to png
- opts.format = opts.format || 'png';
-
- var isSizeGood = function(size) {
- // undefined and null are valid options
- if(size === undefined || size === null) {
- return true;
- }
-
- if(isNumeric(size) && size > 1) {
- return true;
+ var redrawFunc = helpers.getRedrawFunc(clonedGd);
+
+ function wait() {
+ return new Promise(function(resolve) {
+ setTimeout(resolve, helpers.getDelay(clonedGd._fullLayout));
+ });
+ }
+
+ function convert() {
+ return new Promise(function(resolve, reject) {
+ var svg = toSVG(clonedGd);
+ var width = clonedGd._fullLayout.width;
+ var height = clonedGd._fullLayout.height;
+
+ Plotly.purge(clonedGd);
+ document.body.removeChild(clonedGd);
+
+ if(format === 'svg') {
+ if(imageDataOnly) {
+ return resolve(svg);
+ } else {
+ return resolve('data:image/svg+xml,' + encodeURIComponent(svg));
+ }
}
- return false;
- };
-
- if(!isSizeGood(opts.width) || !isSizeGood(opts.height)) {
- reject(new Error('Height and width should be pixel values.'));
- }
-
- // first clone the GD so we can operate in a clean environment
- var clone = clonePlot(gd, {format: 'png', height: opts.height, width: opts.width});
- var clonedGd = clone.gd;
-
- // put the cloned div somewhere off screen before attaching to DOM
- clonedGd.style.position = 'absolute';
- clonedGd.style.left = '-5000px';
- document.body.appendChild(clonedGd);
-
- function wait() {
- var delay = helpers.getDelay(clonedGd._fullLayout);
-
- return new Promise(function(resolve, reject) {
- setTimeout(function() {
- var svg = toSVG(clonedGd);
-
- var canvas = document.createElement('canvas');
- canvas.id = Lib.randstr();
-
- svgToImg({
- format: opts.format,
- width: clonedGd._fullLayout.width,
- height: clonedGd._fullLayout.height,
- canvas: canvas,
- svg: svg,
- // ask svgToImg to return a Promise
- // rather than EventEmitter
- // leave EventEmitter for backward
- // compatibility
- promise: true
- }).then(function(url) {
- if(clonedGd) document.body.removeChild(clonedGd);
- resolve(url);
- }).catch(function(err) {
- reject(err);
- });
-
- }, delay);
- });
+ var canvas = document.createElement('canvas');
+ canvas.id = Lib.randstr();
+
+ svgToImg({
+ format: format,
+ width: width,
+ height: height,
+ canvas: canvas,
+ svg: svg,
+ // ask svgToImg to return a Promise
+ // rather than EventEmitter
+ // leave EventEmitter for backward
+ // compatibility
+ promise: true
+ })
+ .then(resolve)
+ .catch(reject);
+ });
+ }
+
+ function urlToImageData(url) {
+ if(imageDataOnly) {
+ return url.replace(IMAGE_URL_PREFIX, '');
+ } else {
+ return url;
}
+ }
- var redrawFunc = helpers.getRedrawFunc(clonedGd);
-
- Plotly.plot(clonedGd, clone.data, clone.layout, clone.config)
+ return new Promise(function(resolve, reject) {
+ Plotly.plot(clonedGd, data, layoutImage, configImage)
.then(redrawFunc)
.then(wait)
- .then(function(url) { resolve(url); })
- .catch(function(err) {
- reject(err);
- });
+ .then(convert)
+ .then(function(url) { resolve(urlToImageData(url)); })
+ .catch(function(err) { reject(err); });
});
-
- return promise;
}
module.exports = toImage;
diff --git a/src/plots/gl2d/scene2d.js b/src/plots/gl2d/scene2d.js
index 96e5045ab32..57b9e6f9bbf 100644
--- a/src/plots/gl2d/scene2d.js
+++ b/src/plots/gl2d/scene2d.js
@@ -356,6 +356,8 @@ proto.handleAnnotations = function() {
};
proto.destroy = function() {
+ if(!this.glplot) return;
+
var traces = this.traces;
if(traces) {
diff --git a/src/plots/gl3d/scene.js b/src/plots/gl3d/scene.js
index 1dee8b4917d..071310a78ec 100644
--- a/src/plots/gl3d/scene.js
+++ b/src/plots/gl3d/scene.js
@@ -593,6 +593,8 @@ proto.plot = function(sceneData, fullLayout, layout) {
};
proto.destroy = function() {
+ if(!this.glplot) return;
+
this.camera.mouseListener.enabled = false;
this.container.removeEventListener('wheel', this.camera.wheelListener);
this.camera = this.glplot.camera = null;
diff --git a/src/plots/mapbox/mapbox.js b/src/plots/mapbox/mapbox.js
index 272bd9afe80..dbe3bd228bc 100644
--- a/src/plots/mapbox/mapbox.js
+++ b/src/plots/mapbox/mapbox.js
@@ -454,8 +454,8 @@ proto.destroy = function() {
if(this.map) {
this.map.remove();
this.map = null;
+ this.container.removeChild(this.div);
}
- this.container.removeChild(this.div);
};
proto.toImage = function() {
diff --git a/src/snapshot/svgtoimg.js b/src/snapshot/svgtoimg.js
index f90e4bb386b..86310cf5413 100644
--- a/src/snapshot/svgtoimg.js
+++ b/src/snapshot/svgtoimg.js
@@ -12,49 +12,27 @@ var Lib = require('../lib');
var EventEmitter = require('events').EventEmitter;
function svgToImg(opts) {
-
var ev = opts.emitter || new EventEmitter();
var promise = new Promise(function(resolve, reject) {
-
var Image = window.Image;
-
var svg = opts.svg;
var format = opts.format || 'png';
- // IE is very strict, so we will need to clean
- // svg with the following regex
- // yes this is messy, but do not know a better way
- // Even with this IE will not work due to tainted canvas
- // see https://github.com/kangax/fabric.js/issues/1957
- // http://stackoverflow.com/questions/18112047/canvas-todataurl-working-in-all-browsers-except-ie10
- // Leave here just in case the CORS/tainted IE issue gets resolved
- if(Lib.isIE()) {
- // replace double quote with single quote
- svg = svg.replace(/"/gi, '\'');
- // url in svg are single quoted
- // since we changed double to single
- // we'll need to change these to double-quoted
- svg = svg.replace(/(\('#)([^']*)('\))/gi, '(\"$2\")');
- // font names with spaces will be escaped single-quoted
- // we'll need to change these to double-quoted
- svg = svg.replace(/(\\')/gi, '\"');
- // IE only support svg
- if(format !== 'svg') {
- var ieSvgError = new Error('Sorry IE does not support downloading from canvas. Try {format:\'svg\'} instead.');
- reject(ieSvgError);
- // eventually remove the ev
- // in favor of promises
- if(!opts.promise) {
- return ev.emit('error', ieSvgError);
- } else {
- return promise;
- }
+ // IE only support svg
+ if(Lib.isIE() && format !== 'svg') {
+ var ieSvgError = new Error('Sorry IE does not support downloading from canvas. Try {format:\'svg\'} instead.');
+ reject(ieSvgError);
+ // eventually remove the ev
+ // in favor of promises
+ if(!opts.promise) {
+ return ev.emit('error', ieSvgError);
+ } else {
+ return promise;
}
}
var canvas = opts.canvas;
-
var ctx = canvas.getContext('2d');
var img = new Image();
@@ -89,11 +67,12 @@ function svgToImg(opts) {
imgData = url;
break;
default:
- reject(new Error('Image format is not jpeg, png or svg'));
+ var errorMsg = 'Image format is not jpeg, png, svg or webp.';
+ reject(new Error(errorMsg));
// eventually remove the ev
// in favor of promises
if(!opts.promise) {
- return ev.emit('error', 'Image format is not jpeg, png or svg');
+ return ev.emit('error', errorMsg);
}
}
resolve(imgData);
diff --git a/src/snapshot/tosvg.js b/src/snapshot/tosvg.js
index 70308d112e1..ea7189bedc3 100644
--- a/src/snapshot/tosvg.js
+++ b/src/snapshot/tosvg.js
@@ -11,6 +11,7 @@
var d3 = require('d3');
+var Lib = require('../lib');
var Drawing = require('../components/drawing');
var Color = require('../components/color');
@@ -143,5 +144,24 @@ module.exports = function toSVG(gd, format) {
// Fix quotations around font strings and gradient URLs
s = s.replace(DUMMY_REGEX, '\'');
+ // IE is very strict, so we will need to clean
+ // svg with the following regex
+ // yes this is messy, but do not know a better way
+ // Even with this IE will not work due to tainted canvas
+ // see https://github.com/kangax/fabric.js/issues/1957
+ // http://stackoverflow.com/questions/18112047/canvas-todataurl-working-in-all-browsers-except-ie10
+ // Leave here just in case the CORS/tainted IE issue gets resolved
+ if(Lib.isIE()) {
+ // replace double quote with single quote
+ s = s.replace(/"/gi, '\'');
+ // url in svg are single quoted
+ // since we changed double to single
+ // we'll need to change these to double-quoted
+ s = s.replace(/(\('#)([^']*)('\))/gi, '(\"$2\")');
+ // font names with spaces will be escaped single-quoted
+ // we'll need to change these to double-quoted
+ s = s.replace(/(\\')/gi, '\"');
+ }
+
return s;
};
diff --git a/test/jasmine/tests/is_plain_object_test.js b/test/jasmine/tests/is_plain_object_test.js
index cf2ba311f25..803d595770d 100644
--- a/test/jasmine/tests/is_plain_object_test.js
+++ b/test/jasmine/tests/is_plain_object_test.js
@@ -31,7 +31,8 @@ describe('isPlainObject', function() {
new Array(10),
new Date(),
new RegExp('foo'),
- new String('string')
+ new String('string'),
+ document.createElement('div')
];
shouldPass.forEach(function(obj) {
diff --git a/test/jasmine/tests/toimage_test.js b/test/jasmine/tests/toimage_test.js
index 6cde6567067..df348abf85e 100644
--- a/test/jasmine/tests/toimage_test.js
+++ b/test/jasmine/tests/toimage_test.js
@@ -1,29 +1,35 @@
-// move toimage to plot_api_test.js
-// once established and confirmed?
+var Plotly = require('@lib');
+var Lib = require('@src/lib');
-var Plotly = require('@lib/index');
-
-var d3 = require('d3');
var createGraphDiv = require('../assets/create_graph_div');
+var destroyGraphDiv = require('../assets/destroy_graph_div');
+var fail = require('../assets/fail_test');
+var customMatchers = require('../assets/custom_matchers');
var subplotMock = require('@mocks/multiple_subplots.json');
-
describe('Plotly.toImage', function() {
'use strict';
var gd;
+ beforeAll(function() {
+ jasmine.addMatchers(customMatchers);
+ });
+
beforeEach(function() {
gd = createGraphDiv();
});
- afterEach(function() {
+ afterEach(destroyGraphDiv);
- // make sure ALL graph divs are deleted,
- // even the ones generated by Plotly.toImage
- d3.selectAll('.js-plotly-plot').remove();
- d3.selectAll('#graph').remove();
- });
+ function createImage(url) {
+ return new Promise(function(resolve, reject) {
+ var img = document.createElement('img');
+ img.src = url;
+ img.onload = function() { return resolve(img); };
+ img.onerror = function() { return reject('error during createImage'); };
+ });
+ }
it('should be attached to Plotly', function() {
expect(Plotly.toImage).toBeDefined();
@@ -43,80 +49,137 @@ describe('Plotly.toImage', function() {
});
it('should throw error with unsupported file type', function(done) {
- // error should actually come in the svgToImg step
-
- Plotly.plot(gd, subplotMock.data, subplotMock.layout)
- .then(function(gd) {
- Plotly.toImage(gd, {format: 'x'}).catch(function(err) {
- expect(err.message).toEqual('Image format is not jpeg, png or svg');
- done();
- });
- });
-
+ var fig = Lib.extendDeep({}, subplotMock);
+
+ Plotly.plot(gd, fig.data, fig.layout)
+ .then(function(gd) {
+ expect(function() { Plotly.toImage(gd, {format: 'x'}); })
+ .toThrow(new Error('Image format is not jpeg, png, svg or webp.'));
+ })
+ .catch(fail)
+ .then(done);
});
it('should throw error with height and/or width < 1', function(done) {
- // let user know that Plotly expects pixel values
- Plotly.plot(gd, subplotMock.data, subplotMock.layout)
- .then(function(gd) {
- return Plotly.toImage(gd, {height: 0.5}).catch(function(err) {
- expect(err.message).toEqual('Height and width should be pixel values.');
- });
- }).then(function() {
- Plotly.toImage(gd, {width: 0.5}).catch(function(err) {
- expect(err.message).toEqual('Height and width should be pixel values.');
- done();
- });
- });
+ var fig = Lib.extendDeep({}, subplotMock);
+
+ Plotly.plot(gd, fig.data, fig.layout)
+ .then(function() {
+ expect(function() { Plotly.toImage(gd, {height: 0.5}); })
+ .toThrow(new Error('Height and width should be pixel values.'));
+ })
+ .then(function() {
+ expect(function() { Plotly.toImage(gd, {width: 0.5}); })
+ .toThrow(new Error('Height and width should be pixel values.'));
+ })
+ .catch(fail)
+ .then(done);
});
it('should create img with proper height and width', function(done) {
- var img = document.createElement('img');
+ var fig = Lib.extendDeep({}, subplotMock);
// specify height and width
- subplotMock.layout.height = 600;
- subplotMock.layout.width = 700;
+ fig.layout.height = 600;
+ fig.layout.width = 700;
- Plotly.plot(gd, subplotMock.data, subplotMock.layout).then(function(gd) {
+ Plotly.plot(gd, fig.data, fig.layout).then(function(gd) {
expect(gd.layout.height).toBe(600);
expect(gd.layout.width).toBe(700);
return Plotly.toImage(gd);
- }).then(function(url) {
- return new Promise(function(resolve) {
- img.src = url;
- img.onload = function() {
- expect(img.height).toBe(600);
- expect(img.width).toBe(700);
- };
- // now provide height and width in opts
- resolve(Plotly.toImage(gd, {height: 400, width: 400}));
- });
- }).then(function(url) {
- img.src = url;
- img.onload = function() {
- expect(img.height).toBe(400);
- expect(img.width).toBe(400);
- done();
- };
- });
+ })
+ .then(createImage)
+ .then(function(img) {
+ expect(img.height).toBe(600);
+ expect(img.width).toBe(700);
+
+ return Plotly.toImage(gd, {height: 400, width: 400});
+ })
+ .then(createImage)
+ .then(function(img) {
+ expect(img.height).toBe(400);
+ expect(img.width).toBe(400);
+ })
+ .catch(fail)
+ .then(done);
});
it('should create proper file type', function(done) {
- var plot = Plotly.plot(gd, subplotMock.data, subplotMock.layout);
+ var fig = Lib.extendDeep({}, subplotMock);
- plot.then(function(gd) {
- return Plotly.toImage(gd, {format: 'png'});
- }).then(function(url) {
+ Plotly.plot(gd, fig.data, fig.layout)
+ .then(function() { return Plotly.toImage(gd, {format: 'png'}); })
+ .then(function(url) {
expect(url.split('png')[0]).toBe('data:image/');
- // now do jpeg
- return Plotly.toImage(gd, {format: 'jpeg'});
- }).then(function(url) {
+ })
+ .then(function() { return Plotly.toImage(gd, {format: 'jpeg'}); })
+ .then(function(url) {
expect(url.split('jpeg')[0]).toBe('data:image/');
- // now do svg
- return Plotly.toImage(gd, {format: 'svg'});
- }).then(function(url) {
+ })
+ .then(function() { return Plotly.toImage(gd, {format: 'svg'}); })
+ .then(function(url) {
expect(url.split('svg')[0]).toBe('data:image/');
- done();
- });
+ })
+ .then(function() { return Plotly.toImage(gd, {format: 'webp'}); })
+ .then(function(url) {
+ expect(url.split('webp')[0]).toBe('data:image/');
+ })
+ .catch(fail)
+ .then(done);
+ });
+
+ it('should strip *data:image* prefix when *imageDataOnly* is turned on', function(done) {
+ var fig = Lib.extendDeep({}, subplotMock);
+
+ Plotly.plot(gd, fig.data, fig.layout)
+ .then(function() { return Plotly.toImage(gd, {format: 'png', imageDataOnly: true}); })
+ .then(function(d) {
+ expect(d.indexOf('data:image/')).toBe(-1);
+ expect(d.length).toBeWithin(53660, 1e3, 'png image length');
+ })
+ .then(function() { return Plotly.toImage(gd, {format: 'jpeg', imageDataOnly: true}); })
+ .then(function(d) {
+ expect(d.indexOf('data:image/')).toBe(-1);
+ expect(d.length).toBeWithin(43251, 5e3, 'jpeg image length');
+ })
+ .then(function() { return Plotly.toImage(gd, {format: 'svg', imageDataOnly: true}); })
+ .then(function(d) {
+ expect(d.indexOf('data:image/')).toBe(-1);
+ expect(d.length).toBeWithin(39485, 1e3, 'svg image length');
+ })
+ .then(function() { return Plotly.toImage(gd, {format: 'webp', imageDataOnly: true}); })
+ .then(function(d) {
+ expect(d.indexOf('data:image/')).toBe(-1);
+ expect(d.length).toBeWithin(15831, 1e3, 'webp image length');
+ })
+ .catch(fail)
+ .then(done);
+ });
+
+ it('should accept data/layout/config figure object as input', function(done) {
+ var fig = Lib.extendDeep({}, subplotMock);
+
+ Plotly.toImage(fig)
+ .then(createImage)
+ .then(function(img) {
+ expect(img.width).toBe(700);
+ expect(img.height).toBe(450);
+ })
+ .catch(fail)
+ .then(done);
+ });
+
+ it('should accept graph div id as input', function(done) {
+ var fig = Lib.extendDeep({}, subplotMock);
+
+ Plotly.plot(gd, fig)
+ .then(function() { return Plotly.toImage('graph'); })
+ .then(createImage)
+ .then(function(img) {
+ expect(img.width).toBe(700);
+ expect(img.height).toBe(450);
+ })
+ .catch(fail)
+ .then(done);
});
});