Skip to content

Commit 95e9259

Browse files
committed
modebar: make module more consistent with other components
by: - making modebar/index.js require what needs to be exposed for other parts of the code - in consequence old modebar/index.js -> modebar/modebar.js - var ModeBar = require('modebar/') and use ModeBar.manage in plot_api.js
1 parent 873f3ae commit 95e9259

File tree

5 files changed

+294
-282
lines changed

5 files changed

+294
-282
lines changed

src/components/modebar/index.js

+1-277
Original file line numberDiff line numberDiff line change
@@ -9,280 +9,4 @@
99

1010
'use strict';
1111

12-
var d3 = require('d3');
13-
14-
var Lib = require('../../lib');
15-
var Icons = require('../../../build/ploticon');
16-
17-
18-
/**
19-
* UI controller for interactive plots
20-
* @Class
21-
* @Param {object} opts
22-
* @Param {object} opts.buttons nested arrays of grouped buttons config objects
23-
* @Param {object} opts.container container div to append modeBar
24-
* @Param {object} opts.graphInfo primary plot object containing data and layout
25-
*/
26-
function ModeBar(opts) {
27-
this.container = opts.container;
28-
this.element = document.createElement('div');
29-
30-
this.update(opts.graphInfo, opts.buttons);
31-
32-
this.container.appendChild(this.element);
33-
}
34-
35-
var proto = ModeBar.prototype;
36-
37-
/**
38-
* Update modeBar (buttons and logo)
39-
*
40-
* @param {object} graphInfo primary plot object containing data and layout
41-
* @param {array of arrays} buttons nested arrays of grouped buttons to initialize
42-
*
43-
*/
44-
proto.update = function(graphInfo, buttons) {
45-
this.graphInfo = graphInfo;
46-
47-
var context = this.graphInfo._context;
48-
49-
if(context.displayModeBar === 'hover') {
50-
this.element.className = 'modebar modebar--hover';
51-
}
52-
else this.element.className = 'modebar';
53-
54-
// if buttons or logo have changed, redraw modebar interior
55-
var needsNewButtons = !this.hasButtons(buttons),
56-
needsNewLogo = (this.hasLogo !== context.displaylogo);
57-
58-
if(needsNewButtons || needsNewLogo) {
59-
this.removeAllButtons();
60-
61-
this.updateButtons(buttons);
62-
63-
if(context.displaylogo) {
64-
this.element.appendChild(this.getLogo());
65-
this.hasLogo = true;
66-
}
67-
}
68-
69-
this.updateActiveButton();
70-
};
71-
72-
proto.updateButtons = function(buttons) {
73-
var _this = this;
74-
75-
this.buttons = buttons;
76-
this.buttonElements = [];
77-
this.buttonsNames = [];
78-
79-
this.buttons.forEach(function(buttonGroup) {
80-
var group = _this.createGroup();
81-
82-
buttonGroup.forEach(function(buttonConfig) {
83-
var buttonName = buttonConfig.name;
84-
if(!buttonName) {
85-
throw new Error('must provide button \'name\' in button config');
86-
}
87-
if(_this.buttonsNames.indexOf(buttonName) !== -1) {
88-
throw new Error('button name \'' + buttonName + '\' is taken');
89-
}
90-
_this.buttonsNames.push(buttonName);
91-
92-
var button = _this.createButton(buttonConfig);
93-
_this.buttonElements.push(button);
94-
group.appendChild(button);
95-
});
96-
97-
_this.element.appendChild(group);
98-
});
99-
};
100-
101-
/**
102-
* Empty div for containing a group of buttons
103-
* @Return {HTMLelement}
104-
*/
105-
proto.createGroup = function() {
106-
var group = document.createElement('div');
107-
group.className = 'modebar-group';
108-
109-
return group;
110-
};
111-
112-
/**
113-
* Create a new button div and set constant and configurable attributes
114-
* @Param {object} config (see ./buttons.js for more info)
115-
* @Return {HTMLelement}
116-
*/
117-
proto.createButton = function(config) {
118-
var _this = this,
119-
button = document.createElement('a');
120-
121-
button.setAttribute('rel', 'tooltip');
122-
button.className = 'modebar-btn';
123-
124-
var title = config.title;
125-
if(title === undefined) title = config.name;
126-
if(title || title === 0) button.setAttribute('data-title', title);
127-
128-
if(config.attr !== undefined) button.setAttribute('data-attr', config.attr);
129-
130-
var val = config.val;
131-
if(val !== undefined) {
132-
if(typeof val === 'function') val = val(this.graphInfo);
133-
button.setAttribute('data-val', val);
134-
}
135-
136-
var click = config.click;
137-
if(typeof click !== 'function') {
138-
throw new Error('must provide button \'click\' function in button config');
139-
}
140-
else {
141-
button.addEventListener('click', function(ev) {
142-
config.click(_this.graphInfo, ev);
143-
144-
// only needed for 'hoverClosestGeo' which does not call relayout
145-
_this.updateActiveButton(ev.currentTarget);
146-
});
147-
}
148-
149-
button.setAttribute('data-toggle', config.toggle || false);
150-
if(config.toggle) button.classList.add('active');
151-
152-
button.appendChild(this.createIcon(config.icon || Icons.question));
153-
button.setAttribute('data-gravity', config.gravity || 'n');
154-
155-
return button;
156-
};
157-
158-
/**
159-
* Add an icon to a button
160-
* @Param {object} thisIcon
161-
* @Param {number} thisIcon.width
162-
* @Param {string} thisIcon.path
163-
* @Return {HTMLelement}
164-
*/
165-
proto.createIcon = function(thisIcon) {
166-
var iconHeight = thisIcon.ascent - thisIcon.descent,
167-
svgNS = 'http://www.w3.org/2000/svg',
168-
icon = document.createElementNS(svgNS, 'svg'),
169-
path = document.createElementNS(svgNS, 'path');
170-
171-
icon.setAttribute('height', '1em');
172-
icon.setAttribute('width', (thisIcon.width / iconHeight) + 'em');
173-
icon.setAttribute('viewBox', [0, 0, thisIcon.width, iconHeight].join(' '));
174-
175-
path.setAttribute('d', thisIcon.path);
176-
path.setAttribute('transform', 'matrix(1 0 0 -1 0 ' + thisIcon.ascent + ')');
177-
icon.appendChild(path);
178-
179-
return icon;
180-
};
181-
182-
/**
183-
* Updates active button with attribute specified in layout
184-
* @Param {object} graphInfo plot object containing data and layout
185-
* @Return {HTMLelement}
186-
*/
187-
proto.updateActiveButton = function(buttonClicked) {
188-
var fullLayout = this.graphInfo._fullLayout,
189-
dataAttrClicked = (buttonClicked !== undefined) ?
190-
buttonClicked.getAttribute('data-attr') :
191-
null;
192-
193-
this.buttonElements.forEach(function(button) {
194-
var thisval = button.getAttribute('data-val') || true,
195-
dataAttr = button.getAttribute('data-attr'),
196-
isToggleButton = (button.getAttribute('data-toggle') === 'true'),
197-
button3 = d3.select(button);
198-
199-
// Use 'data-toggle' and 'buttonClicked' to toggle buttons
200-
// that have no one-to-one equivalent in fullLayout
201-
if(isToggleButton) {
202-
if(dataAttr === dataAttrClicked) {
203-
button3.classed('active', !button3.classed('active'));
204-
}
205-
}
206-
else {
207-
var val = (dataAttr === null) ?
208-
dataAttr :
209-
Lib.nestedProperty(fullLayout, dataAttr).get();
210-
211-
button3.classed('active', val === thisval);
212-
}
213-
214-
});
215-
};
216-
217-
/**
218-
* Check if modeBar is configured as button configuration argument
219-
*
220-
* @Param {object} buttons 2d array of grouped button config objects
221-
* @Return {boolean}
222-
*/
223-
proto.hasButtons = function(buttons) {
224-
var currentButtons = this.buttons;
225-
226-
if(!currentButtons) return false;
227-
228-
if(buttons.length !== currentButtons.length) return false;
229-
230-
for(var i = 0; i < buttons.length; ++i) {
231-
if(buttons[i].length !== currentButtons[i].length) return false;
232-
for(var j = 0; j < buttons[i].length; j++) {
233-
if(buttons[i][j].name !== currentButtons[i][j].name) return false;
234-
}
235-
}
236-
237-
return true;
238-
};
239-
240-
/**
241-
* @return {HTMLDivElement} The logo image wrapped in a group
242-
*/
243-
proto.getLogo = function() {
244-
var group = this.createGroup(),
245-
a = document.createElement('a');
246-
247-
a.href = 'https://plot.ly/';
248-
a.target = '_blank';
249-
a.setAttribute('data-title', 'Produced with Plotly');
250-
a.className = 'modebar-btn plotlyjsicon modebar-btn--logo';
251-
252-
a.appendChild(this.createIcon(Icons.plotlylogo));
253-
254-
group.appendChild(a);
255-
return group;
256-
};
257-
258-
proto.removeAllButtons = function() {
259-
while(this.element.firstChild) {
260-
this.element.removeChild(this.element.firstChild);
261-
}
262-
263-
this.hasLogo = false;
264-
};
265-
266-
proto.destroy = function() {
267-
Lib.removeElement(this.container.querySelector('.modebar'));
268-
};
269-
270-
function createModeBar(gd, buttons) {
271-
var fullLayout = gd._fullLayout;
272-
273-
var modeBar = new ModeBar({
274-
graphInfo: gd,
275-
container: fullLayout._paperdiv.node(),
276-
buttons: buttons
277-
});
278-
279-
if(fullLayout._privateplot) {
280-
d3.select(modeBar.element).append('span')
281-
.classed('badge-private float--left', true)
282-
.text('PRIVATE');
283-
}
284-
285-
return modeBar;
286-
}
287-
288-
module.exports = createModeBar;
12+
exports.manage = require('./manage');

src/components/modebar/manage.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
var Axes = require('../../plots/cartesian/axes');
1313
var scatterSubTypes = require('../../traces/scatter/subtypes');
1414

15-
var createModeBar = require('./');
15+
var createModeBar = require('./modebar');
1616
var modeBarButtons = require('./buttons');
1717

1818
/**

0 commit comments

Comments
 (0)