diff --git a/src/components/rangeslider/range_plot.js b/src/components/rangeslider/range_plot.js index 39dc6e1aa5d..b70f5dbab5f 100644 --- a/src/components/rangeslider/range_plot.js +++ b/src/components/rangeslider/range_plot.js @@ -8,6 +8,8 @@ 'use strict'; +var d3 = require('d3'); + var Symbols = require('../drawing/symbol_defs'); var Drawing = require('../drawing'); @@ -38,7 +40,7 @@ module.exports = function rangePlot(gd, w, h) { clipDefs.appendChild(clip); var rangePlot = document.createElementNS(svgNS, 'g'); - rangePlot.setAttribute('clip-path', 'url(#range-clip-path)'); + d3.select(rangePlot).call(Drawing.setClipUrl, 'range-clip-path'); rangePlot.appendChild(clipDefs); diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index dc6940341e0..6ed76ab6270 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -2913,10 +2913,8 @@ function lsInner(gd) { }); - plotinfo.plot.attr({ - 'transform': 'translate(' + xa._offset + ', ' + ya._offset + ')', - 'clip-path': 'url(#' + clipId + ')' - }); + plotinfo.plot.call(Lib.setTranslate, xa._offset, ya._offset); + plotinfo.plot.call(Drawing.setClipUrl, clipId); var xlw = Drawing.crispRound(gd, xa.linewidth, 1), ylw = Drawing.crispRound(gd, ya.linewidth, 1), diff --git a/test/jasmine/tests/drawing_test.js b/test/jasmine/tests/drawing_test.js new file mode 100644 index 00000000000..0394715de5e --- /dev/null +++ b/test/jasmine/tests/drawing_test.js @@ -0,0 +1,52 @@ +var Drawing = require('@src/components/drawing'); + +var d3 = require('d3'); + + +describe('Drawing.setClipUrl', function() { + 'use strict'; + + beforeEach(function() { + this.svg = d3.select('body').append('svg'); + this.g = this.svg.append('g'); + }); + + afterEach(function() { + this.svg.remove(); + this.g.remove(); + }); + + it('should set the clip-path attribute', function() { + expect(this.g.attr('clip-path')).toBe(null); + + Drawing.setClipUrl(this.g, 'id1'); + + expect(this.g.attr('clip-path')).toEqual('url(#id1)'); + }); + + it('should unset the clip-path if arg is falsy', function() { + this.g.attr('clip-path', 'url(#id2)'); + + Drawing.setClipUrl(this.g, false); + + expect(this.g.attr('clip-path')).toBe(null); + }); + + it('should append window URL to clip-path if is present', function() { + + // append with href + var base = d3.select('body') + .append('base') + .attr('href', 'https://plot.ly'); + + // grab window URL + var href = window.location.href; + + Drawing.setClipUrl(this.g, 'id3'); + + expect(this.g.attr('clip-path')) + .toEqual('url(' + href + '#id3)'); + + base.remove(); + }); +}); diff --git a/test/jasmine/tests/plot_interact_test.js b/test/jasmine/tests/plot_interact_test.js index 8748b9d9bb2..9ca7f2b3f2f 100644 --- a/test/jasmine/tests/plot_interact_test.js +++ b/test/jasmine/tests/plot_interact_test.js @@ -436,3 +436,73 @@ describe('Test plot structure', function() { }); }); }); + +describe('plot svg clip paths', function() { + + // plot with all features that rely on clip paths + function plot() { + return Plotly.plot(createGraphDiv(), [{ + type: 'contour', + z: [[1,2,3], [2,3,1]] + }, { + type: 'scatter', + y: [2, 1, 2] + }], { + showlegend: true, + xaxis: { + rangeslider: {} + }, + shapes: [{ + xref: 'x', + yref: 'y', + x0: 0, + y0: 0, + x1: 3, + y1: 3 + }] + }); + } + + afterEach(destroyGraphDiv); + + it('should set clip path url to ids (base case)', function(done) { + plot().then(function() { + + d3.selectAll('[clip-path]').each(function() { + var cp = d3.select(this).attr('clip-path'); + + expect(cp.substring(0, 5)).toEqual('url(#'); + expect(cp.substring(cp.length - 1)).toEqual(')'); + }); + + done(); + }); + }); + + it('should set clip path url to ids appended to window url', function(done) { + + // this case occurs in some past versions of AngularJS + // https://github.com/angular/angular.js/issues/8934 + + // append with href + var base = d3.select('body') + .append('base') + .attr('href', 'https://plot.ly'); + + // grab window URL + var href = window.location.href; + + plot().then(function() { + + d3.selectAll('[clip-path]').each(function() { + var cp = d3.select(this).attr('clip-path'); + + expect(cp.substring(0, 5 + href.length)).toEqual('url(' + href + '#'); + expect(cp.substring(cp.length - 1)).toEqual(')'); + }); + + base.remove(); + done(); + }); + }); +});