Skip to content

Commit 297f0a7

Browse files
authored
Merge pull request #1016 from plotly/lib-commands
Common interface to interpret and execute API methods
2 parents ec0b0a4 + df2d5bb commit 297f0a7

File tree

11 files changed

+1279
-41
lines changed

11 files changed

+1279
-41
lines changed

src/components/sliders/attributes.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ module.exports = {
6969
active: {
7070
valType: 'number',
7171
role: 'info',
72-
min: -10,
72+
min: 0,
7373
dflt: 0,
7474
description: [
7575
'Determines which button (by index starting from 0) is',

src/components/sliders/draw.js

+23-15
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
var d3 = require('d3');
1313

14-
var Plotly = require('../../plotly');
1514
var Plots = require('../../plots/plots');
1615
var Lib = require('../../lib');
1716
var Color = require('../color');
@@ -52,6 +51,9 @@ module.exports = function draw(gd) {
5251
sliderGroups.exit().each(function(sliderOpts) {
5352
d3.select(this).remove();
5453

54+
sliderOpts._commandObserver.remove();
55+
delete sliderOpts._commandObserver;
56+
5557
Plots.autoMargin(gd, constants.autoMarginIdRoot + sliderOpts._index);
5658
});
5759

@@ -65,12 +67,20 @@ module.exports = function draw(gd) {
6567
// If it has fewer than two options, it's not really a slider:
6668
if(sliderOpts.steps.length < 2) return;
6769

70+
var gSlider = d3.select(this);
71+
6872
computeLabelSteps(sliderOpts);
6973

74+
Plots.manageCommandObserver(gd, sliderOpts, sliderOpts.steps, function(data) {
75+
if(sliderOpts.active === data.index) return;
76+
if(sliderOpts._dragging) return;
77+
78+
setActive(gd, gSlider, sliderOpts, data.index, false, true);
79+
});
80+
7081
drawSlider(gd, d3.select(this), sliderOpts);
7182

7283
// makeInputProxy(gd, d3.select(this), sliderOpts);
73-
7484
});
7585
};
7686

@@ -227,7 +237,9 @@ function drawSlider(gd, sliderGroup, sliderOpts) {
227237
// Position the rectangle:
228238
Lib.setTranslate(sliderGroup, sliderOpts.lx + sliderOpts.pad.l, sliderOpts.ly + sliderOpts.pad.t);
229239

230-
setActive(gd, sliderGroup, sliderOpts, sliderOpts.active, false, false);
240+
sliderGroup.call(setGripPosition, sliderOpts, sliderOpts.active / (sliderOpts.steps.length - 1), false);
241+
sliderGroup.call(drawCurrentValue, sliderOpts);
242+
231243
}
232244

233245
function drawCurrentValue(sliderGroup, sliderOpts, valueOverride) {
@@ -371,19 +383,9 @@ function setActive(gd, sliderGroup, sliderOpts, index, doCallback, doTransition)
371383
sliderGroup._nextMethod = {step: step, doCallback: doCallback, doTransition: doTransition};
372384
sliderGroup._nextMethodRaf = window.requestAnimationFrame(function() {
373385
var _step = sliderGroup._nextMethod.step;
374-
var args = _step.args;
375386
if(!_step.method) return;
376387

377-
sliderOpts._invokingCommand = true;
378-
Plotly[_step.method](gd, args[0], args[1], args[2]).then(function() {
379-
sliderOpts._invokingCommand = false;
380-
}, function() {
381-
sliderOpts._invokingCommand = false;
382-
383-
// This is not a disaster. Some methods like `animate` reject if interrupted
384-
// and *should* nicely log a warning.
385-
Lib.warn('Warning: Plotly.' + _step.method + ' was called and rejected.');
386-
});
388+
Plots.executeAPICommand(gd, _step.method, _step.args);
387389

388390
sliderGroup._nextMethod = null;
389391
sliderGroup._nextMethodRaf = null;
@@ -405,13 +407,15 @@ function attachGripEvents(item, gd, sliderGroup, sliderOpts) {
405407

406408
var normalizedPosition = positionToNormalizedValue(sliderOpts, d3.mouse(node)[0]);
407409
handleInput(gd, sliderGroup, sliderOpts, normalizedPosition, true);
410+
sliderOpts._dragging = true;
408411

409412
$gd.on('mousemove', function() {
410413
var normalizedPosition = positionToNormalizedValue(sliderOpts, d3.mouse(node)[0]);
411414
handleInput(gd, sliderGroup, sliderOpts, normalizedPosition, false);
412415
});
413416

414417
$gd.on('mouseup', function() {
418+
sliderOpts._dragging = false;
415419
grip.call(Color.fill, sliderOpts.bgcolor);
416420
$gd.on('mouseup', null);
417421
$gd.on('mousemove', null);
@@ -467,8 +471,12 @@ function setGripPosition(sliderGroup, sliderOpts, position, doTransition) {
467471

468472
var x = normalizedValueToPosition(sliderOpts, position);
469473

474+
// If this is true, then *this component* is already invoking its own command
475+
// and has triggered its own animation.
476+
if(sliderOpts._invokingCommand) return;
477+
470478
var el = grip;
471-
if(doTransition && sliderOpts.transition.duration > 0 && !sliderOpts._invokingCommand) {
479+
if(doTransition && sliderOpts.transition.duration > 0) {
472480
el = el.transition()
473481
.duration(sliderOpts.transition.duration)
474482
.ease(sliderOpts.transition.easing);

src/components/updatemenus/draw.js

+23-16
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
var d3 = require('d3');
1313

14-
var Plotly = require('../../plotly');
1514
var Plots = require('../../plots/plots');
1615
var Lib = require('../../lib');
1716
var Color = require('../color');
@@ -21,7 +20,6 @@ var anchorUtils = require('../legend/anchor_utils');
2120

2221
var constants = require('./constants');
2322

24-
2523
module.exports = function draw(gd) {
2624
var fullLayout = gd._fullLayout,
2725
menuData = makeMenuData(fullLayout);
@@ -115,6 +113,11 @@ module.exports = function draw(gd) {
115113
headerGroups.each(function(menuOpts) {
116114
var gHeader = d3.select(this);
117115

116+
var _gButton = menuOpts.type === 'dropdown' ? gButton : null;
117+
Plots.manageCommandObserver(gd, menuOpts, menuOpts.buttons, function(data) {
118+
setActive(gd, menuOpts, menuOpts.buttons[data.index], gHeader, _gButton, data.index, true);
119+
});
120+
118121
if(menuOpts.type === 'dropdown') {
119122
drawHeader(gd, gHeader, gButton, menuOpts);
120123

@@ -293,21 +296,9 @@ function drawButtons(gd, gHeader, gButton, menuOpts) {
293296
.call(setItemPosition, menuOpts, posOpts);
294297

295298
button.on('click', function() {
296-
// update 'active' attribute in menuOpts
297-
menuOpts._input.active = menuOpts.active = buttonIndex;
298-
299-
// fold up buttons and redraw header
300-
gButton.attr(constants.menuIndexAttrName, '-1');
299+
setActive(gd, menuOpts, buttonOpts, gHeader, gButton, buttonIndex);
301300

302-
if(menuOpts.type === 'dropdown') {
303-
drawHeader(gd, gHeader, gButton, menuOpts);
304-
}
305-
306-
drawButtons(gd, gHeader, gButton, menuOpts);
307-
308-
// call button method
309-
var args = buttonOpts.args;
310-
Plotly[buttonOpts.method](gd, args[0], args[1], args[2]);
301+
Plots.executeAPICommand(gd, buttonOpts.method, buttonOpts.args);
311302
});
312303

313304
button.on('mouseover', function() {
@@ -326,6 +317,22 @@ function drawButtons(gd, gHeader, gButton, menuOpts) {
326317
Lib.setTranslate(gButton, menuOpts.lx, menuOpts.ly);
327318
}
328319

320+
function setActive(gd, menuOpts, buttonOpts, gHeader, gButton, buttonIndex, isSilentUpdate) {
321+
// update 'active' attribute in menuOpts
322+
menuOpts._input.active = menuOpts.active = buttonIndex;
323+
324+
if(menuOpts.type === 'dropdown') {
325+
// fold up buttons and redraw header
326+
gButton.attr(constants.menuIndexAttrName, '-1');
327+
328+
drawHeader(gd, gHeader, gButton, menuOpts);
329+
}
330+
331+
if(!isSilentUpdate || menuOpts.type === 'buttons') {
332+
drawButtons(gd, gHeader, gButton, menuOpts);
333+
}
334+
}
335+
329336
function drawItem(item, menuOpts, itemOpts) {
330337
item.call(drawItemRect, menuOpts)
331338
.call(drawItemText, menuOpts, itemOpts);

src/plot_api/plot_api.js

+10-8
Original file line numberDiff line numberDiff line change
@@ -2325,14 +2325,7 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, animationOpts) {
23252325
var newFrame = trans._currentFrame = trans._frameQueue.shift();
23262326

23272327
if(newFrame) {
2328-
gd.emit('plotly_animatingframe', {
2329-
name: newFrame.name,
2330-
frame: newFrame.frame,
2331-
animation: {
2332-
frame: newFrame.frameOpts,
2333-
transition: newFrame.transitionOpts,
2334-
}
2335-
});
2328+
gd._fullLayout._currentFrame = newFrame.name;
23362329

23372330
trans._lastFrameAt = Date.now();
23382331
trans._timeToNext = newFrame.frameOpts.duration;
@@ -2347,6 +2340,15 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, animationOpts) {
23472340
newFrame.frameOpts,
23482341
newFrame.transitionOpts
23492342
);
2343+
2344+
gd.emit('plotly_animatingframe', {
2345+
name: newFrame.name,
2346+
frame: newFrame.frame,
2347+
animation: {
2348+
frame: newFrame.frameOpts,
2349+
transition: newFrame.transitionOpts,
2350+
}
2351+
});
23502352
} else {
23512353
// If there are no more frames, then stop the RAF loop:
23522354
stopAnimationLoop();

0 commit comments

Comments
 (0)