Skip to content

Commit 8ef1445

Browse files
authored
Merge pull request #3272 from plotly/snapshot-clippath-base
Do not add <base> href to SVG clip paths during toImage
2 parents bd7fefa + 76f5ad0 commit 8ef1445

File tree

25 files changed

+131
-82
lines changed

25 files changed

+131
-82
lines changed

src/components/annotations/draw.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -411,14 +411,14 @@ function drawRaw(gd, options, index, subplotId, xa, ya) {
411411
x: borderfull + xShift - 1,
412412
y: borderfull + yShift
413413
})
414-
.call(Drawing.setClipUrl, isSizeConstrained ? annClipID : null);
414+
.call(Drawing.setClipUrl, isSizeConstrained ? annClipID : null, gd);
415415
}
416416
else {
417417
var texty = borderfull + yShift - anntextBB.top;
418418
var textx = borderfull + xShift - anntextBB.left;
419419

420420
annText.call(svgTextUtils.positionText, textx, texty)
421-
.call(Drawing.setClipUrl, isSizeConstrained ? annClipID : null);
421+
.call(Drawing.setClipUrl, isSizeConstrained ? annClipID : null, gd);
422422
}
423423

424424
annTextClip.select('rect').call(Drawing.setRect, borderfull, borderfull,

src/components/drawing/index.js

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,32 +1000,28 @@ function nodeHash(node) {
10001000
node.getAttribute('style');
10011001
}
10021002

1003-
/*
1004-
* make a robust clipPath url from a local id
1005-
* note! We'd better not be exporting from a page
1006-
* with a <base> or the svg will not be portable!
1003+
/**
1004+
* Set clipPath URL in a way that work for all situations.
1005+
*
1006+
* In details, graphs on pages with <base> HTML tags need to prepend
1007+
* the clip path ids with the page's base url EXCEPT during toImage exports.
1008+
*
1009+
* @param {d3 selection} s : node to add clip-path attribute
1010+
* @param {string} localId : local clip-path (w/o base url) id
1011+
* @param {DOM element || object} gd
1012+
* - context._baseUrl {string}
1013+
* - context._exportedPlot {boolean}
10071014
*/
1008-
drawing.setClipUrl = function(s, localId) {
1015+
drawing.setClipUrl = function(s, localId, gd) {
10091016
if(!localId) {
10101017
s.attr('clip-path', null);
10111018
return;
10121019
}
10131020

1014-
if(drawing.baseUrl === undefined) {
1015-
var base = d3.select('base');
1016-
1017-
// Stash base url once and for all!
1018-
// We may have to stash this elsewhere when
1019-
// we'll try to support for child windows
1020-
// more info -> https://github.com/plotly/plotly.js/issues/702
1021-
if(base.size() && base.attr('href')) {
1022-
drawing.baseUrl = window.location.href.split('#')[0];
1023-
} else {
1024-
drawing.baseUrl = '';
1025-
}
1026-
}
1021+
var context = gd._context;
1022+
var baseUrl = context._exportedPlot ? '' : (context._baseUrl || '');
10271023

1028-
s.attr('clip-path', 'url(' + drawing.baseUrl + '#' + localId + ')');
1024+
s.attr('clip-path', 'url(' + baseUrl + '#' + localId + ')');
10291025
};
10301026

10311027
drawing.getTranslate = function(element) {

src/components/errorbars/plot.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ var isNumeric = require('fast-isnumeric');
1515
var Drawing = require('../drawing');
1616
var subTypes = require('../../traces/scatter/subtypes');
1717

18-
module.exports = function plot(traces, plotinfo, transitionOpts) {
18+
module.exports = function plot(gd, traces, plotinfo, transitionOpts) {
1919
var isNew;
2020

2121
var xa = plotinfo.xaxis;
@@ -66,7 +66,7 @@ module.exports = function plot(traces, plotinfo, transitionOpts) {
6666
.style('opacity', 1);
6767
}
6868

69-
Drawing.setClipUrl(errorbars, plotinfo.layerClipId);
69+
Drawing.setClipUrl(errorbars, plotinfo.layerClipId, gd);
7070

7171
errorbars.each(function(d) {
7272
var errorbar = d3.select(this);

src/components/images/draw.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,10 @@ module.exports = function draw(gd) {
168168
yId = ya ? ya._id : '',
169169
clipAxes = xId + yId;
170170

171-
thisImage.call(Drawing.setClipUrl, clipAxes ?
172-
('clip' + fullLayout._uid + clipAxes) :
173-
null
171+
Drawing.setClipUrl(
172+
thisImage,
173+
clipAxes ? ('clip' + fullLayout._uid + clipAxes) : null,
174+
gd
174175
);
175176
}
176177

src/components/legend/draw.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ module.exports = function draw(gd) {
224224
y: opts.borderwidth
225225
});
226226

227-
Drawing.setClipUrl(scrollBox, clipId);
227+
Drawing.setClipUrl(scrollBox, clipId, gd);
228228

229229
Drawing.setRect(scrollBar, 0, 0, 0, 0);
230230
delete opts._scrollY;
@@ -262,7 +262,7 @@ module.exports = function draw(gd) {
262262
y: opts.borderwidth + scrollBoxY
263263
});
264264

265-
Drawing.setClipUrl(scrollBox, clipId);
265+
Drawing.setClipUrl(scrollBox, clipId, gd);
266266

267267
scrollHandler(scrollBoxY, scrollBarHeight, scrollRatio);
268268

src/components/rangeslider/draw.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
401401

402402
rangePlots.enter().append('g')
403403
.attr('class', function(id) { return constants.rangePlotClassName + ' ' + id; })
404-
.call(Drawing.setClipUrl, opts._clipId);
404+
.call(Drawing.setClipUrl, opts._clipId, gd);
405405

406406
rangePlots.order();
407407

src/components/shapes/draw.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,10 @@ function setClipPath(shapePath, gd, shapeOptions) {
120120
// spans two subplots. See https://github.com/plotly/plotly.js/issues/1452
121121
var clipAxes = (shapeOptions.xref + shapeOptions.yref).replace(/paper/g, '');
122122

123-
shapePath.call(Drawing.setClipUrl, clipAxes ?
124-
('clip' + gd._fullLayout._uid + clipAxes) :
125-
null
123+
Drawing.setClipUrl(
124+
shapePath,
125+
clipAxes ? 'clip' + gd._fullLayout._uid + clipAxes : null,
126+
gd
126127
);
127128
}
128129

@@ -493,9 +494,10 @@ function setupDragElement(gd, shapePath, shapeOptions, index, shapeLayer) {
493494
if(xref !== 'paper' && !xa.autorange) clipAxes += xref;
494495
if(yref !== 'paper' && !ya.autorange) clipAxes += yref;
495496

496-
shapePath.call(Drawing.setClipUrl, clipAxes ?
497-
'clip' + gd._fullLayout._uid + clipAxes :
498-
null
497+
Drawing.setClipUrl(
498+
shapePath,
499+
clipAxes ? 'clip' + gd._fullLayout._uid + clipAxes : null,
500+
gd
499501
);
500502
}
501503
}

src/components/updatemenus/scrollbox.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ ScrollBox.prototype.enable = function enable(position, translateX, translateY) {
254254
height: Math.ceil(clipB) - Math.floor(clipT)
255255
});
256256

257-
this.container.call(Drawing.setClipUrl, clipId);
257+
this.container.call(Drawing.setClipUrl, clipId, this.gd);
258258

259259
this.bg.attr({
260260
x: l,

src/plot_api/plot_api.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,6 @@ exports.plot = function(gd, data, layout, config) {
110110
// so we can share cached text across tabs
111111
Drawing.makeTester();
112112

113-
// clear stashed base url
114-
delete Drawing.baseUrl;
115-
116113
// collect promises for any async actions during plotting
117114
// any part of the plotting code can push to gd._promises, then
118115
// before we move to the next step, we check that they're all
@@ -419,7 +416,16 @@ function opaqueSetBackground(gd, bgColor) {
419416
}
420417

421418
function setPlotContext(gd, config) {
422-
if(!gd._context) gd._context = Lib.extendDeep({}, defaultConfig);
419+
if(!gd._context) {
420+
gd._context = Lib.extendDeep({}, defaultConfig);
421+
422+
// stash <base> href, used to make robust clipPath URLs
423+
var base = d3.select('base');
424+
gd._context._baseUrl = base.size() && base.attr('href') ?
425+
window.location.href.split('#')[0] :
426+
'';
427+
}
428+
423429
var context = gd._context;
424430

425431
var i, keys, key;
@@ -465,6 +471,9 @@ function setPlotContext(gd, config) {
465471
}
466472
}
467473
}
474+
475+
// not part of the user-facing config options
476+
context._exportedPlot = config._exportedPlot;
468477
}
469478

470479
// staticPlot forces a bunch of others:

src/plot_api/subroutines.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ function lsInner(gd) {
224224
layerClipId = null;
225225
}
226226

227-
Drawing.setClipUrl(plotinfo.plot, plotClipId);
227+
Drawing.setClipUrl(plotinfo.plot, plotClipId, gd);
228228

229229
// stash layer clipId value (null or same as clipId)
230230
// to DRY up Drawing.setClipUrl calls on trace-module and trace layers

0 commit comments

Comments
 (0)