From 2445406fc1c8616761392065f8f3e547fe7f7b3a Mon Sep 17 00:00:00 2001 From: Michael Huynh Date: Sun, 11 Oct 2020 16:42:20 +0800 Subject: [PATCH 1/5] Fix staticPlot behaviour for range slider and legend These changes ensure that when `staticPlot` is active: 1. Items inside a legend cannot be toggled 2. The range slider cannot be interacted with, and the grab handles for adjusting the slider box are hidden. Fixes #5177 --- src/components/legend/draw.js | 2 ++ src/components/rangeslider/draw.js | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/legend/draw.js b/src/components/legend/draw.js index 945067b5a40..6e2cab68a7f 100644 --- a/src/components/legend/draw.js +++ b/src/components/legend/draw.js @@ -460,6 +460,8 @@ function ensureLength(str, maxLength) { } function setupTraceToggle(g, gd) { + if(gd._context.staticPlot) return; + var doubleClickDelay = gd._context.doubleClickDelay; var newMouseDownTime; var numClicks = 1; diff --git a/src/components/rangeslider/draw.js b/src/components/rangeslider/draw.js index 584477e9721..54a5191c72e 100644 --- a/src/components/rangeslider/draw.js +++ b/src/components/rangeslider/draw.js @@ -232,6 +232,8 @@ module.exports = function(gd) { }; function setupDragElement(rangeSlider, gd, axisOpts, opts) { + if(gd._context.staticPlot) return; + var slideBox = rangeSlider.select('rect.' + constants.slideBoxClassName).node(); var grabAreaMin = rangeSlider.select('rect.' + constants.grabAreaMinClassName).node(); var grabAreaMax = rangeSlider.select('rect.' + constants.grabAreaMaxClassName).node(); @@ -590,6 +592,8 @@ function drawSlideBox(rangeSlider, gd, axisOpts, opts) { } function drawGrabbers(rangeSlider, gd, axisOpts, opts) { + if(gd._context.staticPlot) return; + // var grabberMin = Lib.ensureSingle(rangeSlider, 'g', constants.grabberMinClassName); var grabberMax = Lib.ensureSingle(rangeSlider, 'g', constants.grabberMaxClassName); @@ -619,8 +623,6 @@ function drawGrabbers(rangeSlider, gd, axisOpts, opts) { handleMax.attr(handleDynamicAttrs); // - if(gd._context.staticPlot) return; - var grabAreaFixAttrs = { width: constants.grabAreaWidth, x: 0, From 73d4606d2daacba0bd2f434f32dcd30723576707 Mon Sep 17 00:00:00 2001 From: Michael Huynh Date: Fri, 16 Oct 2020 08:19:30 +0800 Subject: [PATCH 2/5] Make range slider grabbers visible even with staticPlot enabled Fixes #5177 --- src/components/rangeslider/draw.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/rangeslider/draw.js b/src/components/rangeslider/draw.js index 54a5191c72e..e47f0474f97 100644 --- a/src/components/rangeslider/draw.js +++ b/src/components/rangeslider/draw.js @@ -592,8 +592,6 @@ function drawSlideBox(rangeSlider, gd, axisOpts, opts) { } function drawGrabbers(rangeSlider, gd, axisOpts, opts) { - if(gd._context.staticPlot) return; - // var grabberMin = Lib.ensureSingle(rangeSlider, 'g', constants.grabberMinClassName); var grabberMax = Lib.ensureSingle(rangeSlider, 'g', constants.grabberMaxClassName); @@ -628,7 +626,7 @@ function drawGrabbers(rangeSlider, gd, axisOpts, opts) { x: 0, y: 0, fill: constants.grabAreaFill, - cursor: constants.grabAreaCursor + cursor: !gd._context.staticPlot ? constants.grabAreaCursor : undefined, }; var grabAreaMin = Lib.ensureSingle(grabberMin, 'rect', constants.grabAreaMinClassName, function(s) { From 4c1cacb9e2d3d3f3cdd3af787b22e5a53ec78924 Mon Sep 17 00:00:00 2001 From: Michael Huynh Date: Fri, 16 Oct 2020 11:08:57 +0800 Subject: [PATCH 3/5] Adjust rendering of legend to resolve image baselines It appears the element marked with `legendtoggle` contributes visually, which means it should not be skipped over when rendering in order to preserve the existing tests for image baselines. Fixes #5177 --- src/components/legend/draw.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/components/legend/draw.js b/src/components/legend/draw.js index 6e2cab68a7f..b106ae7cb72 100644 --- a/src/components/legend/draw.js +++ b/src/components/legend/draw.js @@ -460,18 +460,19 @@ function ensureLength(str, maxLength) { } function setupTraceToggle(g, gd) { - if(gd._context.staticPlot) return; - var doubleClickDelay = gd._context.doubleClickDelay; var newMouseDownTime; var numClicks = 1; var traceToggle = Lib.ensureSingle(g, 'rect', 'legendtoggle', function(s) { - s.style('cursor', 'pointer') - .attr('pointer-events', 'all') - .call(Color.fill, 'rgba(0,0,0,0)'); + if(!gd._context.staticPlot) { + s.style('cursor', 'pointer').attr('pointer-events', 'all'); + } + s.call(Color.fill, 'rgba(0,0,0,0)'); }); + if(gd._context.staticPlot) return; + traceToggle.on('mousedown', function() { newMouseDownTime = (new Date()).getTime(); if(newMouseDownTime - gd._legendMouseDownTime < doubleClickDelay) { From 00a7054e130604bdca1637016bbcb86c769f32eb Mon Sep 17 00:00:00 2001 From: Michael Huynh Date: Sat, 17 Oct 2020 21:38:25 +0800 Subject: [PATCH 4/5] Add tests to cover staticPlot for legend and range slider These Jasmine tests should help ensure that neither the legend nor range slider can be interacted with if `staticPlot` is set. Fixes #5177 --- test/jasmine/tests/legend_test.js | 41 +++++++++++++++++++++++++ test/jasmine/tests/range_slider_test.js | 34 ++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/test/jasmine/tests/legend_test.js b/test/jasmine/tests/legend_test.js index 21f25626989..06de0f4643f 100644 --- a/test/jasmine/tests/legend_test.js +++ b/test/jasmine/tests/legend_test.js @@ -1289,6 +1289,47 @@ describe('legend interaction', function() { }); }); + describe('staticPlot', function() { + var gd; + + beforeEach(function() { + gd = createGraphDiv(); + }); + + afterEach(destroyGraphDiv); + + function toggleTrace() { + var toggle = d3.select('.legendtoggle').node(); + expect(toggle).not.toEqual(null); + + toggle.dispatchEvent(new MouseEvent('mousedown')); + toggle.dispatchEvent(new MouseEvent('mouseup')); + + // Delay needs to be long enough for Plotly to react + return delay(300)(); + } + + function assertToggled(toggled) { + return function() { + var container = d3.select('g.traces').node(); + expect(container).not.toEqual(null); + expect(container.style.opacity).toBe(toggled ? '0.5' : '1'); + }; + } + + it('should prevent toggling if set', function(done) { + var data = [{ x: [0, 1], y: [0, 1], type: 'scatter' }]; + var layout = { showlegend: true }; + var config = { staticPlot: true }; + + Plotly.newPlot(gd, data, layout, config) + .then(toggleTrace) + .then(assertToggled(false)) + .catch(failTest) + .then(done); + }); + }); + describe('visible toggle', function() { var gd; diff --git a/test/jasmine/tests/range_slider_test.js b/test/jasmine/tests/range_slider_test.js index a7232261480..467783d9dc6 100644 --- a/test/jasmine/tests/range_slider_test.js +++ b/test/jasmine/tests/range_slider_test.js @@ -201,6 +201,40 @@ describe('Visible rangesliders', function() { .then(done); }); + fit('should not react to any interactions when staticPlot is set', function(done) { + var mockCopy = Lib.extendDeep({}, mock); + var moveDelta = 50; + Plotly.newPlot(gd, mockCopy.data, mockCopy.layout, { staticPlot: true }) + .then(function() { + // Try move minimum handle + var minHandle = d3.select('.' + constants.grabberMinClassName).node(); + expect(minHandle).not.toEqual(null); + var minHandleRect = minHandle.getBoundingClientRect(); + var x = minHandleRect.x + minHandleRect.width / 2; + var y = minHandleRect.y + minHandleRect.height / 2; + return slide(x, y, x + moveDelta, y); + }) + .then(function() { + // Try move maximum handle + var maxHandle = d3.select('.' + constants.grabberMaxClassName).node(); + expect(maxHandle).not.toEqual(null); + var maxHandleRect = maxHandle.getBoundingClientRect(); + var x = maxHandleRect.x + maxHandleRect.width / 2; + var y = maxHandleRect.y + maxHandleRect.height / 2; + return slide(x, y, x - moveDelta, y); + }) + .then(function() { + // Slidebox should not exist + var slidebox = d3.select('.' + constants.slideBoxClassName).node(); + expect(slidebox).toEqual(null); + }) + .then(function() { + expect(gd.layout.xaxis.range).toBeCloseToArray([0, 49]); + }) + .catch(failTest) + .then(done); + }); + it('should update correctly when moving slider on an axis with rangebreaks', function(done) { var start = 250; var end = 300; From 256f4de9abb1058de9a90bbebcf97dc99b0c1ddd Mon Sep 17 00:00:00 2001 From: Michael Huynh Date: Sat, 17 Oct 2020 22:35:37 +0800 Subject: [PATCH 5/5] Remove constrained test execution for range slider Accidentally left the focused test in as part of writing it up. Fixes #5177 --- test/jasmine/tests/range_slider_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jasmine/tests/range_slider_test.js b/test/jasmine/tests/range_slider_test.js index 467783d9dc6..72ebcd18711 100644 --- a/test/jasmine/tests/range_slider_test.js +++ b/test/jasmine/tests/range_slider_test.js @@ -201,7 +201,7 @@ describe('Visible rangesliders', function() { .then(done); }); - fit('should not react to any interactions when staticPlot is set', function(done) { + it('should not react to any interactions when staticPlot is set', function(done) { var mockCopy = Lib.extendDeep({}, mock); var moveDelta = 50; Plotly.newPlot(gd, mockCopy.data, mockCopy.layout, { staticPlot: true })