diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js index a6a4a62f9f1..c17f12befaa 100644 --- a/src/plot_api/plot_api.js +++ b/src/plot_api/plot_api.js @@ -194,6 +194,30 @@ Plotly.plot = function(gd, data, layout, config) { } } + fullLayout._glcanvas = fullLayout._glcontainer.selectAll('.gl-canvas').data(fullLayout._hasCategory('gl') ? [{ + key: 'contextLayer' + }, { + key: 'focusLayer' + }, { + key: 'pickLayer' + }] : []); + + fullLayout._glcanvas.enter().append('canvas') + .attr('class', function(d) { + return 'gl-canvas gl-canvas-' + d.key.replace('Layer', ''); + }) + .style('position', 'absolute') + .style('top', 0) + .style('left', 0) + .style('width', '100%') + .style('height', '100%') + .style('pointer-events', 'none') + .style('overflow', 'visible') + .attr('width', fullLayout.width) + .attr('height', fullLayout.height); + + fullLayout._glcanvas.exit().remove(); + return Lib.syncOrAsync([ subroutines.layoutStyles ], gd); @@ -3027,10 +3051,14 @@ function makePlotFramework(gd) { // TODO: sort out all the ordering so we don't have to // explicitly delete anything fullLayout._glcontainer = fullLayout._paperdiv.selectAll('.gl-container') - .data([0]); + .data([{}]); + fullLayout._glcontainer.enter().append('div') .classed('gl-container', true); + // That is initialized in drawFramework if there are `gl` traces + fullLayout._glcanvas = null; + fullLayout._paperdiv.selectAll('.main-svg').remove(); fullLayout._paper = fullLayout._paperdiv.insert('svg', ':first-child') diff --git a/src/plots/gl2d/scene2d.js b/src/plots/gl2d/scene2d.js index 57b9e6f9bbf..a19404f4f3f 100644 --- a/src/plots/gl2d/scene2d.js +++ b/src/plots/gl2d/scene2d.js @@ -111,7 +111,7 @@ proto.makeFramework = function() { this.gl = STATIC_CONTEXT; } else { - var liveCanvas = document.createElement('canvas'); + var liveCanvas = this.container.querySelector('.gl-canvas-focus'); var gl = getContext({ canvas: liveCanvas, @@ -139,7 +139,7 @@ proto.makeFramework = function() { // disabling user select on the canvas // sanitizes double-clicks interactions // ref: https://github.com/plotly/plotly.js/issues/744 - canvas.className += 'user-select-none'; + canvas.className += ' user-select-none'; // create SVG container for hover text var svgContainer = this.svgContainer = document.createElementNS( @@ -158,7 +158,6 @@ proto.makeFramework = function() { // append canvas, hover svg and mouse div to container var container = this.container; - container.appendChild(canvas); container.appendChild(svgContainer); container.appendChild(mouseContainer); @@ -369,7 +368,6 @@ proto.destroy = function() { this.glplot.dispose(); - if(!this.staticPlot) this.container.removeChild(this.canvas); this.container.removeChild(this.svgContainer); this.container.removeChild(this.mouseContainer); diff --git a/src/plots/plots.js b/src/plots/plots.js index e8ff7e50bc8..9e29fcbfa9b 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -458,6 +458,7 @@ plots.supplyDefaults = function(gd) { // attach helper method to check whether a plot type is present on graph newFullLayout._has = plots._hasPlotType.bind(newFullLayout); + newFullLayout._hasCategory = plots._hasCategory.bind(newFullLayout); // special cases that introduce interactions between traces var _modules = newFullLayout._modules; @@ -576,6 +577,21 @@ plots._hasPlotType = function(category) { return false; }; +// check whether trace has a category +plots._hasCategory = function(category) { + var modules = this._modules || []; + + // create canvases only in case if there is at least one regl component + for(var i = 0; i < modules.length; i++) { + var _ = modules[i]; + if(_.categories && _.categories.indexOf(category) >= 0) { + return true; + } + } + + return false; +}; + plots.cleanPlot = function(newFullData, newFullLayout, oldFullData, oldFullLayout) { var i, j; diff --git a/src/traces/contourgl/index.js b/src/traces/contourgl/index.js index ac4fca3b72d..a1d6f961cd6 100644 --- a/src/traces/contourgl/index.js +++ b/src/traces/contourgl/index.js @@ -21,7 +21,7 @@ ContourGl.plot = require('./convert'); ContourGl.moduleType = 'trace'; ContourGl.name = 'contourgl'; ContourGl.basePlotModule = require('../../plots/gl2d'); -ContourGl.categories = ['gl2d', '2dMap']; +ContourGl.categories = ['gl', 'gl2d', '2dMap']; ContourGl.meta = { description: [ 'WebGL contour (beta)' diff --git a/src/traces/heatmapgl/index.js b/src/traces/heatmapgl/index.js index 19ac6fe15f4..dca703e7f85 100644 --- a/src/traces/heatmapgl/index.js +++ b/src/traces/heatmapgl/index.js @@ -21,7 +21,7 @@ HeatmapGl.plot = require('./convert'); HeatmapGl.moduleType = 'trace'; HeatmapGl.name = 'heatmapgl'; HeatmapGl.basePlotModule = require('../../plots/gl2d'); -HeatmapGl.categories = ['gl2d', '2dMap']; +HeatmapGl.categories = ['gl', 'gl2d', '2dMap']; HeatmapGl.meta = { description: [ 'WebGL version of the heatmap trace type.' diff --git a/src/traces/parcoords/attributes.js b/src/traces/parcoords/attributes.js index 83855a2da16..46729697a6e 100644 --- a/src/traces/parcoords/attributes.js +++ b/src/traces/parcoords/attributes.js @@ -18,7 +18,6 @@ var extendDeep = require('../../lib/extend').extendDeep; var extendFlat = require('../../lib/extend').extendFlat; module.exports = { - domain: { x: { valType: 'info_array', @@ -120,36 +119,26 @@ module.exports = { description: 'The dimensions (variables) of the parallel coordinates chart. 2..60 dimensions are supported.' }, - line: extendFlat({}, - + line: extendFlat( // the default autocolorscale isn't quite usable for parcoords due to context ambiguity around 0 (grey, off-white) - // autocolorscale therefore defaults to false too, to avoid being overridden by the blue-white-red autocolor palette + // autocolorscale therefore defaults to false too, to avoid being overridden by the blue-white-red autocolor palette extendDeep( - {}, colorAttributes('line'), { - colorscale: extendDeep( - {}, - colorAttributes('line').colorscale, - {dflt: colorscales.Viridis} - ), - autocolorscale: extendDeep( - {}, - colorAttributes('line').autocolorscale, - { - dflt: false, - description: [ - 'Has an effect only if line.color` is set to a numerical array.', - 'Determines whether the colorscale is a default palette (`autocolorscale: true`)', - 'or the palette determined by `line.colorscale`.', - 'In case `colorscale` is unspecified or `autocolorscale` is true, the default ', - 'palette will be chosen according to whether numbers in the `color` array are', - 'all positive, all negative or mixed.', - 'The default value is false, so that `parcoords` colorscale can default to `Viridis`.' - ].join(' ') - } - ) + colorscale: {dflt: colorscales.Viridis}, + autocolorscale: { + dflt: false, + description: [ + 'Has an effect only if line.color` is set to a numerical array.', + 'Determines whether the colorscale is a default palette (`autocolorscale: true`)', + 'or the palette determined by `line.colorscale`.', + 'In case `colorscale` is unspecified or `autocolorscale` is true, the default ', + 'palette will be chosen according to whether numbers in the `color` array are', + 'all positive, all negative or mixed.', + 'The default value is false, so that `parcoords` colorscale can default to `Viridis`.' + ].join(' ') + } } ), diff --git a/src/traces/parcoords/base_plot.js b/src/traces/parcoords/base_plot.js index e5be3285b75..d34583c8be7 100644 --- a/src/traces/parcoords/base_plot.js +++ b/src/traces/parcoords/base_plot.js @@ -12,7 +12,6 @@ var d3 = require('d3'); var Plots = require('../../plots/plots'); var parcoordsPlot = require('./plot'); var xmlnsNamespaces = require('../../constants/xmlns_namespaces'); -var c = require('./constants'); exports.name = 'parcoords'; @@ -28,8 +27,6 @@ exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout) var hasParcoords = (newFullLayout._has && newFullLayout._has('parcoords')); if(hadParcoords && !hasParcoords) { - oldFullLayout._paperdiv.selectAll('.parcoords-line-layers').remove(); - oldFullLayout._paperdiv.selectAll('.parcoords-line-layers').remove(); oldFullLayout._paperdiv.selectAll('.parcoords').remove(); oldFullLayout._paperdiv.selectAll('.parcoords').remove(); oldFullLayout._glimages.selectAll('*').remove(); @@ -41,23 +38,21 @@ exports.toSVG = function(gd) { var imageRoot = gd._fullLayout._glimages; var root = d3.select(gd).selectAll('.svg-container'); var canvases = root.filter(function(d, i) {return i === root.size() - 1;}) - .selectAll('.parcoords-lines.context, .parcoords-lines.focus'); + .selectAll('.gl-canvas-context, .gl-canvas-focus'); - function canvasToImage(d) { + function canvasToImage() { var canvas = this; var imageData = canvas.toDataURL('image/png'); var image = imageRoot.append('svg:image'); - var size = gd._fullLayout._size; - var domain = gd._fullData[d.model.key].domain; image.attr({ xmlns: xmlnsNamespaces.svg, 'xlink:href': imageData, - x: size.l + size.w * domain.x[0] - c.overdrag, - y: size.t + size.h * (1 - domain.y[1]), - width: (domain.x[1] - domain.x[0]) * size.w + 2 * c.overdrag, - height: (domain.y[1] - domain.y[0]) * size.h, - preserveAspectRatio: 'none' + preserveAspectRatio: 'none', + x: 0, + y: 0, + width: canvas.width, + height: canvas.height }); } diff --git a/src/traces/parcoords/lines.js b/src/traces/parcoords/lines.js index 92776dabf0a..98495e53ad8 100644 --- a/src/traces/parcoords/lines.js +++ b/src/traces/parcoords/lines.js @@ -10,7 +10,7 @@ var createREGL = require('regl'); var glslify = require('glslify'); -var verticalPadding = require('./constants').verticalPadding; +var c = require('./constants'); var vertexShaderSource = glslify('./shaders/vertex.glsl'); var pickVertexShaderSource = glslify('./shaders/pick_vertex.glsl'); var fragmentShaderSource = glslify('./shaders/fragment.glsl'); @@ -56,7 +56,8 @@ function renderBlock(regl, glAes, renderState, blockLineCount, sampleCount, item item.offset = sectionVertexCount * blockNumber * blockLineCount; item.count = sectionVertexCount * count; if(blockNumber === 0) { - window.cancelAnimationFrame(renderState.currentRafs[rafKey]); // stop drawing possibly stale glyphs before clearing + // stop drawing possibly stale glyphs before clearing + window.cancelAnimationFrame(renderState.currentRafs[rafKey]); delete renderState.currentRafs[rafKey]; clear(regl, item.scissorX, item.scissorY, item.scissorWidth, item.viewBoxSize[1]); } @@ -165,7 +166,19 @@ function valid(i, offset, panelCount) { return i + offset <= panelCount; } -module.exports = function(canvasGL, lines, canvasWidth, canvasHeight, initialDimensions, initialPanels, unitToColor, context, pick, scatter) { +module.exports = function(canvasGL, d, scatter) { + var model = d.model, + vm = d.viewModel, + domain = model.domain; + + var lines = model.lines, + canvasWidth = model.canvasWidth, + canvasHeight = model.canvasHeight, + initialDimensions = vm.dimensions, + initialPanels = vm.panels, + unitToColor = model.unitToColor, + context = d.context, + pick = d.pick; var renderState = { currentRafs: {}, @@ -248,6 +261,13 @@ module.exports = function(canvasGL, lines, canvasWidth, canvasHeight, initialDim } }, + viewport: { + x: regl.prop('viewportX'), + y: regl.prop('viewportY'), + width: regl.prop('viewportWidth'), + height: regl.prop('viewportHeight') + }, + dither: false, vert: pick ? pickVertexShaderSource : vertexShaderSource, @@ -297,7 +317,7 @@ module.exports = function(canvasGL, lines, canvasWidth, canvasHeight, initialDim function makeItem(i, ii, x, y, panelSizeX, canvasPanelSizeY, crossfilterDimensionIndex, scatter, I, leftmost, rightmost) { var loHi, abcd, d, index; var leftRight = [i, ii]; - var filterEpsilon = verticalPadding / canvasPanelSizeY; + var filterEpsilon = c.verticalPadding / canvasPanelSizeY; var dims = [0, 1].map(function() {return [0, 1, 2, 3].map(function() {return new Float32Array(16);});}); var lims = [0, 1].map(function() {return [0, 1, 2, 3].map(function() {return new Float32Array(16);});}); @@ -341,10 +361,16 @@ module.exports = function(canvasGL, lines, canvasWidth, canvasHeight, initialDim colorClamp: colorClamp, scatter: scatter || 0, - scissorX: I === leftmost ? 0 : x + overdrag, + + scissorX: (I === leftmost ? 0 : x + overdrag) + (model.pad.l - overdrag) + model.layoutWidth * domain.x[0], scissorWidth: (I === rightmost ? canvasWidth - x + overdrag : panelSizeX + 0.5) + (I === leftmost ? x + overdrag : 0), - scissorY: y, - scissorHeight: canvasPanelSizeY + scissorY: y + model.pad.b + model.layoutHeight * domain.y[0], + scissorHeight: canvasPanelSizeY, + + viewportX: model.pad.l - overdrag + model.layoutWidth * domain.x[0], + viewportY: model.pad.b + model.layoutHeight * domain.y[0], + viewportWidth: canvasWidth, + viewportHeight: canvasHeight }; } diff --git a/src/traces/parcoords/parcoords.js b/src/traces/parcoords/parcoords.js index 455e76f08f9..33119b9fdb0 100644 --- a/src/traces/parcoords/parcoords.js +++ b/src/traces/parcoords/parcoords.js @@ -166,6 +166,9 @@ function model(layout, d, i) { labelFont: labelFont, tickFont: tickFont, rangeFont: rangeFont, + layoutWidth: width, + layoutHeight: layout.height, + domain: domain, translateX: domain.x[0] * width, translateY: layout.height - domain.y[1] * layout.height, pad: pad, @@ -233,18 +236,6 @@ function viewModel(model) { return viewModel; } -function lineLayerModel(vm) { - return c.layers.map(function(key) { - return { - key: key, - context: key === 'contextLineLayer', - pick: key === 'pickLineLayer', - viewModel: vm, - model: vm.model - }; - }); -} - function styleExtentTexts(selection) { selection .classed('axisExtentText', true) @@ -253,8 +244,7 @@ function styleExtentTexts(selection) { .style('user-select', 'none'); } -module.exports = function(root, svg, styledData, layout, callbacks) { - +module.exports = function(root, svg, parcoordsLineLayers, styledData, layout, callbacks) { var domainBrushing = false; var linePickActive = true; @@ -301,37 +291,26 @@ module.exports = function(root, svg, styledData, layout, callbacks) { .map(model.bind(0, layout)) .map(viewModel); - root.selectAll('.parcoords-line-layers').remove(); - - var parcoordsLineLayers = root.selectAll('.parcoords-line-layers') - .data(vm, keyFun); + parcoordsLineLayers.each(function(d, i) { + return Lib.extendFlat(d, vm[i]); + }); - parcoordsLineLayers.enter() - .insert('div', '.' + svg.attr('class').split(' ').join(' .')) // not hardcoding .main-svg - .classed('parcoords-line-layers', true) - .style('box-sizing', 'content-box'); + var parcoordsLineLayer = parcoordsLineLayers.selectAll('.gl-canvas') + .each(function(d) { + var key = d.key; + d.context = key === 'contextLayer'; + d.pick = key === 'pickLayer'; - parcoordsLineLayers - .style('transform', function(d) { - return 'translate(' + (d.model.translateX - c.overdrag) + 'px,' + d.model.translateY + 'px)'; + // FIXME: figure out how to handle multiple instances + d.viewModel = vm[0]; + d.model = vm[0].model; }); - var parcoordsLineLayer = parcoordsLineLayers.selectAll('.parcoords-lines') - .data(lineLayerModel, keyFun); - var tweakables = {renderers: [], dimensions: []}; var lastHovered = null; - parcoordsLineLayer.enter() - .append('canvas') - .attr('class', function(d) {return 'parcoords-lines ' + (d.context ? 'context' : d.pick ? 'pick' : 'focus');}) - .style('box-sizing', 'content-box') - .style('float', 'left') - .style('clear', 'both') - .style('left', 0) - .style('overflow', 'visible') - .style('position', function(d, i) {return i > 0 ? 'absolute' : 'absolute';}) + parcoordsLineLayer .filter(function(d) {return d.pick;}) .on('mousemove', function(d) { if(linePickActive && d.lineLayer && callbacks && callbacks.hover) { @@ -369,14 +348,6 @@ module.exports = function(root, svg, styledData, layout, callbacks) { }); parcoordsLineLayer - .style('margin', function(d) { - var p = d.model.pad; - return p.t + 'px ' + p.r + 'px ' + p.b + 'px ' + p.l + 'px'; - }) - .attr('width', function(d) {return d.model.canvasWidth;}) - .attr('height', function(d) {return d.model.canvasHeight;}) - .style('width', function(d) {return (d.model.width + 2 * c.overdrag) + 'px';}) - .style('height', function(d) {return d.model.height + 'px';}) .style('opacity', function(d) {return d.pick ? 0.01 : 1;}); svg.style('background', 'rgba(255, 255, 255, 0)'); @@ -479,7 +450,7 @@ module.exports = function(root, svg, styledData, layout, callbacks) { parcoordsLineLayer .each(function(d) { - d.lineLayer = lineLayerMaker(this, d.model.lines, d.model.canvasWidth, d.model.canvasHeight, d.viewModel.dimensions, d.viewModel.panels, d.model.unitToColor, d.context, d.pick, c.scatter); + d.lineLayer = lineLayerMaker(this, d, c.scatter); d.viewModel[d.key] = d.lineLayer; tweakables.renderers.push(function() {d.lineLayer.render(d.viewModel.panels, true);}); d.lineLayer.render(d.viewModel.panels, !d.context); @@ -513,8 +484,8 @@ module.exports = function(root, svg, styledData, layout, callbacks) { .attr('transform', function(d) {return 'translate(' + d.xScale(d.xIndex) + ', 0)';}); d3.select(this).attr('transform', 'translate(' + d.x + ', 0)'); yAxis.each(function(dd, i, ii) {if(ii === d.parent.key) p.dimensions[i] = dd;}); - p.contextLineLayer && p.contextLineLayer.render(p.panels, false, !someFiltersActive(p)); - p.focusLineLayer.render && p.focusLineLayer.render(p.panels); + p.contextLayer && p.contextLayer.render(p.panels, false, !someFiltersActive(p)); + p.focusLayer.render && p.focusLayer.render(p.panels); }) .on('dragend', function(d) { var p = d.parent; @@ -529,9 +500,9 @@ module.exports = function(root, svg, styledData, layout, callbacks) { updatePanelLayout(yAxis, p); d3.select(this) .attr('transform', function(d) {return 'translate(' + d.x + ', 0)';}); - p.contextLineLayer && p.contextLineLayer.render(p.panels, false, !someFiltersActive(p)); - p.focusLineLayer && p.focusLineLayer.render(p.panels); - p.pickLineLayer && p.pickLineLayer.render(p.panels, true); + p.contextLayer && p.contextLayer.render(p.panels, false, !someFiltersActive(p)); + p.focusLayer && p.focusLayer.render(p.panels); + p.pickLayer && p.pickLayer.render(p.panels, true); linePickActive = true; if(callbacks && callbacks.axesMoved) { @@ -743,13 +714,13 @@ module.exports = function(root, svg, styledData, layout, callbacks) { var newExtent = reset ? [0, 1] : extent.slice(); if(newExtent[0] !== filter[0] || newExtent[1] !== filter[1]) { dimensions[dimension.xIndex].filter = newExtent; - p.focusLineLayer && p.focusLineLayer.render(p.panels, true); + p.focusLayer && p.focusLayer.render(p.panels, true); var filtersActive = someFiltersActive(p); if(!contextShown && filtersActive) { - p.contextLineLayer && p.contextLineLayer.render(p.panels, true); + p.contextLayer && p.contextLayer.render(p.panels, true); contextShown = true; } else if(contextShown && !filtersActive) { - p.contextLineLayer && p.contextLineLayer.render(p.panels, true, true); + p.contextLayer && p.contextLayer.render(p.panels, true, true); contextShown = false; } } @@ -770,9 +741,9 @@ module.exports = function(root, svg, styledData, layout, callbacks) { f[1] = Math.min(1, f[1] + 0.05); } d3.select(this).transition().duration(150).call(dimension.brush.extent(f)); - p.focusLineLayer.render(p.panels, true); + p.focusLayer.render(p.panels, true); } - p.pickLineLayer && p.pickLineLayer.render(p.panels, true); + p.pickLayer && p.pickLayer.render(p.panels, true); linePickActive = true; domainBrushing = 'ending'; if(callbacks && callbacks.filterChanged) { diff --git a/src/traces/parcoords/plot.js b/src/traces/parcoords/plot.js index 90cc3353846..8abee427202 100644 --- a/src/traces/parcoords/plot.js +++ b/src/traces/parcoords/plot.js @@ -13,8 +13,9 @@ var parcoords = require('./parcoords'); module.exports = function plot(gd, cdparcoords) { var fullLayout = gd._fullLayout; - var svg = fullLayout._paper; + var svg = fullLayout._toppaper; var root = fullLayout._paperdiv; + var container = fullLayout._glcontainer; var gdDimensions = {}; var gdDimensionsOriginalOrder = {}; @@ -98,6 +99,7 @@ module.exports = function plot(gd, cdparcoords) { parcoords( root, svg, + container, cdparcoords, { width: size.w, diff --git a/src/traces/pointcloud/index.js b/src/traces/pointcloud/index.js index b5cef7bdd2c..dd710caafad 100644 --- a/src/traces/pointcloud/index.js +++ b/src/traces/pointcloud/index.js @@ -20,7 +20,7 @@ pointcloud.plot = require('./convert'); pointcloud.moduleType = 'trace'; pointcloud.name = 'pointcloud'; pointcloud.basePlotModule = require('../../plots/gl2d'); -pointcloud.categories = ['gl2d', 'showLegend']; +pointcloud.categories = ['gl', 'gl2d', 'showLegend']; pointcloud.meta = { description: [ 'The data visualized as a point cloud set in `x` and `y`', diff --git a/src/traces/scattergl/index.js b/src/traces/scattergl/index.js index 35d292f1c90..6ad0666d16a 100644 --- a/src/traces/scattergl/index.js +++ b/src/traces/scattergl/index.js @@ -23,7 +23,7 @@ ScatterGl.selectPoints = require('./select'); ScatterGl.moduleType = 'trace'; ScatterGl.name = 'scattergl'; ScatterGl.basePlotModule = require('../../plots/gl2d'); -ScatterGl.categories = ['gl2d', 'symbols', 'errorBarsOK', 'markerColorscale', 'showLegend', 'scatter-like']; +ScatterGl.categories = ['gl', 'gl2d', 'symbols', 'errorBarsOK', 'markerColorscale', 'showLegend', 'scatter-like']; ScatterGl.meta = { description: [ 'The data visualized as scatter point or lines is set in `x` and `y`', diff --git a/tasks/util/strict_d3.js b/tasks/util/strict_d3.js index 1e51ab8912b..18b8ff25915 100644 --- a/tasks/util/strict_d3.js +++ b/tasks/util/strict_d3.js @@ -18,7 +18,7 @@ module.exports = transformTools.makeRequireTransform('requireTransform', var pathOut; if(pathIn === 'd3' && opts.file !== pathToStrictD3Module) { - pathOut = 'require(\'' + pathToStrictD3Module + '\')'; + pathOut = 'require(' + JSON.stringify(pathToStrictD3Module) + ')'; } if(pathOut) return cb(null, pathOut); diff --git a/test/image/baselines/gl2d_parcoords_2.png b/test/image/baselines/gl2d_parcoords_2.png index 4eebd736916..91d01c98f60 100644 Binary files a/test/image/baselines/gl2d_parcoords_2.png and b/test/image/baselines/gl2d_parcoords_2.png differ diff --git a/test/jasmine/tests/gl_plot_interact_test.js b/test/jasmine/tests/gl_plot_interact_test.js index 7e06a5de92f..39682498707 100644 --- a/test/jasmine/tests/gl_plot_interact_test.js +++ b/test/jasmine/tests/gl_plot_interact_test.js @@ -1286,7 +1286,7 @@ describe('Test gl plot side effects', function() { return Plotly.plot(gd, data); }).then(function() { - countCanvases(1); + countCanvases(3); return Plotly.purge(gd); }).then(function() { @@ -1294,7 +1294,7 @@ describe('Test gl plot side effects', function() { return Plotly.plot(gd, data); }).then(function() { - countCanvases(1); + countCanvases(3); return Plotly.deleteTraces(gd, [0]); }).then(function() {