Skip to content

Commit 85c2e20

Browse files
authored
Merge pull request #764 from nielsenb-jf/fix_child_window
Plotting in child window
2 parents 48eec0c + f218e09 commit 85c2e20

File tree

17 files changed

+288
-76
lines changed

17 files changed

+288
-76
lines changed

build/plotcss.js

+1-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
'use strict';
22

3-
var Plotly = require('../src/plotly');
43
var rules = {
54
"X,X div": "font-family:'Open Sans', verdana, arial, sans-serif;margin:0;padding:0;",
65
"X input,X button": "font-family:'Open Sans', verdana, arial, sans-serif;",
@@ -54,9 +53,4 @@ var rules = {
5453
"Y .notifier-close:hover": "color:#444;text-decoration:none;cursor:pointer;"
5554
};
5655

57-
for(var selector in rules) {
58-
var fullSelector = selector.replace(/^,/,' ,')
59-
.replace(/X/g, '.js-plotly-plot .plotly')
60-
.replace(/Y/g, '.plotly-notifier');
61-
Plotly.Lib.addStyleRule(fullSelector, rules[selector]);
62-
}
56+
module.exports = rules;

src/components/dragelement/index.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ dragElement.init = function init(options) {
8686

8787
if(options.prepFn) options.prepFn(e, startX, startY);
8888

89-
dragCover = coverSlip();
89+
dragCover = coverSlip(gd);
9090

9191
dragCover.onmousemove = onMove;
9292
dragCover.onmouseup = onDone;
@@ -139,7 +139,7 @@ dragElement.init = function init(options) {
139139
if(options.doneFn) options.doneFn(gd._dragged, numClicks);
140140

141141
if(!gd._dragged) {
142-
var e2 = document.createEvent('MouseEvents');
142+
var e2 = gd._document.createEvent('MouseEvents');
143143
e2.initEvent('click', true, true);
144144
initialTarget.dispatchEvent(e2);
145145
}
@@ -159,8 +159,8 @@ dragElement.init = function init(options) {
159159
options.element.style.pointerEvents = 'all';
160160
};
161161

162-
function coverSlip() {
163-
var cover = document.createElement('div');
162+
function coverSlip(gd) {
163+
var cover = gd._document.createElement('div');
164164

165165
cover.className = 'dragcover';
166166
var cStyle = cover.style;
@@ -172,7 +172,7 @@ function coverSlip() {
172172
cStyle.zIndex = 999999999;
173173
cStyle.background = 'none';
174174

175-
document.body.appendChild(cover);
175+
gd._document.body.appendChild(cover);
176176

177177
return cover;
178178
}

src/components/modebar/buttons.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,19 @@ modeBarButtons.toImage = {
5050
click: function(gd) {
5151
var format = 'png';
5252

53-
Lib.notifier('Taking snapshot - this may take a few seconds', 'long');
53+
Lib.notifier(gd, 'Taking snapshot - this may take a few seconds', 'long');
5454

5555
if(Lib.isIE()) {
56-
Lib.notifier('IE only supports svg. Changing format to svg.', 'long');
56+
Lib.notifier(gd, 'IE only supports svg. Changing format to svg.', 'long');
5757
format = 'svg';
5858
}
5959

6060
downloadImage(gd, {'format': format})
6161
.then(function(filename) {
62-
Lib.notifier('Snapshot succeeded - ' + filename, 'long');
62+
Lib.notifier(gd, 'Snapshot succeeded - ' + filename, 'long');
6363
})
6464
.catch(function() {
65-
Lib.notifier('Sorry there was a problem downloading your snapshot!', 'long');
65+
Lib.notifier(gd, 'Sorry there was a problem downloading your snapshot!', 'long');
6666
});
6767
}
6868
};

src/components/rangeslider/create_slider.js

+17-17
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ module.exports = function createSlider(gd) {
3333
var minStart = 0,
3434
maxStart = width;
3535

36-
var slider = document.createElementNS(svgNS, 'g');
36+
var slider = gd._document.createElementNS(svgNS, 'g');
3737
helpers.setAttributes(slider, {
3838
'class': 'range-slider',
3939
'data-min': minStart,
@@ -43,7 +43,7 @@ module.exports = function createSlider(gd) {
4343
});
4444

4545

46-
var sliderBg = document.createElementNS(svgNS, 'rect'),
46+
var sliderBg = gd._document.createElementNS(svgNS, 'rect'),
4747
borderCorrect = options.borderwidth % 2 === 0 ? options.borderwidth : options.borderwidth - 1;
4848
helpers.setAttributes(sliderBg, {
4949
'fill': options.bgcolor,
@@ -56,7 +56,7 @@ module.exports = function createSlider(gd) {
5656
});
5757

5858

59-
var maskMin = document.createElementNS(svgNS, 'rect');
59+
var maskMin = gd._document.createElementNS(svgNS, 'rect');
6060
helpers.setAttributes(maskMin, {
6161
'x': 0,
6262
'width': minStart,
@@ -65,7 +65,7 @@ module.exports = function createSlider(gd) {
6565
});
6666

6767

68-
var maskMax = document.createElementNS(svgNS, 'rect');
68+
var maskMax = gd._document.createElementNS(svgNS, 'rect');
6969
helpers.setAttributes(maskMax, {
7070
'x': maxStart,
7171
'width': width - maxStart,
@@ -74,9 +74,9 @@ module.exports = function createSlider(gd) {
7474
});
7575

7676

77-
var grabberMin = document.createElementNS(svgNS, 'g'),
78-
grabAreaMin = document.createElementNS(svgNS, 'rect'),
79-
handleMin = document.createElementNS(svgNS, 'rect');
77+
var grabberMin = gd._document.createElementNS(svgNS, 'g'),
78+
grabAreaMin = gd._document.createElementNS(svgNS, 'rect'),
79+
handleMin = gd._document.createElementNS(svgNS, 'rect');
8080
helpers.setAttributes(grabberMin, { 'transform': 'translate(' + (minStart - handleWidth - 1) + ')' });
8181
helpers.setAttributes(grabAreaMin, {
8282
'width': 10,
@@ -97,9 +97,9 @@ module.exports = function createSlider(gd) {
9797
helpers.appendChildren(grabberMin, [handleMin, grabAreaMin]);
9898

9999

100-
var grabberMax = document.createElementNS(svgNS, 'g'),
101-
grabAreaMax = document.createElementNS(svgNS, 'rect'),
102-
handleMax = document.createElementNS(svgNS, 'rect');
100+
var grabberMax = gd._document.createElementNS(svgNS, 'g'),
101+
grabAreaMax = gd._document.createElementNS(svgNS, 'rect'),
102+
handleMax = gd._document.createElementNS(svgNS, 'rect');
103103
helpers.setAttributes(grabberMax, { 'transform': 'translate(' + maxStart + ')' });
104104
helpers.setAttributes(grabAreaMax, {
105105
'width': 10,
@@ -120,7 +120,7 @@ module.exports = function createSlider(gd) {
120120
helpers.appendChildren(grabberMax, [handleMax, grabAreaMax]);
121121

122122

123-
var slideBox = document.createElementNS(svgNS, 'rect');
123+
var slideBox = gd._document.createElementNS(svgNS, 'rect');
124124
helpers.setAttributes(slideBox, {
125125
'x': minStart,
126126
'width': maxStart - minStart,
@@ -137,8 +137,8 @@ module.exports = function createSlider(gd) {
137137
minVal = slider.getAttribute('data-min'),
138138
maxVal = slider.getAttribute('data-max');
139139

140-
window.addEventListener('mousemove', mouseMove);
141-
window.addEventListener('mouseup', mouseUp);
140+
gd._document.defaultView.addEventListener('mousemove', mouseMove);
141+
gd._document.defaultView.addEventListener('mouseup', mouseUp);
142142

143143
function mouseMove(e) {
144144
var delta = +e.clientX - startX,
@@ -189,8 +189,8 @@ module.exports = function createSlider(gd) {
189189
}
190190

191191
function mouseUp() {
192-
window.removeEventListener('mousemove', mouseMove);
193-
window.removeEventListener('mouseup', mouseUp);
192+
gd._document.defaultView.removeEventListener('mousemove', mouseMove);
193+
gd._document.defaultView.removeEventListener('mouseup', mouseUp);
194194
slider.style.cursor = 'auto';
195195
}
196196
});
@@ -222,8 +222,8 @@ module.exports = function createSlider(gd) {
222222

223223
function setDataRange(dataMin, dataMax) {
224224

225-
if(window.requestAnimationFrame) {
226-
window.requestAnimationFrame(function() {
225+
if(gd._document.defaultView.requestAnimationFrame) {
226+
gd._document.defaultView.requestAnimationFrame(function() {
227227
Plotly.relayout(gd, 'xaxis.range', [dataMin, dataMax]);
228228
});
229229
} else {

src/lib/index.js

+3-24
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ lib.log = loggersModule.log;
6464
lib.warn = loggersModule.warn;
6565
lib.error = loggersModule.error;
6666

67+
var cssModule = require('./plotcss_utils');
68+
lib.injectStyles = cssModule.injectStyles;
69+
6770
lib.notifier = require('./notifier');
6871

6972
/**
@@ -388,30 +391,6 @@ lib.removeElement = function(el) {
388391
if(elParent) elParent.removeChild(el);
389392
};
390393

391-
/**
392-
* for dynamically adding style rules
393-
* makes one stylesheet that contains all rules added
394-
* by all calls to this function
395-
*/
396-
lib.addStyleRule = function(selector, styleString) {
397-
if(!lib.styleSheet) {
398-
var style = document.createElement('style');
399-
// WebKit hack :(
400-
style.appendChild(document.createTextNode(''));
401-
document.head.appendChild(style);
402-
lib.styleSheet = style.sheet;
403-
}
404-
var styleSheet = lib.styleSheet;
405-
406-
if(styleSheet.insertRule) {
407-
styleSheet.insertRule(selector + '{' + styleString + '}', 0);
408-
}
409-
else if(styleSheet.addRule) {
410-
styleSheet.addRule(selector, styleString, 0);
411-
}
412-
else lib.warn('addStyleRule failed');
413-
};
414-
415394
lib.getTranslate = function(element) {
416395

417396
var re = /.*\btranslate\((\d*\.?\d*)[^\d]*(\d*\.?\d*)[^\d].*/,

src/lib/notifier.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@ var NOTEDATA = [];
1616

1717
/**
1818
* notifier
19+
* @param {object} gd figure Object
1920
* @param {String} text The person's user name
2021
* @param {Number} [delay=1000] The delay time in milliseconds
2122
* or 'long' which provides 2000 ms delay time.
2223
* @return {undefined} this function does not return a value
2324
*/
24-
module.exports = function(text, displayLength) {
25+
module.exports = function(gd, text, displayLength) {
2526
if(NOTEDATA.indexOf(text) !== -1) return;
2627

2728
NOTEDATA.push(text);
@@ -30,7 +31,7 @@ module.exports = function(text, displayLength) {
3031
if(isNumeric(displayLength)) ts = displayLength;
3132
else if(displayLength === 'long') ts = 3000;
3233

33-
var notifierContainer = d3.select('body')
34+
var notifierContainer = d3.select(gd._document.body)
3435
.selectAll('.plotly-notifier')
3536
.data([0]);
3637
notifierContainer.enter()

src/lib/plotcss_utils.js

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**
2+
* Copyright 2012-2016, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
10+
'use strict';
11+
12+
var lib = require('./index');
13+
var plotcss = require('../../build/plotcss');
14+
15+
// Inject styling information into the document containing the graph div
16+
exports.injectStyles = function injectStyles(gd) {
17+
// If the graph div has already been styled, bail
18+
if(gd._plotCSSLoaded) return;
19+
20+
var targetSelectors = exports.getAllRuleSelectors(gd._document);
21+
var targetStyleSheet = null;
22+
23+
if(gd._document.getElementsByTagName('style').length === 0) {
24+
var style = gd._document.createElement('style');
25+
// WebKit hack :(
26+
style.appendChild(gd._document.createTextNode(''));
27+
gd._document.head.appendChild(style);
28+
targetStyleSheet = style.sheet;
29+
}
30+
else {
31+
// Just grab the first style element to append to
32+
targetStyleSheet = gd._document.getElementsByTagName('style')[0].sheet;
33+
}
34+
35+
for(var selector in plotcss) {
36+
var fullSelector = exports.buildFullSelector(selector);
37+
38+
// Don't duplicate selectors
39+
if(targetSelectors.indexOf(fullSelector) === -1) {
40+
if(targetStyleSheet.insertRule) {
41+
targetStyleSheet.insertRule(fullSelector + '{' + plotcss[selector] + '}', 0);
42+
}
43+
else if(targetStyleSheet.addRule) {
44+
targetStyleSheet.addRule(fullSelector, plotcss[selector], 0);
45+
}
46+
else lib.warn('injectStyles failed');
47+
}
48+
}
49+
50+
gd._plotCSSLoaded = true;
51+
};
52+
53+
// expands a plotcss selector
54+
exports.buildFullSelector = function buildFullSelector(selector) {
55+
var fullSelector = selector.replace(/,/, ', ')
56+
.replace(/:after/g, '::after')
57+
.replace(/:before/g, '::before')
58+
.replace(/X/g, '.js-plotly-plot .plotly')
59+
.replace(/Y/g, '.plotly-notifier');
60+
61+
return fullSelector;
62+
};
63+
64+
// Gets all the rules currently attached to the document
65+
exports.getAllRuleSelectors = function getAllRuleSelectors(sourceDocument) {
66+
var allSelectors = [];
67+
68+
for(var i = 0; i < sourceDocument.styleSheets.length; i++) {
69+
var styleSheet = sourceDocument.styleSheets[i];
70+
71+
if(!styleSheet.cssRules) continue; // It's possible for rules to be undefined
72+
73+
for(var j = 0; j < styleSheet.cssRules.length; j++) {
74+
var cssRule = styleSheet.cssRules[j];
75+
76+
allSelectors.push(cssRule.selectorText);
77+
}
78+
}
79+
80+
return allSelectors;
81+
};

src/plot_api/plot_api.js

+12-4
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ Plotly.plot = function(gd, data, layout, config) {
5454

5555
gd = getGraphDiv(gd);
5656

57+
// Get the document the graph div lives in, so we can make sure things like
58+
// drag covers are attached to the correct document
59+
gd._document = gd.ownerDocument || window.document;
60+
61+
// Inject the plot styles into the document where we're plotting, bails if
62+
// already styled
63+
Lib.injectStyles(gd);
64+
5765
// Events.init is idempotent and bails early if gd has already been init'd
5866
Events.init(gd);
5967

@@ -2551,12 +2559,12 @@ function plotAutoSize(gd, aobj) {
25512559
// embedded in an iframe - just take the full iframe size
25522560
// if we get to this point, with no aspect ratio restrictions
25532561
if(gd._context.fillFrame) {
2554-
newWidth = window.innerWidth;
2555-
newHeight = window.innerHeight;
2562+
newWidth = gd._document.defaultView.innerWidth;
2563+
newHeight = gd._document.defaultView.innerHeight;
25562564

25572565
// somehow we get a few extra px height sometimes...
25582566
// just hide it
2559-
document.body.style.overflow = 'hidden';
2567+
gd._document.body.style.overflow = 'hidden';
25602568
}
25612569
else if(isNumeric(context.frameMargins) && context.frameMargins > 0) {
25622570
var reservedMargins = calculateReservedMargins(gd._boundingBoxMargins),
@@ -2573,7 +2581,7 @@ function plotAutoSize(gd, aobj) {
25732581
// provide height and width for the container div,
25742582
// specify size in layout, or take the defaults,
25752583
// but don't enforce any ratio restrictions
2576-
computedStyle = window.getComputedStyle(gd);
2584+
computedStyle = gd._document.defaultView.getComputedStyle(gd);
25772585
newHeight = parseFloat(computedStyle.height) || fullLayout.height;
25782586
newWidth = parseFloat(computedStyle.width) || fullLayout.width;
25792587
}

src/plotly.js

-3
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@ var Lib = exports.Lib = require('./lib');
2626
exports.util = require('./lib/svg_text_utils');
2727
exports.Queue = require('./lib/queue');
2828

29-
// plot css
30-
require('../build/plotcss');
31-
3229
// configuration
3330
exports.MathJaxConfig = require('./fonts/mathjax_config');
3431
exports.defaultConfig = require('./plot_api/plot_config');

src/plots/cartesian/dragbox.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ module.exports = function dragBox(gd, plotinfo, x, y, w, h, ns, ew) {
305305
dragTail(zoomMode);
306306

307307
if(SHOWZOOMOUTTIP && gd.data && gd._context.showTips) {
308-
Lib.notifier('Double-click to<br>zoom back out', 'long');
308+
Lib.notifier(gd, 'Double-click to<br>zoom back out', 'long');
309309
SHOWZOOMOUTTIP = false;
310310
}
311311
}

src/plots/cartesian/set_convert.js

+1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ module.exports = function setConvert(ax) {
114114

115115
if(!isFinite(ax._m) || !isFinite(ax._b)) {
116116
Lib.notifier(
117+
ax._gd,
117118
'Something went wrong with axis scaling',
118119
'long');
119120
ax._gd._replotting = false;

0 commit comments

Comments
 (0)