Skip to content

Commit

Permalink
Merge pull request #2914 from plotly/fix-linearGradient-tosvg
Browse files Browse the repository at this point in the history
Fix `toSVG` for graphs that call `Drawing.gradient`
  • Loading branch information
etpinard authored Aug 16, 2018
2 parents 24a0f91 + 0557bb1 commit fb9e903
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 56 deletions.
9 changes: 7 additions & 2 deletions src/snapshot/tosvg.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,20 @@ module.exports = function toSVG(gd, format, scale) {
}
});

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

// similar to font family styles above,
// we must remove " after the SVG DOM has been serialized
var fill = this.style.fill;
if(fill && fill.indexOf('url(') !== -1) {
pt.style('fill', fill.replace(DOUBLEQUOTE_REGEX, DUMMY_SUB));
}

var stroke = this.style.stroke;
if(stroke && stroke.indexOf('url(') !== -1) {
pt.style('stroke', stroke.replace(DOUBLEQUOTE_REGEX, DUMMY_SUB));
}
});

if(format === 'pdf' || format === 'eps') {
Expand Down
48 changes: 38 additions & 10 deletions tasks/noci_test.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
#! /bin/bash
#
# Run tests that aren't ran on CI (yet)
#
# to run all no-ci tests
# $ (plotly.js) ./tasks/noci_test.sh
#
# to run jasmine no-ci tests
# $ (plotly.js) ./tasks/noci_test.sh jasmine

# to run image no-ci tests
# $ (plotly.js) ./tasks/noci_test.sh image
#
# -----------------------------------------------

EXIT_STATE=0
root=$(dirname $0)/..

# tests that aren't run on CI (yet)

# jasmine specs with @noCI tag
npm run test-jasmine -- --tags=noCI,noCIdep --nowatch || EXIT_STATE=$?
test_jasmine () {
npm run test-jasmine -- --tags=noCI,noCIdep --nowatch || EXIT_STATE=$?
}

# mapbox image tests take too much resources on CI
#
Expand All @@ -15,12 +28,27 @@ npm run test-jasmine -- --tags=noCI,noCIdep --nowatch || EXIT_STATE=$?
# 'old' image server
#
# cone traces don't render correctly in the imagetest container
$root/../orca/bin/orca.js graph \
$root/test/image/mocks/mapbox_* \
$root/test/image/mocks/gl3d_cone* \
--plotly $root/build/plotly.js \
--mapbox-access-token "pk.eyJ1IjoiZXRwaW5hcmQiLCJhIjoiY2luMHIzdHE0MGFxNXVubTRxczZ2YmUxaCJ9.hwWZful0U2CQxit4ItNsiQ" \
--output-dir $root/test/image/baselines/ \
--verbose
test_image () {
$root/../orca/bin/orca.js graph \
$root/test/image/mocks/mapbox_* \
$root/test/image/mocks/gl3d_cone* \
--plotly $root/build/plotly.js \
--mapbox-access-token "pk.eyJ1IjoiZXRwaW5hcmQiLCJhIjoiY2luMHIzdHE0MGFxNXVubTRxczZ2YmUxaCJ9.hwWZful0U2CQxit4ItNsiQ" \
--output-dir $root/test/image/baselines/ \
--verbose || EXIT_STATE=$?
}

case $1 in
jasmine)
test_jasmine
;;
image)
test_image
;;
*)
test_jasmine
test_image
;;
esac

exit $EXIT_STATE
135 changes: 91 additions & 44 deletions test/jasmine/tests/snapshot_test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
var Plotly = require('@lib/index');
var Lib = require('@src/lib');

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 failTest = require('../assets/fail_test');

var subplotMock = require('../../image/mocks/multiple_subplots.json');
var annotationMock = require('../../image/mocks/annotations.json');
Expand Down Expand Up @@ -250,55 +251,101 @@ describe('Plotly.Snapshot', function() {
});
});

