Skip to content

Commit b83f64b

Browse files
kurkleetimberg
authored andcommitted
Rewrite animation logic (#6845)
* Rewrite animation logic * Review update 1 * Review update 2 * Review update 3 * Add 'none' to api.md
1 parent 3abe9bf commit b83f64b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+2832
-2509
lines changed

.eslintrc.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
extends: chartjs
22

33
env:
4+
es6: true
45
browser: true
56
node: true
67

docs/configuration/animations.md

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,33 @@ The following animation options are available. The global options for are define
1010
| ---- | ---- | ------- | -----------
1111
| `duration` | `number` | `1000` | The number of milliseconds an animation takes.
1212
| `easing` | `string` | `'easeOutQuart'` | Easing function to use. [more...](#easing)
13+
| `debug` | `boolean` | `undefined` | Running animation count + FPS display in upper left corner of the chart.
1314
| `onProgress` | `function` | `null` | Callback called on each step of an animation. [more...](#animation-callbacks)
14-
| `onComplete` | `function` | `null` | Callback called at the end of an animation. [more...](#animation-callbacks)
15+
| `onComplete` | `function` | `null` | Callback called when all animations are completed. [more...](#animation-callbacks)
16+
| `delay` | `number` | `undefined` | Delay before starting the animations.
17+
| `loop` | `boolean` | `undefined` | If set to `true`, loop the animations loop endlessly.
18+
| `type` | `string` | `typeof property` | Type of property, determines the interpolator used. Possible values: `'number'`, '`color`'.
19+
| `from` | <code>number&#124;Color</code> | `undefined` | Start value for the animation. Current value is used when `undefined`
20+
| `active` | `object` | `{ duration: 400 }` | Option overrides for `active` animations (hover)
21+
| `resize` | `object` | `{ duration: 0 }` | Option overrides for `resize` animations.
22+
| [property] | `object` | `undefined` | Option overrides for [property].
23+
| [collection] | `object` | `undefined` | Option overrides for multiple properties, identified by `properties` array.
24+
25+
Default collections:
26+
| Name | option | value
27+
| `numbers` | `type` | `'number'`
28+
| | `properties` | `['x', 'y', 'borderWidth', 'radius', 'tension']`
29+
| `colors` | `type` | `'color'`
30+
| | `properties` | `['borderColor', 'backgroundColor']`
31+
32+
Direct property configuration overrides configuration of same property in a collection.
33+
34+
These defaults can be overridden in `options.animation` and `dataset.animation`.
1535

1636
## Easing
1737

1838
Available options are:
39+
1940
* `'linear'`
2041
* `'easeInQuad'`
2142
* `'easeOutQuad'`
@@ -52,34 +73,23 @@ See [Robert Penner's easing equations](http://robertpenner.com/easing/).
5273

5374
## Animation Callbacks
5475

55-
The `onProgress` and `onComplete` callbacks are useful for synchronizing an external draw to the chart animation. The callback is passed a `Chart.Animation` instance:
76+
The `onProgress` and `onComplete` callbacks are useful for synchronizing an external draw to the chart animation. The callback is passed following object:
5677

5778
```javascript
5879
{
5980
// Chart object
6081
chart: Chart,
6182

62-
// Current Animation frame number
83+
// Number of animations still in progress
6384
currentStep: number,
6485

65-
// Number of animation frames
86+
// Total number of animations at the start of current animation
6687
numSteps: number,
67-
68-
// Animation easing to use
69-
easing: string,
70-
71-
// Function that renders the chart
72-
render: function,
73-
74-
// User callback
75-
onAnimationProgress: function,
76-
77-
// User callback
78-
onAnimationComplete: function
7988
}
8089
```
8190

8291
The following example fills a progress bar during the chart animation.
92+
8393
```javascript
8494
var chart = new Chart(ctx, {
8595
type: 'line',

docs/configuration/tooltip.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ The tooltip model contains parameters that can be used to render the tooltip.
356356

357357
// 0 opacity is a hidden tooltip
358358
opacity: number,
359-
legendColorBackground: Color,
359+
multiKeyBackground: Color,
360360
displayColors: boolean,
361361
borderColor: Color,
362362
borderWidth: number

docs/developers/api.md

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

20-
## .update(config)
20+
## .update(mode)
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

2424
```javascript
25-
// duration is the time for the animation of the redraw in milliseconds
26-
// lazy is a boolean. if true, the animation can be interrupted by other animations
2725
myLineChart.data.datasets[0].data[2] = 50; // Would update the first dataset's value of 'March' to be 50
2826
myLineChart.update(); // Calling update now animates the position of March from 90 to 50.
2927
```
3028

3129
> **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: [...]}`.
3230
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.
31+
A `mode` string can be provided to indicate what should be updated and what animation configuration should be used. Core calls this method using any of `undefined`, `'reset'`, `'resize'` or `'active'`. `'none'` is also a supported mode for skipping animations for single update.
3932

4033
Example:
34+
4135
```javascript
42-
myChart.update({
43-
duration: 800,
44-
easing: 'easeOutBounce'
45-
});
36+
myChart.update();
4637
```
4738

4839
See [Updating Charts](updates.md) for more details.
@@ -55,25 +46,13 @@ Reset the chart to it's state before the initial animation. A new animation can
5546
myLineChart.reset();
5647
```
5748

58-
## .render(config)
49+
## .render()
5950

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

62-
See `.update(config)` for more details on the config object.
63-
64-
```javascript
65-
// duration is the time for the animation of the redraw in milliseconds
66-
// lazy is a boolean. if true, the animation can be interrupted by other animations
67-
myLineChart.render({
68-
duration: 800,
69-
lazy: false,
70-
easing: 'easeOutBounce'
71-
});
72-
```
73-
7453
## .stop()
7554

76-
Use this to stop any current animation loop. This will pause the chart during any current animation frame. Call `.render()` to re-animate.
55+
Use this to stop any current animation. This will pause the chart during any current animation frame. Call `.render()` to re-animate.
7756

7857
```javascript
7958
// Stops the charts animation loop at its current frame
@@ -175,5 +154,5 @@ Extensive examples of usage are available in the [Chart.js tests](https://github
175154

176155
```javascript
177156
var meta = myChart.getDatasetMeta(0);
178-
var x = meta.data[0]._model.x;
157+
var x = meta.data[0].x;
179158
```

docs/developers/charts.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,13 +94,13 @@ var custom = Chart.controllers.bubble.extend({
9494
// Now we can do some custom drawing for this dataset. Here we'll draw a red box around the first point in each dataset
9595
var meta = this.getMeta();
9696
var pt0 = meta.data[0];
97-
var radius = pt0._view.radius;
97+
var radius = pt0.radius;
9898

9999
var ctx = this.chart.chart.ctx;
100100
ctx.save();
101101
ctx.strokeStyle = 'red';
102102
ctx.lineWidth = 1;
103-
ctx.strokeRect(pt0._view.x - radius, pt0._view.y - radius, 2 * radius, 2 * radius);
103+
ctx.strokeRect(pt0.x - radius, pt0.y - radius, 2 * radius, 2 * radius);
104104
ctx.restore();
105105
}
106106
});

docs/developers/updates.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,4 @@ Code sample for updating options can be found in [toggle-scale-type.html](../../
9797

9898
## Preventing Animations
9999

100-
Sometimes when a chart updates, you may not want an animation. To achieve this you can call `update` with a duration of `0`. This will render the chart synchronously and without an animation.
100+
Sometimes when a chart updates, you may not want an animation. To achieve this you can call `update` with `'none'` as mode.

docs/general/interactions/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,3 @@ The hover configuration is passed into the `options.hover` namespace. The global
77
| `mode` | `string` | `'nearest'` | Sets which elements appear in the tooltip. See [Interaction Modes](./modes.md#interaction-modes) for details.
88
| `intersect` | `boolean` | `true` | if true, the hover mode only applies when the mouse position intersects an item on the chart.
99
| `axis` | `string` | `'x'` | Can be set to `'x'`, `'y'`, or `'xy'` to define which directions are used in calculating distances. Defaults to `'x'` for `'index'` mode and `'xy'` in `dataset` and `'nearest'` modes.
10-
| `animationDuration` | `number` | `400` | Duration in milliseconds it takes to animate hover style changes.

docs/general/performance.md

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,7 @@ new Chart(ctx, {
2323
type: 'line',
2424
data: data,
2525
options: {
26-
animation: {
27-
duration: 0 // general animation time
28-
},
29-
hover: {
30-
animationDuration: 0 // duration of animations when hovering an item
31-
},
32-
responsiveAnimationDuration: 0 // animation duration after a resize
26+
animation: false
3327
}
3428
});
3529
```

docs/general/responsive.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ Chart.js provides a [few options](#configuration-options) to enable responsivene
1414
| Name | Type | Default | Description
1515
| ---- | ---- | ------- | -----------
1616
| `responsive` | `boolean` | `true` | Resizes the chart canvas when its container does ([important note...](#important-note)).
17-
| `responsiveAnimationDuration` | `number` | `0` | Duration in milliseconds it takes to animate to new size after a resize event.
1817
| `maintainAspectRatio` | `boolean` | `true` | Maintain the original canvas aspect ratio `(width / height)` when resizing.
1918
| `aspectRatio` | `number` | `2` | Canvas aspect ratio (i.e. `width / height`, a value of 1 representing a square canvas). Note that this option is ignored if the height is explicitly defined either as attribute or via the style.
2019
| `onResize` | `function` | `null` | Called when a resize occurs. Gets passed two arguments: the chart instance and the new size.

docs/getting-started/v3-migration.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ Chart.js 3.0 introduces a number of breaking changes. Chart.js 2.0 was released
4949
* `scales.[x/y]Axes.time.max` was renamed to `scales[id].max`
5050
* `scales.[x/y]Axes.time.min` was renamed to `scales[id].min`
5151

52+
### Animations
53+
54+
Animation system was completely rewritten in Chart.js v3. Each property can now be animated separately. Please see [animations](../configuration/animations.md) docs for details.
55+
56+
* `hover.animationDuration` is now configured in `animation.active.duration`
57+
* `responsiveAnimationDuration` is now configured in `animation.resize.duration`
58+
5259
## Developer migration
5360

5461
### Removed
@@ -90,10 +97,8 @@ Chart.js 3.0 introduces a number of breaking changes. Chart.js 2.0 was released
9097

9198
* `Chart.data.datasets[datasetIndex]._meta`
9299
* `Element._ctx`
93-
* `Element._model.datasetLabel`
94-
* `Element._model.label`
95-
* `Point._model.tension`
96-
* `Point._model.steppedLine`
100+
* `Element._model`
101+
* `Element._view`
97102
* `TimeScale._getPixelForOffset`
98103
* `TimeScale.getLabelWidth`
99104

@@ -108,7 +113,6 @@ Chart.js 3.0 introduces a number of breaking changes. Chart.js 2.0 was released
108113
* `helpers.log10` was renamed to `helpers.math.log10`
109114
* `helpers.almostEquals` was renamed to `helpers.math.almostEquals`
110115
* `helpers.almostWhole` was renamed to `helpers.math.almostWhole`
111-
* `helpers._decimalPlaces` was renamed to `helpers.math._decimalPlaces`
112116
* `helpers.distanceBetweenPoints` was renamed to `helpers.math.distanceBetweenPoints`
113117
* `helpers.isNumber` was renamed to `helpers.math.isNumber`
114118
* `helpers.sign` was renamed to `helpers.math.sign`
@@ -129,10 +133,12 @@ Chart.js 3.0 introduces a number of breaking changes. Chart.js 2.0 was released
129133
* `TimeScale.getLabelCapacity` was renamed to `TimeScale._getLabelCapacity`
130134
* `TimeScale.tickFormatFunction` was renamed to `TimeScale._tickFormatFunction`
131135
* `TimeScale.getPixelForOffset` was renamed to `TimeScale._getPixelForOffset`
136+
* `Tooltip.options.legendColorBackgroupd` was renamed to `Tooltip.options.multiKeyBackground`
132137

133138
#### Renamed private APIs
134139

135140
* `helpers._alignPixel` was renamed to `helpers.canvas._alignPixel`
141+
* `helpers._decimalPlaces` was renamed to `helpers.math._decimalPlaces`
136142

137143
### Changed
138144

samples/animations/delay.html

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<!doctype html>
2+
<html>
3+
4+
<head>
5+
<title>Stacked Bar Chart</title>
6+
<script src="../../dist/Chart.min.js"></script>
7+
<script src="../utils.js"></script>
8+
<style>
9+
canvas {
10+
-moz-user-select: none;
11+
-webkit-user-select: none;
12+
-ms-user-select: none;
13+
}
14+
</style>
15+
</head>
16+
17+
<body>
18+
<div style="width: 75%">
19+
<canvas id="canvas"></canvas>
20+
</div>
21+
<button id="randomizeData">Randomize Data</button>
22+
<script>
23+
var barChartData = {
24+
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
25+
datasets: [{
26+
label: 'Dataset 1',
27+
backgroundColor: window.chartColors.red,
28+
data: [
29+
randomScalingFactor(),
30+
randomScalingFactor(),
31+
randomScalingFactor(),
32+
randomScalingFactor(),
33+
randomScalingFactor(),
34+
randomScalingFactor(),
35+
randomScalingFactor()
36+
]
37+
}, {
38+
label: 'Dataset 2',
39+
backgroundColor: window.chartColors.blue,
40+
data: [
41+
randomScalingFactor(),
42+
randomScalingFactor(),
43+
randomScalingFactor(),
44+
randomScalingFactor(),
45+
randomScalingFactor(),
46+
randomScalingFactor(),
47+
randomScalingFactor()
48+
]
49+
}, {
50+
label: 'Dataset 3',
51+
backgroundColor: window.chartColors.green,
52+
data: [
53+
randomScalingFactor(),
54+
randomScalingFactor(),
55+
randomScalingFactor(),
56+
randomScalingFactor(),
57+
randomScalingFactor(),
58+
randomScalingFactor(),
59+
randomScalingFactor()
60+
]
61+
}]
62+
63+
};
64+
window.onload = function() {
65+
var ctx = document.getElementById('canvas').getContext('2d');
66+
var started = {};
67+
window.myBar = new Chart(ctx, {
68+
type: 'bar',
69+
data: barChartData,
70+
options: {
71+
animation: (context) => {
72+
if (context.active) {
73+
return {
74+
duration: 400
75+
};
76+
}
77+
var delay = 0;
78+
var dsIndex = context.datasetIndex;
79+
var index = context.dataIndex;
80+
if (!started[index + dsIndex * 1000]) {
81+
delay = index * 300 + dsIndex * 100;
82+
started[index + dsIndex * 1000] = true;
83+
}
84+
return {
85+
easing: 'linear',
86+
duration: 600,
87+
delay
88+
};
89+
},
90+
title: {
91+
display: true,
92+
text: 'Chart.js Bar Chart - Stacked'
93+
},
94+
tooltips: {
95+
mode: 'index',
96+
intersect: false
97+
},
98+
responsive: true,
99+
scales: {
100+
x: {
101+
stacked: true,
102+
},
103+
y: {
104+
stacked: true
105+
}
106+
}
107+
}
108+
});
109+
};
110+
111+
document.getElementById('randomizeData').addEventListener('click', function() {
112+
barChartData.datasets.forEach(function(dataset) {
113+
dataset.data = dataset.data.map(function() {
114+
return randomScalingFactor();
115+
});
116+
});
117+
window.myBar.update();
118+
});
119+
</script>
120+
</body>
121+
122+
</html>

0 commit comments

Comments
 (0)