Skip to content
Merged
1 change: 1 addition & 0 deletions src/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ lib.getElementAndAncestors = domModule.getElementAndAncestors;
lib.equalDomRects = domModule.equalDomRects;

lib.clearResponsive = require('./clear_responsive');
lib.preserveDrawingBuffer = require('./preserve_drawing_buffer');

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

Expand Down
68 changes: 68 additions & 0 deletions src/lib/preserve_drawing_buffer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* Copyright 2012-2020, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var isNumeric = require('fast-isnumeric');
var isMobileOrTablet = require('is-mobile');

module.exports = function preserveDrawingBuffer(opts) {
var ua;

if(opts && opts.hasOwnProperty('userAgent')) {
ua = opts.userAgent;
} else {
ua = getUserAgent();
}

if(typeof ua !== 'string') return true;

var enable = isMobileOrTablet({
ua: { headers: {'user-agent': ua }},
tablet: true,
featureDetect: false
});

if(!enable) {
var allParts = ua.split(' ');
for(var i = 1; i < allParts.length; i++) {
var part = allParts[i];
if(part.indexOf('Safari') !== -1) {
// find Safari version
for(var k = i - 1; k > -1; k--) {
var prevPart = allParts[k];
if(prevPart.substr(0, 8) === 'Version/') {
var v = prevPart.substr(8).split('.')[0];
if(isNumeric(v)) v = +v;
if(v >= 13) return true;
}
}
}
}
}

return enable;
};

function getUserAgent() {
// similar to https://github.com/juliangruber/is-mobile/blob/91ca39ccdd4cfc5edfb5391e2515b923a730fbea/index.js#L14-L17
var ua;
if(typeof navigator !== 'undefined') {
ua = navigator.userAgent;
}

if(
ua &&
ua.headers &&
typeof ua.headers['user-agent'] === 'string'
) {
ua = ua.headers['user-agent'];
}

return ua;
}
34 changes: 16 additions & 18 deletions src/plots/gl3d/scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ var passiveSupported = require('has-passive-events');

var Registry = require('../../registry');
var Lib = require('../../lib');
var preserveDrawingBuffer = Lib.preserveDrawingBuffer();

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

var isMobile = require('is-mobile')({ tablet: true, featureDetect: true });


var STATIC_CANVAS, STATIC_CONTEXT;

function Scene(options, fullLayout) {
Expand Down Expand Up @@ -98,7 +96,7 @@ proto.prepareOptions = function() {
canvas: scene.canvas,
gl: scene.gl,
glOptions: {
preserveDrawingBuffer: isMobile,
preserveDrawingBuffer: preserveDrawingBuffer,
premultipliedAlpha: true,
antialias: true
},
Expand Down Expand Up @@ -148,26 +146,26 @@ proto.tryCreatePlot = function() {
try {
scene.glplot = createPlot(opts);
} catch(e) {
if(scene.staticMode || !firstInit) {
if(scene.staticMode || !firstInit || preserveDrawingBuffer) {
success = false;
} else { // try second time
// enable preserveDrawingBuffer setup
// in case is-mobile not detecting the right device
Lib.warn([
'webgl setup failed possibly due to',
'false preserveDrawingBuffer config.',
'The mobile/tablet device may not be detected by is-mobile module.',
'Enabling preserveDrawingBuffer in second attempt to create webgl scene...'
].join(' '));

try {
// invert preserveDrawingBuffer setup which could be resulted from is-mobile not detecting the right device
Lib.warn([
'webgl setup failed possibly due to',
isMobile ? 'disabling' : 'enabling',
'preserveDrawingBuffer config.',
'The device may not be supported by is-mobile module!',
'Inverting preserveDrawingBuffer option in second attempt to create webgl scene.'
].join(' '));

// invert is-mobile
isMobile = opts.glOptions.preserveDrawingBuffer = !opts.glOptions.preserveDrawingBuffer;
// invert preserveDrawingBuffer
preserveDrawingBuffer = opts.glOptions.preserveDrawingBuffer = true;

scene.glplot = createPlot(opts);
} catch(e) {
// revert changes to is-mobile
isMobile = opts.glOptions.preserveDrawingBuffer = !opts.glOptions.preserveDrawingBuffer;
// revert changes to preserveDrawingBuffer
preserveDrawingBuffer = opts.glOptions.preserveDrawingBuffer = false;

success = false;
}
Expand Down
111 changes: 111 additions & 0 deletions test/jasmine/tests/lib_drawing_buffer_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
var preserveDrawingBuffer = require('@src/lib').preserveDrawingBuffer;

describe('preserveDrawingBuffer for gl3d scenes depending on device', function() {
'use strict';

function examine(msg, exp, userAgent) {
var v = preserveDrawingBuffer({
userAgent: userAgent
});

expect(v).toBe(exp, msg);
}

it('Mac running Safari 14', function() {
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');
examine('FireFox 84', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:84.0) Gecko/20100101 Firefox/84.0');
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');
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');
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');
});

it('Safari on iPads', function() {
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');
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');
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');
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');
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');
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');
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');
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');
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');
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');
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');
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');
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');
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');

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');
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');
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');
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');
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');
});

describe('Mac', function() {
it('Big Sur', function() {
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');
examine('FireFox v83', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:83.0) Gecko/20100101 Firefox/83.0');
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');
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');
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');
});

it('Catalina', function() {
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');
examine('FireFox v83', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:83.0) Gecko/20100101 Firefox/83.0');
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');
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');
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');
});

it('Mojave', function() {
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');
examine('FireFox v83', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:83.0) Gecko/20100101 Firefox/83.0');
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');
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');
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');
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');
});

it('High Sierra', function() {
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');
examine('FireFox v83', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:83.0) Gecko/20100101 Firefox/83.0');
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');
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');
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');
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');
});

it('Sierra', function() {
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');
examine('FireFox v83', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:83.0) Gecko/20100101 Firefox/83.0');
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');
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');
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');
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');
});

it('El Capitan', function() {
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');
examine('FireFox v78', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:78.0) Gecko/20100101 Firefox/78.0');
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');
});

it('Yosemite', function() {
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');
examine('FireFox v78', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:78.0) Gecko/20100101 Firefox/78.0');
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');
});

it('Mavericks', function() {
examine('FireFox v78', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:78.0) Gecko/20100101 Firefox/78.0');
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');
});

it('Mountain Lion', function() {
examine('FireFox v48', false, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:48.0) Gecko/20100101 Firefox/48.0');
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');
});
});
});