Skip to content

Commit fb9e903

Browse files
authored
Merge pull request #2914 from plotly/fix-linearGradient-tosvg
Fix `toSVG` for graphs that call `Drawing.gradient`
2 parents 24a0f91 + 0557bb1 commit fb9e903

File tree

3 files changed

+136
-56
lines changed

3 files changed

+136
-56
lines changed

src/snapshot/tosvg.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,20 @@ module.exports = function toSVG(gd, format, scale) {
116116
}
117117
});
118118

119-
svg.selectAll('.point,.scatterpts').each(function() {
119+
svg.selectAll('.point, .scatterpts, .legendfill>path, .legendlines>path, .cbfill').each(function() {
120120
var pt = d3.select(this);
121-
var fill = this.style.fill;
122121

123122
// similar to font family styles above,
124123
// we must remove " after the SVG DOM has been serialized
124+
var fill = this.style.fill;
125125
if(fill && fill.indexOf('url(') !== -1) {
126126
pt.style('fill', fill.replace(DOUBLEQUOTE_REGEX, DUMMY_SUB));
127127
}
128+
129+
var stroke = this.style.stroke;
130+
if(stroke && stroke.indexOf('url(') !== -1) {
131+
pt.style('stroke', stroke.replace(DOUBLEQUOTE_REGEX, DUMMY_SUB));
132+
}
128133
});
129134

130135
if(format === 'pdf' || format === 'eps') {

tasks/noci_test.sh

+38-10
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
11
#! /bin/bash
2+
#
3+
# Run tests that aren't ran on CI (yet)
4+
#
5+
# to run all no-ci tests
6+
# $ (plotly.js) ./tasks/noci_test.sh
7+
#
8+
# to run jasmine no-ci tests
9+
# $ (plotly.js) ./tasks/noci_test.sh jasmine
10+
11+
# to run image no-ci tests
12+
# $ (plotly.js) ./tasks/noci_test.sh image
13+
#
14+
# -----------------------------------------------
215

316
EXIT_STATE=0
417
root=$(dirname $0)/..
518

6-
# tests that aren't run on CI (yet)
7-
819
# jasmine specs with @noCI tag
9-
npm run test-jasmine -- --tags=noCI,noCIdep --nowatch || EXIT_STATE=$?
20+
test_jasmine () {
21+
npm run test-jasmine -- --tags=noCI,noCIdep --nowatch || EXIT_STATE=$?
22+
}
1023

1124
# mapbox image tests take too much resources on CI
1225
#
@@ -15,12 +28,27 @@ npm run test-jasmine -- --tags=noCI,noCIdep --nowatch || EXIT_STATE=$?
1528
# 'old' image server
1629
#
1730
# cone traces don't render correctly in the imagetest container
18-
$root/../orca/bin/orca.js graph \
19-
$root/test/image/mocks/mapbox_* \
20-
$root/test/image/mocks/gl3d_cone* \
21-
--plotly $root/build/plotly.js \
22-
--mapbox-access-token "pk.eyJ1IjoiZXRwaW5hcmQiLCJhIjoiY2luMHIzdHE0MGFxNXVubTRxczZ2YmUxaCJ9.hwWZful0U2CQxit4ItNsiQ" \
23-
--output-dir $root/test/image/baselines/ \
24-
--verbose
31+
test_image () {
32+
$root/../orca/bin/orca.js graph \
33+
$root/test/image/mocks/mapbox_* \
34+
$root/test/image/mocks/gl3d_cone* \
35+
--plotly $root/build/plotly.js \
36+
--mapbox-access-token "pk.eyJ1IjoiZXRwaW5hcmQiLCJhIjoiY2luMHIzdHE0MGFxNXVubTRxczZ2YmUxaCJ9.hwWZful0U2CQxit4ItNsiQ" \
37+
--output-dir $root/test/image/baselines/ \
38+
--verbose || EXIT_STATE=$?
39+
}
40+
41+
case $1 in
42+
jasmine)
43+
test_jasmine
44+
;;
45+
image)
46+
test_image
47+
;;
48+
*)
49+
test_jasmine
50+
test_image
51+
;;
52+
esac
2553

2654
exit $EXIT_STATE

test/jasmine/tests/snapshot_test.js

+91-44
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
var Plotly = require('@lib/index');
2+
var Lib = require('@src/lib');
23

34
var d3 = require('d3');
45
var createGraphDiv = require('../assets/create_graph_div');
56
var destroyGraphDiv = require('../assets/destroy_graph_div');
6-
var fail = require('../assets/fail_test');
7+
var failTest = require('../assets/fail_test');
78

89
var subplotMock = require('../../image/mocks/multiple_subplots.json');
910
var annotationMock = require('../../image/mocks/annotations.json');
@@ -250,55 +251,101 @@ describe('Plotly.Snapshot', function() {
250251
});
251252
});
252253

