Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 2 additions & 1 deletion src/components/legend/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ module.exports = {
scrollBarWidth: 4,
scrollBarHeight: 20,
scrollBarColor: '#808BA4',
scrollBarMargin: 4
scrollBarMargin: 4,
DBLCLICKDELAY: 300
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid duplication we should probably put this (and a few other things) into constants/interactions and reference it from legend and dragelement - which for obsolete reasons currently gets these constants out of cartesian/constants

};
109 changes: 84 additions & 25 deletions src/components/legend/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ module.exports = function draw(gd) {

if(!fullLayout._infolayer || !gd.calcdata) return;

if(!gd._legendMouseDownTime) gd._legendMouseDownTime = 0;

var opts = fullLayout.legend,
legendData = fullLayout.showlegend && getLegendData(gd.calcdata, opts),
hiddenSlices = fullLayout.hiddenlabels || [];
Expand Down Expand Up @@ -395,9 +397,9 @@ function drawTexts(g, gd) {
}

function setupTraceToggle(g, gd) {
var hiddenSlices = gd._fullLayout.hiddenlabels ?
gd._fullLayout.hiddenlabels.slice() :
[];
var newMouseDownTime,
numClicks = 1,
DBLCLICKDELAY = constants.DBLCLICKDELAY;

var traceToggle = g.selectAll('rect')
.data([0]);
Expand All @@ -408,41 +410,98 @@ function setupTraceToggle(g, gd) {
.attr('pointer-events', 'all')
.call(Color.fill, 'rgba(0,0,0,0)');

traceToggle.on('click', function() {

traceToggle.on('mousedown', function() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we could reuse the dragelement abstraction here? This is a non- ⛔ comment of course.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly - but this reminds me that we had better ensure that this change is compatible with the additional interactions the legend supports in {editable: true} config. For clarity, here's how that works currently and should continue to work:

  • clicking on legend symbols toggles the trace (so doubleclicking them should isolate the trace)
  • clicking on legend text, which outside of editable mode also toggles the trace, instead edits the text (so doubleclick should do nothing there)
  • dragging anywhere in the legend - symbol, text, or background/border - moves the legend and does not toggle anything.

@rpaskowitz you can convert the plot you're testing to editable by calling:

Plotly.newPlot(gd, gd.data, gd.layout, {editable: true})

newMouseDownTime = (new Date()).getTime();
if(newMouseDownTime - gd._legendMouseDownTime < DBLCLICKDELAY) {
// in a click train
numClicks += 1;
}
else {
// new click train
numClicks = 1;
gd._legendMouseDownTime = newMouseDownTime;
}
});
traceToggle.on('mouseup', function() {
if(gd._dragged) return;
var legend = gd._fullLayout.legend;

var legendItem = g.data()[0][0],
fullData = gd._fullData,
trace = legendItem.trace,
legendgroup = trace.legendgroup,
traceIndicesInGroup = [],
tracei,
newVisible;
if((new Date()).getTime() - gd._legendMouseDownTime > DBLCLICKDELAY) {
numClicks = Math.max(numClicks - 1, 1);
}

if(Registry.traceIs(trace, 'pie')) {
var thisLabel = legendItem.label,
thisLabelIndex = hiddenSlices.indexOf(thisLabel);
if(numClicks === 1) {
legend._clickTimeout = setTimeout(function() { handleClick(g, gd, numClicks); }, 300);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be DBLCLICKDELAY, will correct when refactoring where that's defined.

} else if(numClicks === 2) {
if(legend._clickTimeout) {
clearTimeout(legend._clickTimeout);
}
handleClick(g, gd, numClicks);
}
});
}

function handleClick(g, gd, numClicks) {
var hiddenSlices = gd._fullLayout.hiddenlabels ?
gd._fullLayout.hiddenlabels.slice() :
[];

var legendItem = g.data()[0][0],
fullData = gd._fullData,
trace = legendItem.trace,
legendgroup = trace.legendgroup,
traceIndicesInGroup = [],
tracei,
newVisible;

if(Registry.traceIs(trace, 'pie')) {
var thisLabel = legendItem.label,
thisLabelIndex = hiddenSlices.indexOf(thisLabel);

if(numClicks === 1) {
if(thisLabelIndex === -1) hiddenSlices.push(thisLabel);
else hiddenSlices.splice(thisLabelIndex, 1);
} else if(numClicks === 2) {
hiddenSlices = [];
gd.calcdata[0].forEach(function(d) {
if(thisLabel !== d.label) {
hiddenSlices.push(d.label);
}
});
}

Plotly.relayout(gd, 'hiddenlabels', hiddenSlices);
} else {
var otherTraces = [],
traceIndex,
i;

for(i = 0; i < fullData.length; i++) {
otherTraces.push(i);
}

Plotly.relayout(gd, 'hiddenlabels', hiddenSlices);
if(legendgroup === '') {
traceIndicesInGroup = [trace.index];
otherTraces.splice(trace.index, 1);
} else {
if(legendgroup === '') {
traceIndicesInGroup = [trace.index];
} else {
for(var i = 0; i < fullData.length; i++) {
tracei = fullData[i];
if(tracei.legendgroup === legendgroup) {
traceIndicesInGroup.push(tracei.index);
}
for(i = 0; i < fullData.length; i++) {
tracei = fullData[i];
if(tracei.legendgroup === legendgroup) {
traceIndicesInGroup.push(tracei.index);
traceIndex = otherTraces.indexOf(i);
otherTraces.splice(traceIndex, 1);
}
}

}
if(numClicks === 1) {
newVisible = trace.visible === true ? 'legendonly' : true;
Plotly.restyle(gd, 'visible', newVisible, traceIndicesInGroup);
} else if(numClicks === 2) {
Plotly.restyle(gd, 'visible', true, traceIndicesInGroup);
Plotly.restyle(gd, 'visible', 'legendonly', otherTraces);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you work this into a single call Plotly.restyle(gd, 'visible', [true, 'legendonly', ...], allTraces);?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a way this may make things easier, no more array splicing, I can just build up a traceVisibility array as I iterate.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Please convert this to a single restyle call 🐎

}
});
}
}

function computeTextDimensions(g, gd) {
Expand Down