it('should handle quoted style properties', function(done) {
Plotly.plot(gd, [{
y: [1, 2, 1],
marker: {
gradient: {
type: 'radial',
color: '#fff'
},
color: ['red', 'blue', 'green']
}
}], {
font: { family: 'Times New Roman' },
showlegend: true
})
.then(function() {
d3.selectAll('text').each(function() {
expect(this.style.fontFamily).toEqual('\"Times New Roman\"');
});
describe('should handle quoted style properties', function() {
function checkURL(actual, msg) {
// which is enough tot check that toSVG did its job right
expect((actual || '').substr(0, 6)).toBe('url(\"#', msg);
}

d3.selectAll('.point,.scatterpts').each(function() {
expect(this.style.fill.substr(0, 6)).toEqual('url(\"#');
});
it('- marker-gradient case', function(done) {
Plotly.plot(gd, [{
y: [1, 2, 1],
marker: {
gradient: {
type: 'radial',
color: '#fff'
},
color: ['red', 'blue', 'green']
}
}], {
font: { family: 'Times New Roman' },
showlegend: true
})
.then(function() {
d3.selectAll('text').each(function() {
expect(this.style.fontFamily).toEqual('\"Times New Roman\"');
});

d3.selectAll('.point,.scatterpts').each(function() {
checkURL(this.style.fill);
});

return Plotly.Snapshot.toSVG(gd);
})
.then(function(svg) {
var svgDOM = parser.parseFromString(svg, 'image/svg+xml');
var i;

var textElements = svgDOM.getElementsByTagName('text');
expect(textElements.length).toEqual(12);

for(i = 0; i < textElements.length; i++) {
expect(textElements[i].style.fontFamily).toEqual('\"Times New Roman\"');
}

return Plotly.Snapshot.toSVG(gd);
})
.then(function(svg) {
var svgDOM = parser.parseFromString(svg, 'image/svg+xml');
var i;
var pointElements = svgDOM.getElementsByClassName('point');
expect(pointElements.length).toEqual(3);

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

for(i = 0; i < textElements.length; i++) {
expect(textElements[i].style.fontFamily).toEqual('\"Times New Roman\"');
}
var legendPointElements = svgDOM.getElementsByClassName('scatterpts');
expect(legendPointElements.length).toEqual(1);
checkURL(legendPointElements[0].style.fill);
})
.catch(failTest)
.then(done);
});

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

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

var legendPointElements = svgDOM.getElementsByClassName('scatterpts');
expect(legendPointElements.length).toEqual(1);
expect(legendPointElements[0].style.fill.substr(0, 6)).toEqual('url(\"#');
})
.catch(fail)
.then(done);
var fillItems = svgDOM.getElementsByClassName('legendfill');
for(var i = 0; i < fillItemIndices.length; i++) {
checkURL(fillItems[fillItemIndices[i]].firstChild.style.fill, 'fill gradient ' + i);
}

var lineItems = svgDOM.getElementsByClassName('legendlines');
checkURL(lineItems[1].firstChild.style.stroke, 'stroke gradient');
})
.catch(failTest)
.then(done);
});

it('- colorbar case', function(done) {
var fig = Lib.extendDeep({}, require('@mocks/16.json'));

Plotly.plot(gd, fig)
.then(function() { return Plotly.Snapshot.toSVG(gd); })
.then(function(svg) {
var svgDOM = parser.parseFromString(svg, 'image/svg+xml');

var fillItems = svgDOM.getElementsByClassName('cbfill');
expect(fillItems.length).toBe(1, '# of colorbars');
for(var i = 0; i < fillItems.length; i++) {
checkURL(fillItems[i].style.fill, 'fill gradient ' + i);
}
})
.catch(failTest)
.then(done);
});
});

it('should adapt *viewBox* attribute under *scale* option', function(done) {
Expand All @@ -317,7 +364,7 @@ describe('Plotly.Snapshot', function() {
expect(el.getAttribute('height')).toBe('1000', 'height');
expect(el.getAttribute('viewBox')).toBe('0 0 300 400', 'viewbox');
})
.catch(fail)
.catch(failTest)
.then(done);
});
});
Expand Down

0 comments on commit fb9e903

Please sign in to comment.