Skip to content

Commit 8e1ad5e

Browse files
authoredDec 18, 2020
Merge pull request #5351 from plotly/preserve-drawing-buffer-safari14
Preserve drawing buffer for gl3d scenes when using Safari 13
2 parents d45eef5 + 7ebfd3d commit 8e1ad5e

File tree

4 files changed

+196
-18
lines changed

4 files changed

+196
-18
lines changed
 

‎src/lib/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ lib.getElementAndAncestors = domModule.getElementAndAncestors;
154154
lib.equalDomRects = domModule.equalDomRects;
155155

156156
lib.clearResponsive = require('./clear_responsive');
157+
lib.preserveDrawingBuffer = require('./preserve_drawing_buffer');
157158

158159
lib.makeTraceGroups = require('./make_trace_groups');
159160

‎src/lib/preserve_drawing_buffer.js

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* Copyright 2012-2020, 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+
'use strict';
10+
11+
var isNumeric = require('fast-isnumeric');
12+
var isMobileOrTablet = require('is-mobile');
13+
14+
module.exports = function preserveDrawingBuffer(opts) {
15+
var ua;
16+
17+
if(opts && opts.hasOwnProperty('userAgent')) {
18+
ua = opts.userAgent;
19+
} else {
20+
ua = getUserAgent();
21+
}
22+
23+
if(typeof ua !== 'string') return true;
24+
25+
var enable = isMobileOrTablet({
26+
ua: { headers: {'user-agent': ua }},
27+
tablet: true,
28+
featureDetect: false
29+
});
30+
31+
if(!enable) {
32+
var allParts = ua.split(' ');
33+
for(var i = 1; i < allParts.length; i++) {
34+
var part = allParts[i];
35+
if(part.indexOf('Safari') !== -1) {
36+
// find Safari version
37+
for(var k = i - 1; k > -1; k--) {
38+
var prevPart = allParts[k];
39+
if(prevPart.substr(0, 8) === 'Version/') {
40+
var v = prevPart.substr(8).split('.')[0];
41+
if(isNumeric(v)) v = +v;
42+
if(v >= 13) return true;
43+
}
44+
}
45+
}
46+
}
47+
}
48+
49+
return enable;
50+
};
51+
52+
function getUserAgent() {
53+
// similar to https://github.com/juliangruber/is-mobile/blob/91ca39ccdd4cfc5edfb5391e2515b923a730fbea/index.js#L14-L17
54+
var ua;
55+
if(typeof navigator !== 'undefined') {
56+
ua = navigator.userAgent;
57+
}
58+
59+
if(
60+
ua &&
61+
ua.headers &&
62+
typeof ua.headers['user-agent'] === 'string'
63+
) {
64+
ua = ua.headers['user-agent'];
65+
}
66+
67+
return ua;
68+
}

‎src/plots/gl3d/scene.js

+16-18
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ var passiveSupported = require('has-passive-events');
1818

1919
var Registry = require('../../registry');
2020
var Lib = require('../../lib');
21+
var preserveDrawingBuffer = Lib.preserveDrawingBuffer();
2122

2223
var Axes = require('../../plots/cartesian/axes');
2324
var Fx = require('../../components/fx');
@@ -30,9 +31,6 @@ var createAxesOptions = require('./layout/convert');
3031
var createSpikeOptions = require('./layout/spikes');
3132
var computeTickMarks = require('./layout/tick_marks');
3233

33-
var isMobile = require('is-mobile')({ tablet: true, featureDetect: true });
34-
35-
3634
var STATIC_CANVAS, STATIC_CONTEXT;
3735

