Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite animation logic #6845

Merged
merged 5 commits into from
Dec 27, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
extends: chartjs

env:
es6: true
browser: true
node: true

Expand Down
41 changes: 25 additions & 16 deletions docs/configuration/animations.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,31 @@ The following animation options are available. The global options for are define
| `duration` | `number` | `1000` | The number of milliseconds an animation takes.
| `easing` | `string` | `'easeOutQuart'` | Easing function to use. [more...](#easing)
| `onProgress` | `function` | `null` | Callback called on each step of an animation. [more...](#animation-callbacks)
| `onComplete` | `function` | `null` | Callback called at the end of an animation. [more...](#animation-callbacks)
| `onComplete` | `function` | `null` | Callback called when all animations are completed. [more...](#animation-callbacks)
| `delay` | `number` | `undefined` | Delay before starting the animations.
benmccann marked this conversation as resolved.
Show resolved Hide resolved
| `loop` | `boolean` | `undefined` | If set to `true`, loop the animations loop endlessly.
benmccann marked this conversation as resolved.
Show resolved Hide resolved
| `type` | `string` | `typeof property` | Type of property, determines the interpolator used. Possible values: `'number'`, '`color`'.
| `from` | <code>number&#124;Color</code> | `undefined` | Start value for the animation. Current value is used when `undefined`
| `active` | `object` | `{ duration: 400 }` | Option overrides for `active` animations (hover)
| `resize` | `object` | `{ duration: 0 }` | Option overrides for `resize` animations.
kurkle marked this conversation as resolved.
Show resolved Hide resolved
| [property] | `object` | `undefined` | Option overrides for [property].
| [collection] | `object` | `undefined` | Option overrides for multiple properties, identified by `properties` array.

Default collections:
| Name | option | value
| `numbers` | `type` | `'number'`
| | `properties` | `['x', 'y', 'borderWidth', 'radius', 'tension']`
| `colors` | `type` | `'color'`
| | `properties` | `['borderColor', 'backgroundColor']`

Direct property configuration overrides configuration of same property in a collection.

These defaults can be overridden in `options.animation` and `dataset.animation`.

## Easing

Available options are:

* `'linear'`
* `'easeInQuad'`
* `'easeOutQuad'`
Expand Down Expand Up @@ -52,34 +72,23 @@ See [Robert Penner's easing equations](http://robertpenner.com/easing/).

## Animation Callbacks

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

```javascript
{
// Chart object
chart: Chart,

// Current Animation frame number
// Number of animations still in progress
currentStep: number,

// Number of animation frames
// Total number of animations at the start of current animation
numSteps: number,

// Animation easing to use
easing: string,

// Function that renders the chart
render: function,

// User callback
onAnimationProgress: function,

// User callback
onAnimationComplete: function
}
```

The following example fills a progress bar during the chart animation.

```javascript
var chart = new Chart(ctx, {
type: 'line',
Expand Down
2 changes: 1 addition & 1 deletion docs/configuration/tooltip.md
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ The tooltip model contains parameters that can be used to render the tooltip.

// 0 opacity is a hidden tooltip
opacity: number,
legendColorBackground: Color,
multiKeyBackground: Color,
kurkle marked this conversation as resolved.
Show resolved Hide resolved
displayColors: boolean,
borderColor: Color,
borderWidth: number
Expand Down
34 changes: 6 additions & 28 deletions docs/developers/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,22 @@ This must be called before the canvas is reused for a new chart.
myLineChart.destroy();
```

## .update(config)
## .update(mode)

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.

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

> **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: [...]}`.

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.

The following properties are supported:
* **duration** (number): Time for the animation of the redraw in milliseconds
* **lazy** (boolean): If true, the animation can be interrupted by other animations
* **easing** (string): The animation easing function. See [Animation Easing](../configuration/animations.md) for possible values.
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'`.

Example:
```javascript
myChart.update({
duration: 800,
easing: 'easeOutBounce'
});
myChart.update();
```

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

## .render(config)
## .render()

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

See `.update(config)` for more details on the config object.

```javascript
// duration is the time for the animation of the redraw in milliseconds
// lazy is a boolean. if true, the animation can be interrupted by other animations
myLineChart.render({
duration: 800,
lazy: false,
easing: 'easeOutBounce'
});
```

## .stop()

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

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

```javascript
var meta = myChart.getDatasetMeta(0);
var x = meta.data[0]._model.x;
var x = meta.data[0].x;
```
4 changes: 2 additions & 2 deletions docs/developers/charts.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,13 @@ var custom = Chart.controllers.bubble.extend({
// Now we can do some custom drawing for this dataset. Here we'll draw a red box around the first point in each dataset
var meta = this.getMeta();
var pt0 = meta.data[0];
var radius = pt0._view.radius;
var radius = pt0.radius;

var ctx = this.chart.chart.ctx;
ctx.save();
ctx.strokeStyle = 'red';
ctx.lineWidth = 1;
ctx.strokeRect(pt0._view.x - radius, pt0._view.y - radius, 2 * radius, 2 * radius);
ctx.strokeRect(pt0.x - radius, pt0.y - radius, 2 * radius, 2 * radius);
ctx.restore();
}
});
Expand Down
2 changes: 1 addition & 1 deletion docs/developers/updates.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,4 @@ Code sample for updating options can be found in [toggle-scale-type.html](../../

## Preventing Animations

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.
Sometimes when a chart updates, you may not want an animation. To achieve this you can call `update` with `'none'` as mode.
benmccann marked this conversation as resolved.
Show resolved Hide resolved
1 change: 0 additions & 1 deletion docs/general/interactions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,3 @@ The hover configuration is passed into the `options.hover` namespace. The global
| `mode` | `string` | `'nearest'` | Sets which elements appear in the tooltip. See [Interaction Modes](./modes.md#interaction-modes) for details.
| `intersect` | `boolean` | `true` | if true, the hover mode only applies when the mouse position intersects an item on the chart.
| `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.
| `animationDuration` | `number` | `400` | Duration in milliseconds it takes to animate hover style changes.
8 changes: 1 addition & 7 deletions docs/general/performance.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,7 @@ new Chart(ctx, {
type: 'line',
data: data,
options: {
animation: {
duration: 0 // general animation time
},
hover: {
animationDuration: 0 // duration of animations when hovering an item
},
responsiveAnimationDuration: 0 // animation duration after a resize
animation: false
}
});
```
Expand Down
1 change: 0 additions & 1 deletion docs/general/responsive.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ Chart.js provides a [few options](#configuration-options) to enable responsivene
| Name | Type | Default | Description
| ---- | ---- | ------- | -----------
| `responsive` | `boolean` | `true` | Resizes the chart canvas when its container does ([important note...](#important-note)).
| `responsiveAnimationDuration` | `number` | `0` | Duration in milliseconds it takes to animate to new size after a resize event.
| `maintainAspectRatio` | `boolean` | `true` | Maintain the original canvas aspect ratio `(width / height)` when resizing.
| `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.
| `onResize` | `function` | `null` | Called when a resize occurs. Gets passed two arguments: the chart instance and the new size.
Expand Down
16 changes: 11 additions & 5 deletions docs/getting-started/v3-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ Chart.js 3.0 introduces a number of breaking changes. Chart.js 2.0 was released
* `scales.[x/y]Axes.time.max` was renamed to `scales[id].max`
* `scales.[x/y]Axes.time.min` was renamed to `scales[id].min`

### Animations

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.

* `hover.animationDuration` is now configured in `animation.active.duration`
* `responsiveAnimationDuration` is now configured in `animation.resize.duration`

## Developer migration

### Removed
Expand Down Expand Up @@ -89,10 +96,8 @@ Chart.js 3.0 introduces a number of breaking changes. Chart.js 2.0 was released

* `Chart.data.datasets[datasetIndex]._meta`
* `Element._ctx`
* `Element._model.datasetLabel`
* `Element._model.label`
* `Point._model.tension`
* `Point._model.steppedLine`
* `Element._model`
* `Element._view`
* `TimeScale._getPixelForOffset`
* `TimeScale.getLabelWidth`

Expand All @@ -107,7 +112,6 @@ Chart.js 3.0 introduces a number of breaking changes. Chart.js 2.0 was released
* `helpers.log10` was renamed to `helpers.math.log10`
* `helpers.almostEquals` was renamed to `helpers.math.almostEquals`
* `helpers.almostWhole` was renamed to `helpers.math.almostWhole`
* `helpers._decimalPlaces` was renamed to `helpers.math._decimalPlaces`
* `helpers.distanceBetweenPoints` was renamed to `helpers.math.distanceBetweenPoints`
* `helpers.isNumber` was renamed to `helpers.math.isNumber`
* `helpers.sign` was renamed to `helpers.math.sign`
Expand All @@ -128,10 +132,12 @@ Chart.js 3.0 introduces a number of breaking changes. Chart.js 2.0 was released
* `TimeScale.getLabelCapacity` was renamed to `TimeScale._getLabelCapacity`
* `TimeScale.tickFormatFunction` was renamed to `TimeScale._tickFormatFunction`
* `TimeScale.getPixelForOffset` was renamed to `TimeScale._getPixelForOffset`
* `Tooltip.options.legendColorBackgroupd` was renamed to `Tooltip.options.multiKeyBackground`

#### Renamed private APIs

* `helpers._alignPixel` was renamed to `helpers.canvas._alignPixel`
* `helpers._decimalPlaces` was renamed to `helpers.math._decimalPlaces`

### Changed

Expand Down
122 changes: 122 additions & 0 deletions samples/animations/delay.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<!doctype html>
<html>

<head>
<title>Stacked Bar Chart</title>
<script src="../../dist/Chart.min.js"></script>
<script src="../utils.js"></script>
<style>
canvas {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
</style>
</head>

<body>
<div style="width: 75%">
<canvas id="canvas"></canvas>
</div>
<button id="randomizeData">Randomize Data</button>
<script>
var barChartData = {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [{
label: 'Dataset 1',
backgroundColor: window.chartColors.red,
data: [
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor()
]
}, {
label: 'Dataset 2',
backgroundColor: window.chartColors.blue,
data: [
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor()
]
}, {
label: 'Dataset 3',
backgroundColor: window.chartColors.green,
data: [
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor()
]
}]

};
window.onload = function() {
var ctx = document.getElementById('canvas').getContext('2d');
var started = {};
window.myBar = new Chart(ctx, {
type: 'bar',
data: barChartData,
options: {
animation: (context) => {
if (context.active) {
return {
duration: 400
};
}
var delay = 0;
var dsIndex = context.datasetIndex;
var index = context.dataIndex;
if (!started[index + dsIndex * 1000]) {
delay = index * 300 + dsIndex * 100;
started[index + dsIndex * 1000] = true;
}
return {
easing: 'linear',
duration: 600,
delay
};
},
title: {
display: true,
text: 'Chart.js Bar Chart - Stacked'
},
tooltips: {
mode: 'index',
intersect: false
},
responsive: true,
scales: {
x: {
stacked: true,
},
y: {
stacked: true
}
}
}
});
};

document.getElementById('randomizeData').addEventListener('click', function() {
barChartData.datasets.forEach(function(dataset) {
dataset.data = dataset.data.map(function() {
return randomScalingFactor();
});
});
window.myBar.update();
});
</script>
</body>

</html>
Loading