Skip to content

Commit 2165998

Browse files
committed
Merge pull request #23 from plotly/custom-modebar
Add config options to remove specific modebar buttons
2 parents 71765f1 + eadd7fb commit 2165998

File tree

12 files changed

+1195
-686
lines changed

12 files changed

+1195
-686
lines changed

src/components/modebar/buttons.js

Lines changed: 474 additions & 0 deletions
Large diffs are not rendered by default.

src/components/modebar/index.js

Lines changed: 119 additions & 507 deletions
Large diffs are not rendered by default.

src/components/modebar/manage.js

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/**
2+
* Copyright 2012-2015, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
10+
'use strict';
11+
12+
var Plotly = require('../../plotly');
13+
14+
var createModeBar = require('./');
15+
var modeBarButtons = require('./buttons');
16+
17+
/**
18+
* ModeBar wrapper around 'create' and 'update',
19+
* chooses buttons to pass to ModeBar constructor based on
20+
* plot type and plot config.
21+
*
22+
* @param {object} gd main plot object
23+
*
24+
*/
25+
module.exports = function manageModeBar(gd) {
26+
var fullLayout = gd._fullLayout,
27+
context = gd._context,
28+
modeBar = fullLayout._modeBar;
29+
30+
if(!context.displayModeBar && modeBar) {
31+
modeBar.destroy();
32+
delete fullLayout._modeBar;
33+
return;
34+
}
35+
36+
if(!Array.isArray(context.modeBarButtonsToRemove)) {
37+
throw new Error([
38+
'*modeBarButtonsToRemove* configuration options',
39+
'must be an array.'
40+
].join(' '));
41+
}
42+
43+
if(!Array.isArray(context.modeBarButtonsToAdd)) {
44+
throw new Error([
45+
'*modeBarButtonsToAdd* configuration options',
46+
'must be an array.'
47+
].join(' '));
48+
}
49+
50+
var customButtons = context.modeBarButtons;
51+
var buttonGroups;
52+
53+
if(Array.isArray(customButtons) && customButtons.length) {
54+
buttonGroups = fillCustomButton(customButtons);
55+
}
56+
else {
57+
buttonGroups = getButtonGroups(
58+
fullLayout,
59+
context.modeBarButtonsToRemove,
60+
context.modeBarButtonsToAdd
61+
);
62+
}
63+
64+
if(modeBar) modeBar.update(gd, buttonGroups);
65+
else fullLayout._modeBar = createModeBar(gd, buttonGroups);
66+
};
67+
68+
// logic behind which buttons are displayed by default
69+
function getButtonGroups(fullLayout, buttonsToRemove, buttonsToAdd) {
70+
var groups = [];
71+
72+
function addGroup(newGroup) {
73+
var out = [];
74+
75+
for(var i = 0; i < newGroup.length; i++) {
76+
var button = newGroup[i];
77+
if(buttonsToRemove.indexOf(button) !== -1) continue;
78+
out.push(modeBarButtons[button]);
79+
}
80+
81+
groups.push(out);
82+
}
83+
84+
// buttons common to all plot types
85+
addGroup(['toImage', 'sendDataToCloud']);
86+
87+
if(fullLayout._hasGL3D) {
88+
addGroup(['zoom3d', 'pan3d', 'orbitRotation', 'tableRotation']);
89+
addGroup(['resetCameraDefault3d', 'resetCameraLastSave3d']);
90+
addGroup(['hoverClosest3d']);
91+
}
92+
93+
if(fullLayout._hasGeo) {
94+
addGroup(['zoomInGeo', 'zoomOutGeo', 'resetGeo']);
95+
addGroup(['hoverClosestGeo']);
96+
}
97+
98+
var hasCartesian = fullLayout._hasCartesian,
99+
hasGL2D = fullLayout._hasGL2D,
100+
allAxesFixed = areAllAxesFixed(fullLayout);
101+
102+
if((hasCartesian || hasGL2D) && !allAxesFixed) {
103+
addGroup(['zoom2d', 'pan2d']);
104+
addGroup(['zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d']);
105+
}
106+
107+
if(hasCartesian) {
108+
addGroup(['hoverClosestCartesian', 'hoverCompareCartesian']);
109+
}
110+
if(hasGL2D) {
111+
addGroup(['hoverClosestGl2d']);
112+
}
113+
if(fullLayout._hasPie) {
114+
addGroup(['hoverClosestPie']);
115+
}
116+
117+
// append buttonsToAdd to the groups
118+
if(buttonsToAdd.length) {
119+
if(Array.isArray(buttonsToAdd[0])) {
120+
for(var i = 0; i < buttonsToAdd.length; i++) {
121+
groups.push(buttonsToAdd[i]);
122+
}
123+
}
124+
else groups.push(buttonsToAdd);
125+
}
126+
127+
return groups;
128+
}
129+
130+
function areAllAxesFixed(fullLayout) {
131+
var axList = Plotly.Axes.list({_fullLayout: fullLayout}, null, true);
132+
var allFixed = true;
133+
134+
for(var i = 0; i < axList.length; i++) {
135+
if(!axList[i].fixedrange) {
136+
allFixed = false;
137+
break;
138+
}
139+
}
140+
141+
return allFixed;
142+
}
143+
144+
// fill in custom buttons referring to default mode bar buttons
145+
function fillCustomButton(customButtons) {
146+
for(var i = 0; i < customButtons.length; i++) {
147+
var buttonGroup = customButtons[i];
148+
149+
for(var j = 0; j < buttonGroup.length; j++) {
150+
var button = buttonGroup[j];
151+
152+
if(typeof button === 'string')
153+
if(modeBarButtons[button] !== undefined) {
154+
customButtons[i][j] = modeBarButtons[button];
155+
}
156+
else {
157+
throw new Error([
158+
'*modeBarButtons* configuration options',
159+
'invalid button name'
160+
].join(' '));
161+
}
162+
}
163+
}
164+
165+
return customButtons;
166+
}

