Skip to content

Commit fc722c3

Browse files
committed
fall back to plot subtitle if title is not suitable for filename
1 parent 7b7753f commit fc722c3

3 files changed

Lines changed: 50 additions & 4 deletions

File tree

src/snapshot/download.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ var toImage = require('../plot_api/to_image');
88
var fileSaver = require('./filesaver');
99
var helpers = require('./helpers');
1010

11+
// Maximum length of filename (without extension) when deriving filename from plot title.
12+
// 40 is somewhat arbitrary, just trying to strike a balance between being informative
13+
// while still generating a reasonable-length filename.
14+
// Technically, this is actually the number of code points rather than characters, which only differs
15+
// from character count in the case of certain emojis or special characters containing multiple code points
16+
const MAX_FILENAME_LENGTH_CHARS = 40;
17+
1118
/**
1219
* Plotly.downloadImage
1320
*
@@ -30,7 +37,7 @@ function downloadImage(gd, opts) {
3037

3138
return new Promise(function(resolve, reject) {
3239
if(_gd && _gd._snapshotInProgress) {
33-
reject(new Error('Snapshotting already in progress.'));
40+
reject(new Error('Image capture already in progress.'));
3441
}
3542

3643
if(_gd) _gd._snapshotInProgress = true;
@@ -41,8 +48,14 @@ function downloadImage(gd, opts) {
4148
const plotTitle = helpers.getPlotTitle(gd);
4249
// Trying to slugify a LaTeX string can result in weird ugly filenames,
4350
// so ignore the title entirely if it contains LaTeX markup
44-
if (!svgTextUtils.matchTex(plotTitle)) {
45-
potentialFilename = Lib.slugify(plotTitle, 40);
51+
if (plotTitle && !svgTextUtils.matchTex(plotTitle)) {
52+
potentialFilename = Lib.slugify(plotTitle, MAX_FILENAME_LENGTH_CHARS);
53+
} else {
54+
// If the title is empty or contains LaTeX, fall back to subtitle
55+
const plotSubtitle = helpers.getPlotSubtitle(gd);
56+
if (plotSubtitle && !svgTextUtils.matchTex(plotSubtitle)) {
57+
potentialFilename = Lib.slugify(plotSubtitle, MAX_FILENAME_LENGTH_CHARS);
58+
}
4659
}
4760
}
4861

src/snapshot/helpers.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,18 @@ exports.getPlotTitle = function(gd) {
6868
return gd.layout?.title?.text;
6969
};
7070

71+
/**
72+
* Get the resolved plot subtitle, or undefined if there is none.
73+
*/
74+
exports.getPlotSubtitle = function(gd) {
75+
var fullLayout = gd._fullLayout;
76+
if(fullLayout) {
77+
var subtitle = fullLayout.title?.subtitle?.text;
78+
return subtitle === fullLayout._dfltTitle?.subtitle ? undefined : subtitle;
79+
}
80+
return gd.layout?.title?.subtitle?.text;
81+
};
82+
7183
// Taken from https://bl.ocks.org/nolanlawson/0eac306e4dac2114c752
7284
function fixBinary(b) {
7385
var len = b.length;

test/jasmine/tests/download_test.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,28 @@ describe('Plotly.downloadImage', function() {
128128
.then(done, done.fail);
129129
}, LONG_TIMEOUT_INTERVAL);
130130

131-
it('falls back to plot-image as filename when there is no title', function(done) {
131+
it('falls back to subtitle when title contains MathJax', function(done) {
132+
downloadDefault({
133+
title: {
134+
text: '$Ax^2 + bx + c$',
135+
subtitle: {text: 'Quadratic Equation'}
136+
},
137+
})
138+
.then(function(filename) {
139+
expect(filename).toBe('quadratic-equation.png');
140+
})
141+
.then(done, done.fail);
142+
}, LONG_TIMEOUT_INTERVAL);
143+
144+
it('falls back to plot-image as filename when title contains MathJax and there is no subtitle', function(done) {
145+
downloadDefault({title: {text: '$Ax^2 + bx + c$'}})
146+
.then(function(filename) {
147+
expect(filename).toBe('plot-image.png');
148+
})
149+
.then(done, done.fail);
150+
}, LONG_TIMEOUT_INTERVAL);
151+
152+
it('falls back to plot-image as filename when there is no title or subtitle', function(done) {
132153
downloadDefault({})
133154
.then(function(filename) {
134155
expect(filename).toBe('plot-image.png');

0 commit comments

Comments
 (0)