From 117e39ca81045e9231de8bd7813123415ef76caa Mon Sep 17 00:00:00 2001 From: archmoj Date: Fri, 14 May 2021 15:01:27 -0400 Subject: [PATCH 01/11] organize modebar attributes and defaults and register it --- src/components/modebar/attributes.js | 41 ++++++++++++++++++++++++++++ src/components/modebar/defaults.js | 18 ++++++++++++ src/components/modebar/index.js | 10 ++++++- src/core.js | 3 +- src/plots/layout_attributes.js | 34 ----------------------- src/plots/plots.js | 10 +++---- 6 files changed, 74 insertions(+), 42 deletions(-) create mode 100644 src/components/modebar/attributes.js create mode 100644 src/components/modebar/defaults.js diff --git a/src/components/modebar/attributes.js b/src/components/modebar/attributes.js new file mode 100644 index 00000000000..c18bce1cad7 --- /dev/null +++ b/src/components/modebar/attributes.js @@ -0,0 +1,41 @@ +'use strict'; + +module.exports = { + editType: 'modebar', + + modebar: { + editType: 'modebar', + + orientation: { + valType: 'enumerated', + values: ['v', 'h'], + dflt: 'h', + editType: 'modebar', + description: 'Sets the orientation of the modebar.' + }, + bgcolor: { + valType: 'color', + editType: 'modebar', + description: 'Sets the background color of the modebar.' + }, + color: { + valType: 'color', + editType: 'modebar', + description: 'Sets the color of the icons in the modebar.' + }, + activecolor: { + valType: 'color', + editType: 'modebar', + description: 'Sets the color of the active or hovered on icons in the modebar.' + }, + uirevision: { + valType: 'any', + editType: 'none', + description: [ + 'Controls persistence of user-driven changes related to the modebar,', + 'including `hovermode`, `dragmode`, and `showspikes` at both the', + 'root level and inside subplots. Defaults to `layout.uirevision`.' + ].join(' ') + }, + } +}; diff --git a/src/components/modebar/defaults.js b/src/components/modebar/defaults.js new file mode 100644 index 00000000000..13f9a5827f6 --- /dev/null +++ b/src/components/modebar/defaults.js @@ -0,0 +1,18 @@ +'use strict'; + +var Lib = require('../../lib'); +var Color = require('../color'); +var attributes = require('./attributes'); + +module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) { + function coerce(attr, dflt) { + return Lib.coerce(layoutIn, layoutOut, attributes, attr, dflt); + } + + coerce('modebar.orientation'); + coerce('modebar.bgcolor', Color.addOpacity(layoutOut.paper_bgcolor, 0.5)); + var defaultColor = Color.contrast(Color.rgb(layoutOut.modebar.bgcolor)); + coerce('modebar.color', Color.addOpacity(defaultColor, 0.3)); + coerce('modebar.activecolor', Color.addOpacity(defaultColor, 0.7)); + coerce('modebar.uirevision', layoutOut.uirevision); +}; diff --git a/src/components/modebar/index.js b/src/components/modebar/index.js index 06a2d6dae7b..1bae66bdf3b 100644 --- a/src/components/modebar/index.js +++ b/src/components/modebar/index.js @@ -1,3 +1,11 @@ 'use strict'; -exports.manage = require('./manage'); +module.exports = { + moduleType: 'component', + name: 'modebar', + + layoutAttributes: require('./attributes'), + supplyLayoutDefaults: require('./defaults'), + + manage: require('./manage') +}; diff --git a/src/core.js b/src/core.js index 42419221789..d9ea5c74115 100644 --- a/src/core.js +++ b/src/core.js @@ -44,7 +44,8 @@ register([ require('./components/grid'), require('./components/errorbars'), require('./components/colorscale'), - require('./components/colorbar') + require('./components/colorbar'), + require('./components/modebar') ]); // locales en and en-US are required for default behavior diff --git a/src/plots/layout_attributes.js b/src/plots/layout_attributes.js index 545bac3845b..100503d9c21 100644 --- a/src/plots/layout_attributes.js +++ b/src/plots/layout_attributes.js @@ -388,40 +388,6 @@ module.exports = { 'make an item with matching `templateitemname` and `visible: false`.' ].join(' ') }, - modebar: { - orientation: { - valType: 'enumerated', - values: ['v', 'h'], - dflt: 'h', - editType: 'modebar', - description: 'Sets the orientation of the modebar.' - }, - bgcolor: { - valType: 'color', - editType: 'modebar', - description: 'Sets the background color of the modebar.' - }, - color: { - valType: 'color', - editType: 'modebar', - description: 'Sets the color of the icons in the modebar.' - }, - activecolor: { - valType: 'color', - editType: 'modebar', - description: 'Sets the color of the active or hovered on icons in the modebar.' - }, - uirevision: { - valType: 'any', - editType: 'none', - description: [ - 'Controls persistence of user-driven changes related to the modebar,', - 'including `hovermode`, `dragmode`, and `showspikes` at both the', - 'root level and inside subplots. Defaults to `layout.uirevision`.' - ].join(' ') - }, - editType: 'modebar' - }, newshape: drawNewShapeAttrs.newshape, activeshape: drawNewShapeAttrs.activeshape, diff --git a/src/plots/plots.js b/src/plots/plots.js index a3789026460..e350ccc75ef 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -1517,12 +1517,10 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut, formatObj) { coerce('editrevision', uirevision); coerce('selectionrevision', uirevision); - coerce('modebar.orientation'); - coerce('modebar.bgcolor', Color.addOpacity(layoutOut.paper_bgcolor, 0.5)); - var modebarDefaultColor = Color.contrast(Color.rgb(layoutOut.modebar.bgcolor)); - coerce('modebar.color', Color.addOpacity(modebarDefaultColor, 0.3)); - coerce('modebar.activecolor', Color.addOpacity(modebarDefaultColor, 0.7)); - coerce('modebar.uirevision', uirevision); + Registry.getComponentMethod( + 'modebar', + 'supplyLayoutDefaults' + )(layoutIn, layoutOut); Registry.getComponentMethod( 'shapes', From 154431f5d0290904516afd8960553f6a323630b9 Mon Sep 17 00:00:00 2001 From: archmoj Date: Fri, 14 May 2021 15:36:43 -0400 Subject: [PATCH 02/11] add buttonstoadd to layout.modebar --- src/components/modebar/attributes.js | 23 +++++++++++++++++++++++ src/components/modebar/defaults.js | 1 + src/components/modebar/manage.js | 3 ++- test/jasmine/tests/modebar_test.js | 1 + 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/components/modebar/attributes.js b/src/components/modebar/attributes.js index c18bce1cad7..6d50d0ce989 100644 --- a/src/components/modebar/attributes.js +++ b/src/components/modebar/attributes.js @@ -37,5 +37,28 @@ module.exports = { 'root level and inside subplots. Defaults to `layout.uirevision`.' ].join(' ') }, + buttonstoadd: { + valType: 'flaglist', + flags: [ + 'v1hovermode', + 'hoverclosest', + 'hovercompare', + 'togglehover', + 'togglespikelines', + 'drawclosedpath', + 'drawopenpath', + 'drawline', + 'drawrect', + 'drawcircle', + 'eraseshape', + ], + dflt: '', + editType: 'modebar', + description: [ + 'Determines which predefined modebar buttons to add.', + 'Please note that these buttons will only be shown if they are compatible', + 'with all trace types used in a graph.' + ].join(' ') + } } }; diff --git a/src/components/modebar/defaults.js b/src/components/modebar/defaults.js index 13f9a5827f6..5402f72076e 100644 --- a/src/components/modebar/defaults.js +++ b/src/components/modebar/defaults.js @@ -15,4 +15,5 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) { coerce('modebar.color', Color.addOpacity(defaultColor, 0.3)); coerce('modebar.activecolor', Color.addOpacity(defaultColor, 0.7)); coerce('modebar.uirevision', layoutOut.uirevision); + coerce('modebar.buttonstoadd'); }; diff --git a/src/components/modebar/manage.js b/src/components/modebar/manage.js index 1e4f9f8fc50..2a31106d53b 100644 --- a/src/components/modebar/manage.js +++ b/src/components/modebar/manage.js @@ -72,8 +72,9 @@ function getButtonGroups(gd) { var fullLayout = gd._fullLayout; var fullData = gd._fullData; var context = gd._context; + var layoutButtonsToAdd = fullLayout.modebar.buttonstoadd.split('+'); + var buttonsToAdd = context.modeBarButtonsToAdd.concat(layoutButtonsToAdd); var buttonsToRemove = context.modeBarButtonsToRemove; - var buttonsToAdd = context.modeBarButtonsToAdd; var hasCartesian = fullLayout._has('cartesian'); var hasGL3D = fullLayout._has('gl3d'); diff --git a/test/jasmine/tests/modebar_test.js b/test/jasmine/tests/modebar_test.js index 5c0457d602a..b1588acd80c 100644 --- a/test/jasmine/tests/modebar_test.js +++ b/test/jasmine/tests/modebar_test.js @@ -42,6 +42,7 @@ describe('ModeBar', function() { _has: Plots._hasPlotType, _subplots: {xaxis: xaxes || [], yaxis: yaxes || []}, modebar: { + buttonstoadd: '', orientation: 'h', bgcolor: 'rgba(255,255,255,0.7)', color: 'rgba(0, 31, 95, 0.3)', From dd842bd125c41b7f8807a330589b7f2781c6fab3 Mon Sep 17 00:00:00 2001 From: archmoj Date: Fri, 14 May 2021 16:37:22 -0400 Subject: [PATCH 03/11] add relayout jasmine tests to modebar --- test/jasmine/tests/modebar_test.js | 77 +++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/test/jasmine/tests/modebar_test.js b/test/jasmine/tests/modebar_test.js index b1588acd80c..59f195c8ae4 100644 --- a/test/jasmine/tests/modebar_test.js +++ b/test/jasmine/tests/modebar_test.js @@ -1435,7 +1435,7 @@ describe('ModeBar', function() { }); }); - describe('modebar styling', function() { + describe('modebar relayout', function() { var gd; var colors = ['rgba(128, 128, 128, 0.7)', 'rgba(255, 0, 128, 0.2)']; var targetBtn = 'pan2d'; @@ -1559,6 +1559,81 @@ describe('ModeBar', function() { }) .then(done, done.fail); }); + + it('add and remove predefined shape drawing and hover buttons via layout.modebar.buttonstoadd', function(done) { + function countButtons() { + var modeBarEl = gd._fullLayout._modeBar.element; + return d3Select(modeBarEl).selectAll('a.modebar-btn').size(); + } + + var initial = 10; + Plotly.newPlot(gd, [{y: [1, 2]}], {}) + .then(function() { + expect(countButtons()).toBe(initial); + + return Plotly.relayout(gd, 'modebar.buttonstoadd', [ + 'drawline', + 'drawopenpath', + 'drawclosedpath', + 'drawcircle', + 'drawrect', + 'eraseshape' + ].join('+')); + }) + .then(function() { + expect(countButtons()).toBe(initial + 6); + + return Plotly.relayout(gd, 'modebar.buttonstoadd', ''); + }) + .then(function() { + expect(countButtons()).toBe(initial); + + return Plotly.relayout(gd, 'modebar.buttonstoadd', [ + 'hovercompare', + 'hoverclosest', + 'togglespikelines' + ].join('+')); + }) + .then(function() { + expect(countButtons()).toBe(initial + 3); + + return Plotly.relayout(gd, 'modebar.buttonstoadd', ''); + }) + .then(function() { + expect(countButtons()).toBe(initial); + + return Plotly.relayout(gd, 'modebar.buttonstoadd', [ + 'v1hovermode', + 'togglespikelines' + ].join('+')); + }) + .then(function() { + expect(countButtons()).toBe(initial + 3); + + return Plotly.relayout(gd, 'modebar.buttonstoadd', [ + 'v1hovermode', + 'togglespikelines', + 'togglehover', + 'hovercompare', + 'hoverclosest', + 'eraseshape', + 'eraseshape', + 'eraseshape' + ].join('+')); + }) + .then(function() { + expect(countButtons()).toBe(initial + 4, 'skip duplicates'); + + return Plotly.relayout(gd, 'modebar.buttonstoadd', [ + 'drawline', + 'invalid' + ].join('+')); + }) + .then(function() { + expect(countButtons()).toBe(initial + 1, 'skip invalid'); + }) + .then(done, done.fail); + }); }); describe('modebar html', function() { From 3933b8888c01de83d7712f5fd0e0a999b00acfcd Mon Sep 17 00:00:00 2001 From: archmoj Date: Fri, 14 May 2021 17:06:29 -0400 Subject: [PATCH 04/11] fixup template defaults and modebar attributes --- src/components/modebar/attributes.js | 108 +++++++++++++-------------- src/components/modebar/defaults.js | 18 +++-- test/jasmine/tests/modebar_test.js | 12 ++- 3 files changed, 74 insertions(+), 64 deletions(-) diff --git a/src/components/modebar/attributes.js b/src/components/modebar/attributes.js index 6d50d0ce989..73bd848e337 100644 --- a/src/components/modebar/attributes.js +++ b/src/components/modebar/attributes.js @@ -3,62 +3,58 @@ module.exports = { editType: 'modebar', - modebar: { + orientation: { + valType: 'enumerated', + values: ['v', 'h'], + dflt: 'h', editType: 'modebar', - - orientation: { - valType: 'enumerated', - values: ['v', 'h'], - dflt: 'h', - editType: 'modebar', - description: 'Sets the orientation of the modebar.' - }, - bgcolor: { - valType: 'color', - editType: 'modebar', - description: 'Sets the background color of the modebar.' - }, - color: { - valType: 'color', - editType: 'modebar', - description: 'Sets the color of the icons in the modebar.' - }, - activecolor: { - valType: 'color', - editType: 'modebar', - description: 'Sets the color of the active or hovered on icons in the modebar.' - }, - uirevision: { - valType: 'any', - editType: 'none', - description: [ - 'Controls persistence of user-driven changes related to the modebar,', - 'including `hovermode`, `dragmode`, and `showspikes` at both the', - 'root level and inside subplots. Defaults to `layout.uirevision`.' - ].join(' ') - }, - buttonstoadd: { - valType: 'flaglist', - flags: [ - 'v1hovermode', - 'hoverclosest', - 'hovercompare', - 'togglehover', - 'togglespikelines', - 'drawclosedpath', - 'drawopenpath', - 'drawline', - 'drawrect', - 'drawcircle', - 'eraseshape', - ], - dflt: '', - editType: 'modebar', - description: [ - 'Determines which predefined modebar buttons to add.', - 'Please note that these buttons will only be shown if they are compatible', - 'with all trace types used in a graph.' - ].join(' ') - } + description: 'Sets the orientation of the modebar.' + }, + bgcolor: { + valType: 'color', + editType: 'modebar', + description: 'Sets the background color of the modebar.' + }, + color: { + valType: 'color', + editType: 'modebar', + description: 'Sets the color of the icons in the modebar.' + }, + activecolor: { + valType: 'color', + editType: 'modebar', + description: 'Sets the color of the active or hovered on icons in the modebar.' + }, + uirevision: { + valType: 'any', + editType: 'none', + description: [ + 'Controls persistence of user-driven changes related to the modebar,', + 'including `hovermode`, `dragmode`, and `showspikes` at both the', + 'root level and inside subplots. Defaults to `layout.uirevision`.' + ].join(' ') + }, + buttonstoadd: { + valType: 'flaglist', + flags: [ + 'v1hovermode', + 'hoverclosest', + 'hovercompare', + 'togglehover', + 'togglespikelines', + 'drawclosedpath', + 'drawopenpath', + 'drawline', + 'drawrect', + 'drawcircle', + 'eraseshape', + ], + dflt: '', + editType: 'modebar', + description: [ + 'Determines which predefined modebar buttons to add.', + 'Please note that these buttons will only be shown if they are compatible', + 'with all trace types used in a graph.' + ].join(' ') } }; diff --git a/src/components/modebar/defaults.js b/src/components/modebar/defaults.js index 5402f72076e..d96b8783a8a 100644 --- a/src/components/modebar/defaults.js +++ b/src/components/modebar/defaults.js @@ -2,18 +2,22 @@ var Lib = require('../../lib'); var Color = require('../color'); +var Template = require('../../plot_api/plot_template'); var attributes = require('./attributes'); module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) { + var containerIn = layoutIn.modebar || {}; + var containerOut = Template.newContainer(layoutOut, 'modebar'); + function coerce(attr, dflt) { - return Lib.coerce(layoutIn, layoutOut, attributes, attr, dflt); + return Lib.coerce(containerIn, containerOut, attributes, attr, dflt); } - coerce('modebar.orientation'); - coerce('modebar.bgcolor', Color.addOpacity(layoutOut.paper_bgcolor, 0.5)); + coerce('orientation'); + coerce('bgcolor', Color.addOpacity(layoutOut.paper_bgcolor, 0.5)); var defaultColor = Color.contrast(Color.rgb(layoutOut.modebar.bgcolor)); - coerce('modebar.color', Color.addOpacity(defaultColor, 0.3)); - coerce('modebar.activecolor', Color.addOpacity(defaultColor, 0.7)); - coerce('modebar.uirevision', layoutOut.uirevision); - coerce('modebar.buttonstoadd'); + coerce('color', Color.addOpacity(defaultColor, 0.3)); + coerce('activecolor', Color.addOpacity(defaultColor, 0.7)); + coerce('uirevision', layoutOut.uirevision); + coerce('buttonstoadd'); }; diff --git a/test/jasmine/tests/modebar_test.js b/test/jasmine/tests/modebar_test.js index 59f195c8ae4..5ca65194026 100644 --- a/test/jasmine/tests/modebar_test.js +++ b/test/jasmine/tests/modebar_test.js @@ -1560,7 +1560,7 @@ describe('ModeBar', function() { .then(done, done.fail); }); - it('add and remove predefined shape drawing and hover buttons via layout.modebar.buttonstoadd', function(done) { + it('add and remove predefined shape drawing and hover buttons via layout.modebar.buttonstoadd and template', function(done) { function countButtons() { var modeBarEl = gd._fullLayout._modeBar.element; return d3Select(modeBarEl).selectAll('a.modebar-btn').size(); @@ -1631,6 +1631,16 @@ describe('ModeBar', function() { }) .then(function() { expect(countButtons()).toBe(initial + 1, 'skip invalid'); + + return Plotly.relayout(gd, 'modebar.buttonstoadd', ''); + }) + .then(function() { + expect(countButtons()).toBe(initial); + + return Plotly.relayout(gd, 'template.layout.modebar.buttonstoadd', 'v1hovermode'); + }) + .then(function() { + expect(countButtons()).toBe(initial + 2, 'via template'); }) .then(done, done.fail); }); From aeb1626cecc37d752a3da8fea4dbdc9242e85db7 Mon Sep 17 00:00:00 2001 From: archmoj Date: Fri, 14 May 2021 18:23:06 -0400 Subject: [PATCH 05/11] rename modebar.buttonstoadd to modebar.add --- src/components/modebar/attributes.js | 2 +- src/components/modebar/defaults.js | 2 +- src/components/modebar/manage.js | 2 +- test/jasmine/tests/modebar_test.js | 22 +++++++++++----------- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/components/modebar/attributes.js b/src/components/modebar/attributes.js index 73bd848e337..196b124e4e2 100644 --- a/src/components/modebar/attributes.js +++ b/src/components/modebar/attributes.js @@ -34,7 +34,7 @@ module.exports = { 'root level and inside subplots. Defaults to `layout.uirevision`.' ].join(' ') }, - buttonstoadd: { + add: { valType: 'flaglist', flags: [ 'v1hovermode', diff --git a/src/components/modebar/defaults.js b/src/components/modebar/defaults.js index d96b8783a8a..35b5352d191 100644 --- a/src/components/modebar/defaults.js +++ b/src/components/modebar/defaults.js @@ -19,5 +19,5 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) { coerce('color', Color.addOpacity(defaultColor, 0.3)); coerce('activecolor', Color.addOpacity(defaultColor, 0.7)); coerce('uirevision', layoutOut.uirevision); - coerce('buttonstoadd'); + coerce('add'); }; diff --git a/src/components/modebar/manage.js b/src/components/modebar/manage.js index 2a31106d53b..1c36beb6ae9 100644 --- a/src/components/modebar/manage.js +++ b/src/components/modebar/manage.js @@ -72,7 +72,7 @@ function getButtonGroups(gd) { var fullLayout = gd._fullLayout; var fullData = gd._fullData; var context = gd._context; - var layoutButtonsToAdd = fullLayout.modebar.buttonstoadd.split('+'); + var layoutButtonsToAdd = fullLayout.modebar.add.split('+'); var buttonsToAdd = context.modeBarButtonsToAdd.concat(layoutButtonsToAdd); var buttonsToRemove = context.modeBarButtonsToRemove; diff --git a/test/jasmine/tests/modebar_test.js b/test/jasmine/tests/modebar_test.js index 5ca65194026..ff29c8aab4a 100644 --- a/test/jasmine/tests/modebar_test.js +++ b/test/jasmine/tests/modebar_test.js @@ -42,7 +42,7 @@ describe('ModeBar', function() { _has: Plots._hasPlotType, _subplots: {xaxis: xaxes || [], yaxis: yaxes || []}, modebar: { - buttonstoadd: '', + add: '', orientation: 'h', bgcolor: 'rgba(255,255,255,0.7)', color: 'rgba(0, 31, 95, 0.3)', @@ -1560,7 +1560,7 @@ describe('ModeBar', function() { .then(done, done.fail); }); - it('add and remove predefined shape drawing and hover buttons via layout.modebar.buttonstoadd and template', function(done) { + it('add and remove predefined shape drawing and hover buttons via layout.modebar.add and template', function(done) { function countButtons() { var modeBarEl = gd._fullLayout._modeBar.element; return d3Select(modeBarEl).selectAll('a.modebar-btn').size(); @@ -1571,7 +1571,7 @@ describe('ModeBar', function() { .then(function() { expect(countButtons()).toBe(initial); - return Plotly.relayout(gd, 'modebar.buttonstoadd', [ + return Plotly.relayout(gd, 'modebar.add', [ 'drawline', 'drawopenpath', 'drawclosedpath', @@ -1583,12 +1583,12 @@ describe('ModeBar', function() { .then(function() { expect(countButtons()).toBe(initial + 6); - return Plotly.relayout(gd, 'modebar.buttonstoadd', ''); + return Plotly.relayout(gd, 'modebar.add', ''); }) .then(function() { expect(countButtons()).toBe(initial); - return Plotly.relayout(gd, 'modebar.buttonstoadd', [ + return Plotly.relayout(gd, 'modebar.add', [ 'hovercompare', 'hoverclosest', 'togglespikelines' @@ -1597,12 +1597,12 @@ describe('ModeBar', function() { .then(function() { expect(countButtons()).toBe(initial + 3); - return Plotly.relayout(gd, 'modebar.buttonstoadd', ''); + return Plotly.relayout(gd, 'modebar.add', ''); }) .then(function() { expect(countButtons()).toBe(initial); - return Plotly.relayout(gd, 'modebar.buttonstoadd', [ + return Plotly.relayout(gd, 'modebar.add', [ 'v1hovermode', 'togglespikelines' ].join('+')); @@ -1610,7 +1610,7 @@ describe('ModeBar', function() { .then(function() { expect(countButtons()).toBe(initial + 3); - return Plotly.relayout(gd, 'modebar.buttonstoadd', [ + return Plotly.relayout(gd, 'modebar.add', [ 'v1hovermode', 'togglespikelines', 'togglehover', @@ -1624,7 +1624,7 @@ describe('ModeBar', function() { .then(function() { expect(countButtons()).toBe(initial + 4, 'skip duplicates'); - return Plotly.relayout(gd, 'modebar.buttonstoadd', [ + return Plotly.relayout(gd, 'modebar.add', [ 'drawline', 'invalid' ].join('+')); @@ -1632,12 +1632,12 @@ describe('ModeBar', function() { .then(function() { expect(countButtons()).toBe(initial + 1, 'skip invalid'); - return Plotly.relayout(gd, 'modebar.buttonstoadd', ''); + return Plotly.relayout(gd, 'modebar.add', ''); }) .then(function() { expect(countButtons()).toBe(initial); - return Plotly.relayout(gd, 'template.layout.modebar.buttonstoadd', 'v1hovermode'); + return Plotly.relayout(gd, 'template.layout.modebar.add', 'v1hovermode'); }) .then(function() { expect(countButtons()).toBe(initial + 2, 'via template'); From 20567731f722358a5ed734ddf62c47a9562da835 Mon Sep 17 00:00:00 2001 From: archmoj Date: Fri, 14 May 2021 23:22:47 -0400 Subject: [PATCH 06/11] implement modebar.remove & improve config.modeBarButtonsToRemove to use exact and short names --- src/components/modebar/attributes.js | 59 +++++++++++++++----- src/components/modebar/buttons.js | 24 ++++++++ src/components/modebar/defaults.js | 1 + src/components/modebar/manage.js | 24 ++++++-- test/jasmine/tests/modebar_test.js | 83 +++++++++++++++++++++++++++- 5 files changed, 168 insertions(+), 23 deletions(-) diff --git a/src/components/modebar/attributes.js b/src/components/modebar/attributes.js index 196b124e4e2..911dadf164b 100644 --- a/src/components/modebar/attributes.js +++ b/src/components/modebar/attributes.js @@ -1,5 +1,35 @@ 'use strict'; +var modeBarButtons = require('./buttons'); +var buttonList = Object.keys(modeBarButtons); +var backButtons = [ + 'v1hovermode', + 'hoverclosest', + 'hovercompare', + 'togglehover', + 'togglespikelines', + 'drawclosedpath', + 'drawopenpath', + 'drawline', + 'drawrect', + 'drawcircle', + 'eraseshape', +]; + +var foreButtons = []; +var addToForeButtons = function(b) { + if(backButtons.indexOf(b._cat || b.name) !== -1) return; + // for convenience add lowercase shotname e.g. zoomin as well fullname zoomInGeo + var name = b.name; + var _cat = (b._cat || b.name).toLowerCase(); + if(foreButtons.indexOf(name) === -1) foreButtons.push(name); + if(foreButtons.indexOf(_cat) === -1) foreButtons.push(_cat); +}; +buttonList.forEach(function(k) { + addToForeButtons(modeBarButtons[k]); +}); +foreButtons.sort(); + module.exports = { editType: 'modebar', @@ -36,25 +66,24 @@ module.exports = { }, add: { valType: 'flaglist', - flags: [ - 'v1hovermode', - 'hoverclosest', - 'hovercompare', - 'togglehover', - 'togglespikelines', - 'drawclosedpath', - 'drawopenpath', - 'drawline', - 'drawrect', - 'drawcircle', - 'eraseshape', - ], + flags: backButtons, dflt: '', editType: 'modebar', description: [ 'Determines which predefined modebar buttons to add.', - 'Please note that these buttons will only be shown if they are compatible', - 'with all trace types used in a graph.' + 'Please note that these buttons will only be shown if they are', + 'compatible with all trace types used in a graph.', + 'Similar to `config.modeBarButtonsToAdd` option' + ].join(' ') + }, + remove: { + valType: 'flaglist', + flags: foreButtons, + dflt: '', + editType: 'modebar', + description: [ + 'Determines which predefined modebar buttons to remove.', + 'Similar to `config.modeBarButtonsToRemove` option' ].join(' ') } }; diff --git a/src/components/modebar/buttons.js b/src/components/modebar/buttons.js index 6558abe05c5..3428489b25b 100644 --- a/src/components/modebar/buttons.js +++ b/src/components/modebar/buttons.js @@ -92,6 +92,7 @@ modeBarButtons.editInChartStudio = { modeBarButtons.zoom2d = { name: 'zoom2d', + _cat: 'zoom', title: function(gd) { return _(gd, 'Zoom'); }, attr: 'dragmode', val: 'zoom', @@ -101,6 +102,7 @@ modeBarButtons.zoom2d = { modeBarButtons.pan2d = { name: 'pan2d', + _cat: 'pan', title: function(gd) { return _(gd, 'Pan'); }, attr: 'dragmode', val: 'pan', @@ -110,6 +112,7 @@ modeBarButtons.pan2d = { modeBarButtons.select2d = { name: 'select2d', + _cat: 'select', title: function(gd) { return _(gd, 'Box Select'); }, attr: 'dragmode', val: 'select', @@ -119,6 +122,7 @@ modeBarButtons.select2d = { modeBarButtons.lasso2d = { name: 'lasso2d', + _cat: 'lasso', title: function(gd) { return _(gd, 'Lasso Select'); }, attr: 'dragmode', val: 'lasso', @@ -180,6 +184,7 @@ modeBarButtons.eraseshape = { modeBarButtons.zoomIn2d = { name: 'zoomIn2d', + _cat: 'zoomin', title: function(gd) { return _(gd, 'Zoom in'); }, attr: 'zoom', val: 'in', @@ -189,6 +194,7 @@ modeBarButtons.zoomIn2d = { modeBarButtons.zoomOut2d = { name: 'zoomOut2d', + _cat: 'zoomout', title: function(gd) { return _(gd, 'Zoom out'); }, attr: 'zoom', val: 'out', @@ -198,6 +204,7 @@ modeBarButtons.zoomOut2d = { modeBarButtons.autoScale2d = { name: 'autoScale2d', + _cat: 'autoscale', title: function(gd) { return _(gd, 'Autoscale'); }, attr: 'zoom', val: 'auto', @@ -207,6 +214,7 @@ modeBarButtons.autoScale2d = { modeBarButtons.resetScale2d = { name: 'resetScale2d', + _cat: 'resetscale', title: function(gd) { return _(gd, 'Reset axes'); }, attr: 'zoom', val: 'reset', @@ -216,6 +224,7 @@ modeBarButtons.resetScale2d = { modeBarButtons.hoverClosestCartesian = { name: 'hoverClosestCartesian', + _cat: 'hoverclosest', title: function(gd) { return _(gd, 'Show closest data on hover'); }, attr: 'hovermode', val: 'closest', @@ -226,6 +235,7 @@ modeBarButtons.hoverClosestCartesian = { modeBarButtons.hoverCompareCartesian = { name: 'hoverCompareCartesian', + _cat: 'hoverCompare', title: function(gd) { return _(gd, 'Compare data on hover'); }, attr: 'hovermode', val: function(gd) { @@ -309,6 +319,7 @@ function handleCartesian(gd, ev) { modeBarButtons.zoom3d = { name: 'zoom3d', + _cat: 'zoom', title: function(gd) { return _(gd, 'Zoom'); }, attr: 'scene.dragmode', val: 'zoom', @@ -318,6 +329,7 @@ modeBarButtons.zoom3d = { modeBarButtons.pan3d = { name: 'pan3d', + _cat: 'pan', title: function(gd) { return _(gd, 'Pan'); }, attr: 'scene.dragmode', val: 'pan', @@ -365,6 +377,7 @@ function handleDrag3d(gd, ev) { modeBarButtons.resetCameraDefault3d = { name: 'resetCameraDefault3d', + _cat: 'resetCameraDefault', title: function(gd) { return _(gd, 'Reset camera to default'); }, attr: 'resetDefault', icon: Icons.home, @@ -373,6 +386,7 @@ modeBarButtons.resetCameraDefault3d = { modeBarButtons.resetCameraLastSave3d = { name: 'resetCameraLastSave3d', + _cat: 'resetCameraLastSave', title: function(gd) { return _(gd, 'Reset camera to last save'); }, attr: 'resetLastSave', icon: Icons.movie, @@ -422,6 +436,7 @@ function handleCamera3d(gd, ev) { modeBarButtons.hoverClosest3d = { name: 'hoverClosest3d', + _cat: 'hoverclosest', title: function(gd) { return _(gd, 'Toggle show closest data on hover'); }, attr: 'hovermode', val: null, @@ -476,6 +491,7 @@ function handleHover3d(gd, ev) { modeBarButtons.zoomInGeo = { name: 'zoomInGeo', + _cat: 'zoomin', title: function(gd) { return _(gd, 'Zoom in'); }, attr: 'zoom', val: 'in', @@ -485,6 +501,7 @@ modeBarButtons.zoomInGeo = { modeBarButtons.zoomOutGeo = { name: 'zoomOutGeo', + _cat: 'zoomout', title: function(gd) { return _(gd, 'Zoom out'); }, attr: 'zoom', val: 'out', @@ -494,6 +511,7 @@ modeBarButtons.zoomOutGeo = { modeBarButtons.resetGeo = { name: 'resetGeo', + _cat: 'reset', title: function(gd) { return _(gd, 'Reset'); }, attr: 'reset', val: null, @@ -503,6 +521,7 @@ modeBarButtons.resetGeo = { modeBarButtons.hoverClosestGeo = { name: 'hoverClosestGeo', + _cat: 'hoverclosest', title: function(gd) { return _(gd, 'Toggle show closest data on hover'); }, attr: 'hovermode', val: null, @@ -538,6 +557,7 @@ function handleGeo(gd, ev) { modeBarButtons.hoverClosestGl2d = { name: 'hoverClosestGl2d', + _cat: 'hoverclosest', title: function(gd) { return _(gd, 'Toggle show closest data on hover'); }, attr: 'hovermode', val: null, @@ -549,6 +569,7 @@ modeBarButtons.hoverClosestGl2d = { modeBarButtons.hoverClosestPie = { name: 'hoverClosestPie', + _cat: 'hoverclosest', title: function(gd) { return _(gd, 'Toggle show closest data on hover'); }, attr: 'hovermode', val: 'closest', @@ -661,6 +682,7 @@ function setSpikelineVisibility(gd) { modeBarButtons.resetViewMapbox = { name: 'resetViewMapbox', + _cat: 'resetView', title: function(gd) { return _(gd, 'Reset view'); }, attr: 'reset', icon: Icons.home, @@ -671,6 +693,7 @@ modeBarButtons.resetViewMapbox = { modeBarButtons.zoomInMapbox = { name: 'zoomInMapbox', + _cat: 'zoomin', title: function(gd) { return _(gd, 'Zoom in'); }, attr: 'zoom', val: 'in', @@ -680,6 +703,7 @@ modeBarButtons.zoomInMapbox = { modeBarButtons.zoomOutMapbox = { name: 'zoomOutMapbox', + _cat: 'zoomout', title: function(gd) { return _(gd, 'Zoom out'); }, attr: 'zoom', val: 'out', diff --git a/src/components/modebar/defaults.js b/src/components/modebar/defaults.js index 35b5352d191..a9930fa3fb6 100644 --- a/src/components/modebar/defaults.js +++ b/src/components/modebar/defaults.js @@ -20,4 +20,5 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) { coerce('activecolor', Color.addOpacity(defaultColor, 0.7)); coerce('uirevision', layoutOut.uirevision); coerce('add'); + coerce('remove'); }; diff --git a/src/components/modebar/manage.js b/src/components/modebar/manage.js index 1c36beb6ae9..84c87d672fa 100644 --- a/src/components/modebar/manage.js +++ b/src/components/modebar/manage.js @@ -72,9 +72,10 @@ function getButtonGroups(gd) { var fullLayout = gd._fullLayout; var fullData = gd._fullData; var context = gd._context; - var layoutButtonsToAdd = fullLayout.modebar.add.split('+'); - var buttonsToAdd = context.modeBarButtonsToAdd.concat(layoutButtonsToAdd); - var buttonsToRemove = context.modeBarButtonsToRemove; + var buttonsToAdd = context.modeBarButtonsToAdd + .concat(fullLayout.modebar.add.split('+')); + var buttonsToRemove = context.modeBarButtonsToRemove + .concat(fullLayout.modebar.remove.split('+')); var hasCartesian = fullLayout._has('cartesian'); var hasGL3D = fullLayout._has('gl3d'); @@ -97,9 +98,20 @@ function getButtonGroups(gd) { var out = []; for(var i = 0; i < newGroup.length; i++) { - var button = newGroup[i]; - if(buttonsToRemove.indexOf(button) !== -1) continue; - out.push(modeBarButtons[button]); + var name = newGroup[i]; + var B = modeBarButtons[name]; + var v0 = B.name.toLowerCase(); + var v1 = (B._cat || B.name).toLowerCase(); + var found = false; + for(var q = 0; q < buttonsToRemove.length; q++) { + var t = buttonsToRemove[q].toLowerCase(); + if(t === v0 || t === v1) { + found = true; + break; + } + } + if(found) continue; + out.push(modeBarButtons[name]); } groups.push(out); diff --git a/test/jasmine/tests/modebar_test.js b/test/jasmine/tests/modebar_test.js index ff29c8aab4a..ae3f871f0bc 100644 --- a/test/jasmine/tests/modebar_test.js +++ b/test/jasmine/tests/modebar_test.js @@ -43,6 +43,7 @@ describe('ModeBar', function() { _subplots: {xaxis: xaxes || [], yaxis: yaxes || []}, modebar: { add: '', + remove: '', orientation: 'h', bgcolor: 'rgba(255,255,255,0.7)', color: 'rgba(0, 31, 95, 0.3)', @@ -851,7 +852,7 @@ describe('ModeBar', function() { expect(countButtons(gd._fullLayout._modeBar)).toEqual(6); }); - it('updates mode bar buttons if modeBarButtonsToRemove changes', function() { + it('updates mode bar buttons if modeBarButtonsToRemove changes (exact camel case)', function() { var gd = setupGraphInfo(); manageModeBar(gd); var initialButtonCount = countButtons(gd._fullLayout._modeBar); @@ -863,6 +864,18 @@ describe('ModeBar', function() { .toEqual(initialButtonCount - 2); }); + it('updates mode bar buttons if modeBarButtonsToRemove changes (lowercase and short names)', function() { + var gd = setupGraphInfo(); + manageModeBar(gd); + var initialButtonCount = countButtons(gd._fullLayout._modeBar); + + gd._context.modeBarButtonsToRemove = ['toimage', 'zoom']; + manageModeBar(gd); + + expect(countButtons(gd._fullLayout._modeBar)) + .toEqual(initialButtonCount - 2); + }); + it('updates mode bar buttons if modeBarButtonsToAdd changes', function() { var gd = setupGraphInfo(); manageModeBar(gd); @@ -1560,7 +1573,7 @@ describe('ModeBar', function() { .then(done, done.fail); }); - it('add and remove predefined shape drawing and hover buttons via layout.modebar.add and template', function(done) { + it('add predefined shape drawing and hover buttons via layout.modebar.add and template', function(done) { function countButtons() { var modeBarEl = gd._fullLayout._modeBar.element; return d3Select(modeBarEl).selectAll('a.modebar-btn').size(); @@ -1644,6 +1657,72 @@ describe('ModeBar', function() { }) .then(done, done.fail); }); + + it('remove buttons using exact (camel case) and short (lower case) names via layout.modebar.remove and template', function(done) { + function countButtons() { + var modeBarEl = gd._fullLayout._modeBar.element; + return d3Select(modeBarEl).selectAll('a.modebar-btn').size(); + } + + var initial = 10; + Plotly.newPlot(gd, [{y: [1, 2]}], {}) + .then(function() { + expect(countButtons()).toBe(initial); + + return Plotly.relayout(gd, 'modebar.remove', [ + 'zoom', + 'zoomin', + 'zoomout', + 'pan', + 'select', + 'lasso', + 'autoscale', + 'resetscale', + 'toimage', + ].join('+')); + }) + .then(function() { + expect(countButtons()).toBe(initial - 9); + + return Plotly.relayout(gd, 'modebar.remove', ''); + }) + .then(function() { + expect(countButtons()).toBe(initial); + + return Plotly.relayout(gd, 'modebar.remove', [ + 'zoom2d', + 'zoomIn2d', + 'zoomOut2d', + 'pan2d', + 'select2d', + 'lasso2d', + 'autoScale2d', + 'resetScale2d', + 'toImage', + ].join('+')); + }) + .then(function() { + expect(countButtons()).toBe(initial - 9); + + return Plotly.relayout(gd, 'modebar.remove', ''); + }) + .then(function() { + expect(countButtons()).toBe(initial); + + return Plotly.relayout(gd, 'template.layout.modebar.remove', [ + 'zoom', + 'zoomin', + 'zoomout', + 'pan', + 'select', + 'lasso', + 'autoscale', + 'resetscale', + 'toimage', + ].join('+')); + }) + .then(done, done.fail); + }); }); describe('modebar html', function() { From bf3416d64137d528e32022efb3d464a2355d0793 Mon Sep 17 00:00:00 2001 From: archmoj Date: Fri, 14 May 2021 23:37:28 -0400 Subject: [PATCH 07/11] complete remove test --- test/jasmine/tests/modebar_test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/jasmine/tests/modebar_test.js b/test/jasmine/tests/modebar_test.js index ae3f871f0bc..c600fa8d5e4 100644 --- a/test/jasmine/tests/modebar_test.js +++ b/test/jasmine/tests/modebar_test.js @@ -1721,6 +1721,9 @@ describe('ModeBar', function() { 'toimage', ].join('+')); }) + .then(function() { + expect(countButtons()).toBe(initial - 9); + }) .then(done, done.fail); }); }); From 3daa2f3ddb9a4d5cd2a9f6b054f59f8206a929db Mon Sep 17 00:00:00 2001 From: archmoj Date: Mon, 17 May 2021 19:17:46 -0400 Subject: [PATCH 08/11] filter layout additions if removed by config and vice versa --- src/components/modebar/manage.js | 31 ++++++++++++++++++++--- test/jasmine/tests/modebar_test.js | 40 ++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/components/modebar/manage.js b/src/components/modebar/manage.js index 84c87d672fa..2b38ee5fdfb 100644 --- a/src/components/modebar/manage.js +++ b/src/components/modebar/manage.js @@ -72,10 +72,33 @@ function getButtonGroups(gd) { var fullLayout = gd._fullLayout; var fullData = gd._fullData; var context = gd._context; - var buttonsToAdd = context.modeBarButtonsToAdd - .concat(fullLayout.modebar.add.split('+')); - var buttonsToRemove = context.modeBarButtonsToRemove - .concat(fullLayout.modebar.remove.split('+')); + + function match(name, B) { + if(typeof B === 'string') { + if(B === name) return true; + } else { + if(B.name === name || B._cat === name) return true; + } + return false; + } + + var buttonsToAdd = context.modeBarButtonsToAdd.concat( + fullLayout.modebar.add.split('+').filter(function(e) { + for(var i = 0; i < context.modeBarButtonsToRemove.length; i++) { + if(match(e, context.modeBarButtonsToRemove[i])) return false; + } + return true; + }) + ); + + var buttonsToRemove = context.modeBarButtonsToRemove.concat( + fullLayout.modebar.remove.split('+').filter(function(e) { + for(var i = 0; i < context.modeBarButtonsToAdd.length; i++) { + if(match(e, context.modeBarButtonsToAdd[i])) return false; + } + return true; + }) + ); var hasCartesian = fullLayout._has('cartesian'); var hasGL3D = fullLayout._has('gl3d'); diff --git a/test/jasmine/tests/modebar_test.js b/test/jasmine/tests/modebar_test.js index c600fa8d5e4..a16f3be9391 100644 --- a/test/jasmine/tests/modebar_test.js +++ b/test/jasmine/tests/modebar_test.js @@ -1726,6 +1726,46 @@ describe('ModeBar', function() { }) .then(done, done.fail); }); + + it('add button if removed by layout and added by config', function(done) { + function countButtons() { + var modeBarEl = gd._fullLayout._modeBar.element; + return d3Select(modeBarEl).selectAll('a.modebar-btn').size(); + } + + var initial = 10; + Plotly.newPlot(gd, [{y: [1, 2]}], { + modebar: { + remove: 'zoom' + } + }, { + modeBarButtonsToAdd: ['zoom'] + }) + .then(function() { + expect(countButtons()).toBe(initial); + }) + .then(done, done.fail); + }); + + it('remove button if added by layout and removed by config', function(done) { + function countButtons() { + var modeBarEl = gd._fullLayout._modeBar.element; + return d3Select(modeBarEl).selectAll('a.modebar-btn').size(); + } + + var initial = 10; + Plotly.newPlot(gd, [{y: [1, 2]}], { + modebar: { + add: 'drawline' + } + }, { + modeBarButtonsToRemove: ['drawline'] + }) + .then(function() { + expect(countButtons()).toBe(initial); + }) + .then(done, done.fail); + }); }); describe('modebar html', function() { From 096674c5288156da116168e1dc10229c7dae2b16 Mon Sep 17 00:00:00 2001 From: archmoj Date: Mon, 17 May 2021 19:55:03 -0400 Subject: [PATCH 09/11] match lowercase and improve test --- src/components/modebar/manage.js | 7 ++++-- test/jasmine/tests/modebar_test.js | 36 ++++++++++++++++-------------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/components/modebar/manage.js b/src/components/modebar/manage.js index 2b38ee5fdfb..84d4ce370f8 100644 --- a/src/components/modebar/manage.js +++ b/src/components/modebar/manage.js @@ -75,9 +75,12 @@ function getButtonGroups(gd) { function match(name, B) { if(typeof B === 'string') { - if(B === name) return true; + if(B.toLowerCase() === name.toLowerCase()) return true; } else { - if(B.name === name || B._cat === name) return true; + var v0 = B.name; + var v1 = (B._cat || B.name); + + if(v0 === name || v1 === name.toLowerCase()) return true; } return false; } diff --git a/test/jasmine/tests/modebar_test.js b/test/jasmine/tests/modebar_test.js index a16f3be9391..2ae90017bb3 100644 --- a/test/jasmine/tests/modebar_test.js +++ b/test/jasmine/tests/modebar_test.js @@ -1727,24 +1727,26 @@ describe('ModeBar', function() { .then(done, done.fail); }); - it('add button if removed by layout and added by config', function(done) { - function countButtons() { - var modeBarEl = gd._fullLayout._modeBar.element; - return d3Select(modeBarEl).selectAll('a.modebar-btn').size(); - } - - var initial = 10; - Plotly.newPlot(gd, [{y: [1, 2]}], { - modebar: { - remove: 'zoom' + ['zoom', 'zoomin', 'zoomOut'].forEach(function(t) { + it('add ' + t + ' button if removed by layout and added by config', function(done) { + function countButtons() { + var modeBarEl = gd._fullLayout._modeBar.element; + return d3Select(modeBarEl).selectAll('a.modebar-btn').size(); } - }, { - modeBarButtonsToAdd: ['zoom'] - }) - .then(function() { - expect(countButtons()).toBe(initial); - }) - .then(done, done.fail); + + var initial = 10; + Plotly.newPlot(gd, [{y: [1, 2]}], { + modebar: { + remove: t + } + }, { + modeBarButtonsToAdd: [t] + }) + .then(function() { + expect(countButtons()).toBe(initial); + }) + .then(done, done.fail); + }); }); it('remove button if added by layout and removed by config', function(done) { From 5c17d6b0899ee22d1af7c634108cabc3aee4dfdd Mon Sep 17 00:00:00 2001 From: archmoj Date: Mon, 17 May 2021 21:01:06 -0400 Subject: [PATCH 10/11] switch from flaglist to arrayOk string --- src/components/modebar/attributes.js | 38 ++----------- src/components/modebar/manage.js | 52 +++++++++++++---- test/jasmine/tests/modebar_test.js | 85 ++++++++++++++++++---------- 3 files changed, 101 insertions(+), 74 deletions(-) diff --git a/src/components/modebar/attributes.js b/src/components/modebar/attributes.js index 911dadf164b..75d9a8ba6e0 100644 --- a/src/components/modebar/attributes.js +++ b/src/components/modebar/attributes.js @@ -1,35 +1,5 @@ 'use strict'; -var modeBarButtons = require('./buttons'); -var buttonList = Object.keys(modeBarButtons); -var backButtons = [ - 'v1hovermode', - 'hoverclosest', - 'hovercompare', - 'togglehover', - 'togglespikelines', - 'drawclosedpath', - 'drawopenpath', - 'drawline', - 'drawrect', - 'drawcircle', - 'eraseshape', -]; - -var foreButtons = []; -var addToForeButtons = function(b) { - if(backButtons.indexOf(b._cat || b.name) !== -1) return; - // for convenience add lowercase shotname e.g. zoomin as well fullname zoomInGeo - var name = b.name; - var _cat = (b._cat || b.name).toLowerCase(); - if(foreButtons.indexOf(name) === -1) foreButtons.push(name); - if(foreButtons.indexOf(_cat) === -1) foreButtons.push(_cat); -}; -buttonList.forEach(function(k) { - addToForeButtons(modeBarButtons[k]); -}); -foreButtons.sort(); - module.exports = { editType: 'modebar', @@ -65,8 +35,8 @@ module.exports = { ].join(' ') }, add: { - valType: 'flaglist', - flags: backButtons, + valType: 'string', + arrayOk: true, dflt: '', editType: 'modebar', description: [ @@ -77,8 +47,8 @@ module.exports = { ].join(' ') }, remove: { - valType: 'flaglist', - flags: foreButtons, + valType: 'string', + arrayOk: true, dflt: '', editType: 'modebar', description: [ diff --git a/src/components/modebar/manage.js b/src/components/modebar/manage.js index 84d4ce370f8..1014244a546 100644 --- a/src/components/modebar/manage.js +++ b/src/components/modebar/manage.js @@ -7,6 +7,39 @@ var isUnifiedHover = require('../fx/helpers').isUnifiedHover; var createModeBar = require('./modebar'); var modeBarButtons = require('./buttons'); +var buttonList = Object.keys(modeBarButtons); + +var DRAW_MODES = [ + 'drawline', + 'drawopenpath', + 'drawclosedpath', + 'drawcircle', + 'drawrect', + 'eraseshape' +]; + +var backButtons = [ + 'v1hovermode', + 'hoverclosest', + 'hovercompare', + 'togglehover', + 'togglespikelines' +].concat(DRAW_MODES); + +var foreButtons = []; +var addToForeButtons = function(b) { + if(backButtons.indexOf(b._cat || b.name) !== -1) return; + // for convenience add lowercase shotname e.g. zoomin as well fullname zoomInGeo + var name = b.name; + var _cat = (b._cat || b.name).toLowerCase(); + if(foreButtons.indexOf(name) === -1) foreButtons.push(name); + if(foreButtons.indexOf(_cat) === -1) foreButtons.push(_cat); +}; +buttonList.forEach(function(k) { + addToForeButtons(modeBarButtons[k]); +}); +foreButtons.sort(); + /** * ModeBar wrapper around 'create' and 'update', @@ -58,15 +91,6 @@ module.exports = function manageModeBar(gd) { else fullLayout._modeBar = createModeBar(gd, buttonGroups); }; -var DRAW_MODES = [ - 'drawline', - 'drawopenpath', - 'drawclosedpath', - 'drawcircle', - 'drawrect', - 'eraseshape' -]; - // logic behind which buttons are displayed by default function getButtonGroups(gd) { var fullLayout = gd._fullLayout; @@ -85,8 +109,14 @@ function getButtonGroups(gd) { return false; } + var layoutAdd = fullLayout.modebar.add; + if(typeof layoutAdd === 'string') layoutAdd = [layoutAdd]; + + var layoutRemove = fullLayout.modebar.remove; + if(typeof layoutRemove === 'string') layoutRemove = [layoutRemove]; + var buttonsToAdd = context.modeBarButtonsToAdd.concat( - fullLayout.modebar.add.split('+').filter(function(e) { + layoutAdd.filter(function(e) { for(var i = 0; i < context.modeBarButtonsToRemove.length; i++) { if(match(e, context.modeBarButtonsToRemove[i])) return false; } @@ -95,7 +125,7 @@ function getButtonGroups(gd) { ); var buttonsToRemove = context.modeBarButtonsToRemove.concat( - fullLayout.modebar.remove.split('+').filter(function(e) { + layoutRemove.filter(function(e) { for(var i = 0; i < context.modeBarButtonsToAdd.length; i++) { if(match(e, context.modeBarButtonsToAdd[i])) return false; } diff --git a/test/jasmine/tests/modebar_test.js b/test/jasmine/tests/modebar_test.js index 2ae90017bb3..d4f60d1147c 100644 --- a/test/jasmine/tests/modebar_test.js +++ b/test/jasmine/tests/modebar_test.js @@ -1573,7 +1573,7 @@ describe('ModeBar', function() { .then(done, done.fail); }); - it('add predefined shape drawing and hover buttons via layout.modebar.add and template', function(done) { + it('add predefined shape drawing and hover buttons via layout.modebar.add', function(done) { function countButtons() { var modeBarEl = gd._fullLayout._modeBar.element; return d3Select(modeBarEl).selectAll('a.modebar-btn').size(); @@ -1591,7 +1591,7 @@ describe('ModeBar', function() { 'drawcircle', 'drawrect', 'eraseshape' - ].join('+')); + ]); }) .then(function() { expect(countButtons()).toBe(initial + 6); @@ -1605,7 +1605,7 @@ describe('ModeBar', function() { 'hovercompare', 'hoverclosest', 'togglespikelines' - ].join('+')); + ]); }) .then(function() { expect(countButtons()).toBe(initial + 3); @@ -1618,7 +1618,7 @@ describe('ModeBar', function() { return Plotly.relayout(gd, 'modebar.add', [ 'v1hovermode', 'togglespikelines' - ].join('+')); + ]); }) .then(function() { expect(countButtons()).toBe(initial + 3); @@ -1629,10 +1629,8 @@ describe('ModeBar', function() { 'togglehover', 'hovercompare', 'hoverclosest', - 'eraseshape', - 'eraseshape', 'eraseshape' - ].join('+')); + ]); }) .then(function() { expect(countButtons()).toBe(initial + 4, 'skip duplicates'); @@ -1640,7 +1638,7 @@ describe('ModeBar', function() { return Plotly.relayout(gd, 'modebar.add', [ 'drawline', 'invalid' - ].join('+')); + ]); }) .then(function() { expect(countButtons()).toBe(initial + 1, 'skip invalid'); @@ -1649,11 +1647,6 @@ describe('ModeBar', function() { }) .then(function() { expect(countButtons()).toBe(initial); - - return Plotly.relayout(gd, 'template.layout.modebar.add', 'v1hovermode'); - }) - .then(function() { - expect(countButtons()).toBe(initial + 2, 'via template'); }) .then(done, done.fail); }); @@ -1679,7 +1672,7 @@ describe('ModeBar', function() { 'autoscale', 'resetscale', 'toimage', - ].join('+')); + ]); }) .then(function() { expect(countButtons()).toBe(initial - 9); @@ -1699,30 +1692,64 @@ describe('ModeBar', function() { 'autoScale2d', 'resetScale2d', 'toImage', - ].join('+')); + ]); }) .then(function() { expect(countButtons()).toBe(initial - 9); + }) + .then(done, done.fail); + }); - return Plotly.relayout(gd, 'modebar.remove', ''); + it('remove buttons using template', function(done) { + function countButtons() { + var modeBarEl = gd._fullLayout._modeBar.element; + return d3Select(modeBarEl).selectAll('a.modebar-btn').size(); + } + + var initial = 10; + Plotly.newPlot(gd, [{y: [1, 2]}], { + template: { + layout: { + modebar: { + remove: [ + 'zoom', + 'zoomin', + 'zoomout', + 'pan', + 'select', + 'lasso', + 'autoscale', + 'resetscale', + 'toimage', + ] + } + } + } }) .then(function() { - expect(countButtons()).toBe(initial); + expect(countButtons()).toBe(initial - 9); + }) + .then(done, done.fail); + }); - return Plotly.relayout(gd, 'template.layout.modebar.remove', [ - 'zoom', - 'zoomin', - 'zoomout', - 'pan', - 'select', - 'lasso', - 'autoscale', - 'resetscale', - 'toimage', - ].join('+')); + it('add buttons using template', function(done) { + function countButtons() { + var modeBarEl = gd._fullLayout._modeBar.element; + return d3Select(modeBarEl).selectAll('a.modebar-btn').size(); + } + + var initial = 10; + Plotly.newPlot(gd, [{y: [1, 2]}], { + template: { + layout: { + modebar: { + add: 'drawcircle' + } + } + } }) .then(function() { - expect(countButtons()).toBe(initial - 9); + expect(countButtons()).toBe(initial + 1); }) .then(done, done.fail); }); From 329309789b0840c76eaccec3d24a047b92c95078 Mon Sep 17 00:00:00 2001 From: archmoj Date: Mon, 17 May 2021 21:16:30 -0400 Subject: [PATCH 11/11] add constant file and list options in descriptions --- src/components/modebar/attributes.js | 8 ++++-- src/components/modebar/constants.js | 41 ++++++++++++++++++++++++++++ src/components/modebar/manage.js | 34 +---------------------- 3 files changed, 48 insertions(+), 35 deletions(-) create mode 100644 src/components/modebar/constants.js diff --git a/src/components/modebar/attributes.js b/src/components/modebar/attributes.js index 75d9a8ba6e0..06435784c42 100644 --- a/src/components/modebar/attributes.js +++ b/src/components/modebar/attributes.js @@ -1,5 +1,7 @@ 'use strict'; +var constants = require('./constants'); + module.exports = { editType: 'modebar', @@ -43,7 +45,8 @@ module.exports = { 'Determines which predefined modebar buttons to add.', 'Please note that these buttons will only be shown if they are', 'compatible with all trace types used in a graph.', - 'Similar to `config.modeBarButtonsToAdd` option' + 'Similar to `config.modeBarButtonsToAdd` option.', + 'This may include *' + constants.backButtons.join('*, *') + '*.' ].join(' ') }, remove: { @@ -53,7 +56,8 @@ module.exports = { editType: 'modebar', description: [ 'Determines which predefined modebar buttons to remove.', - 'Similar to `config.modeBarButtonsToRemove` option' + 'Similar to `config.modeBarButtonsToRemove` option.', + 'This may include *' + constants.foreButtons.join('*, *') + '*.' ].join(' ') } }; diff --git a/src/components/modebar/constants.js b/src/components/modebar/constants.js new file mode 100644 index 00000000000..788cbb5ae4e --- /dev/null +++ b/src/components/modebar/constants.js @@ -0,0 +1,41 @@ +'use strict'; + +var modeBarButtons = require('./buttons'); +var buttonList = Object.keys(modeBarButtons); + +var DRAW_MODES = [ + 'drawline', + 'drawopenpath', + 'drawclosedpath', + 'drawcircle', + 'drawrect', + 'eraseshape' +]; + +var backButtons = [ + 'v1hovermode', + 'hoverclosest', + 'hovercompare', + 'togglehover', + 'togglespikelines' +].concat(DRAW_MODES); + +var foreButtons = []; +var addToForeButtons = function(b) { + if(backButtons.indexOf(b._cat || b.name) !== -1) return; + // for convenience add lowercase shotname e.g. zoomin as well fullname zoomInGeo + var name = b.name; + var _cat = (b._cat || b.name).toLowerCase(); + if(foreButtons.indexOf(name) === -1) foreButtons.push(name); + if(foreButtons.indexOf(_cat) === -1) foreButtons.push(_cat); +}; +buttonList.forEach(function(k) { + addToForeButtons(modeBarButtons[k]); +}); +foreButtons.sort(); + +module.exports = { + DRAW_MODES: DRAW_MODES, + backButtons: backButtons, + foreButtons: foreButtons +}; diff --git a/src/components/modebar/manage.js b/src/components/modebar/manage.js index 1014244a546..718a790f5e3 100644 --- a/src/components/modebar/manage.js +++ b/src/components/modebar/manage.js @@ -7,39 +7,7 @@ var isUnifiedHover = require('../fx/helpers').isUnifiedHover; var createModeBar = require('./modebar'); var modeBarButtons = require('./buttons'); -var buttonList = Object.keys(modeBarButtons); - -var DRAW_MODES = [ - 'drawline', - 'drawopenpath', - 'drawclosedpath', - 'drawcircle', - 'drawrect', - 'eraseshape' -]; - -var backButtons = [ - 'v1hovermode', - 'hoverclosest', - 'hovercompare', - 'togglehover', - 'togglespikelines' -].concat(DRAW_MODES); - -var foreButtons = []; -var addToForeButtons = function(b) { - if(backButtons.indexOf(b._cat || b.name) !== -1) return; - // for convenience add lowercase shotname e.g. zoomin as well fullname zoomInGeo - var name = b.name; - var _cat = (b._cat || b.name).toLowerCase(); - if(foreButtons.indexOf(name) === -1) foreButtons.push(name); - if(foreButtons.indexOf(_cat) === -1) foreButtons.push(_cat); -}; -buttonList.forEach(function(k) { - addToForeButtons(modeBarButtons[k]); -}); -foreButtons.sort(); - +var DRAW_MODES = require('./constants').DRAW_MODES; /** * ModeBar wrapper around 'create' and 'update',