src/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ exports.deleteTraces = Plotly.deleteTraces;
3232
exports.moveTraces = Plotly.moveTraces;
3333
exports.setPlotConfig = require('./plot_api/set_plot_config');
3434

35+
// plot icons
36+
exports.Icons = require('../build/ploticon');
37+
3538
// unofficial 'beta' plot methods, use at your own risk
3639
exports.Plots = Plotly.Plots;
3740
exports.Fx = Plotly.Fx;

src/plot_api/plot_api.js

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
var Plotly = require('../plotly');
1313
var Events = require('../lib/events');
14+
var manageModeBar = require('../components/modebar/manage');
1415

1516
var d3 = require('d3');
1617
var m4FromQuat = require('gl-mat4/fromQuat');
@@ -31,7 +32,7 @@ var plots = Plotly.Plots;
3132
* object describing the overall display of the plot,
3233
* all the stuff that doesn't pertain to any individual trace
3334
* @param {object} config
34-
* configuration options
35+
* configuration options (see ./plot_config.js for more info)
3536
*
3637
*/
3738
Plotly.plot = function(gd, data, layout, config) {
@@ -399,11 +400,6 @@ function setPlotContext(gd, config) {
399400
}
400401
});
401402

402-
// cause a remake of the modebar any time we change context
403-
if(gd._fullLayout && gd._fullLayout._modebar) {
404-
delete gd._fullLayout._modebar;
405-
}
406-
407403
// map plot3dPixelRatio to plotGlPixelRatio for backward compatibility
408404
if(config.plot3dPixelRatio && !context.plotGlPixelRatio) {
409405
context.plotGlPixelRatio = context.plot3dPixelRatio;
@@ -2176,7 +2172,6 @@ Plotly.relayout = function relayout(gd, astr, val) {
21762172
doplot = false,
21772173
docalc = false,
21782174
domodebar = false,
2179-
doSceneDragmode = false,
21802175
newkey, axes, keys, xyref, scene, axisAttr;
21812176

21822177
if(typeof astr === 'string') aobj[astr] = val;
@@ -2410,8 +2405,7 @@ Plotly.relayout = function relayout(gd, astr, val) {
24102405
* height, width, autosize get dealt with below. Except for the case of
24112406
* of subplots - scenes - which require scene.handleDragmode to be called.
24122407
*/
2413-
else if(ai==='hovermode') domodebar = true;
2414-
else if (ai === 'dragmode') doSceneDragmode = true;
2408+
else if(['hovermode', 'dragmode'].indexOf(ai) !== -1) domodebar = true;
24152409
else if(['hovermode','dragmode','height',
24162410
'width','autosize'].indexOf(ai)===-1) {
24172411
doplot = true;
@@ -2468,11 +2462,12 @@ Plotly.relayout = function relayout(gd, astr, val) {
24682462
return plots.previousPromises(gd);
24692463
});
24702464
}
2465+
24712466
// this is decoupled enough it doesn't need async regardless
2472-
if(domodebar) Plotly.Fx.modeBar(gd);
2467+
if(domodebar) {
2468+
manageModeBar(gd);
24732469

2474-
var subplotIds;
2475-
if(doSceneDragmode || domodebar) {
2470+
var subplotIds;
24762471
subplotIds = plots.getSubplotIds(fullLayout, 'gl3d');
24772472
for(i = 0; i < subplotIds.length; i++) {
24782473
scene = fullLayout[subplotIds[i]]._scene;
@@ -3006,7 +3001,7 @@ function lsInner(gd) {
30063001

30073002
Plotly.Titles.draw(gd, 'gtitle');
30083003

3009-
Plotly.Fx.modeBar(gd);
3004+
manageModeBar(gd);
30103005

30113006
return gd._promises.length && Promise.all(gd._promises);
30123007
}

src/plot_api/plot_config.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,24 @@ module.exports = {
5555
// false or function adding source(s) to linkText <text>
5656
showSources: false,
5757

58-
// display the modebar (true, false, or 'hover')
58+
// display the mode bar (true, false, or 'hover')
5959
displayModeBar: 'hover',
6060

61-
// add the plotly logo on the end of the modebar
61+
// remove mode bar button by name
62+
// (see ./components/modebar/buttons.js for the list of names)
63+
modeBarButtonsToRemove: [],
64+
65+
// add mode bar button using config objects
66+
// (see ./components/modebar/buttons.js for list of arguments)
67+
modeBarButtonsToAdd: [],
68+
69+
// fully custom mode bar buttons as nested array,
70+
// where the outer arrays represents button groups, and
71+
// the inner arrays have buttons config objects or names of default buttons
72+
// (see ./components/modebar/buttons.js for more info)
73+
modeBarButtons: false,
74+
75+
// add the plotly logo on the end of the mode bar
6276
displaylogo: true,
6377

6478
// increase the pixel ratio for Gl plot images

src/plotly.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ exports.Lib = require('./lib');
2525
exports.util = require('./lib/svg_text_utils');
2626
exports.Queue = require('./lib/queue');
2727

28-
// plot icons svg and plot css
29-
exports.Icons = require('../build/ploticon');
28+
// plot css
3029
require('../build/plotcss');
3130

3231
// configuration

src/plots/cartesian/axes.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -935,7 +935,7 @@ axes.doAutoRange = function(ax) {
935935
};
936936

937937
// save a copy of the initial axis ranges in fullLayout
938-
// use them in modebar and dblclick events
938+
// use them in mode bar and dblclick events
939939
axes.saveRangeInitial = function(gd, overwrite) {
940940
var axList = axes.list(gd, '', true),
941941
hasOneAxisChanged = false;

0 commit comments

Comments
 (0)