Skip to content

Add legend.groupclick options to toggle single item within a group #5906

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 26, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions draftlogs/5849_add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Add `legend.groupclick` options [[#5849](https://github.com/plotly/plotly.js/pull/5849), [#5906](https://github.com/plotly/plotly.js/pull/5906)],
with thanks to @brussee for the contribution!
18 changes: 13 additions & 5 deletions src/components/legend/attributes.js
Original file line number Diff line number Diff line change
@@ -84,7 +84,6 @@ module.exports = {
editType: 'legend',
description: 'Sets the width (in px) of the legend item symbols (the part other than the title.text).',
},

itemclick: {
valType: 'enumerated',
values: ['toggle', 'toggleothers', false],
@@ -94,7 +93,7 @@ module.exports = {
'Determines the behavior on legend item click.',
'*toggle* toggles the visibility of the item clicked on the graph.',
'*toggleothers* makes the clicked item the sole visible item on the graph.',
'*false* disable legend item click interactions.'
'*false* disables legend item click interactions.'
].join(' ')
},
itemdoubleclick: {
@@ -106,10 +105,20 @@ module.exports = {
'Determines the behavior on legend item double-click.',
'*toggle* toggles the visibility of the item clicked on the graph.',
'*toggleothers* makes the clicked item the sole visible item on the graph.',
'*false* disable legend item double-click interactions.'
'*false* disables legend item double-click interactions.'
].join(' ')
},
groupclick: {
valType: 'enumerated',
values: ['toggleitem', 'togglegroup'],
dflt: 'togglegroup',
editType: 'legend',
description: [
'Determines the behavior on legend group item click.',
'*toggleitem* toggles the visibility of the individual item clicked on the graph.',
'*togglegroup* toggles the visibility of all items in the same legendgroup as the item clicked on the graph.'
].join(' ')
},

x: {
valType: 'number',
min: -2,
@@ -208,6 +217,5 @@ module.exports = {
},
editType: 'legend',
},

editType: 'legend'
};
1 change: 1 addition & 0 deletions src/components/legend/defaults.js
Original file line number Diff line number Diff line change
@@ -110,6 +110,7 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {

coerce('itemclick');
coerce('itemdoubleclick');
coerce('groupclick');

coerce('x', defaultX);
coerce('xanchor');
2 changes: 1 addition & 1 deletion src/components/legend/get_legend_data.js
Original file line number Diff line number Diff line change
@@ -152,7 +152,7 @@ module.exports = function getLegendData(calcdata, opts) {
trace: {
showlegend: firstItemTrace.showlegend,
legendgroup: firstItemTrace.legendgroup,
visible: firstItemTrace.visible
visible: opts.groupclick === 'toggleitem' ? true : firstItemTrace.visible
}
});
}
17 changes: 12 additions & 5 deletions src/components/legend/handle_click.js
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@ module.exports = function handleClick(g, gd, numClicks) {

var itemClick = fullLayout.legend.itemclick;
var itemDoubleClick = fullLayout.legend.itemdoubleclick;
var groupClick = fullLayout.legend.groupclick;

if(numClicks === 1 && itemClick === 'toggle' && itemDoubleClick === 'toggleothers' &&
SHOWISOLATETIP && gd.data && gd._context.showTips
@@ -27,6 +28,8 @@ module.exports = function handleClick(g, gd, numClicks) {
else if(numClicks === 2) mode = itemDoubleClick;
if(!mode) return;

var toggleGroup = groupClick === 'togglegroup';

var hiddenSlices = fullLayout.hiddenlabels ?
fullLayout.hiddenlabels.slice() :
[];
@@ -148,10 +151,14 @@ module.exports = function handleClick(g, gd, numClicks) {
}

if(hasLegendgroup) {
for(i = 0; i < fullData.length; i++) {
if(fullData[i].visible !== false && fullData[i].legendgroup === legendgroup) {
setVisibility(fullData[i], nextVisibility);
if(toggleGroup) {
for(i = 0; i < fullData.length; i++) {
if(fullData[i].visible !== false && fullData[i].legendgroup === legendgroup) {
setVisibility(fullData[i], nextVisibility);
}
}
} else {
setVisibility(fullTrace, nextVisibility);
}
} else {
setVisibility(fullTrace, nextVisibility);
@@ -192,7 +199,7 @@ module.exports = function handleClick(g, gd, numClicks) {
// N.B. consider traces that have a set legendgroup as toggleable
notInLegend = (fullData[i].showlegend !== true && !fullData[i].legendgroup);
isInGroup = isClicked || (hasLegendgroup && fullData[i].legendgroup === legendgroup);
setVisibility(fullData[i], (isInGroup || notInLegend) ? true : otherState);
setVisibility(fullData[i], ((isInGroup && toggleGroup) || notInLegend) ? true : otherState);
break;
}
}
@@ -219,7 +226,7 @@ module.exports = function handleClick(g, gd, numClicks) {
for(i = 0; i < keys.length; i++) {
key = keys[i];
for(j = 0; j < attrIndices.length; j++) {
// Use hasOwnPropety to protect against falsey values:
// Use hasOwnProperty to protect against falsy values:
if(!attrUpdate[key].hasOwnProperty(j)) {
attrUpdate[key][j] = undefined;
}
43 changes: 43 additions & 0 deletions test/jasmine/tests/legend_test.js
Original file line number Diff line number Diff line change
@@ -1782,6 +1782,49 @@ describe('legend interaction', function() {
});
});

describe('legendgroup visibility case of groupclick: "toggleitem"', function() {
beforeEach(function(done) {
Plotly.newPlot(gd, [{
x: [1, 2],
y: [3, 4],
visible: false
}, {
x: [1, 2, 3, 4],
y: [0, 1, 2, 3],
legendgroup: 'foo'
}, {
x: [1, 2, 3, 4],
y: [1, 3, 2, 4],
}, {
x: [1, 2, 3, 4],
y: [1, 3, 2, 4],
legendgroup: 'foo'
}], {
legend: {
groupclick: 'toggleitem'
}
}).then(done);
});

it('toggles visibilities', function(done) {
Promise.resolve()
.then(assertVisible([false, true, true, true]))
.then(click(0))
.then(assertVisible([false, 'legendonly', true, true]))
.then(click(0))
.then(assertVisible([false, true, true, true]))
.then(click(1))
.then(assertVisible([false, true, true, 'legendonly']))
.then(click(1))
.then(assertVisible([false, true, true, true]))
.then(click(2))
.then(assertVisible([false, true, 'legendonly', true]))
.then(click(2))
.then(assertVisible([false, true, true, true]))
.then(done, done.fail);
});
});

describe('legend visibility toggles with groupby', function() {
beforeEach(function(done) {
Plotly.newPlot(gd, [{
14 changes: 12 additions & 2 deletions test/plot-schema.json
Original file line number Diff line number Diff line change
@@ -2683,8 +2683,18 @@
"valType": "number"
}
},
"groupclick": {
"description": "Determines the behavior on legend group item click. *toggleitem* toggles the visibility of the individual item clicked on the graph. *togglegroup* toggles the visibility of all items in the same legendgroup as the item clicked on the graph.",
"dflt": "togglegroup",
"editType": "legend",
"valType": "enumerated",
"values": [
"toggleitem",
"togglegroup"
]
},
"itemclick": {
"description": "Determines the behavior on legend item click. *toggle* toggles the visibility of the item clicked on the graph. *toggleothers* makes the clicked item the sole visible item on the graph. *false* disable legend item click interactions.",
"description": "Determines the behavior on legend item click. *toggle* toggles the visibility of the item clicked on the graph. *toggleothers* makes the clicked item the sole visible item on the graph. *false* disables legend item click interactions.",
"dflt": "toggle",
"editType": "legend",
"valType": "enumerated",
@@ -2695,7 +2705,7 @@
]
},
"itemdoubleclick": {
"description": "Determines the behavior on legend item double-click. *toggle* toggles the visibility of the item clicked on the graph. *toggleothers* makes the clicked item the sole visible item on the graph. *false* disable legend item double-click interactions.",
"description": "Determines the behavior on legend item double-click. *toggle* toggles the visibility of the item clicked on the graph. *toggleothers* makes the clicked item the sole visible item on the graph. *false* disables legend item double-click interactions.",
"dflt": "toggleothers",
"editType": "legend",
"valType": "enumerated",