Skip to content

Commit 93c5a88

Browse files
committed
let modebar display more buttons in multi-type subplot cases
1 parent fde97d7 commit 93c5a88

File tree

4 files changed

+116
-52
lines changed

4 files changed

+116
-52
lines changed

src/components/modebar/buttons.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,10 @@ function handleDrag3d(gd, ev) {
302302
layoutUpdate[sceneIds[i] + '.' + parts[1]] = val;
303303
}
304304

305+
// for multi-type subplots
306+
var val2d = (val === 'pan') ? val : 'zoom';
307+
layoutUpdate.dragmode = val2d;
308+
305309
Plotly.relayout(gd, layoutUpdate);
306310
}
307311

src/components/modebar/manage.js

Lines changed: 55 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,13 @@ function getButtonGroups(gd, buttonsToRemove, buttonsToAdd) {
8282
var hasTernary = fullLayout._has('ternary');
8383
var hasMapbox = fullLayout._has('mapbox');
8484
var hasPolar = fullLayout._has('polar');
85+
var allAxesFixed = areAllAxesFixed(fullLayout);
8586

8687
var groups = [];
8788

8889
function addGroup(newGroup) {
90+
if(!newGroup.length) return;
91+
8992
var out = [];
9093

9194
for(var i = 0; i < newGroup.length; i++) {
@@ -100,55 +103,71 @@ function getButtonGroups(gd, buttonsToRemove, buttonsToAdd) {
100103
// buttons common to all plot types
101104
addGroup(['toImage', 'sendDataToCloud']);
102105

103-
// graphs with more than one plot types get 'union buttons'
104-
// which reset the view or toggle hover labels across all subplots.
105-
if((hasCartesian || hasGL2D || hasPie || hasTernary) + hasGeo + hasGL3D > 1) {
106-
addGroup(['resetViews', 'toggleHover']);
107-
return appendButtonsToGroups(groups, buttonsToAdd);
108-
}
106+
var zoomGroup = [];
107+
var hoverGroup = [];
108+
var resetGroup = [];
109+
var dragModeGroup = [];
109110

110-
if(hasGL3D) {
111-
addGroup(['zoom3d', 'pan3d', 'orbitRotation', 'tableRotation']);
112-
addGroup(['resetCameraDefault3d', 'resetCameraLastSave3d']);
113-
addGroup(['hoverClosest3d']);
111+
if((hasCartesian || hasGL2D || hasPie || hasTernary) + hasGeo + hasGL3D + hasMapbox + hasPolar > 1) {
112+
// graphs with more than one plot types get 'union buttons'
113+
// which reset the view or toggle hover labels across all subplots.
114+
hoverGroup = ['toggleHover'];
115+
resetGroup = ['resetViews'];
116+
}
117+
else if(hasGeo) {
118+
zoomGroup = ['zoomInGeo', 'zoomOutGeo'];
119+
hoverGroup = ['hoverClosestGeo'];
120+
resetGroup = ['resetGeo'];
121+
}
122+
else if(hasGL3D) {
123+
hoverGroup = ['hoverClosest3d'];
124+
resetGroup = ['resetCameraDefault3d', 'resetCameraLastSave3d'];
125+
}
126+
else if(hasMapbox) {
127+
hoverGroup = ['toggleHover'];
128+
resetGroup = ['resetViewMapbox'];
129+
}
130+
else if(hasGL2D) {
131+
hoverGroup = ['hoverClosestGl2d'];
132+
}
133+
else if(hasPie) {
134+
hoverGroup = ['hoverClosestPie'];
135+
}
136+
else { // hasPolar, hasTernary
137+
// always show at least one hover icon.
138+
hoverGroup = ['toggleHover'];
139+
}
140+
// if we have cartesian, allow switching between closest and compare
141+
// regardless of what other types are on the plot, since they'll all
142+
// just treat any truthy hovermode as 'closest'
143+
if(hasCartesian) {
144+
hoverGroup = ['toggleSpikelines', 'hoverClosestCartesian', 'hoverCompareCartesian'];
114145
}
115146

116-
var allAxesFixed = areAllAxesFixed(fullLayout),
117-
dragModeGroup = [];
147+
if((hasCartesian || hasGL2D) && !allAxesFixed) {
148+
zoomGroup = ['zoomIn2d', 'zoomOut2d', 'autoScale2d'];
149+
if(resetGroup[0] !== 'resetViews') resetGroup = ['resetScale2d'];
150+
}
118151

119-
if(((hasCartesian || hasGL2D) && !allAxesFixed) || hasTernary) {
152+
if(hasGL3D) {
153+
dragModeGroup = ['zoom3d', 'pan3d', 'orbitRotation', 'tableRotation'];
154+
}
155+
else if(((hasCartesian || hasGL2D) && !allAxesFixed) || hasTernary) {
120156
dragModeGroup = ['zoom2d', 'pan2d'];
121157
}
122-
if(hasMapbox || hasGeo) {
158+
else if(hasMapbox || hasGeo) {
123159
dragModeGroup = ['pan2d'];
124160
}
125-
if(hasPolar) {
161+
else if(hasPolar) {
126162
dragModeGroup = ['zoom2d'];
127163
}
128164
if(isSelectable(fullData)) {
129-
dragModeGroup.push('select2d');
130-
dragModeGroup.push('lasso2d');
131-
}
132-
if(dragModeGroup.length) addGroup(dragModeGroup);
133-
134-
if((hasCartesian || hasGL2D) && !allAxesFixed && !hasTernary) {
135-
addGroup(['zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d']);
165+
dragModeGroup.push('select2d', 'lasso2d');
136166
}
137167

138-
if(hasCartesian && hasPie) {
139-
addGroup(['toggleHover']);
140-
} else if(hasGL2D) {
141-
addGroup(['hoverClosestGl2d']);
142-
} else if(hasCartesian) {
143-
addGroup(['toggleSpikelines', 'hoverClosestCartesian', 'hoverCompareCartesian']);
144-
} else if(hasPie) {
145-
addGroup(['hoverClosestPie']);
146-
} else if(hasMapbox) {
147-
addGroup(['resetViewMapbox', 'toggleHover']);
148-
} else if(hasGeo) {
149-
addGroup(['zoomInGeo', 'zoomOutGeo', 'resetGeo']);
150-
addGroup(['hoverClosestGeo']);
151-
}
168+
addGroup(dragModeGroup);
169+
addGroup(zoomGroup.concat(resetGroup));
170+
addGroup(hoverGroup);
152171

153172
return appendButtonsToGroups(groups, buttonsToAdd);
154173
}

test/jasmine/tests/gl3d_plot_interact_test.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ describe('@gl Test gl3d modebar handlers', function() {
483483

484484
buttonZoom3d.click();
485485
assertScenes(gd._fullLayout, 'dragmode', 'zoom');
486-
expect(gd.layout.dragmode).toBe(undefined);
486+
expect(gd.layout.dragmode).toBe('zoom'); // for multi-type subplots
487487
expect(gd._fullLayout.dragmode).toBe('zoom');
488488
expect(buttonTurntable.isActive()).toBe(false);
489489
expect(buttonZoom3d.isActive()).toBe(true);
@@ -504,8 +504,8 @@ describe('@gl Test gl3d modebar handlers', function() {
504504

505505
buttonPan3d.click();
506506
assertScenes(gd._fullLayout, 'dragmode', 'pan');
507-
expect(gd.layout.dragmode).toBe(undefined);
508-
expect(gd._fullLayout.dragmode).toBe('zoom');
507+
expect(gd.layout.dragmode).toBe('pan'); // for multi-type subplots
508+
expect(gd._fullLayout.dragmode).toBe('pan');
509509
expect(buttonTurntable.isActive()).toBe(false);
510510
expect(buttonPan3d.isActive()).toBe(true);
511511

@@ -525,7 +525,7 @@ describe('@gl Test gl3d modebar handlers', function() {
525525

526526
buttonOrbit.click();
527527
assertScenes(gd._fullLayout, 'dragmode', 'orbit');
528-
expect(gd.layout.dragmode).toBe(undefined);
528+
expect(gd.layout.dragmode).toBe('zoom'); // fallback for multi-type subplots
529529
expect(gd._fullLayout.dragmode).toBe('zoom');
530530
expect(buttonTurntable.isActive()).toBe(false);
531531
expect(buttonOrbit.isActive()).toBe(true);

test/jasmine/tests/modebar_test.js

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,11 @@ describe('ModeBar', function() {
175175
expectedButtonCount += group.length;
176176
});
177177

178-
expect(modeBar.hasButtons(buttons)).toBe(true, 'modeBar.hasButtons');
178+
var actualButtons = modeBar.buttons.map(function(group) {
179+
return group.map(function(button) { return button.name; }).join(', ');
180+
}).join(' - ');
181+
182+
expect(modeBar.hasButtons(buttons)).toBe(true, 'modeBar.hasButtons: ' + actualButtons);
179183
expect(countGroups(modeBar)).toBe(expectedGroupCount, 'correct group count');
180184
expect(countButtons(modeBar)).toBe(expectedButtonCount, 'correct button count');
181185
expect(countLogo(modeBar)).toBe(1, 'correct logo count');
@@ -323,7 +327,8 @@ describe('ModeBar', function() {
323327
var buttons = getButtons([
324328
['toImage', 'sendDataToCloud'],
325329
['pan2d'],
326-
['resetViewMapbox', 'toggleHover']
330+
['resetViewMapbox'],
331+
['toggleHover']
327332
]);
328333

329334
var gd = getMockGraphInfo();
@@ -339,7 +344,8 @@ describe('ModeBar', function() {
339344
var buttons = getButtons([
340345
['toImage', 'sendDataToCloud'],
341346
['pan2d', 'select2d', 'lasso2d'],
342-
['resetViewMapbox', 'toggleHover']
347+
['resetViewMapbox'],
348+
['toggleHover']
343349
]);
344350

345351
var gd = getMockGraphInfo();
@@ -393,7 +399,9 @@ describe('ModeBar', function() {
393399
it('creates mode bar (cartesian + gl3d version)', function() {
394400
var buttons = getButtons([
395401
['toImage', 'sendDataToCloud'],
396-
['resetViews', 'toggleHover']
402+
['zoom3d', 'pan3d', 'orbitRotation', 'tableRotation'],
403+
['resetViews'],
404+
['toggleSpikelines', 'hoverClosestCartesian', 'hoverCompareCartesian']
397405
]);
398406

399407
var gd = getMockGraphInfo();
@@ -405,14 +413,41 @@ describe('ModeBar', function() {
405413
checkButtons(modeBar, buttons, 1);
406414
});
407415

408-
it('creates mode bar (cartesian + geo version)', function() {
416+
it('creates mode bar (cartesian + geo unselectable version)', function() {
409417
var buttons = getButtons([
410418
['toImage', 'sendDataToCloud'],
411-
['resetViews', 'toggleHover']
419+
['zoom2d', 'pan2d'],
420+
['zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetViews'],
421+
['toggleSpikelines', 'hoverClosestCartesian', 'hoverCompareCartesian']
412422
]);
413423

414-
var gd = getMockGraphInfo();
424+
var gd = getMockGraphInfo(['x'], ['y']);
425+
gd._fullLayout._basePlotModules = [{ name: 'cartesian' }, { name: 'geo' }];
426+
gd._fullLayout.xaxis = {fixedrange: false};
427+
428+
manageModeBar(gd);
429+
var modeBar = gd._fullLayout._modeBar;
430+
431+
checkButtons(modeBar, buttons, 1);
432+
});
433+
434+
it('creates mode bar (cartesian + geo selectable version)', function() {
435+
var buttons = getButtons([
436+
['toImage', 'sendDataToCloud'],
437+
['zoom2d', 'pan2d', 'select2d', 'lasso2d'],
438+
['zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetViews'],
439+
['toggleSpikelines', 'hoverClosestCartesian', 'hoverCompareCartesian']
440+
]);
441+
442+
var gd = getMockGraphInfo(['x'], ['y']);
415443
gd._fullLayout._basePlotModules = [{ name: 'cartesian' }, { name: 'geo' }];
444+
gd._fullLayout.xaxis = {fixedrange: false};
445+
gd._fullData = [{
446+
type: 'scatter',
447+
visible: true,
448+
mode: 'markers',
449+
_module: {selectPoints: true}
450+
}];
416451

417452
manageModeBar(gd);
418453
var modeBar = gd._fullLayout._modeBar;
@@ -425,7 +460,7 @@ describe('ModeBar', function() {
425460
['toImage', 'sendDataToCloud'],
426461
['zoom2d', 'pan2d', 'select2d', 'lasso2d'],
427462
['zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d'],
428-
['toggleHover']
463+
['toggleSpikelines', 'hoverClosestCartesian', 'hoverCompareCartesian']
429464
]);
430465

431466
var gd = getMockGraphInfo(['x'], ['y']);
@@ -447,7 +482,9 @@ describe('ModeBar', function() {
447482
it('creates mode bar (gl3d + geo version)', function() {
448483
var buttons = getButtons([
449484
['toImage', 'sendDataToCloud'],
450-
['resetViews', 'toggleHover']
485+
['zoom3d', 'pan3d', 'orbitRotation', 'tableRotation'],
486+
['resetViews'],
487+
['toggleHover']
451488
]);
452489

453490
var gd = getMockGraphInfo();
@@ -462,7 +499,8 @@ describe('ModeBar', function() {
462499
it('creates mode bar (un-selectable ternary version)', function() {
463500
var buttons = getButtons([
464501
['toImage', 'sendDataToCloud'],
465-
['zoom2d', 'pan2d']
502+
['zoom2d', 'pan2d'],
503+
['toggleHover']
466504
]);
467505

468506
var gd = getMockGraphInfo();
@@ -477,7 +515,8 @@ describe('ModeBar', function() {
477515
it('creates mode bar (selectable ternary version)', function() {
478516
var buttons = getButtons([
479517
['toImage', 'sendDataToCloud'],
480-
['zoom2d', 'pan2d', 'select2d', 'lasso2d']
518+
['zoom2d', 'pan2d', 'select2d', 'lasso2d'],
519+
['toggleHover']
481520
]);
482521

483522
var gd = getMockGraphInfo();
@@ -514,7 +553,9 @@ describe('ModeBar', function() {
514553
it('creates mode bar (ternary + gl3d version)', function() {
515554
var buttons = getButtons([
516555
['toImage', 'sendDataToCloud'],
517-
['resetViews', 'toggleHover']
556+
['zoom3d', 'pan3d', 'orbitRotation', 'tableRotation'],
557+
['resetViews'],
558+
['toggleHover']
518559
]);
519560

520561
var gd = getMockGraphInfo();

0 commit comments

Comments
 (0)