Skip to content

Commit 9ccde7e

Browse files
committed
Merge branch 'master' into dates-as-dates
2 parents 451ee24 + 000a409 commit 9ccde7e

40 files changed

+3136
-378
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@
8585
"ndarray-ops": "^1.2.2",
8686
"right-now": "^1.0.0",
8787
"robust-orientation": "^1.1.3",
88-
"sane-topojson": "^1.2.0",
88+
"sane-topojson": "^2.0.0",
8989
"superscript-text": "^1.0.0",
9090
"tinycolor2": "^1.3.0",
9191
"topojson": "^1.6.20",

src/components/images/draw.js

+24-18
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,21 @@ module.exports = function draw(gd) {
5555
function setImage(d) {
5656
var thisImage = d3.select(this);
5757

58+
if(this.img && this.img.src === d.source) {
59+
return;
60+
}
61+
5862
thisImage.attr('xmlns', xmlnsNamespaces.svg);
5963

6064
var imagePromise = new Promise(function(resolve) {
6165

6266
var img = new Image();
67+
this.img = img;
6368

6469
// If not set, a `tainted canvas` error is thrown
6570
img.setAttribute('crossOrigin', 'anonymous');
6671
img.onerror = errorHandler;
6772
img.onload = function() {
68-
6973
var canvas = document.createElement('canvas');
7074
canvas.width = this.width;
7175
canvas.height = this.height;
@@ -88,7 +92,7 @@ module.exports = function draw(gd) {
8892
thisImage.remove();
8993
resolve();
9094
}
91-
});
95+
}.bind(this));
9296

9397
gd._promises.push(imagePromise);
9498
}
@@ -146,29 +150,31 @@ module.exports = function draw(gd) {
146150
}
147151
}
148152

149-
150-
// Required for updating images
151-
function keyFunction(d, i) {
152-
return d.source + i;
153-
}
154-
155-
156153
var imagesBelow = fullLayout._imageLowerLayer.selectAll('image')
157-
.data(imageDataBelow, keyFunction),
154+
.data(imageDataBelow),
158155
imagesSubplot = fullLayout._imageSubplotLayer.selectAll('image')
159-
.data(imageDataSubplot, keyFunction),
156+
.data(imageDataSubplot),
160157
imagesAbove = fullLayout._imageUpperLayer.selectAll('image')
161-
.data(imageDataAbove, keyFunction);
158+
.data(imageDataAbove);
162159

163-
imagesBelow.enter().append('image').each(setImage);
164-
imagesSubplot.enter().append('image').each(setImage);
165-
imagesAbove.enter().append('image').each(setImage);
160+
imagesBelow.enter().append('image');
161+
imagesSubplot.enter().append('image');
162+
imagesAbove.enter().append('image');
166163

167164
imagesBelow.exit().remove();
168165
imagesSubplot.exit().remove();
169166
imagesAbove.exit().remove();
170167

171-
imagesBelow.each(applyAttributes);
172-
imagesSubplot.each(applyAttributes);
173-
imagesAbove.each(applyAttributes);
168+
imagesBelow.each(function(d) {
169+
setImage.bind(this)(d);
170+
applyAttributes.bind(this)(d);
171+
});
172+
imagesSubplot.each(function(d) {
173+
setImage.bind(this)(d);
174+
applyAttributes.bind(this)(d);
175+
});
176+
imagesAbove.each(function(d) {
177+
setImage.bind(this)(d);
178+
applyAttributes.bind(this)(d);
179+
});
174180
};

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/lib/coerce.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ exports.valObjects = {
228228
any: {
229229
description: 'Any type.',
230230
requiredOpts: [],
231-
otherOpts: ['dflt', 'values'],
231+
otherOpts: ['dflt', 'values', 'arrayOk'],
232232
coerceFunction: function(v, propOut, dflt) {
233233
if(v === undefined) propOut.set(dflt);
234234
else propOut.set(v);

src/plot_api/plot_api.js

+11-8
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,7 @@ function _restyle(gd, aobj, _traces) {
12671267
'x', 'y', 'z',
12681268
'a', 'b', 'c',
12691269
'open', 'high', 'low', 'close',
1270+
'base', 'width', 'offset',
12701271
'xtype', 'x0', 'dx', 'ytype', 'y0', 'dy', 'xaxis', 'yaxis',
12711272
'line.width',
12721273
'connectgaps', 'transpose', 'zsmooth',
@@ -2325,14 +2326,7 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, animationOpts) {
23252326
var newFrame = trans._currentFrame = trans._frameQueue.shift();
23262327

23272328
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-
});
2329+
gd._fullLayout._currentFrame = newFrame.name;
23362330

23372331
trans._lastFrameAt = Date.now();
23382332
trans._timeToNext = newFrame.frameOpts.duration;
@@ -2347,6 +2341,15 @@ Plotly.animate = function(gd, frameOrGroupNameOrFrameList, animationOpts) {
23472341
newFrame.frameOpts,
23482342
newFrame.transitionOpts
23492343
);
2344+
2345+
gd.emit('plotly_animatingframe', {
2346+
name: newFrame.name,
2347+
frame: newFrame.frame,
2348+
animation: {
2349+
frame: newFrame.frameOpts,
2350+
transition: newFrame.transitionOpts,
2351+
}
2352+
});
23502353
} else {
23512354
// If there are no more frames, then stop the RAF loop:
23522355
stopAnimationLoop();

0 commit comments

Comments
 (0)