253-
it('should handle quoted style properties', function(done) {
254-
Plotly.plot(gd, [{
255-
y: [1, 2, 1],
256-
marker: {
257-
gradient: {
258-
type: 'radial',
259-
color: '#fff'
260-
},
261-
color: ['red', 'blue', 'green']
262-
}
263-
}], {
264-
font: { family: 'Times New Roman' },
265-
showlegend: true
266-
})
267-
.then(function() {
268-
d3.selectAll('text').each(function() {
269-
expect(this.style.fontFamily).toEqual('\"Times New Roman\"');
270-
});
254+
describe('should handle quoted style properties', function() {
255+
function checkURL(actual, msg) {
256+
// which is enough tot check that toSVG did its job right
257+
expect((actual || '').substr(0, 6)).toBe('url(\"#', msg);
258+
}
271259

272-
d3.selectAll('.point,.scatterpts').each(function() {
273-
expect(this.style.fill.substr(0, 6)).toEqual('url(\"#');
274-
});
260+
it('- marker-gradient case', function(done) {
261+
Plotly.plot(gd, [{
262+
y: [1, 2, 1],
263+
marker: {
264+
gradient: {
265+
type: 'radial',
266+
color: '#fff'
267+
},
268+
color: ['red', 'blue', 'green']
269+
}
270+
}], {
271+
font: { family: 'Times New Roman' },
272+
showlegend: true
273+
})
274+
.then(function() {
275+
d3.selectAll('text').each(function() {
276+
expect(this.style.fontFamily).toEqual('\"Times New Roman\"');
277+
});
278+
279+
d3.selectAll('.point,.scatterpts').each(function() {
280+
checkURL(this.style.fill);
281+
});
282+
283+
return Plotly.Snapshot.toSVG(gd);
284+
})
285+
.then(function(svg) {
286+
var svgDOM = parser.parseFromString(svg, 'image/svg+xml');
287+
var i;
288+
289+
var textElements = svgDOM.getElementsByTagName('text');
290+
expect(textElements.length).toEqual(12);
291+
292+
for(i = 0; i < textElements.length; i++) {
293+
expect(textElements[i].style.fontFamily).toEqual('\"Times New Roman\"');
294+
}
275295

276-
return Plotly.Snapshot.toSVG(gd);
277-
})
278-
.then(function(svg) {
279-
var svgDOM = parser.parseFromString(svg, 'image/svg+xml');
280-
var i;
296+
var pointElements = svgDOM.getElementsByClassName('point');
297+
expect(pointElements.length).toEqual(3);
281298

282-
var textElements = svgDOM.getElementsByTagName('text');
283-
expect(textElements.length).toEqual(12);
299+
for(i = 0; i < pointElements.length; i++) {
300+
checkURL(pointElements[i].style.fill);
301+
}
284302

285-
for(i = 0; i < textElements.length; i++) {
286-
expect(textElements[i].style.fontFamily).toEqual('\"Times New Roman\"');
287-
}
303+
var legendPointElements = svgDOM.getElementsByClassName('scatterpts');
304+
expect(legendPointElements.length).toEqual(1);
305+
checkURL(legendPointElements[0].style.fill);
306+
})
307+
.catch(failTest)
308+
.then(done);
309+
});
288310

289-
var pointElements = svgDOM.getElementsByClassName('point');
290-
expect(pointElements.length).toEqual(3);
311+
it('- legend with contour items case', function(done) {
312+
var fig = Lib.extendDeep({}, require('@mocks/contour_legend.json'));
313+
var fillItemIndices = [0, 4, 5];
291314

292-
for(i = 0; i < pointElements.length; i++) {
293-
expect(pointElements[i].style.fill.substr(0, 6)).toEqual('url(\"#');
294-
}
315+
Plotly.plot(gd, fig)
316+
.then(function() { return Plotly.Snapshot.toSVG(gd); })
317+
.then(function(svg) {
318+
var svgDOM = parser.parseFromString(svg, 'image/svg+xml');
295319

296-
var legendPointElements = svgDOM.getElementsByClassName('scatterpts');
297-
expect(legendPointElements.length).toEqual(1);
298-
expect(legendPointElements[0].style.fill.substr(0, 6)).toEqual('url(\"#');
299-
})
300-
.catch(fail)
301-
.then(done);
320+
var fillItems = svgDOM.getElementsByClassName('legendfill');
321+
for(var i = 0; i < fillItemIndices.length; i++) {
322+
checkURL(fillItems[fillItemIndices[i]].firstChild.style.fill, 'fill gradient ' + i);
323+
}
324+
325+
var lineItems = svgDOM.getElementsByClassName('legendlines');
326+
checkURL(lineItems[1].firstChild.style.stroke, 'stroke gradient');
327+
})
328+
.catch(failTest)
329+
.then(done);
330+
});
331+
332+
it('- colorbar case', function(done) {
333+
var fig = Lib.extendDeep({}, require('@mocks/16.json'));
334+
335+
Plotly.plot(gd, fig)
336+
.then(function() { return Plotly.Snapshot.toSVG(gd); })
337+
.then(function(svg) {
338+
var svgDOM = parser.parseFromString(svg, 'image/svg+xml');
339+
340+
var fillItems = svgDOM.getElementsByClassName('cbfill');
341+
expect(fillItems.length).toBe(1, '# of colorbars');
342+
for(var i = 0; i < fillItems.length; i++) {
343+
checkURL(fillItems[i].style.fill, 'fill gradient ' + i);
344+
}
345+
})
346+
.catch(failTest)
347+
.then(done);
348+
});
302349
});
303350

304351
it('should adapt *viewBox* attribute under *scale* option', function(done) {
@@ -317,7 +364,7 @@ describe('Plotly.Snapshot', function() {
317364
expect(el.getAttribute('height')).toBe('1000', 'height');
318365
expect(el.getAttribute('viewBox')).toBe('0 0 300 400', 'viewbox');
319366
})
320-
.catch(fail)
367+
.catch(failTest)
321368
.then(done);
322369
});
323370
});

0 commit comments

Comments
 (0)