Skip to content

Commit 009ae4d

Browse files
Ricardo Costaetimberg
authored andcommitted
Support hover animation duration during updates (#4300)
See discussion in the issue for context and possible approaches. When invoking update() inside an event handler, such as onHover, `options.hover.animationDuration` was not being respected. Given that some use cases may require additional animation properties for the manual update call, this commit changes that method signature to accept a configuration object. This object provides backwards compatibility with duration and lazy properties, and also introduces the easing property so that the event animation is different from the global one. Add tests that guarantee that when update is called manually with arguments, it properly builds the _bufferedRequest or calls render with the proper arguments. It includes test cases for when update is called with legacy arguments (duration and lazy) instead of the config object. .update() documentation was previously updated but .render() was left out. Since the backwards compatible change was also made to render(), this commit adds documentation for it.
1 parent 5e58114 commit 009ae4d

File tree

4 files changed

+149
-10
lines changed

4 files changed

+149
-10
lines changed

docs/developers/api.md

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ This must be called before the canvas is reused for a new chart.
1717
myLineChart.destroy();
1818
```
1919

20-
## .update(duration, lazy)
20+
## .update(config)
2121

2222
Triggers an update of the chart. This can be safely called after updating the data object. This will update all scales, legends, and then re-render the chart.
2323

@@ -30,6 +30,21 @@ myLineChart.update(); // Calling update now animates the position of March from
3030

3131
> **Note:** replacing the data reference (e.g. `myLineChart.data = {datasets: [...]}` only works starting **version 2.6**. Prior that, replacing the entire data object could be achieved with the following workaround: `myLineChart.config.data = {datasets: [...]}`.
3232
33+
A `config` object can be provided with additional configuration for the update process. This is useful when `update` is manually called inside an event handler and some different animation is desired.
34+
35+
The following properties are supported:
36+
* **duration** (number): Time for the animation of the redraw in milliseconds
37+
* **lazy** (boolean): If true, the animation can be interrupted by other animations
38+
* **easing** (string): The animation easing function. See [Animation Easing](../configuration/animations.md) for possible values.
39+
40+
Example:
41+
```javascript
42+
myChart.update({
43+
duration: 800,
44+
easing: 'easeOutBounce'
45+
})
46+
```
47+
3348
See [Updating Charts](updates.md) for more details.
3449

3550
## .reset()
@@ -40,14 +55,20 @@ Reset the chart to it's state before the initial animation. A new animation can
4055
myLineChart.reset();
4156
```
4257

43-
## .render(duration, lazy)
58+
## .render(config)
4459

4560
Triggers a redraw of all chart elements. Note, this does not update elements for new data. Use `.update()` in that case.
4661

62+
See `.update(config)` for more details on the config object.
63+
4764
```javascript
4865
// duration is the time for the animation of the redraw in milliseconds
4966
// lazy is a boolean. if true, the animation can be interrupted by other animations
50-
myLineChart.render(duration, lazy);
67+
myLineChart.render({
68+
duration: 800,
69+
lazy: false,
70+
easing: 'easeOutBounce'
71+
});
5172
```
5273

5374
## .stop()

src/core/core.controller.js

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -334,9 +334,17 @@ module.exports = function(Chart) {
334334
this.tooltip.initialize();
335335
},
336336

337-
update: function(animationDuration, lazy) {
337+
update: function(config) {
338338
var me = this;
339339

340+
if (!config || typeof config !== 'object') {
341+
// backwards compatibility
342+
config = {
343+
duration: config,
344+
lazy: arguments[1]
345+
};
346+
}
347+
340348
updateConfig(me);
341349

342350
if (plugins.notify(me, 'beforeUpdate') === false) {
@@ -368,11 +376,12 @@ module.exports = function(Chart) {
368376

369377
if (me._bufferedRender) {
370378
me._bufferedRequest = {
371-
lazy: lazy,
372-
duration: animationDuration
379+
duration: config.duration,
380+
easing: config.easing,
381+
lazy: config.lazy
373382
};
374383
} else {
375-
me.render(animationDuration, lazy);
384+
me.render(config);
376385
}
377386
},
378387

@@ -442,9 +451,20 @@ module.exports = function(Chart) {
442451
plugins.notify(me, 'afterDatasetUpdate', [args]);
443452
},
444453

445-
render: function(duration, lazy) {
454+
render: function(config) {
446455
var me = this;
447456

457+
if (!config || typeof config !== 'object') {
458+
// backwards compatibility
459+
config = {
460+
duration: config,
461+
lazy: arguments[1]
462+
};
463+
}
464+
465+
var duration = config.duration;
466+
var lazy = config.lazy;
467+
448468
if (plugins.notify(me, 'beforeRender') === false) {
449469
return;
450470
}
@@ -458,7 +478,7 @@ module.exports = function(Chart) {
458478
if (animationOptions && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && animationOptions.duration !== 0))) {
459479
var animation = new Chart.Animation({
460480
numSteps: (duration || animationOptions.duration) / 16.66, // 60 fps
461-
easing: animationOptions.easing,
481+
easing: config.easing || animationOptions.easing,
462482

463483
render: function(chart, animationObject) {
464484
var easingFunction = helpers.easingEffects[animationObject.easing];
@@ -771,7 +791,7 @@ module.exports = function(Chart) {
771791
var bufferedRequest = me._bufferedRequest;
772792
if (bufferedRequest) {
773793
// If we have an update that was triggered, we need to do a normal render
774-
me.render(bufferedRequest.duration, bufferedRequest.lazy);
794+
me.render(bufferedRequest);
775795
} else if (changed && !me.animating) {
776796
// If entering, leaving, or changing elements, animate the change via pivot
777797
me.stop();

test/specs/core.controller.tests.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,4 +807,46 @@ describe('Chart', function() {
807807
]);
808808
});
809809
});
810+
811+
describe('controller.update', function() {
812+
beforeEach(function() {
813+
this.chart = acquireChart({
814+
type: 'doughnut',
815+
options: {
816+
animation: {
817+
easing: 'linear',
818+
duration: 500
819+
}
820+
}
821+
});
822+
823+
this.addAnimationSpy = spyOn(Chart.animationService, 'addAnimation');
824+
});
825+
826+
it('should add an animation with the default options', function() {
827+
this.chart.update();
828+
829+
expect(this.addAnimationSpy).toHaveBeenCalledWith(
830+
this.chart,
831+
jasmine.objectContaining({easing: 'linear'}),
832+
undefined,
833+
undefined
834+
);
835+
});
836+
837+
it('should add an animation with the provided options', function() {
838+
this.chart.update({
839+
duration: 800,
840+
easing: 'easeOutBounce',
841+
lazy: false,
842+
});
843+
844+
expect(this.addAnimationSpy).toHaveBeenCalledWith(
845+
this.chart,
846+
jasmine.objectContaining({easing: 'easeOutBounce'}),
847+
800,
848+
false
849+
);
850+
});
851+
});
810852
});

test/specs/global.deprecations.tests.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,60 @@
11
describe('Deprecations', function() {
2+
describe('Version 2.7.0', function() {
3+
describe('Chart.Controller.update(duration, lazy)', function() {
4+
beforeEach(function() {
5+
this.chart = acquireChart({
6+
type: 'doughnut',
7+
options: {
8+
animation: {
9+
easing: 'linear',
10+
duration: 500
11+
}
12+
}
13+
});
14+
15+
this.addAnimationSpy = spyOn(Chart.animationService, 'addAnimation');
16+
});
17+
18+
it('should add an animation with the provided options', function() {
19+
this.chart.update(800, false);
20+
21+
expect(this.addAnimationSpy).toHaveBeenCalledWith(
22+
this.chart,
23+
jasmine.objectContaining({easing: 'linear'}),
24+
800,
25+
false
26+
);
27+
});
28+
});
29+
30+
describe('Chart.Controller.render(duration, lazy)', function() {
31+
beforeEach(function() {
32+
this.chart = acquireChart({
33+
type: 'doughnut',
34+
options: {
35+
animation: {
36+
easing: 'linear',
37+
duration: 500
38+
}
39+
}
40+
});
41+
42+
this.addAnimationSpy = spyOn(Chart.animationService, 'addAnimation');
43+
});
44+
45+
it('should add an animation with the provided options', function() {
46+
this.chart.render(800, true);
47+
48+
expect(this.addAnimationSpy).toHaveBeenCalledWith(
49+
this.chart,
50+
jasmine.objectContaining({easing: 'linear'}),
51+
800,
52+
true
53+
);
54+
});
55+
});
56+
});
57+
258
describe('Version 2.6.0', function() {
359
// https://github.com/chartjs/Chart.js/issues/2481
460
describe('Chart.Controller', function() {

0 commit comments

Comments
 (0)