3836
function Scene(options, fullLayout) {
@@ -98,7 +96,7 @@ proto.prepareOptions = function() {
9896
canvas: scene.canvas,
9997
gl: scene.gl,
10098
glOptions: {
101-
preserveDrawingBuffer: isMobile,
99+
preserveDrawingBuffer: preserveDrawingBuffer,
102100
premultipliedAlpha: true,
103101
antialias: true
104102
},
@@ -148,26 +146,26 @@ proto.tryCreatePlot = function() {
148146
try {
149147
scene.glplot = createPlot(opts);
150148
} catch(e) {
151-
if(scene.staticMode || !firstInit) {
149+
if(scene.staticMode || !firstInit || preserveDrawingBuffer) {
152150
success = false;
153151
} else { // try second time
152+
// enable preserveDrawingBuffer setup
153+
// in case is-mobile not detecting the right device
154+
Lib.warn([
155+
'webgl setup failed possibly due to',
156+
'false preserveDrawingBuffer config.',
157+
'The mobile/tablet device may not be detected by is-mobile module.',
158+
'Enabling preserveDrawingBuffer in second attempt to create webgl scene...'
159+
].join(' '));
160+
154161
try {
155-
// invert preserveDrawingBuffer setup which could be resulted from is-mobile not detecting the right device
156-
Lib.warn([
157-
'webgl setup failed possibly due to',
158-
isMobile ? 'disabling' : 'enabling',
159-
'preserveDrawingBuffer config.',
160-
'The device may not be supported by is-mobile module!',
161-
'Inverting preserveDrawingBuffer option in second attempt to create webgl scene.'
162-
].join(' '));
163-
164-
// invert is-mobile
165-
isMobile = opts.glOptions.preserveDrawingBuffer = !opts.glOptions.preserveDrawingBuffer;
162+
// invert preserveDrawingBuffer
163+
preserveDrawingBuffer = opts.glOptions.preserveDrawingBuffer = true;
166164

167165
scene.glplot = createPlot(opts);
168166
} catch(e) {
169-
// revert changes to is-mobile
170-
isMobile = opts.glOptions.preserveDrawingBuffer = !opts.glOptions.preserveDrawingBuffer;
167+
// revert changes to preserveDrawingBuffer
168+
preserveDrawingBuffer = opts.glOptions.preserveDrawingBuffer = false;
171169

172170
success = false;
173171
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
var preserveDrawingBuffer = require('@src/lib').preserveDrawingBuffer;
2+
3+
describe('preserveDrawingBuffer for gl3d scenes depending on device', function() {
4+
'use strict';
5+
6+
function examine(msg, exp, userAgent) {
7+
var v = preserveDrawingBuffer({
8+
userAgent: userAgent
9+
});
10+
11+
expect(v).toBe(exp, msg);
12+
}
13+
14+
it('Mac running Safari 14', function() {
15+
examine('Safari 14', true, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.2 Safari/605.1.15');
16+
examine('FireFox 84', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0');
17+
examine('Chrome 87', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36');
18+
examine('Edge 85', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_16_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36 Edg/85.0.564.68');
19+
examine('Brave 80', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_16_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36');
20+
});
21+
22+
it('Safari on iPads', function() {
23+
examine('iPad Pro 12.9 2020 | 14', true, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Safari/605.1.15');
24+
examine('iPad Pro 12.9 2018 | 12', true, 'Mozilla/5.0 (iPad; CPU OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1');
25+
examine('iPad Pro 12.9 2017 | 11', true, 'Mozilla/5.0 (iPad; CPU OS 11_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1');
26+
examine('iPad Pro 11 2018 | 12', true, 'Mozilla/5.0 (iPad; CPU OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.1 Mobile/15E148 Safari/604.1');
27+
examine('iPad 8th | 14', true, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Safari/605.1.15');
28+
examine('iPad 6th | 11', true, 'Mozilla/5.0 (iPad; CPU OS 11_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1');
29+
examine('iPad 5th | 11', true, 'Mozilla/5.0 (iPad; CPU OS 11_0_3 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A432 Safari/604.1');
30+
examine('iPad Air 4 | 14', true, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Safari/605.1.15');
31+
examine('iPad Air 2019 | 12', true, 'Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1 Mobile/15E148 Safari/604.1');
32+
examine('iPad Air 2 | 8', true, 'Mozilla/5.0 (iPad; CPU OS 8_4 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12H143 Safari/600.1.4');
33+
examine('iPad Mini 2019 | 13', true, 'Mozilla/5.0 (iPad; CPU OS 13_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Mobile/15E148 Safari/604.1');
34+
examine('iPad Mini 2019 | 12', true, 'Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1 Mobile/15E148 Safari/604.1');
35+
examine('iPad Mini 4 | 11', true, 'Mozilla/5.0 (iPad; CPU OS 11_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1');
36+
examine('iPad Mini 3 | 8', true, 'Mozilla/5.0 (iPad; CPU OS 8_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B410 Safari/600.1.4');
37+
38+
examine('iPad Pro 12.9 2020 | 13', true, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15');
39+
examine('iPad Pro 12.9 2018 | 13', true, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Safari/605.1.15');
40+
examine('iPad Pro 11 2020 | 13', true, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15');
41+
examine('iPad 7th | 13', true, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1');
42+
examine('iPad Air 2019 | 13', true, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Safari/605.1.15');
43+
});
44+
45+
describe('Mac', function() {
46+
it('Big Sur', function() {
47+
examine('Safari v14', true, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.1 Safari/605.1.15');
48+
examine('FireFox v83', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:83.0) Gecko/20100101 Firefox/83.0');
49+
examine('Chrome v87', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36');
50+
examine('Edge v87', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36 Edg/87.0.664.41');
51+
examine('Opera v73', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 OPR/73.0.3856.257');
52+
});
53+
54+
it('Catalina', function() {
55+
examine('Safari v13.1', true, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.2 Safari/605.1.15');
56+
examine('FireFox v83', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:83.0) Gecko/20100101 Firefox/83.0');
57+
examine('Chrome v87', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36');
58+
examine('Edge v87', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36 Edg/87.0.664.41');
59+
examine('Opera v73', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 OPR/73.0.3856.257');
60+
});
61+
62+
it('Mojave', function() {
63+
examine('Safari v12.1', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.2 Safari/605.1.15');
64+
examine('FireFox v83', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:83.0) Gecko/20100101 Firefox/83.0');
65+
examine('Chrome v87', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36');
66+
examine('Edge v87', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36 Edg/87.0.664.41');
67+
examine('Opera v73', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 OPR/73.0.3856.257');
68+
examine('Yandex v14.12', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 YaBrowser/14.12.2125.9577 Safari/537.36');
69+
});
70+
71+
it('High Sierra', function() {
72+
examine('Safari v11.1', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1.2 Safari/605.1.15');
73+
examine('FireFox v83', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:83.0) Gecko/20100101 Firefox/83.0');
74+
examine('Chrome v87', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36');
75+
examine('Edge v87', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36 Edg/87.0.664.41');
76+
examine('Opera v73', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 OPR/73.0.3856.257');
77+
examine('Yandex v14.12', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 YaBrowser/14.12.2125.9577 Safari/537.36');
78+
});
79+
80+
it('Sierra', function() {
81+
examine('Safari v10.1', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8');
82+
examine('FireFox v83', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:83.0) Gecko/20100101 Firefox/83.0');
83+
examine('Chrome v87', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36');
84+
examine('Opera v73', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.67 Safari/537.36 OPR/73.0.3856.257');
85+
examine('Yandex v14.12', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 YaBrowser/14.12.2125.9577 Safari/537.36');
86+
examine('Edge v87', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36 Edg/87.0.664.41');
87+
});
88+
89+
it('El Capitan', function() {
90+
examine('Safari v9.1', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/601.7.8 (KHTML, like Gecko) Version/9.1.3 Safari/601.7.8');
91+
examine('FireFox v78', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:78.0) Gecko/20100101 Firefox/78.0');
92+
examine('Chrome v87', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36');
93+
});
94+
95+
it('Yosemite', function() {
96+
examine('Safari v8', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/600.8.9 (KHTML, like Gecko) Version/8.0.8 Safari/600.8.9');
97+
examine('FireFox v78', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:78.0) Gecko/20100101 Firefox/78.0');
98+
examine('Chrome v87', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36');
99+
});
100+
101+
it('Mavericks', function() {
102+
examine('FireFox v78', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:78.0) Gecko/20100101 Firefox/78.0');
103+
examine('Chrome v67', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36');
104+
});
105+
106+
it('Mountain Lion', function() {
107+
examine('FireFox v48', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:48.0) Gecko/20100101 Firefox/48.0');
108+
examine('Chrome v49', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36');
109+
});
110+
});
111+
});

0 commit comments

Comments
 (0)
Please sign in to comment.