mirror of
https://github.com/chartjs/Chart.js.git
synced 2025-12-08 20:36:08 +00:00
Rewrite animation logic (#6845)
* Rewrite animation logic * Review update 1 * Review update 2 * Review update 3 * Add 'none' to api.md
This commit is contained in:
parent
3abe9bfebf
commit
b83f64b16e
@ -1,6 +1,7 @@
|
||||
extends: chartjs
|
||||
|
||||
env:
|
||||
es6: true
|
||||
browser: true
|
||||
node: true
|
||||
|
||||
|
||||
@ -10,12 +10,33 @@ 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)
|
||||
| `debug` | `boolean` | `undefined` | Running animation count + FPS display in upper left corner of the chart.
|
||||
| `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.
|
||||
| `loop` | `boolean` | `undefined` | If set to `true`, loop the animations loop endlessly.
|
||||
| `type` | `string` | `typeof property` | Type of property, determines the interpolator used. Possible values: `'number'`, '`color`'.
|
||||
| `from` | <code>number|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.
|
||||
| [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'`
|
||||
@ -52,34 +73,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',
|
||||
|
||||
@ -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,
|
||||
displayColors: boolean,
|
||||
borderColor: Color,
|
||||
borderWidth: number
|
||||
|
||||
@ -17,32 +17,23 @@ 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'`. `'none'` is also a supported mode for skipping animations for single update.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
myChart.update({
|
||||
duration: 800,
|
||||
easing: 'easeOutBounce'
|
||||
});
|
||||
myChart.update();
|
||||
```
|
||||
|
||||
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
|
||||
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
|
||||
@ -175,5 +154,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;
|
||||
```
|
||||
|
||||
@ -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();
|
||||
}
|
||||
});
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
@ -90,10 +97,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`
|
||||
|
||||
@ -108,7 +113,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`
|
||||
@ -129,10 +133,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
|
||||
|
||||
|
||||
122
samples/animations/delay.html
Normal file
122
samples/animations/delay.html
Normal file
@ -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>
|
||||
175
samples/animations/drop.html
Normal file
175
samples/animations/drop.html
Normal file
@ -0,0 +1,175 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Line 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>
|
||||
<br>
|
||||
<br>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<button id="addDataset">Add Dataset</button>
|
||||
<button id="removeDataset">Remove Dataset</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<script>
|
||||
var MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
||||
var config = {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
|
||||
datasets: [{
|
||||
label: 'My First dataset',
|
||||
animation: {
|
||||
y: {
|
||||
duration: 2000,
|
||||
delay: 100
|
||||
}
|
||||
},
|
||||
backgroundColor: window.chartColors.red,
|
||||
borderColor: window.chartColors.red,
|
||||
data: [
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor()
|
||||
],
|
||||
fill: false,
|
||||
}, {
|
||||
label: 'My Second dataset',
|
||||
fill: false,
|
||||
backgroundColor: window.chartColors.blue,
|
||||
borderColor: window.chartColors.blue,
|
||||
data: [
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor()
|
||||
],
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
animation: {
|
||||
y: {
|
||||
easing: 'easeInOutElastic',
|
||||
from: 0
|
||||
}
|
||||
},
|
||||
responsive: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Chart.js Line Chart'
|
||||
},
|
||||
tooltips: {
|
||||
mode: 'index',
|
||||
intersect: false,
|
||||
},
|
||||
hover: {
|
||||
mode: 'nearest',
|
||||
intersect: true
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
display: true,
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'Month'
|
||||
}
|
||||
},
|
||||
y: {
|
||||
display: true,
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'Value'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById('canvas').getContext('2d');
|
||||
window.myLine = new Chart(ctx, config);
|
||||
};
|
||||
|
||||
document.getElementById('randomizeData').addEventListener('click', function() {
|
||||
config.data.datasets.forEach(function(dataset) {
|
||||
dataset.data = dataset.data.map(function() {
|
||||
return randomScalingFactor();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
});
|
||||
|
||||
var colorNames = Object.keys(window.chartColors);
|
||||
document.getElementById('addDataset').addEventListener('click', function() {
|
||||
var colorName = colorNames[config.data.datasets.length % colorNames.length];
|
||||
var newColor = window.chartColors[colorName];
|
||||
var newDataset = {
|
||||
label: 'Dataset ' + config.data.datasets.length,
|
||||
backgroundColor: newColor,
|
||||
borderColor: newColor,
|
||||
data: [],
|
||||
fill: false
|
||||
};
|
||||
|
||||
for (var index = 0; index < config.data.labels.length; ++index) {
|
||||
newDataset.data.push(randomScalingFactor());
|
||||
}
|
||||
|
||||
config.data.datasets.push(newDataset);
|
||||
window.myLine.update();
|
||||
});
|
||||
|
||||
document.getElementById('addData').addEventListener('click', function() {
|
||||
if (config.data.datasets.length > 0) {
|
||||
var month = MONTHS[config.data.labels.length % MONTHS.length];
|
||||
config.data.labels.push(month);
|
||||
|
||||
config.data.datasets.forEach(function(dataset) {
|
||||
dataset.data.push(randomScalingFactor());
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('removeDataset').addEventListener('click', function() {
|
||||
config.data.datasets.splice(0, 1);
|
||||
window.myLine.update();
|
||||
});
|
||||
|
||||
document.getElementById('removeData').addEventListener('click', function() {
|
||||
config.data.labels.splice(-1, 1); // remove the label first
|
||||
|
||||
config.data.datasets.forEach(function(dataset) {
|
||||
dataset.data.pop();
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
181
samples/animations/loop.html
Normal file
181
samples/animations/loop.html
Normal file
@ -0,0 +1,181 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Line 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>
|
||||
<br>
|
||||
<br>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<button id="addDataset">Add Dataset</button>
|
||||
<button id="removeDataset">Remove Dataset</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<script>
|
||||
var MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
||||
var config = {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
|
||||
datasets: [{
|
||||
label: 'My First dataset',
|
||||
fill: false,
|
||||
backgroundColor: window.chartColors.red,
|
||||
borderColor: window.chartColors.red,
|
||||
data: [
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor()
|
||||
],
|
||||
}, {
|
||||
label: 'My Second dataset',
|
||||
fill: false,
|
||||
backgroundColor: window.chartColors.blue,
|
||||
borderColor: window.chartColors.blue,
|
||||
data: [
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor(),
|
||||
randomScalingFactor()
|
||||
],
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
animation: (context) => {
|
||||
if (context.active) {
|
||||
return {
|
||||
radius: {
|
||||
duration: 400,
|
||||
loop: true
|
||||
}
|
||||
};
|
||||
}
|
||||
return Chart.defaults.global.animation;
|
||||
},
|
||||
elements: {
|
||||
point: {
|
||||
hoverRadius: 6
|
||||
}
|
||||
},
|
||||
responsive: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Chart.js Line Chart'
|
||||
},
|
||||
tooltips: {
|
||||
mode: 'nearest',
|
||||
axis: 'x',
|
||||
intersect: false,
|
||||
},
|
||||
hover: {
|
||||
mode: 'nearest',
|
||||
axis: 'x',
|
||||
intersect: false
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
display: true,
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'Month'
|
||||
}
|
||||
},
|
||||
y: {
|
||||
display: true,
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'Value'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById('canvas').getContext('2d');
|
||||
window.myLine = new Chart(ctx, config);
|
||||
};
|
||||
|
||||
document.getElementById('randomizeData').addEventListener('click', function() {
|
||||
config.data.datasets.forEach(function(dataset) {
|
||||
dataset.data = dataset.data.map(function() {
|
||||
return randomScalingFactor();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
});
|
||||
|
||||
var colorNames = Object.keys(window.chartColors);
|
||||
document.getElementById('addDataset').addEventListener('click', function() {
|
||||
var colorName = colorNames[config.data.datasets.length % colorNames.length];
|
||||
var newColor = window.chartColors[colorName];
|
||||
var newDataset = {
|
||||
label: 'Dataset ' + config.data.datasets.length,
|
||||
backgroundColor: newColor,
|
||||
borderColor: newColor,
|
||||
data: [],
|
||||
fill: false
|
||||
};
|
||||
|
||||
for (var index = 0; index < config.data.labels.length; ++index) {
|
||||
newDataset.data.push(randomScalingFactor());
|
||||
}
|
||||
|
||||
config.data.datasets.push(newDataset);
|
||||
window.myLine.update();
|
||||
});
|
||||
|
||||
document.getElementById('addData').addEventListener('click', function() {
|
||||
if (config.data.datasets.length > 0) {
|
||||
var month = MONTHS[config.data.labels.length % MONTHS.length];
|
||||
config.data.labels.push(month);
|
||||
|
||||
config.data.datasets.forEach(function(dataset) {
|
||||
dataset.data.push(randomScalingFactor());
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('removeDataset').addEventListener('click', function() {
|
||||
config.data.datasets.splice(0, 1);
|
||||
window.myLine.update();
|
||||
});
|
||||
|
||||
document.getElementById('removeData').addEventListener('click', function() {
|
||||
config.data.labels.splice(-1, 1); // remove the label first
|
||||
|
||||
config.data.datasets.forEach(function(dataset) {
|
||||
dataset.data.pop();
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -29,9 +29,6 @@
|
||||
var addedCount = 0;
|
||||
var color = Chart.helpers.color;
|
||||
var bubbleChartData = {
|
||||
animation: {
|
||||
duration: 10000
|
||||
},
|
||||
datasets: [{
|
||||
label: 'My First dataset',
|
||||
backgroundColor: color(window.chartColors.red).alpha(0.5).rgbString(),
|
||||
|
||||
@ -65,6 +65,9 @@
|
||||
}, {
|
||||
title: 'Other charts',
|
||||
items: [{
|
||||
title: 'Bubble',
|
||||
path: 'charts/bubble.html'
|
||||
}, {
|
||||
title: 'Scatter',
|
||||
path: 'charts/scatter/basic.html'
|
||||
}, {
|
||||
@ -209,6 +212,18 @@
|
||||
title: 'Radar Chart',
|
||||
path: 'scriptable/radar.html'
|
||||
}]
|
||||
}, {
|
||||
title: 'Animations',
|
||||
items: [{
|
||||
title: 'Delay',
|
||||
path: 'animations/delay.html'
|
||||
}, {
|
||||
title: 'Drop',
|
||||
path: 'animations/drop.html'
|
||||
}, {
|
||||
title: 'Loop',
|
||||
path: 'animations/loop.html'
|
||||
}]
|
||||
}, {
|
||||
title: 'Advanced',
|
||||
items: [{
|
||||
|
||||
@ -30,7 +30,13 @@ defaults._set('global', {
|
||||
datasets: {
|
||||
bar: {
|
||||
categoryPercentage: 0.8,
|
||||
barPercentage: 0.9
|
||||
barPercentage: 0.9,
|
||||
animation: {
|
||||
numbers: {
|
||||
type: 'number',
|
||||
properties: ['x', 'y', 'base', 'width', 'height']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -267,50 +273,53 @@ module.exports = DatasetController.extend({
|
||||
meta.bar = true;
|
||||
},
|
||||
|
||||
update: function(reset) {
|
||||
update: function(mode) {
|
||||
const me = this;
|
||||
const rects = me._cachedMeta.data;
|
||||
|
||||
me.updateElements(rects, 0, rects.length, reset);
|
||||
me.updateElements(rects, 0, rects.length, mode);
|
||||
},
|
||||
|
||||
updateElements: function(rectangles, start, count, reset) {
|
||||
updateElements: function(rectangles, start, count, mode) {
|
||||
const me = this;
|
||||
const reset = mode === 'reset';
|
||||
const vscale = me._cachedMeta.vScale;
|
||||
const base = vscale.getBasePixel();
|
||||
const horizontal = vscale.isHorizontal();
|
||||
const ruler = me.getRuler();
|
||||
const firstOpts = me._resolveDataElementOptions(start, mode);
|
||||
const sharedOptions = me._getSharedOptions(mode, rectangles[start], firstOpts);
|
||||
const includeOptions = me._includeOptions(mode, sharedOptions);
|
||||
|
||||
let i;
|
||||
|
||||
for (i = 0; i < start + count; i++) {
|
||||
const rectangle = rectangles[i];
|
||||
const options = me._resolveDataElementOptions(i);
|
||||
const options = me._resolveDataElementOptions(i, mode);
|
||||
const vpixels = me.calculateBarValuePixels(i, options);
|
||||
const ipixels = me.calculateBarIndexPixels(i, ruler, options);
|
||||
|
||||
rectangle._model = {
|
||||
backgroundColor: options.backgroundColor,
|
||||
borderColor: options.borderColor,
|
||||
borderSkipped: options.borderSkipped,
|
||||
borderWidth: options.borderWidth
|
||||
const properties = {
|
||||
horizontal,
|
||||
base: reset ? base : vpixels.base,
|
||||
x: horizontal ? reset ? base : vpixels.head : ipixels.center,
|
||||
y: horizontal ? ipixels.center : reset ? base : vpixels.head,
|
||||
height: horizontal ? ipixels.size : undefined,
|
||||
width: horizontal ? undefined : ipixels.size
|
||||
};
|
||||
|
||||
const model = rectangle._model;
|
||||
|
||||
// all borders are drawn for floating bar
|
||||
/* TODO: float bars border skipping magic
|
||||
if (me._getParsed(i)._custom) {
|
||||
model.borderSkipped = null;
|
||||
}
|
||||
|
||||
model.horizontal = horizontal;
|
||||
model.base = reset ? base : vpixels.base;
|
||||
model.x = horizontal ? reset ? base : vpixels.head : ipixels.center;
|
||||
model.y = horizontal ? ipixels.center : reset ? base : vpixels.head;
|
||||
model.height = horizontal ? ipixels.size : undefined;
|
||||
model.width = horizontal ? undefined : ipixels.size;
|
||||
|
||||
rectangle.pivot(me.chart._animationsDisabled);
|
||||
*/
|
||||
if (includeOptions) {
|
||||
properties.options = options;
|
||||
}
|
||||
me._updateElement(rectangles[i], i, properties, mode);
|
||||
}
|
||||
|
||||
me._updateSharedOptions(sharedOptions, mode);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@ -1,14 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
var DatasetController = require('../core/core.datasetController');
|
||||
var defaults = require('../core/core.defaults');
|
||||
var elements = require('../elements/index');
|
||||
var helpers = require('../helpers/index');
|
||||
const DatasetController = require('../core/core.datasetController');
|
||||
const defaults = require('../core/core.defaults');
|
||||
const elements = require('../elements/index');
|
||||
const helpers = require('../helpers/index');
|
||||
|
||||
var valueOrDefault = helpers.valueOrDefault;
|
||||
var resolve = helpers.options.resolve;
|
||||
const resolve = helpers.options.resolve;
|
||||
|
||||
defaults._set('bubble', {
|
||||
animation: {
|
||||
numbers: {
|
||||
properties: ['x', 'y', 'borderWidth', 'radius']
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
type: 'linear',
|
||||
@ -43,11 +47,8 @@ module.exports = DatasetController.extend({
|
||||
'backgroundColor',
|
||||
'borderColor',
|
||||
'borderWidth',
|
||||
'hoverBackgroundColor',
|
||||
'hoverBorderColor',
|
||||
'hoverBorderWidth',
|
||||
'hoverRadius',
|
||||
'hitRadius',
|
||||
'radius',
|
||||
'pointStyle',
|
||||
'rotation'
|
||||
],
|
||||
@ -77,15 +78,14 @@ module.exports = DatasetController.extend({
|
||||
* @private
|
||||
*/
|
||||
_getMaxOverflow: function() {
|
||||
var me = this;
|
||||
var meta = me._cachedMeta;
|
||||
var data = meta.data || [];
|
||||
if (!data.length) {
|
||||
return false;
|
||||
const me = this;
|
||||
const meta = me._cachedMeta;
|
||||
let i = (meta.data || []).length - 1;
|
||||
let max = 0;
|
||||
for (; i >= 0; --i) {
|
||||
max = Math.max(max, me.getStyle(i, true).radius);
|
||||
}
|
||||
var firstPoint = data[0].size();
|
||||
var lastPoint = data[data.length - 1].size();
|
||||
return Math.max(firstPoint, lastPoint) / 2;
|
||||
return max > 0 && max;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -109,72 +109,56 @@ module.exports = DatasetController.extend({
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
update: function(reset) {
|
||||
update: function(mode) {
|
||||
const me = this;
|
||||
const points = me._cachedMeta.data;
|
||||
|
||||
// Update Points
|
||||
me.updateElements(points, 0, points.length, reset);
|
||||
me.updateElements(points, 0, points.length, mode);
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
updateElements: function(points, start, count, reset) {
|
||||
updateElements: function(points, start, count, mode) {
|
||||
const me = this;
|
||||
const reset = mode === 'reset';
|
||||
const {xScale, yScale} = me._cachedMeta;
|
||||
const firstOpts = me._resolveDataElementOptions(start, mode);
|
||||
const sharedOptions = me._getSharedOptions(mode, points[start], firstOpts);
|
||||
const includeOptions = me._includeOptions(mode, sharedOptions);
|
||||
let i;
|
||||
|
||||
for (i = start; i < start + count; i++) {
|
||||
const point = points[i];
|
||||
const options = me._resolveDataElementOptions(i);
|
||||
const parsed = !reset && me._getParsed(i);
|
||||
const x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(parsed[xScale.id]);
|
||||
const y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(parsed[yScale.id]);
|
||||
|
||||
point._options = options;
|
||||
point._model = {
|
||||
backgroundColor: options.backgroundColor,
|
||||
borderColor: options.borderColor,
|
||||
borderWidth: options.borderWidth,
|
||||
hitRadius: options.hitRadius,
|
||||
pointStyle: options.pointStyle,
|
||||
rotation: options.rotation,
|
||||
radius: reset ? 0 : options.radius,
|
||||
skip: isNaN(x) || isNaN(y),
|
||||
x: x,
|
||||
y: y,
|
||||
const properties = {
|
||||
x,
|
||||
y,
|
||||
skip: isNaN(x) || isNaN(y)
|
||||
};
|
||||
|
||||
point.pivot(me.chart._animationsDisabled);
|
||||
if (includeOptions) {
|
||||
properties.options = i === start ? firstOpts
|
||||
: me._resolveDataElementOptions(i, mode);
|
||||
|
||||
if (reset) {
|
||||
properties.options.radius = 0;
|
||||
}
|
||||
}
|
||||
|
||||
me._updateElement(point, i, properties, mode);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
setHoverStyle: function(point) {
|
||||
var model = point._model;
|
||||
var options = point._options;
|
||||
var getHoverColor = helpers.getHoverColor;
|
||||
|
||||
point.$previousStyle = {
|
||||
backgroundColor: model.backgroundColor,
|
||||
borderColor: model.borderColor,
|
||||
borderWidth: model.borderWidth,
|
||||
radius: model.radius
|
||||
};
|
||||
|
||||
model.backgroundColor = valueOrDefault(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
|
||||
model.borderColor = valueOrDefault(options.hoverBorderColor, getHoverColor(options.borderColor));
|
||||
model.borderWidth = valueOrDefault(options.hoverBorderWidth, options.borderWidth);
|
||||
model.radius = options.radius + options.hoverRadius;
|
||||
me._updateSharedOptions(sharedOptions, mode);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_resolveDataElementOptions: function(index) {
|
||||
_resolveDataElementOptions: function(index, mode) {
|
||||
var me = this;
|
||||
var chart = me.chart;
|
||||
var dataset = me.getDataset();
|
||||
@ -190,12 +174,16 @@ module.exports = DatasetController.extend({
|
||||
};
|
||||
|
||||
// In case values were cached (and thus frozen), we need to clone the values
|
||||
if (me._cachedDataOpts === values) {
|
||||
values = helpers.extend({}, values);
|
||||
if (values.$shared) {
|
||||
values = helpers.extend({}, values, {$shared: false});
|
||||
}
|
||||
|
||||
|
||||
// Custom radius resolution
|
||||
values.radius = resolve([
|
||||
if (mode !== 'active') {
|
||||
values.radius = 0;
|
||||
}
|
||||
values.radius += resolve([
|
||||
parsed && parsed._custom,
|
||||
me._config.radius,
|
||||
chart.options.elements.point.radius
|
||||
|
||||
@ -13,6 +13,10 @@ var HALF_PI = PI / 2;
|
||||
|
||||
defaults._set('doughnut', {
|
||||
animation: {
|
||||
numbers: {
|
||||
type: 'number',
|
||||
properties: ['x', 'y', 'startAngle', 'endAngle', 'innerRadius', 'outerRadius']
|
||||
},
|
||||
// Boolean - Whether we animate the rotation of the Doughnut
|
||||
animateRotate: true,
|
||||
// Boolean - Whether we animate scaling the Doughnut from the centre
|
||||
@ -160,7 +164,7 @@ module.exports = DatasetController.extend({
|
||||
return ringIndex;
|
||||
},
|
||||
|
||||
update: function(reset) {
|
||||
update: function(mode) {
|
||||
var me = this;
|
||||
var chart = me.chart;
|
||||
var chartArea = chart.chartArea;
|
||||
@ -200,7 +204,7 @@ module.exports = DatasetController.extend({
|
||||
}
|
||||
|
||||
for (i = 0, ilen = arcs.length; i < ilen; ++i) {
|
||||
arcs[i]._options = me._resolveDataElementOptions(i);
|
||||
arcs[i]._options = me._resolveDataElementOptions(i, mode);
|
||||
}
|
||||
|
||||
chart.borderWidth = me.getMaxBorderWidth();
|
||||
@ -217,57 +221,45 @@ module.exports = DatasetController.extend({
|
||||
me.outerRadius = chart.outerRadius - chart.radiusLength * me._getRingWeightOffset(me.index);
|
||||
me.innerRadius = Math.max(me.outerRadius - chart.radiusLength * chartWeight, 0);
|
||||
|
||||
me.updateElements(arcs, 0, arcs.length, reset);
|
||||
me.updateElements(arcs, 0, arcs.length, mode);
|
||||
},
|
||||
|
||||
updateElements: function(arcs, start, count, reset) {
|
||||
updateElements: function(arcs, start, count, mode) {
|
||||
const me = this;
|
||||
const reset = mode === 'reset';
|
||||
const chart = me.chart;
|
||||
const chartArea = chart.chartArea;
|
||||
const opts = chart.options;
|
||||
const animationOpts = opts.animation;
|
||||
const centerX = (chartArea.left + chartArea.right) / 2;
|
||||
const centerY = (chartArea.top + chartArea.bottom) / 2;
|
||||
const startAngle = opts.rotation; // non reset case handled later
|
||||
const endAngle = opts.rotation; // non reset case handled later
|
||||
const meta = me.getMeta();
|
||||
const innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius;
|
||||
const outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius;
|
||||
let startAngle = opts.rotation;
|
||||
let i;
|
||||
|
||||
for (i = 0; i < start + count; ++i) {
|
||||
const arc = arcs[i];
|
||||
const circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(meta._parsed[i] * opts.circumference / DOUBLE_PI);
|
||||
const options = arc._options || {};
|
||||
const model = {
|
||||
// Desired view properties
|
||||
backgroundColor: options.backgroundColor,
|
||||
borderColor: options.borderColor,
|
||||
borderWidth: options.borderWidth,
|
||||
borderAlign: options.borderAlign,
|
||||
if (i < start) {
|
||||
startAngle += circumference;
|
||||
continue;
|
||||
}
|
||||
const properties = {
|
||||
x: centerX + chart.offsetX,
|
||||
y: centerY + chart.offsetY,
|
||||
startAngle: startAngle,
|
||||
endAngle: endAngle,
|
||||
circumference: circumference,
|
||||
outerRadius: outerRadius,
|
||||
innerRadius: innerRadius
|
||||
startAngle,
|
||||
endAngle: startAngle + circumference,
|
||||
circumference,
|
||||
outerRadius,
|
||||
innerRadius,
|
||||
options
|
||||
};
|
||||
startAngle += circumference;
|
||||
|
||||
arc._model = model;
|
||||
|
||||
// Set correct angles if not resetting
|
||||
if (!reset || !animationOpts.animateRotate) {
|
||||
if (i === 0) {
|
||||
model.startAngle = opts.rotation;
|
||||
} else {
|
||||
model.startAngle = me._cachedMeta.data[i - 1]._model.endAngle;
|
||||
}
|
||||
|
||||
model.endAngle = model.startAngle + model.circumference;
|
||||
}
|
||||
|
||||
arc.pivot(chart._animationsDisabled);
|
||||
me._updateElement(arc, i, properties, mode);
|
||||
}
|
||||
},
|
||||
|
||||
@ -304,7 +296,7 @@ module.exports = DatasetController.extend({
|
||||
var me = this;
|
||||
var max = 0;
|
||||
var chart = me.chart;
|
||||
var i, ilen, meta, arc, controller, options, borderWidth, hoverWidth;
|
||||
var i, ilen, meta, controller, options;
|
||||
|
||||
if (!arcs) {
|
||||
// Find the outmost visible dataset
|
||||
@ -312,8 +304,9 @@ module.exports = DatasetController.extend({
|
||||
if (chart.isDatasetVisible(i)) {
|
||||
meta = chart.getDatasetMeta(i);
|
||||
arcs = meta.data;
|
||||
if (i !== me.index) {
|
||||
controller = meta.controller;
|
||||
controller = meta.controller;
|
||||
if (controller !== me) {
|
||||
controller._configure();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -325,43 +318,14 @@ module.exports = DatasetController.extend({
|
||||
}
|
||||
|
||||
for (i = 0, ilen = arcs.length; i < ilen; ++i) {
|
||||
arc = arcs[i];
|
||||
if (controller) {
|
||||
controller._configure();
|
||||
options = controller._resolveDataElementOptions(i);
|
||||
} else {
|
||||
options = arc._options;
|
||||
}
|
||||
options = controller._resolveDataElementOptions(i);
|
||||
if (options.borderAlign !== 'inner') {
|
||||
borderWidth = options.borderWidth;
|
||||
hoverWidth = options.hoverBorderWidth;
|
||||
|
||||
max = borderWidth > max ? borderWidth : max;
|
||||
max = hoverWidth > max ? hoverWidth : max;
|
||||
max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0);
|
||||
}
|
||||
}
|
||||
return max;
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
setHoverStyle: function(arc) {
|
||||
var model = arc._model;
|
||||
var options = arc._options;
|
||||
var getHoverColor = helpers.getHoverColor;
|
||||
|
||||
arc.$previousStyle = {
|
||||
backgroundColor: model.backgroundColor,
|
||||
borderColor: model.borderColor,
|
||||
borderWidth: model.borderWidth,
|
||||
};
|
||||
|
||||
model.backgroundColor = valueOrDefault(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
|
||||
model.borderColor = valueOrDefault(options.hoverBorderColor, getHoverColor(options.borderColor));
|
||||
model.borderWidth = valueOrDefault(options.hoverBorderWidth, options.borderWidth);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get radius length offset of the dataset in relation to the visible datasets weights. This allows determining the inner and outer radius correctly
|
||||
* @private
|
||||
|
||||
@ -7,7 +7,6 @@ const helpers = require('../helpers/index');
|
||||
|
||||
const valueOrDefault = helpers.valueOrDefault;
|
||||
const resolve = helpers.options.resolve;
|
||||
const isPointInArea = helpers.canvas._isPointInArea;
|
||||
|
||||
defaults._set('line', {
|
||||
showLines: true,
|
||||
@ -44,6 +43,7 @@ module.exports = DatasetController.extend({
|
||||
'borderDashOffset',
|
||||
'borderJoinStyle',
|
||||
'borderWidth',
|
||||
'capBezierPoints',
|
||||
'cubicInterpolationMode',
|
||||
'fill'
|
||||
],
|
||||
@ -56,6 +56,7 @@ module.exports = DatasetController.extend({
|
||||
borderColor: 'pointBorderColor',
|
||||
borderWidth: 'pointBorderWidth',
|
||||
hitRadius: 'pointHitRadius',
|
||||
hoverHitRadius: 'pointHitRadius',
|
||||
hoverBackgroundColor: 'pointHoverBackgroundColor',
|
||||
hoverBorderColor: 'pointHoverBorderColor',
|
||||
hoverBorderWidth: 'pointHoverBorderWidth',
|
||||
@ -65,7 +66,7 @@ module.exports = DatasetController.extend({
|
||||
rotation: 'pointRotation'
|
||||
},
|
||||
|
||||
update: function(reset) {
|
||||
update: function(mode) {
|
||||
const me = this;
|
||||
const meta = me._cachedMeta;
|
||||
const line = meta.dataset;
|
||||
@ -73,62 +74,53 @@ module.exports = DatasetController.extend({
|
||||
const options = me.chart.options;
|
||||
const config = me._config;
|
||||
const showLine = me._showLine = valueOrDefault(config.showLine, options.showLines);
|
||||
let i, ilen;
|
||||
|
||||
// Update Line
|
||||
if (showLine) {
|
||||
// Data
|
||||
line._children = points;
|
||||
// Model
|
||||
line._model = me._resolveDatasetElementOptions();
|
||||
if (showLine && mode !== 'resize') {
|
||||
|
||||
line.pivot();
|
||||
const properties = {
|
||||
_children: points,
|
||||
options: me._resolveDatasetElementOptions()
|
||||
};
|
||||
|
||||
me._updateElement(line, undefined, properties, mode);
|
||||
}
|
||||
|
||||
// Update Points
|
||||
me.updateElements(points, 0, points.length, reset);
|
||||
|
||||
if (showLine && line._model.tension !== 0) {
|
||||
me.updateBezierControlPoints();
|
||||
}
|
||||
|
||||
// Now pivot the point for animation
|
||||
for (i = 0, ilen = points.length; i < ilen; ++i) {
|
||||
points[i].pivot(me.chart._animationsDisabled);
|
||||
if (meta.visible) {
|
||||
me.updateElements(points, 0, points.length, mode);
|
||||
}
|
||||
},
|
||||
|
||||
updateElements: function(points, start, count, reset) {
|
||||
updateElements: function(points, start, count, mode) {
|
||||
const me = this;
|
||||
const reset = mode === 'reset';
|
||||
const {xScale, yScale, _stacked} = me._cachedMeta;
|
||||
const firstOpts = me._resolveDataElementOptions(start, mode);
|
||||
const sharedOptions = me._getSharedOptions(mode, points[start], firstOpts);
|
||||
const includeOptions = me._includeOptions(mode, sharedOptions);
|
||||
let i;
|
||||
|
||||
for (i = start; i < start + count; ++i) {
|
||||
const point = points[i];
|
||||
const parsed = me._getParsed(i);
|
||||
const options = me._resolveDataElementOptions(i);
|
||||
const x = xScale.getPixelForValue(parsed[xScale.id]);
|
||||
const y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(_stacked ? me._applyStack(yScale, parsed) : parsed[yScale.id]);
|
||||
|
||||
// Utility
|
||||
point._options = options;
|
||||
|
||||
// Desired view properties
|
||||
point._model = {
|
||||
x: x,
|
||||
y: y,
|
||||
skip: isNaN(x) || isNaN(y),
|
||||
// Appearance
|
||||
radius: options.radius,
|
||||
pointStyle: options.pointStyle,
|
||||
rotation: options.rotation,
|
||||
backgroundColor: options.backgroundColor,
|
||||
borderColor: options.borderColor,
|
||||
borderWidth: options.borderWidth,
|
||||
// Tooltip
|
||||
hitRadius: options.hitRadius
|
||||
const properties = {
|
||||
x,
|
||||
y,
|
||||
skip: isNaN(x) || isNaN(y)
|
||||
};
|
||||
|
||||
if (includeOptions) {
|
||||
properties.options = i === start ? firstOpts
|
||||
: me._resolveDataElementOptions(i, mode);
|
||||
}
|
||||
|
||||
me._updateElement(point, i, properties, mode);
|
||||
}
|
||||
|
||||
me._updateSharedOptions(sharedOptions, mode);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -161,67 +153,12 @@ module.exports = DatasetController.extend({
|
||||
if (!data.length) {
|
||||
return false;
|
||||
}
|
||||
const border = me._showLine ? meta.dataset._model.borderWidth : 0;
|
||||
const border = me._showLine && meta.dataset.options.borderWidth || 0;
|
||||
const firstPoint = data[0].size();
|
||||
const lastPoint = data[data.length - 1].size();
|
||||
return Math.max(border, firstPoint, lastPoint) / 2;
|
||||
},
|
||||
|
||||
updateBezierControlPoints: function() {
|
||||
const me = this;
|
||||
const chart = me.chart;
|
||||
const meta = me._cachedMeta;
|
||||
const lineModel = meta.dataset._model;
|
||||
const area = chart.chartArea;
|
||||
let points = meta.data || [];
|
||||
let i, ilen;
|
||||
|
||||
// Only consider points that are drawn in case the spanGaps option is used
|
||||
if (lineModel.spanGaps) {
|
||||
points = points.filter(function(pt) {
|
||||
return !pt._model.skip;
|
||||
});
|
||||
}
|
||||
|
||||
function capControlPoint(pt, min, max) {
|
||||
return Math.max(Math.min(pt, max), min);
|
||||
}
|
||||
|
||||
if (lineModel.cubicInterpolationMode === 'monotone') {
|
||||
helpers.curve.splineCurveMonotone(points);
|
||||
} else {
|
||||
for (i = 0, ilen = points.length; i < ilen; ++i) {
|
||||
const model = points[i]._model;
|
||||
const controlPoints = helpers.curve.splineCurve(
|
||||
points[Math.max(0, i - 1)]._model,
|
||||
model,
|
||||
points[Math.min(i + 1, ilen - 1)]._model,
|
||||
lineModel.tension
|
||||
);
|
||||
model.controlPointPreviousX = controlPoints.previous.x;
|
||||
model.controlPointPreviousY = controlPoints.previous.y;
|
||||
model.controlPointNextX = controlPoints.next.x;
|
||||
model.controlPointNextY = controlPoints.next.y;
|
||||
}
|
||||
}
|
||||
|
||||
if (chart.options.elements.line.capBezierPoints) {
|
||||
for (i = 0, ilen = points.length; i < ilen; ++i) {
|
||||
const model = points[i]._model;
|
||||
if (isPointInArea(model, area)) {
|
||||
if (i > 0 && isPointInArea(points[i - 1]._model, area)) {
|
||||
model.controlPointPreviousX = capControlPoint(model.controlPointPreviousX, area.left, area.right);
|
||||
model.controlPointPreviousY = capControlPoint(model.controlPointPreviousY, area.top, area.bottom);
|
||||
}
|
||||
if (i < points.length - 1 && isPointInArea(points[i + 1]._model, area)) {
|
||||
model.controlPointNextX = capControlPoint(model.controlPointNextX, area.left, area.right);
|
||||
model.controlPointNextY = capControlPoint(model.controlPointNextY, area.top, area.bottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
draw: function() {
|
||||
const me = this;
|
||||
const ctx = me._ctx;
|
||||
@ -233,7 +170,7 @@ module.exports = DatasetController.extend({
|
||||
let i = 0;
|
||||
|
||||
if (me._showLine) {
|
||||
meta.dataset.draw(ctx);
|
||||
meta.dataset.draw(ctx, area);
|
||||
}
|
||||
|
||||
// Draw the points
|
||||
@ -241,25 +178,4 @@ module.exports = DatasetController.extend({
|
||||
points[i].draw(ctx, area);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
setHoverStyle: function(point) {
|
||||
const model = point._model;
|
||||
const options = point._options;
|
||||
const getHoverColor = helpers.getHoverColor;
|
||||
|
||||
point.$previousStyle = {
|
||||
backgroundColor: model.backgroundColor,
|
||||
borderColor: model.borderColor,
|
||||
borderWidth: model.borderWidth,
|
||||
radius: model.radius
|
||||
};
|
||||
|
||||
model.backgroundColor = valueOrDefault(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
|
||||
model.borderColor = valueOrDefault(options.hoverBorderColor, getHoverColor(options.borderColor));
|
||||
model.borderWidth = valueOrDefault(options.hoverBorderWidth, options.borderWidth);
|
||||
model.radius = valueOrDefault(options.hoverRadius, options.radius);
|
||||
},
|
||||
});
|
||||
|
||||
@ -8,6 +8,14 @@ var helpers = require('../helpers/index');
|
||||
var resolve = helpers.options.resolve;
|
||||
|
||||
defaults._set('polarArea', {
|
||||
animation: {
|
||||
numbers: {
|
||||
type: 'number',
|
||||
properties: ['x', 'y', 'startAngle', 'endAngle', 'innerRadius', 'outerRadius']
|
||||
},
|
||||
animateRotate: true,
|
||||
animateScale: true
|
||||
},
|
||||
scales: {
|
||||
r: {
|
||||
type: 'radialLinear',
|
||||
@ -24,12 +32,6 @@ defaults._set('polarArea', {
|
||||
}
|
||||
},
|
||||
|
||||
// Boolean - Whether to animate the rotation of the chart
|
||||
animation: {
|
||||
animateRotate: true,
|
||||
animateScale: true
|
||||
},
|
||||
|
||||
startAngle: -0.5 * Math.PI,
|
||||
legendCallback: function(chart) {
|
||||
var list = document.createElement('ul');
|
||||
@ -135,28 +137,14 @@ module.exports = DatasetController.extend({
|
||||
return this._cachedMeta.rAxisID;
|
||||
},
|
||||
|
||||
update: function(reset) {
|
||||
update: function(mode) {
|
||||
var me = this;
|
||||
var dataset = me.getDataset();
|
||||
var meta = me._cachedMeta;
|
||||
var start = me.chart.options.startAngle || 0;
|
||||
var starts = me._starts = [];
|
||||
var angles = me._angles = [];
|
||||
var arcs = meta.data;
|
||||
var i, ilen, angle;
|
||||
|
||||
me._updateRadius();
|
||||
|
||||
meta.count = me.countVisibleElements();
|
||||
|
||||
for (i = 0, ilen = dataset.data.length; i < ilen; i++) {
|
||||
starts[i] = start;
|
||||
angle = me._computeAngle(i);
|
||||
angles[i] = angle;
|
||||
start += angle;
|
||||
}
|
||||
|
||||
me.updateElements(arcs, 0, arcs.length, reset);
|
||||
me.updateElements(arcs, 0, arcs.length, mode);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -177,8 +165,9 @@ module.exports = DatasetController.extend({
|
||||
me.innerRadius = me.outerRadius - chart.radiusLength;
|
||||
},
|
||||
|
||||
updateElements: function(arcs, start, count, reset) {
|
||||
updateElements: function(arcs, start, count, mode) {
|
||||
const me = this;
|
||||
const reset = mode === 'reset';
|
||||
const chart = me.chart;
|
||||
const dataset = me.getDataset();
|
||||
const opts = chart.options;
|
||||
@ -186,33 +175,43 @@ module.exports = DatasetController.extend({
|
||||
const scale = chart.scales.r;
|
||||
const centerX = scale.xCenter;
|
||||
const centerY = scale.yCenter;
|
||||
var i;
|
||||
const datasetStartAngle = opts.startAngle || 0;
|
||||
let angle = datasetStartAngle;
|
||||
let i;
|
||||
|
||||
for (i = 0; i < start + count; i++) {
|
||||
me._cachedMeta.count = me.countVisibleElements();
|
||||
|
||||
for (i = 0; i < start; ++i) {
|
||||
angle += me._computeAngle(i);
|
||||
}
|
||||
for (; i < start + count; i++) {
|
||||
const arc = arcs[i];
|
||||
// var negHalfPI = -0.5 * Math.PI;
|
||||
const datasetStartAngle = opts.startAngle;
|
||||
const distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[i]);
|
||||
const startAngle = me._starts[i];
|
||||
const endAngle = startAngle + (arc.hidden ? 0 : me._angles[i]);
|
||||
let startAngle = angle;
|
||||
let endAngle = angle + me._computeAngle(i);
|
||||
let outerRadius = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[i]);
|
||||
angle = endAngle;
|
||||
|
||||
const resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[i]);
|
||||
const options = arc._options = me._resolveDataElementOptions(i);
|
||||
if (reset) {
|
||||
if (animationOpts.animateScale) {
|
||||
outerRadius = 0;
|
||||
}
|
||||
if (animationOpts.animateRotate) {
|
||||
startAngle = datasetStartAngle;
|
||||
endAngle = datasetStartAngle;
|
||||
}
|
||||
}
|
||||
|
||||
arc._model = {
|
||||
backgroundColor: options.backgroundColor,
|
||||
borderColor: options.borderColor,
|
||||
borderWidth: options.borderWidth,
|
||||
borderAlign: options.borderAlign,
|
||||
const properties = {
|
||||
x: centerX,
|
||||
y: centerY,
|
||||
innerRadius: 0,
|
||||
outerRadius: reset ? resetRadius : distance,
|
||||
startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle,
|
||||
endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle
|
||||
outerRadius,
|
||||
startAngle,
|
||||
endAngle,
|
||||
options: me._resolveDataElementOptions(i)
|
||||
};
|
||||
|
||||
arc.pivot(chart._animationsDisabled);
|
||||
me._updateElement(arc, i, properties, mode);
|
||||
}
|
||||
},
|
||||
|
||||
@ -230,26 +229,6 @@ module.exports = DatasetController.extend({
|
||||
return count;
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
setHoverStyle: function(arc) {
|
||||
var model = arc._model;
|
||||
var options = arc._options;
|
||||
var getHoverColor = helpers.getHoverColor;
|
||||
var valueOrDefault = helpers.valueOrDefault;
|
||||
|
||||
arc.$previousStyle = {
|
||||
backgroundColor: model.backgroundColor,
|
||||
borderColor: model.borderColor,
|
||||
borderWidth: model.borderWidth,
|
||||
};
|
||||
|
||||
model.backgroundColor = valueOrDefault(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
|
||||
model.borderColor = valueOrDefault(options.hoverBorderColor, getHoverColor(options.borderColor));
|
||||
model.borderWidth = valueOrDefault(options.hoverBorderWidth, options.borderWidth);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
||||
@ -21,14 +21,6 @@ defaults._set('radar', {
|
||||
}
|
||||
});
|
||||
|
||||
function nextItem(collection, index) {
|
||||
return index >= collection.length - 1 ? collection[0] : collection[index + 1];
|
||||
}
|
||||
|
||||
function previousItem(collection, index) {
|
||||
return index <= 0 ? collection[collection.length - 1] : collection[index - 1];
|
||||
}
|
||||
|
||||
module.exports = DatasetController.extend({
|
||||
datasetElementType: elements.Line,
|
||||
|
||||
@ -93,66 +85,49 @@ module.exports = DatasetController.extend({
|
||||
};
|
||||
},
|
||||
|
||||
update: function(reset) {
|
||||
update: function(mode) {
|
||||
var me = this;
|
||||
var meta = me._cachedMeta;
|
||||
var line = meta.dataset;
|
||||
var points = meta.data || [];
|
||||
var animationsDisabled = me.chart._animationsDisabled;
|
||||
var i, ilen;
|
||||
|
||||
// Data
|
||||
line._children = points;
|
||||
line._loop = true;
|
||||
// Model
|
||||
line._model = me._resolveDatasetElementOptions();
|
||||
const properties = {
|
||||
_children: points,
|
||||
_loop: true,
|
||||
options: me._resolveDatasetElementOptions()
|
||||
};
|
||||
|
||||
line.pivot(animationsDisabled);
|
||||
me._updateElement(line, undefined, properties, mode);
|
||||
|
||||
// Update Points
|
||||
me.updateElements(points, 0, points.length, reset);
|
||||
me.updateElements(points, 0, points.length, mode);
|
||||
|
||||
// Update bezier control points
|
||||
me.updateBezierControlPoints();
|
||||
|
||||
// Now pivot the point for animation
|
||||
for (i = 0, ilen = points.length; i < ilen; ++i) {
|
||||
points[i].pivot(animationsDisabled);
|
||||
}
|
||||
line.updateControlPoints(me.chart.chartArea);
|
||||
},
|
||||
|
||||
updateElements: function(points, start, count, reset) {
|
||||
updateElements: function(points, start, count, mode) {
|
||||
const me = this;
|
||||
const dataset = me.getDataset();
|
||||
const scale = me.chart.scales.r;
|
||||
const reset = mode === 'reset';
|
||||
var i;
|
||||
|
||||
for (i = start; i < start + count; i++) {
|
||||
const point = points[i];
|
||||
const pointPosition = scale.getPointPositionForValue(i, dataset.data[i]);
|
||||
const options = me._resolveDataElementOptions(i);
|
||||
const pointPosition = scale.getPointPositionForValue(i, dataset.data[i]);
|
||||
|
||||
const x = reset ? scale.xCenter : pointPosition.x;
|
||||
const y = reset ? scale.yCenter : pointPosition.y;
|
||||
|
||||
// Utility
|
||||
point._options = options;
|
||||
|
||||
// Desired view properties
|
||||
point._model = {
|
||||
x: x, // value not used in dataset scale, but we want a consistent API between scales
|
||||
const properties = {
|
||||
x: x,
|
||||
y: y,
|
||||
skip: isNaN(x) || isNaN(y),
|
||||
// Appearance
|
||||
radius: options.radius,
|
||||
pointStyle: options.pointStyle,
|
||||
rotation: options.rotation,
|
||||
backgroundColor: options.backgroundColor,
|
||||
borderColor: options.borderColor,
|
||||
borderWidth: options.borderWidth,
|
||||
|
||||
// Tooltip
|
||||
hitRadius: options.hitRadius
|
||||
options,
|
||||
};
|
||||
|
||||
me._updateElement(point, i, properties, mode);
|
||||
}
|
||||
},
|
||||
|
||||
@ -169,59 +144,5 @@ module.exports = DatasetController.extend({
|
||||
values.tension = valueOrDefault(config.lineTension, options.elements.line.tension);
|
||||
|
||||
return values;
|
||||
},
|
||||
|
||||
updateBezierControlPoints: function() {
|
||||
var me = this;
|
||||
var meta = me._cachedMeta;
|
||||
var lineModel = meta.dataset._model;
|
||||
var area = me.chart.chartArea;
|
||||
var points = meta.data || [];
|
||||
var i, ilen, model, controlPoints;
|
||||
|
||||
// Only consider points that are drawn in case the spanGaps option is used
|
||||
if (meta.dataset._model.spanGaps) {
|
||||
points = points.filter(function(pt) {
|
||||
return !pt._model.skip;
|
||||
});
|
||||
}
|
||||
|
||||
function capControlPoint(pt, min, max) {
|
||||
return Math.max(Math.min(pt, max), min);
|
||||
}
|
||||
|
||||
for (i = 0, ilen = points.length; i < ilen; ++i) {
|
||||
model = points[i]._model;
|
||||
controlPoints = helpers.curve.splineCurve(
|
||||
previousItem(points, i)._model,
|
||||
model,
|
||||
nextItem(points, i)._model,
|
||||
lineModel.tension
|
||||
);
|
||||
|
||||
// Prevent the bezier going outside of the bounds of the graph
|
||||
model.controlPointPreviousX = capControlPoint(controlPoints.previous.x, area.left, area.right);
|
||||
model.controlPointPreviousY = capControlPoint(controlPoints.previous.y, area.top, area.bottom);
|
||||
model.controlPointNextX = capControlPoint(controlPoints.next.x, area.left, area.right);
|
||||
model.controlPointNextY = capControlPoint(controlPoints.next.y, area.top, area.bottom);
|
||||
}
|
||||
},
|
||||
|
||||
setHoverStyle: function(point) {
|
||||
var model = point._model;
|
||||
var options = point._options;
|
||||
var getHoverColor = helpers.getHoverColor;
|
||||
|
||||
point.$previousStyle = {
|
||||
backgroundColor: model.backgroundColor,
|
||||
borderColor: model.borderColor,
|
||||
borderWidth: model.borderWidth,
|
||||
radius: model.radius
|
||||
};
|
||||
|
||||
model.backgroundColor = valueOrDefault(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
|
||||
model.borderColor = valueOrDefault(options.hoverBorderColor, getHoverColor(options.borderColor));
|
||||
model.borderWidth = valueOrDefault(options.hoverBorderWidth, options.borderWidth);
|
||||
model.radius = valueOrDefault(options.hoverRadius, options.radius);
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,24 +1,92 @@
|
||||
'use strict';
|
||||
|
||||
const Element = require('./core.element');
|
||||
const helpers = require('../helpers/index');
|
||||
|
||||
class Animation extends Element {
|
||||
const transparent = 'transparent';
|
||||
const interpolators = {
|
||||
number: function(from, to, factor) {
|
||||
return from + (to - from) * factor;
|
||||
},
|
||||
color: function(from, to, factor) {
|
||||
var c0 = helpers.color(from || transparent);
|
||||
var c1 = c0.valid && helpers.color(to || transparent);
|
||||
return c1 && c1.valid
|
||||
? c1.mix(c0, factor).rgbaString()
|
||||
: to;
|
||||
}
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super({
|
||||
chart: null, // the animation associated chart instance
|
||||
currentStep: 0, // the current animation step
|
||||
numSteps: 60, // default number of steps
|
||||
easing: '', // the easing to use for this animation
|
||||
render: null, // render function used by the animation service
|
||||
class Animation {
|
||||
constructor(cfg, target, prop, to) {
|
||||
const me = this;
|
||||
let from = cfg.from;
|
||||
|
||||
onAnimationProgress: null, // user specified callback to fire on each step of the animation
|
||||
onAnimationComplete: null, // user specified callback to fire when the animation finishes
|
||||
});
|
||||
helpers.extend(this, props);
|
||||
if (from === undefined) {
|
||||
from = target[prop];
|
||||
}
|
||||
if (to === undefined) {
|
||||
to = target[prop];
|
||||
}
|
||||
|
||||
if (from === undefined) {
|
||||
from = to;
|
||||
} else if (to === undefined) {
|
||||
to = from;
|
||||
}
|
||||
|
||||
me._active = true;
|
||||
me._fn = cfg.fn || interpolators[cfg.type || typeof from];
|
||||
me._easing = helpers.easing.effects[cfg.easing || 'linear'];
|
||||
me._start = Math.floor(Date.now() + (cfg.delay || 0));
|
||||
me._duration = Math.floor(cfg.duration);
|
||||
me._loop = !!cfg.loop;
|
||||
me._target = target;
|
||||
me._prop = prop;
|
||||
me._from = from;
|
||||
me._to = to;
|
||||
}
|
||||
|
||||
active() {
|
||||
return this._active;
|
||||
}
|
||||
|
||||
cancel() {
|
||||
const me = this;
|
||||
if (me._active) {
|
||||
// update current evaluated value, for smoother animations
|
||||
me.tick(Date.now());
|
||||
me._active = false;
|
||||
}
|
||||
}
|
||||
|
||||
tick(date) {
|
||||
const me = this;
|
||||
const elapsed = date - me._start;
|
||||
const duration = me._duration;
|
||||
const prop = me._prop;
|
||||
const from = me._from;
|
||||
const loop = me._loop;
|
||||
const to = me._to;
|
||||
let factor;
|
||||
|
||||
me._active = from !== to && (loop || (elapsed < duration));
|
||||
|
||||
if (!me._active) {
|
||||
me._target[prop] = to;
|
||||
return;
|
||||
}
|
||||
|
||||
if (elapsed < 0) {
|
||||
me._target[prop] = from;
|
||||
return;
|
||||
}
|
||||
|
||||
factor = (elapsed / duration) % 2;
|
||||
factor = loop && factor > 1 ? 2 - factor : factor;
|
||||
factor = me._easing(Math.min(1, Math.max(0, factor)));
|
||||
|
||||
me._target[prop] = me._fn(from, to, factor);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Animation;
|
||||
|
||||
@ -1,121 +1,166 @@
|
||||
'use strict';
|
||||
|
||||
var defaults = require('./core.defaults');
|
||||
var helpers = require('../helpers/index');
|
||||
const Animator = require('./core.animator');
|
||||
const Animation = require('./core.animation');
|
||||
const helpers = require('../helpers/index');
|
||||
const defaults = require('./core.defaults');
|
||||
|
||||
defaults._set('global', {
|
||||
animation: {
|
||||
duration: 1000,
|
||||
easing: 'easeOutQuart',
|
||||
active: {
|
||||
duration: 400
|
||||
},
|
||||
resize: {
|
||||
duration: 0
|
||||
},
|
||||
numbers: {
|
||||
type: 'number',
|
||||
properties: ['x', 'y', 'borderWidth', 'radius', 'tension']
|
||||
},
|
||||
colors: {
|
||||
type: 'color',
|
||||
properties: ['borderColor', 'backgroundColor']
|
||||
},
|
||||
onProgress: helpers.noop,
|
||||
onComplete: helpers.noop
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
animations: [],
|
||||
request: null,
|
||||
function copyOptions(target, values) {
|
||||
let oldOpts = target.options;
|
||||
let newOpts = values.options;
|
||||
if (!oldOpts || !newOpts || newOpts.$shared) {
|
||||
return;
|
||||
}
|
||||
if (oldOpts.$shared) {
|
||||
target.options = helpers.extend({}, oldOpts, newOpts, {$shared: false});
|
||||
} else {
|
||||
helpers.extend(oldOpts, newOpts);
|
||||
}
|
||||
delete values.options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chart} chart - The chart to animate.
|
||||
* @param {Chart.Animation} animation - The animation that we will animate.
|
||||
* @param {number} duration - The animation duration in ms.
|
||||
* @param {boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions
|
||||
*/
|
||||
addAnimation: function(chart, animation, duration, lazy) {
|
||||
var animations = this.animations;
|
||||
var i, ilen;
|
||||
class Animations {
|
||||
constructor(chart, animations) {
|
||||
this._chart = chart;
|
||||
this._properties = new Map();
|
||||
this.configure(animations);
|
||||
}
|
||||
|
||||
animation.chart = chart;
|
||||
animation.startTime = Date.now();
|
||||
animation.duration = duration;
|
||||
configure(animations) {
|
||||
const animatedProps = this._properties;
|
||||
const animDefaults = Object.fromEntries(Object.entries(animations).filter(({1: value}) => !helpers.isObject(value)));
|
||||
|
||||
if (!lazy) {
|
||||
chart.animating = true;
|
||||
}
|
||||
|
||||
for (i = 0, ilen = animations.length; i < ilen; ++i) {
|
||||
if (animations[i].chart === chart) {
|
||||
animations[i] = animation;
|
||||
return;
|
||||
for (let [key, cfg] of Object.entries(animations)) {
|
||||
if (!helpers.isObject(cfg)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
animations.push(animation);
|
||||
|
||||
// If there are no animations queued, manually kickstart a digest, for lack of a better word
|
||||
if (animations.length === 1) {
|
||||
this.requestAnimationFrame();
|
||||
}
|
||||
},
|
||||
|
||||
cancelAnimation: function(chart) {
|
||||
var index = helpers.findIndex(this.animations, function(animation) {
|
||||
return animation.chart === chart;
|
||||
});
|
||||
|
||||
if (index !== -1) {
|
||||
this.animations.splice(index, 1);
|
||||
chart.animating = false;
|
||||
}
|
||||
},
|
||||
|
||||
requestAnimationFrame: function() {
|
||||
var me = this;
|
||||
if (me.request === null) {
|
||||
// Skip animation frame requests until the active one is executed.
|
||||
// This can happen when processing mouse events, e.g. 'mousemove'
|
||||
// and 'mouseout' events will trigger multiple renders.
|
||||
me.request = helpers.requestAnimFrame.call(window, function() {
|
||||
me.request = null;
|
||||
me.startDigest();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
startDigest: function() {
|
||||
var me = this;
|
||||
|
||||
me.advance();
|
||||
|
||||
// Do we have more stuff to animate?
|
||||
if (me.animations.length > 0) {
|
||||
me.requestAnimationFrame();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
advance: function() {
|
||||
var animations = this.animations;
|
||||
var animation, chart, numSteps, nextStep;
|
||||
var i = 0;
|
||||
|
||||
// 1 animation per chart, so we are looping charts here
|
||||
while (i < animations.length) {
|
||||
animation = animations[i];
|
||||
chart = animation.chart;
|
||||
numSteps = animation.numSteps;
|
||||
|
||||
// Make sure that currentStep starts at 1
|
||||
// https://github.com/chartjs/Chart.js/issues/6104
|
||||
nextStep = Math.floor((Date.now() - animation.startTime) / animation.duration * numSteps) + 1;
|
||||
animation.currentStep = Math.min(nextStep, numSteps);
|
||||
|
||||
helpers.callback(animation.render, [chart, animation], chart);
|
||||
helpers.callback(animation.onAnimationProgress, [animation], chart);
|
||||
|
||||
if (animation.currentStep >= numSteps) {
|
||||
helpers.callback(animation.onAnimationComplete, [animation], chart);
|
||||
chart.animating = false;
|
||||
animations.splice(i, 1);
|
||||
} else {
|
||||
++i;
|
||||
for (let prop of cfg.properties || [key]) {
|
||||
// Can have only one config per animation.
|
||||
if (!animatedProps.has(prop)) {
|
||||
animatedProps.set(prop, helpers.extend({}, animDefaults, cfg));
|
||||
} else if (prop === key) {
|
||||
// Single property targetting config wins over multi-targetting.
|
||||
animatedProps.set(prop, helpers.extend({}, animatedProps.get(prop), cfg));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility to handle animation of `options`.
|
||||
* This should not be called, when animating $shared options to $shared new options.
|
||||
* @private
|
||||
* @todo if new options are $shared, target.options should be replaced with those new shared
|
||||
* options after all animations have completed
|
||||
*/
|
||||
_animateOptions(target, values) {
|
||||
const newOptions = values.options;
|
||||
let animations = [];
|
||||
|
||||
if (!newOptions) {
|
||||
return animations;
|
||||
}
|
||||
let options = target.options;
|
||||
if (options) {
|
||||
if (options.$shared) {
|
||||
// If the current / old options are $shared, meaning other elements are
|
||||
// using the same options, we need to clone to become unique.
|
||||
target.options = options = helpers.extend({}, options, {$shared: false, $animations: {}});
|
||||
}
|
||||
animations = this._createAnimations(options, newOptions);
|
||||
} else {
|
||||
target.options = newOptions;
|
||||
}
|
||||
return animations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_createAnimations(target, values) {
|
||||
const animatedProps = this._properties;
|
||||
const animations = [];
|
||||
const running = target.$animations || (target.$animations = {});
|
||||
const props = Object.keys(values);
|
||||
let i;
|
||||
|
||||
for (i = props.length - 1; i >= 0; --i) {
|
||||
let prop = props[i];
|
||||
if (prop.charAt(0) === '$') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prop === 'options') {
|
||||
animations.push.apply(animations, this._animateOptions(target, values));
|
||||
continue;
|
||||
}
|
||||
let value = values[prop];
|
||||
|
||||
const cfg = animatedProps.get(prop);
|
||||
if (!cfg || !cfg.duration) {
|
||||
// not animated, set directly to new value
|
||||
target[prop] = value;
|
||||
continue;
|
||||
}
|
||||
|
||||
let animation = running[prop];
|
||||
if (animation) {
|
||||
animation.cancel();
|
||||
}
|
||||
running[prop] = animation = new Animation(cfg, target, prop, value);
|
||||
animations.push(animation);
|
||||
}
|
||||
return animations;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update `target` properties to new values, using configured animations
|
||||
* @param {object} target - object to update
|
||||
* @param {object} values - new target properties
|
||||
* @returns {boolean|undefined} - `true` if animations were started
|
||||
**/
|
||||
update(target, values) {
|
||||
if (this._properties.size === 0) {
|
||||
// Nothing is animated, just apply the new values.
|
||||
// Options can be shared, need to account for that.
|
||||
copyOptions(target, values);
|
||||
// copyOptions removes the `options` from `values`,
|
||||
// unless it can be directly assigned.
|
||||
helpers.extend(target, values);
|
||||
return;
|
||||
}
|
||||
|
||||
const animations = this._createAnimations(target, values);
|
||||
|
||||
if (animations.length) {
|
||||
Animator.add(this._chart, animations);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Animations;
|
||||
|
||||
211
src/core/core.animator.js
Normal file
211
src/core/core.animator.js
Normal file
@ -0,0 +1,211 @@
|
||||
'use strict';
|
||||
|
||||
const helpers = require('../helpers/index');
|
||||
|
||||
function drawFPS(chart, count, date, lastDate) {
|
||||
const fps = (1000 / (date - lastDate)) | 0;
|
||||
const ctx = chart.ctx;
|
||||
ctx.save();
|
||||
ctx.clearRect(0, 0, 50, 24);
|
||||
ctx.fillStyle = 'black';
|
||||
ctx.textAlign = 'right';
|
||||
if (count) {
|
||||
ctx.fillText(count, 50, 8);
|
||||
ctx.fillText(fps + ' fps', 50, 18);
|
||||
}
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
class Animator {
|
||||
constructor() {
|
||||
this._request = null;
|
||||
this._charts = new Map();
|
||||
this._running = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_notify(chart, anims, date, type) {
|
||||
const callbacks = anims.listeners[type] || [];
|
||||
const numSteps = anims.duration;
|
||||
|
||||
callbacks.forEach(fn => fn({
|
||||
chart: chart,
|
||||
numSteps,
|
||||
currentStep: date - anims.start
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_refresh() {
|
||||
const me = this;
|
||||
|
||||
if (me._request) {
|
||||
return;
|
||||
}
|
||||
me._running = true;
|
||||
|
||||
me._request = helpers.requestAnimFrame.call(window, function() {
|
||||
me._update();
|
||||
me._request = null;
|
||||
|
||||
if (me._running) {
|
||||
me._refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_update() {
|
||||
const me = this;
|
||||
const date = Date.now();
|
||||
const charts = me._charts;
|
||||
let remaining = 0;
|
||||
|
||||
for (let [chart, anims] of charts) {
|
||||
if (!anims.running || !anims.items.length) {
|
||||
continue;
|
||||
}
|
||||
const items = anims.items;
|
||||
let i = items.length - 1;
|
||||
let draw = false;
|
||||
let item;
|
||||
|
||||
for (; i >= 0; --i) {
|
||||
item = items[i];
|
||||
|
||||
if (item._active) {
|
||||
item.tick(date);
|
||||
draw = true;
|
||||
} else {
|
||||
// Remove the item by replacing it with last item and removing the last
|
||||
// A lot faster than splice.
|
||||
items[i] = items[items.length - 1];
|
||||
items.pop();
|
||||
}
|
||||
}
|
||||
|
||||
if (draw) {
|
||||
chart.draw();
|
||||
if (chart.options.animation.debug) {
|
||||
drawFPS(chart, items.length, date, me._lastDate);
|
||||
}
|
||||
}
|
||||
|
||||
me._notify(chart, anims, date, 'progress');
|
||||
|
||||
if (!items.length) {
|
||||
anims.running = false;
|
||||
me._notify(chart, anims, date, 'complete');
|
||||
}
|
||||
|
||||
remaining += items.length;
|
||||
}
|
||||
|
||||
this._lastDate = date;
|
||||
|
||||
if (remaining === 0) {
|
||||
this._running = false;
|
||||
}
|
||||
}
|
||||
|
||||
_getAnims(chart) {
|
||||
const charts = this._charts;
|
||||
let anims = charts.get(chart);
|
||||
if (!anims) {
|
||||
anims = {
|
||||
running: false,
|
||||
items: [],
|
||||
listeners: {
|
||||
complete: [],
|
||||
progress: []
|
||||
}
|
||||
};
|
||||
charts.set(chart, anims);
|
||||
}
|
||||
return anims;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chart} chart
|
||||
* @param {string} event - event name
|
||||
* @param {Function} cb - callback
|
||||
*/
|
||||
listen(chart, event, cb) {
|
||||
this._getAnims(chart).listeners[event].push(cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add animations
|
||||
* @param {Chart} chart
|
||||
* @param {Animation[]} items - animations
|
||||
*/
|
||||
add(chart, items) {
|
||||
if (!items || !items.length) {
|
||||
return;
|
||||
}
|
||||
this._getAnims(chart).items.push(...items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts number of active animations for the chart
|
||||
* @param {Chart} chart
|
||||
*/
|
||||
has(chart) {
|
||||
return this._getAnims(chart).items.length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start animating (all charts)
|
||||
* @param {Chart} chart
|
||||
*/
|
||||
start(chart) {
|
||||
const anims = this._charts.get(chart);
|
||||
if (!anims) {
|
||||
return;
|
||||
}
|
||||
anims.running = true;
|
||||
anims.start = Date.now();
|
||||
anims.duration = anims.items.reduce((acc, cur) => Math.max(acc, cur._duration), 0);
|
||||
this._refresh();
|
||||
}
|
||||
|
||||
running(chart) {
|
||||
if (!this._running) {
|
||||
return false;
|
||||
}
|
||||
const anims = this._charts.get(chart);
|
||||
if (!anims || !anims.running || !anims.items.length) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop all animations for the chart
|
||||
* @param {Chart} chart
|
||||
*/
|
||||
stop(chart) {
|
||||
const anims = this._charts.get(chart);
|
||||
if (!anims || !anims.items.length) {
|
||||
return;
|
||||
}
|
||||
const items = anims.items;
|
||||
let i = items.length - 1;
|
||||
|
||||
for (; i >= 0; --i) {
|
||||
items[i].cancel();
|
||||
}
|
||||
anims.items = [];
|
||||
this._notify(chart, anims, Date.now(), 'complete');
|
||||
}
|
||||
}
|
||||
|
||||
const instance = new Animator();
|
||||
|
||||
module.exports = instance;
|
||||
@ -1,7 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var Animation = require('./core.animation');
|
||||
var animations = require('./core.animations');
|
||||
var Animator = require('./core.animator');
|
||||
var controllers = require('../controllers/index');
|
||||
var defaults = require('./core.defaults');
|
||||
var helpers = require('../helpers/index');
|
||||
@ -26,13 +25,11 @@ defaults._set('global', {
|
||||
hover: {
|
||||
onHover: null,
|
||||
mode: 'nearest',
|
||||
intersect: true,
|
||||
animationDuration: 400
|
||||
intersect: true
|
||||
},
|
||||
onClick: null,
|
||||
maintainAspectRatio: true,
|
||||
responsive: true,
|
||||
responsiveAnimationDuration: 0
|
||||
responsive: true
|
||||
});
|
||||
|
||||
function mergeScaleConfig(config, options) {
|
||||
@ -115,11 +112,7 @@ function initConfig(config) {
|
||||
}
|
||||
|
||||
function isAnimationDisabled(config) {
|
||||
return !config.animation || !(
|
||||
config.animation.duration ||
|
||||
(config.hover && config.hover.animationDuration) ||
|
||||
config.responsiveAnimationDuration
|
||||
);
|
||||
return !config.animation;
|
||||
}
|
||||
|
||||
function updateConfig(chart) {
|
||||
@ -143,8 +136,6 @@ function updateConfig(chart) {
|
||||
chart.ensureScalesHaveIDs();
|
||||
chart.buildOrUpdateScales();
|
||||
|
||||
// Tooltip
|
||||
chart.tooltip._options = newOptions.tooltips;
|
||||
chart.tooltip.initialize();
|
||||
}
|
||||
|
||||
@ -161,6 +152,20 @@ function compare2Level(l1, l2) {
|
||||
};
|
||||
}
|
||||
|
||||
function onAnimationsComplete(ctx) {
|
||||
const chart = ctx.chart;
|
||||
const animationOptions = chart.options.animation;
|
||||
|
||||
plugins.notify(chart, 'afterRender');
|
||||
helpers.callback(animationOptions && animationOptions.onComplete, arguments, chart);
|
||||
}
|
||||
|
||||
function onAnimationProgress(ctx) {
|
||||
const chart = ctx.chart;
|
||||
const animationOptions = chart.options.animation;
|
||||
helpers.callback(animationOptions && animationOptions.onProgress, arguments, chart);
|
||||
}
|
||||
|
||||
var Chart = function(item, config) {
|
||||
this.construct(item, config);
|
||||
return this;
|
||||
@ -213,6 +218,9 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
return;
|
||||
}
|
||||
|
||||
Animator.listen(me, 'complete', onAnimationsComplete);
|
||||
Animator.listen(me, 'progress', onAnimationProgress);
|
||||
|
||||
me.initialize();
|
||||
me.update();
|
||||
},
|
||||
@ -249,8 +257,7 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
// Stops any current animation loop occurring
|
||||
animations.cancelAnimation(this);
|
||||
Animator.stop(this);
|
||||
return this;
|
||||
},
|
||||
|
||||
@ -289,9 +296,7 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
}
|
||||
|
||||
me.stop();
|
||||
me.update({
|
||||
duration: options.responsiveAnimationDuration
|
||||
});
|
||||
me.update('resize');
|
||||
}
|
||||
},
|
||||
|
||||
@ -455,11 +460,11 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
this.tooltip.initialize();
|
||||
},
|
||||
|
||||
update: function(config) {
|
||||
update: function(mode) {
|
||||
var me = this;
|
||||
var i, ilen;
|
||||
|
||||
config = config || {};
|
||||
me._updating = true;
|
||||
|
||||
updateConfig(me);
|
||||
|
||||
@ -471,9 +476,6 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
return;
|
||||
}
|
||||
|
||||
// In case the entire data object changed
|
||||
me.tooltip._data = me.data;
|
||||
|
||||
// Make sure dataset controllers are updated and new controllers are reset
|
||||
var newControllers = me.buildOrUpdateControllers();
|
||||
|
||||
@ -485,40 +487,27 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
me.updateLayout();
|
||||
|
||||
// Can only reset the new controllers after the scales have been updated
|
||||
if (me.options.animation && me.options.animation.duration) {
|
||||
if (me.options.animation) {
|
||||
helpers.each(newControllers, function(controller) {
|
||||
controller.reset();
|
||||
});
|
||||
}
|
||||
|
||||
me.updateDatasets();
|
||||
|
||||
// Need to reset tooltip in case it is displayed with elements that are removed
|
||||
// after update.
|
||||
me.tooltip.initialize();
|
||||
|
||||
// Last active contains items that were previously hovered.
|
||||
me.lastActive = [];
|
||||
me.updateDatasets(mode);
|
||||
|
||||
// Do this before render so that any plugins that need final scale updates can use it
|
||||
plugins.notify(me, 'afterUpdate');
|
||||
|
||||
me._layers.sort(compare2Level('z', '_idx'));
|
||||
|
||||
if (me._bufferedRender) {
|
||||
me._bufferedRequest = {
|
||||
duration: config.duration,
|
||||
easing: config.easing,
|
||||
lazy: config.lazy
|
||||
};
|
||||
} else {
|
||||
me.render(config);
|
||||
}
|
||||
|
||||
// Replay last event from before update
|
||||
if (me._lastEvent) {
|
||||
me.eventHandler(me._lastEvent);
|
||||
}
|
||||
|
||||
me.render();
|
||||
|
||||
me._updating = false;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -557,7 +546,7 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
* hook, in which case, plugins will not be called on `afterDatasetsUpdate`.
|
||||
* @private
|
||||
*/
|
||||
updateDatasets: function() {
|
||||
updateDatasets: function(mode) {
|
||||
var me = this;
|
||||
|
||||
if (plugins.notify(me, 'beforeDatasetsUpdate') === false) {
|
||||
@ -565,7 +554,7 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
}
|
||||
|
||||
for (var i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
|
||||
me.updateDataset(i);
|
||||
me.updateDataset(i, mode);
|
||||
}
|
||||
|
||||
plugins.notify(me, 'afterDatasetsUpdate');
|
||||
@ -576,91 +565,52 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
* hook, in which case, plugins will not be called on `afterDatasetUpdate`.
|
||||
* @private
|
||||
*/
|
||||
updateDataset: function(index) {
|
||||
var me = this;
|
||||
var meta = me.getDatasetMeta(index);
|
||||
var args = {
|
||||
meta: meta,
|
||||
index: index
|
||||
};
|
||||
updateDataset: function(index, mode) {
|
||||
const me = this;
|
||||
const meta = me.getDatasetMeta(index);
|
||||
const args = {meta, index, mode};
|
||||
|
||||
if (plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
meta.controller._update();
|
||||
meta.controller._update(mode);
|
||||
|
||||
plugins.notify(me, 'afterDatasetUpdate', [args]);
|
||||
},
|
||||
|
||||
render: function(config) {
|
||||
var me = this;
|
||||
|
||||
if (!config || typeof config !== 'object') {
|
||||
// backwards compatibility
|
||||
config = {
|
||||
duration: config,
|
||||
lazy: arguments[1]
|
||||
};
|
||||
}
|
||||
|
||||
var animationOptions = me.options.animation;
|
||||
var duration = valueOrDefault(config.duration, animationOptions && animationOptions.duration);
|
||||
var lazy = config.lazy;
|
||||
|
||||
render: function() {
|
||||
const me = this;
|
||||
const animationOptions = me.options.animation;
|
||||
if (plugins.notify(me, 'beforeRender') === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var onComplete = function(animation) {
|
||||
var onComplete = function() {
|
||||
plugins.notify(me, 'afterRender');
|
||||
helpers.callback(animationOptions && animationOptions.onComplete, [animation], me);
|
||||
helpers.callback(animationOptions && animationOptions.onComplete, [], me);
|
||||
};
|
||||
|
||||
if (animationOptions && duration) {
|
||||
var animation = new Animation({
|
||||
numSteps: duration / 16.66, // 60 fps
|
||||
easing: config.easing || animationOptions.easing,
|
||||
|
||||
render: function(chart, animationObject) {
|
||||
const easingFunction = helpers.easing.effects[animationObject.easing];
|
||||
const stepDecimal = animationObject.currentStep / animationObject.numSteps;
|
||||
|
||||
chart.draw(easingFunction(stepDecimal));
|
||||
},
|
||||
|
||||
onAnimationProgress: animationOptions.onProgress,
|
||||
onAnimationComplete: onComplete
|
||||
});
|
||||
|
||||
animations.addAnimation(me, animation, duration, lazy);
|
||||
if (Animator.has(me)) {
|
||||
if (!Animator.running(me)) {
|
||||
Animator.start(me);
|
||||
}
|
||||
} else {
|
||||
me.draw();
|
||||
|
||||
// See https://github.com/chartjs/Chart.js/issues/3781
|
||||
onComplete(new Animation({numSteps: 0, chart: me}));
|
||||
onComplete();
|
||||
}
|
||||
|
||||
return me;
|
||||
},
|
||||
|
||||
draw: function(easingValue) {
|
||||
draw: function() {
|
||||
var me = this;
|
||||
var i, layers;
|
||||
|
||||
me.clear();
|
||||
|
||||
if (helpers.isNullOrUndef(easingValue)) {
|
||||
easingValue = 1;
|
||||
}
|
||||
|
||||
me.transition(easingValue);
|
||||
|
||||
if (me.width <= 0 || me.height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (plugins.notify(me, 'beforeDraw', [easingValue]) === false) {
|
||||
if (plugins.notify(me, 'beforeDraw') === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -672,41 +622,16 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
layers[i].draw(me.chartArea);
|
||||
}
|
||||
|
||||
me.drawDatasets(easingValue);
|
||||
me.drawDatasets();
|
||||
|
||||
// Rest of layers
|
||||
for (; i < layers.length; ++i) {
|
||||
layers[i].draw(me.chartArea);
|
||||
}
|
||||
|
||||
me._drawTooltip(easingValue);
|
||||
me._drawTooltip();
|
||||
|
||||
plugins.notify(me, 'afterDraw', [easingValue]);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
transition: function(easingValue) {
|
||||
const me = this;
|
||||
var i, ilen;
|
||||
|
||||
if (!me._animationsDisabled) {
|
||||
const metas = me._getSortedDatasetMetas();
|
||||
for (i = 0, ilen = metas.length; i < ilen; ++i) {
|
||||
let meta = metas[i];
|
||||
if (meta.visible) {
|
||||
meta.controller.transition(easingValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
me.tooltip.transition(easingValue);
|
||||
|
||||
if (me._lastEvent && me.animating) {
|
||||
// If, during animation, element under mouse changes, let's react to that.
|
||||
me.handleEvent(me._lastEvent);
|
||||
}
|
||||
plugins.notify(me, 'afterDraw');
|
||||
},
|
||||
|
||||
/**
|
||||
@ -740,20 +665,20 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
* hook, in which case, plugins will not be called on `afterDatasetsDraw`.
|
||||
* @private
|
||||
*/
|
||||
drawDatasets: function(easingValue) {
|
||||
drawDatasets: function() {
|
||||
var me = this;
|
||||
var metasets, i;
|
||||
|
||||
if (plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) {
|
||||
if (plugins.notify(me, 'beforeDatasetsDraw') === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
metasets = me._getSortedVisibleDatasetMetas();
|
||||
for (i = metasets.length - 1; i >= 0; --i) {
|
||||
me.drawDataset(metasets[i], easingValue);
|
||||
me.drawDataset(metasets[i]);
|
||||
}
|
||||
|
||||
plugins.notify(me, 'afterDatasetsDraw', [easingValue]);
|
||||
plugins.notify(me, 'afterDatasetsDraw');
|
||||
},
|
||||
|
||||
/**
|
||||
@ -761,7 +686,7 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
* hook, in which case, plugins will not be called on `afterDatasetDraw`.
|
||||
* @private
|
||||
*/
|
||||
drawDataset: function(meta, easingValue) {
|
||||
drawDataset: function(meta) {
|
||||
var me = this;
|
||||
var ctx = me.ctx;
|
||||
var clip = meta._clip;
|
||||
@ -770,7 +695,6 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
var args = {
|
||||
meta: meta,
|
||||
index: meta.index,
|
||||
easingValue: easingValue
|
||||
};
|
||||
|
||||
if (plugins.notify(me, 'beforeDatasetDraw', [args]) === false) {
|
||||
@ -784,7 +708,7 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
bottom: clip.bottom === false ? canvas.height : area.bottom + clip.bottom
|
||||
});
|
||||
|
||||
meta.controller.draw(easingValue);
|
||||
meta.controller.draw();
|
||||
|
||||
helpers.canvas.unclipArea(ctx);
|
||||
|
||||
@ -796,19 +720,18 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
* hook, in which case, plugins will not be called on `afterTooltipDraw`.
|
||||
* @private
|
||||
*/
|
||||
_drawTooltip: function(easingValue) {
|
||||
_drawTooltip: function() {
|
||||
var me = this;
|
||||
var tooltip = me.tooltip;
|
||||
var args = {
|
||||
tooltip: tooltip,
|
||||
easingValue: easingValue
|
||||
tooltip: tooltip
|
||||
};
|
||||
|
||||
if (plugins.notify(me, 'beforeTooltipDraw', [args]) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
tooltip.draw();
|
||||
tooltip.draw(me.ctx);
|
||||
|
||||
plugins.notify(me, 'afterTooltipDraw', [args]);
|
||||
},
|
||||
@ -925,12 +848,7 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
},
|
||||
|
||||
initToolTip: function() {
|
||||
var me = this;
|
||||
me.tooltip = new Tooltip({
|
||||
_chart: me,
|
||||
_data: me.data,
|
||||
_options: me.options.tooltips
|
||||
});
|
||||
this.tooltip = new Tooltip({_chart: this});
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1020,48 +938,22 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
* @private
|
||||
*/
|
||||
eventHandler: function(e) {
|
||||
var me = this;
|
||||
var tooltip = me.tooltip;
|
||||
const me = this;
|
||||
const tooltip = me.tooltip;
|
||||
|
||||
if (plugins.notify(me, 'beforeEvent', [e]) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Buffer any update calls so that renders do not occur
|
||||
me._bufferedRender = true;
|
||||
me._bufferedRequest = null;
|
||||
me.handleEvent(e);
|
||||
|
||||
var changed = me.handleEvent(e);
|
||||
// for smooth tooltip animations issue #4989
|
||||
// the tooltip should be the source of change
|
||||
// Animation check workaround:
|
||||
// tooltip._start will be null when tooltip isn't animating
|
||||
if (tooltip) {
|
||||
changed = tooltip._start
|
||||
? tooltip.handleEvent(e)
|
||||
: changed | tooltip.handleEvent(e);
|
||||
tooltip.handleEvent(e);
|
||||
}
|
||||
|
||||
plugins.notify(me, 'afterEvent', [e]);
|
||||
|
||||
var bufferedRequest = me._bufferedRequest;
|
||||
if (bufferedRequest) {
|
||||
// If we have an update that was triggered, we need to do a normal render
|
||||
me.render(bufferedRequest);
|
||||
} else if (changed && !me.animating) {
|
||||
// If entering, leaving, or changing elements, animate the change via pivot
|
||||
me.stop();
|
||||
|
||||
// We only need to render at this point. Updating will cause scales to be
|
||||
// recomputed generating flicker & using more memory than necessary.
|
||||
me.render({
|
||||
duration: me.options.hover.animationDuration,
|
||||
lazy: true
|
||||
});
|
||||
}
|
||||
|
||||
me._bufferedRender = false;
|
||||
me._bufferedRequest = null;
|
||||
me.render();
|
||||
|
||||
return me;
|
||||
},
|
||||
@ -1086,7 +978,7 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
me._lastEvent = null;
|
||||
} else {
|
||||
me.active = me.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions);
|
||||
me._lastEvent = e.type === 'click' ? null : e;
|
||||
me._lastEvent = e.type === 'click' ? me._lastEvent : e;
|
||||
}
|
||||
|
||||
// Invoke onHover hook
|
||||
@ -1100,8 +992,10 @@ helpers.extend(Chart.prototype, /** @lends Chart */ {
|
||||
}
|
||||
}
|
||||
|
||||
me._updateHoverStyles();
|
||||
changed = !helpers._elementsEqual(me.active, me.lastActive);
|
||||
if (changed) {
|
||||
me._updateHoverStyles();
|
||||
}
|
||||
|
||||
// Remember Last Actives
|
||||
me.lastActive = me.active;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var helpers = require('../helpers/index');
|
||||
var Animations = require('./core.animations');
|
||||
|
||||
var resolve = helpers.options.resolve;
|
||||
|
||||
@ -268,6 +269,8 @@ helpers.extend(DatasetController.prototype, {
|
||||
me.chart = chart;
|
||||
me._ctx = chart.ctx;
|
||||
me.index = datasetIndex;
|
||||
me._cachedAnimations = {};
|
||||
me._cachedDataOpts = {};
|
||||
me._cachedMeta = meta = me.getMeta();
|
||||
me._type = meta.type;
|
||||
me._configure();
|
||||
@ -347,7 +350,7 @@ helpers.extend(DatasetController.prototype, {
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this._update(true);
|
||||
this._update('reset');
|
||||
},
|
||||
|
||||
/**
|
||||
@ -450,7 +453,7 @@ helpers.extend(DatasetController.prototype, {
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the merged user-supplied and default dataset-level options
|
||||
* Merges user-supplied and default dataset-level options
|
||||
* @private
|
||||
*/
|
||||
_configure: function() {
|
||||
@ -740,33 +743,19 @@ helpers.extend(DatasetController.prototype, {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_update: function(reset) {
|
||||
_update: function(mode) {
|
||||
const me = this;
|
||||
const meta = me._cachedMeta;
|
||||
me._configure();
|
||||
me._cachedDataOpts = null;
|
||||
me.update(reset);
|
||||
me._cachedAnimations = {};
|
||||
me._cachedDataOpts = {};
|
||||
me.update(mode);
|
||||
meta._clip = toClip(helpers.valueOrDefault(me._config.clip, defaultClip(meta.xScale, meta.yScale, me._getMaxOverflow())));
|
||||
me._cacheScaleStackStatus();
|
||||
},
|
||||
|
||||
update: helpers.noop,
|
||||
|
||||
transition: function(easingValue) {
|
||||
const meta = this._cachedMeta;
|
||||
const elements = meta.data || [];
|
||||
const ilen = elements.length;
|
||||
let i = 0;
|
||||
|
||||
for (; i < ilen; ++i) {
|
||||
elements[i].transition(easingValue);
|
||||
}
|
||||
|
||||
if (meta.dataset) {
|
||||
meta.dataset.transition(easingValue);
|
||||
}
|
||||
},
|
||||
|
||||
draw: function() {
|
||||
const ctx = this._ctx;
|
||||
const meta = this._cachedMeta;
|
||||
@ -783,30 +772,54 @@ helpers.extend(DatasetController.prototype, {
|
||||
}
|
||||
},
|
||||
|
||||
_addAutomaticHoverColors: function(index, options) {
|
||||
const me = this;
|
||||
const getHoverColor = helpers.getHoverColor;
|
||||
const normalOptions = me.getStyle(index);
|
||||
const missingColors = Object.keys(normalOptions).filter(key => {
|
||||
return key.indexOf('Color') !== -1 && !(key in options);
|
||||
});
|
||||
let i = missingColors.length - 1;
|
||||
let color;
|
||||
for (; i >= 0; i--) {
|
||||
color = missingColors[i];
|
||||
options[color] = getHoverColor(normalOptions[color]);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a set of predefined style properties that should be used to represent the dataset
|
||||
* or the data if the index is specified
|
||||
* @param {number} index - data index
|
||||
* @return {IStyleInterface} style object
|
||||
*/
|
||||
getStyle: function(index) {
|
||||
getStyle: function(index, active) {
|
||||
const me = this;
|
||||
const meta = me._cachedMeta;
|
||||
const dataset = meta.dataset;
|
||||
let style;
|
||||
|
||||
if (dataset && index === undefined) {
|
||||
style = me._resolveDatasetElementOptions();
|
||||
} else {
|
||||
index = index || 0;
|
||||
style = me._resolveDataElementOptions(index);
|
||||
if (!me._config) {
|
||||
me._configure();
|
||||
}
|
||||
|
||||
if (style.fill === false || style.fill === null) {
|
||||
style.backgroundColor = style.borderColor;
|
||||
const options = dataset && index === undefined
|
||||
? me._resolveDatasetElementOptions(active)
|
||||
: me._resolveDataElementOptions(index || 0, active && 'active');
|
||||
if (active) {
|
||||
me._addAutomaticHoverColors(index, options);
|
||||
}
|
||||
return options;
|
||||
},
|
||||
|
||||
_getContext(index, active) {
|
||||
return {
|
||||
chart: this.chart,
|
||||
dataIndex: index,
|
||||
dataset: this.getDataset(),
|
||||
datasetIndex: this.index,
|
||||
active
|
||||
};
|
||||
|
||||
return style;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -819,21 +832,19 @@ helpers.extend(DatasetController.prototype, {
|
||||
const options = chart.options.elements[me.datasetElementType.prototype._type] || {};
|
||||
const elementOptions = me._datasetElementOptions;
|
||||
const values = {};
|
||||
const context = {
|
||||
chart,
|
||||
dataset: me.getDataset(),
|
||||
datasetIndex: me.index,
|
||||
active
|
||||
};
|
||||
let i, ilen, key, readKey;
|
||||
const context = me._getContext(undefined, active);
|
||||
let i, ilen, key, readKey, value;
|
||||
|
||||
for (i = 0, ilen = elementOptions.length; i < ilen; ++i) {
|
||||
key = elementOptions[i];
|
||||
readKey = active ? 'hover' + key.charAt(0).toUpperCase() + key.slice(1) : key;
|
||||
values[key] = resolve([
|
||||
value = resolve([
|
||||
datasetOpts[readKey],
|
||||
options[readKey]
|
||||
], context);
|
||||
if (value !== undefined) {
|
||||
values[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return values;
|
||||
@ -842,72 +853,152 @@ helpers.extend(DatasetController.prototype, {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_resolveDataElementOptions: function(index) {
|
||||
_resolveDataElementOptions: function(index, mode) {
|
||||
const me = this;
|
||||
const active = mode === 'active';
|
||||
const cached = me._cachedDataOpts;
|
||||
if (cached) {
|
||||
return cached;
|
||||
if (cached[mode]) {
|
||||
return cached[mode];
|
||||
}
|
||||
const chart = me.chart;
|
||||
const datasetOpts = me._config;
|
||||
const options = chart.options.elements[me.dataElementType.prototype._type] || {};
|
||||
const elementOptions = me._dataElementOptions;
|
||||
const values = {};
|
||||
const context = {
|
||||
chart: chart,
|
||||
dataIndex: index,
|
||||
dataset: me.getDataset(),
|
||||
datasetIndex: me.index
|
||||
};
|
||||
const info = {cacheable: true};
|
||||
let keys, i, ilen, key;
|
||||
const context = me._getContext(index, active);
|
||||
const info = {cacheable: !active};
|
||||
let keys, i, ilen, key, value, readKey;
|
||||
|
||||
if (helpers.isArray(elementOptions)) {
|
||||
for (i = 0, ilen = elementOptions.length; i < ilen; ++i) {
|
||||
key = elementOptions[i];
|
||||
values[key] = resolve([
|
||||
datasetOpts[key],
|
||||
options[key]
|
||||
readKey = active ? 'hover' + key.charAt(0).toUpperCase() + key.slice(1) : key;
|
||||
value = resolve([
|
||||
datasetOpts[readKey],
|
||||
options[readKey]
|
||||
], context, index, info);
|
||||
if (value !== undefined) {
|
||||
values[key] = value;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
keys = Object.keys(elementOptions);
|
||||
for (i = 0, ilen = keys.length; i < ilen; ++i) {
|
||||
key = keys[i];
|
||||
values[key] = resolve([
|
||||
datasetOpts[elementOptions[key]],
|
||||
datasetOpts[key],
|
||||
options[key]
|
||||
readKey = active ? 'hover' + key.charAt(0).toUpperCase() + key.slice(1) : key;
|
||||
value = resolve([
|
||||
datasetOpts[elementOptions[readKey]],
|
||||
datasetOpts[readKey],
|
||||
options[readKey]
|
||||
], context, index, info);
|
||||
if (value !== undefined) {
|
||||
values[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (info.cacheable) {
|
||||
me._cachedDataOpts = Object.freeze(values);
|
||||
// `$shared` indicades this set of options can be shared between multiple elements.
|
||||
// Sharing is used to reduce number of properties to change during animation.
|
||||
values.$shared = true;
|
||||
|
||||
// We cache options by `mode`, which can be 'active' for example. This enables us
|
||||
// to have the 'active' element options and 'default' options to switch between
|
||||
// when interacting.
|
||||
cached[mode] = values;
|
||||
}
|
||||
|
||||
return values;
|
||||
},
|
||||
|
||||
removeHoverStyle: function(element) {
|
||||
helpers.merge(element._model, element.$previousStyle || {});
|
||||
delete element.$previousStyle;
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_resolveAnimations: function(index, mode, active) {
|
||||
const me = this;
|
||||
const chart = me.chart;
|
||||
const cached = me._cachedAnimations;
|
||||
mode = mode || 'default';
|
||||
|
||||
if (cached[mode]) {
|
||||
return cached[mode];
|
||||
}
|
||||
|
||||
const info = {cacheable: true};
|
||||
const context = me._getContext(index, active);
|
||||
const datasetAnim = resolve([me._config.animation], context, index, info);
|
||||
const chartAnim = resolve([chart.options.animation], context, index, info);
|
||||
let config = helpers.mergeIf({}, [datasetAnim, chartAnim]);
|
||||
|
||||
if (active && config.active) {
|
||||
config = helpers.extend({}, config, config.active);
|
||||
}
|
||||
if (mode === 'resize' && config.resize) {
|
||||
config = helpers.extend({}, config, config.resize);
|
||||
}
|
||||
|
||||
const animations = new Animations(chart, config);
|
||||
|
||||
if (info.cacheable) {
|
||||
cached[mode] = animations && Object.freeze(animations);
|
||||
}
|
||||
|
||||
return animations;
|
||||
},
|
||||
|
||||
/**
|
||||
* Utility for checking if the options are shared and should be animated separately.
|
||||
* @private
|
||||
*/
|
||||
_getSharedOptions: function(mode, el, options) {
|
||||
if (mode !== 'reset' && options && options.$shared && el && el.options && el.options.$shared) {
|
||||
return {target: el.options, options};
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Utility for determining if `options` should be included in the updated properties
|
||||
* @private
|
||||
*/
|
||||
_includeOptions: function(mode, sharedOptions) {
|
||||
return mode !== 'resize' && !sharedOptions;
|
||||
},
|
||||
|
||||
/**
|
||||
* Utility for updating a element with new properties, using animations when appropriate.
|
||||
* @private
|
||||
*/
|
||||
_updateElement: function(element, index, properties, mode) {
|
||||
if (mode === 'reset' || mode === 'none') {
|
||||
helpers.extend(element, properties);
|
||||
} else {
|
||||
this._resolveAnimations(index, mode).update(element, properties);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Utility to animate the shared options, that are potentially affecting multiple elements.
|
||||
* @private
|
||||
*/
|
||||
_updateSharedOptions: function(sharedOptions, mode) {
|
||||
if (sharedOptions) {
|
||||
this._resolveAnimations(undefined, mode).update(sharedOptions.target, sharedOptions.options);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_setStyle(element, index, mode, active) {
|
||||
this._resolveAnimations(index, mode, active).update(element, {options: this.getStyle(index, active)});
|
||||
},
|
||||
|
||||
removeHoverStyle: function(element, datasetIndex, index) {
|
||||
this._setStyle(element, index, 'active', false);
|
||||
},
|
||||
|
||||
setHoverStyle: function(element, datasetIndex, index) {
|
||||
const dataset = this.chart.data.datasets[datasetIndex];
|
||||
const model = element._model;
|
||||
const getHoverColor = helpers.getHoverColor;
|
||||
|
||||
element.$previousStyle = {
|
||||
backgroundColor: model.backgroundColor,
|
||||
borderColor: model.borderColor,
|
||||
borderWidth: model.borderWidth
|
||||
};
|
||||
|
||||
model.backgroundColor = resolve([dataset.hoverBackgroundColor, getHoverColor(model.backgroundColor)], undefined, index);
|
||||
model.borderColor = resolve([dataset.hoverBorderColor, getHoverColor(model.borderColor)], undefined, index);
|
||||
model.borderWidth = resolve([dataset.hoverBorderWidth, model.borderWidth], undefined, index);
|
||||
this._setStyle(element, index, 'active', true);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -917,7 +1008,7 @@ helpers.extend(DatasetController.prototype, {
|
||||
const element = this._cachedMeta.dataset;
|
||||
|
||||
if (element) {
|
||||
this.removeHoverStyle(element);
|
||||
this._setStyle(element, undefined, 'active', false);
|
||||
}
|
||||
},
|
||||
|
||||
@ -926,24 +1017,10 @@ helpers.extend(DatasetController.prototype, {
|
||||
*/
|
||||
_setDatasetHoverStyle: function() {
|
||||
const element = this._cachedMeta.dataset;
|
||||
const prev = {};
|
||||
let i, ilen, key, keys, hoverOptions, model;
|
||||
|
||||
if (!element) {
|
||||
return;
|
||||
if (element) {
|
||||
this._setStyle(element, undefined, 'active', true);
|
||||
}
|
||||
|
||||
model = element._model;
|
||||
hoverOptions = this._resolveDatasetElementOptions(true);
|
||||
|
||||
keys = Object.keys(hoverOptions);
|
||||
for (i = 0, ilen = keys.length; i < ilen; ++i) {
|
||||
key = keys[i];
|
||||
prev[key] = model[key];
|
||||
model[key] = hoverOptions[key];
|
||||
}
|
||||
|
||||
element.$previousStyle = prev;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -986,7 +1063,7 @@ helpers.extend(DatasetController.prototype, {
|
||||
}
|
||||
me._parse(start, count);
|
||||
|
||||
me.updateElements(data, start, count);
|
||||
me.updateElements(data, start, count, 'reset');
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@ -1,119 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
import color from 'chartjs-color';
|
||||
import helpers from '../helpers/index';
|
||||
import {extend, inherits} from '../helpers/helpers.core';
|
||||
import {isNumber} from '../helpers/helpers.math';
|
||||
|
||||
function interpolate(start, view, model, ease) {
|
||||
var keys = Object.keys(model);
|
||||
var i, ilen, key, actual, origin, target, type, c0, c1;
|
||||
|
||||
for (i = 0, ilen = keys.length; i < ilen; ++i) {
|
||||
key = keys[i];
|
||||
|
||||
target = model[key];
|
||||
|
||||
// if a value is added to the model after pivot() has been called, the view
|
||||
// doesn't contain it, so let's initialize the view to the target value.
|
||||
if (!Object.prototype.hasOwnProperty.call(view, key)) {
|
||||
view[key] = target;
|
||||
}
|
||||
|
||||
actual = view[key];
|
||||
|
||||
if (actual === target || key[0] === '_') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Object.prototype.hasOwnProperty.call(start, key)) {
|
||||
start[key] = actual;
|
||||
}
|
||||
|
||||
origin = start[key];
|
||||
|
||||
type = typeof target;
|
||||
|
||||
if (type === typeof origin) {
|
||||
if (type === 'string') {
|
||||
c0 = color(origin);
|
||||
if (c0.valid) {
|
||||
c1 = color(target);
|
||||
if (c1.valid) {
|
||||
view[key] = c1.mix(c0, ease).rgbString();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else if (helpers.isFinite(origin) && helpers.isFinite(target)) {
|
||||
view[key] = origin + (target - origin) * ease;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
view[key] = target;
|
||||
}
|
||||
}
|
||||
|
||||
class Element {
|
||||
|
||||
constructor(configuration) {
|
||||
helpers.extend(this, configuration);
|
||||
extend(this, configuration);
|
||||
|
||||
// this.hidden = false; we assume Element has an attribute called hidden, but do not initialize to save memory
|
||||
}
|
||||
|
||||
pivot(animationsDisabled) {
|
||||
var me = this;
|
||||
if (animationsDisabled) {
|
||||
me._view = me._model;
|
||||
return me;
|
||||
}
|
||||
|
||||
if (!me._view) {
|
||||
me._view = helpers.extend({}, me._model);
|
||||
}
|
||||
me._start = {};
|
||||
return me;
|
||||
}
|
||||
|
||||
transition(ease) {
|
||||
var me = this;
|
||||
var model = me._model;
|
||||
var start = me._start;
|
||||
var view = me._view;
|
||||
|
||||
// No animation -> No Transition
|
||||
if (!model || ease === 1) {
|
||||
// _model has to be cloned to _view
|
||||
// Otherwise, when _model properties are set on hover, _view.* is also set to the same value, and hover animation doesn't occur
|
||||
me._view = helpers.extend({}, model);
|
||||
me._start = null;
|
||||
return me;
|
||||
}
|
||||
|
||||
if (!view) {
|
||||
view = me._view = {};
|
||||
}
|
||||
|
||||
if (!start) {
|
||||
start = me._start = {};
|
||||
}
|
||||
|
||||
interpolate(start, view, model, ease);
|
||||
|
||||
return me;
|
||||
}
|
||||
|
||||
tooltipPosition() {
|
||||
return {
|
||||
x: this._model.x,
|
||||
y: this._model.y
|
||||
x: this.x,
|
||||
y: this.y
|
||||
};
|
||||
}
|
||||
|
||||
hasValue() {
|
||||
return isNumber(this._model.x) && isNumber(this._model.y);
|
||||
return isNumber(this.x) && isNumber(this.y);
|
||||
}
|
||||
}
|
||||
|
||||
Element.extend = helpers.inherits;
|
||||
Element.extend = inherits;
|
||||
export default Element;
|
||||
|
||||
@ -33,7 +33,7 @@ function evaluateAllVisibleItems(chart, handler) {
|
||||
({index, data} = metasets[i]);
|
||||
for (let j = 0, jlen = data.length; j < jlen; ++j) {
|
||||
element = data[j];
|
||||
if (!element._view.skip) {
|
||||
if (!element.skip) {
|
||||
handler(element, index, j);
|
||||
}
|
||||
}
|
||||
@ -66,7 +66,7 @@ function evaluateItemsAtIndex(chart, axis, position, handler) {
|
||||
const metaset = metasets[i];
|
||||
const index = indices[i];
|
||||
const element = metaset.data[index];
|
||||
if (!element._view.skip) {
|
||||
if (!element.skip) {
|
||||
handler(element, metaset.index, index);
|
||||
}
|
||||
}
|
||||
@ -193,7 +193,7 @@ export default {
|
||||
const element = meta.data[index];
|
||||
|
||||
// don't count items that are skipped (null data)
|
||||
if (element && !element._view.skip) {
|
||||
if (element && !element.skip) {
|
||||
elements.push({element, datasetIndex: meta.index, index});
|
||||
}
|
||||
});
|
||||
|
||||
@ -272,20 +272,17 @@ module.exports = {
|
||||
*/
|
||||
/**
|
||||
* @method IPlugin#beforeDraw
|
||||
* @desc Called before drawing `chart` at every animation frame specified by the given
|
||||
* easing value. If any plugin returns `false`, the frame drawing is cancelled until
|
||||
* another `render` is triggered.
|
||||
* @desc Called before drawing `chart` at every animation frame. If any plugin returns `false`,
|
||||
* the frame drawing is cancelled untilanother `render` is triggered.
|
||||
* @param {Chart.Controller} chart - The chart instance.
|
||||
* @param {number} easingValue - The current animation value, between 0.0 and 1.0.
|
||||
* @param {object} options - The plugin options.
|
||||
* @returns {boolean} `false` to cancel the chart drawing.
|
||||
*/
|
||||
/**
|
||||
* @method IPlugin#afterDraw
|
||||
* @desc Called after the `chart` has been drawn for the specific easing value. Note
|
||||
* that this hook will not be called if the drawing has been previously cancelled.
|
||||
* @desc Called after the `chart` has been drawn. Note that this hook will not be called
|
||||
* if the drawing has been previously cancelled.
|
||||
* @param {Chart.Controller} chart - The chart instance.
|
||||
* @param {number} easingValue - The current animation value, between 0.0 and 1.0.
|
||||
* @param {object} options - The plugin options.
|
||||
*/
|
||||
/**
|
||||
@ -293,7 +290,6 @@ module.exports = {
|
||||
* @desc Called before drawing the `chart` datasets. If any plugin returns `false`,
|
||||
* the datasets drawing is cancelled until another `render` is triggered.
|
||||
* @param {Chart.Controller} chart - The chart instance.
|
||||
* @param {number} easingValue - The current animation value, between 0.0 and 1.0.
|
||||
* @param {object} options - The plugin options.
|
||||
* @returns {boolean} `false` to cancel the chart datasets drawing.
|
||||
*/
|
||||
@ -302,7 +298,6 @@ module.exports = {
|
||||
* @desc Called after the `chart` datasets have been drawn. Note that this hook
|
||||
* will not be called if the datasets drawing has been previously cancelled.
|
||||
* @param {Chart.Controller} chart - The chart instance.
|
||||
* @param {number} easingValue - The current animation value, between 0.0 and 1.0.
|
||||
* @param {object} options - The plugin options.
|
||||
*/
|
||||
/**
|
||||
@ -314,7 +309,6 @@ module.exports = {
|
||||
* @param {object} args - The call arguments.
|
||||
* @param {number} args.index - The dataset index.
|
||||
* @param {object} args.meta - The dataset metadata.
|
||||
* @param {number} args.easingValue - The current animation value, between 0.0 and 1.0.
|
||||
* @param {object} options - The plugin options.
|
||||
* @returns {boolean} `false` to cancel the chart datasets drawing.
|
||||
*/
|
||||
@ -327,7 +321,6 @@ module.exports = {
|
||||
* @param {object} args - The call arguments.
|
||||
* @param {number} args.index - The dataset index.
|
||||
* @param {object} args.meta - The dataset metadata.
|
||||
* @param {number} args.easingValue - The current animation value, between 0.0 and 1.0.
|
||||
* @param {object} options - The plugin options.
|
||||
*/
|
||||
/**
|
||||
@ -337,7 +330,6 @@ module.exports = {
|
||||
* @param {Chart} chart - The chart instance.
|
||||
* @param {object} args - The call arguments.
|
||||
* @param {Tooltip} args.tooltip - The tooltip.
|
||||
* @param {number} args.easingValue - The current animation value, between 0.0 and 1.0.
|
||||
* @param {object} options - The plugin options.
|
||||
* @returns {boolean} `false` to cancel the chart tooltip drawing.
|
||||
*/
|
||||
@ -348,7 +340,6 @@ module.exports = {
|
||||
* @param {Chart} chart - The chart instance.
|
||||
* @param {object} args - The call arguments.
|
||||
* @param {Tooltip} args.tooltip - The tooltip.
|
||||
* @param {number} args.easingValue - The current animation value, between 0.0 and 1.0.
|
||||
* @param {object} options - The plugin options.
|
||||
*/
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -66,13 +66,14 @@ function drawFullCircleBorders(ctx, vm, arc, inner) {
|
||||
}
|
||||
|
||||
function drawBorder(ctx, vm, arc) {
|
||||
var inner = vm.borderAlign === 'inner';
|
||||
const options = vm.options;
|
||||
var inner = options.borderAlign === 'inner';
|
||||
|
||||
if (inner) {
|
||||
ctx.lineWidth = vm.borderWidth * 2;
|
||||
ctx.lineWidth = options.borderWidth * 2;
|
||||
ctx.lineJoin = 'round';
|
||||
} else {
|
||||
ctx.lineWidth = vm.borderWidth;
|
||||
ctx.lineWidth = options.borderWidth;
|
||||
ctx.lineJoin = 'bevel';
|
||||
}
|
||||
|
||||
@ -98,75 +99,73 @@ class Arc extends Element {
|
||||
}
|
||||
|
||||
inRange(chartX, chartY) {
|
||||
var vm = this._view;
|
||||
var me = this;
|
||||
|
||||
if (vm) {
|
||||
var pointRelativePosition = getAngleFromPoint(vm, {x: chartX, y: chartY});
|
||||
var angle = pointRelativePosition.angle;
|
||||
var distance = pointRelativePosition.distance;
|
||||
var pointRelativePosition = getAngleFromPoint(me, {x: chartX, y: chartY});
|
||||
var angle = pointRelativePosition.angle;
|
||||
var distance = pointRelativePosition.distance;
|
||||
|
||||
// Sanitise angle range
|
||||
var startAngle = vm.startAngle;
|
||||
var endAngle = vm.endAngle;
|
||||
while (endAngle < startAngle) {
|
||||
endAngle += TAU;
|
||||
}
|
||||
while (angle > endAngle) {
|
||||
angle -= TAU;
|
||||
}
|
||||
while (angle < startAngle) {
|
||||
angle += TAU;
|
||||
}
|
||||
|
||||
// Check if within the range of the open/close angle
|
||||
var betweenAngles = (angle >= startAngle && angle <= endAngle);
|
||||
var withinRadius = (distance >= vm.innerRadius && distance <= vm.outerRadius);
|
||||
|
||||
return (betweenAngles && withinRadius);
|
||||
// Sanitise angle range
|
||||
var startAngle = me.startAngle;
|
||||
var endAngle = me.endAngle;
|
||||
while (endAngle < startAngle) {
|
||||
endAngle += TAU;
|
||||
}
|
||||
return false;
|
||||
while (angle > endAngle) {
|
||||
angle -= TAU;
|
||||
}
|
||||
while (angle < startAngle) {
|
||||
angle += TAU;
|
||||
}
|
||||
|
||||
// Check if within the range of the open/close angle
|
||||
var betweenAngles = (angle >= startAngle && angle <= endAngle);
|
||||
var withinRadius = (distance >= me.innerRadius && distance <= me.outerRadius);
|
||||
|
||||
return (betweenAngles && withinRadius);
|
||||
}
|
||||
|
||||
getCenterPoint() {
|
||||
var vm = this._view;
|
||||
var halfAngle = (vm.startAngle + vm.endAngle) / 2;
|
||||
var halfRadius = (vm.innerRadius + vm.outerRadius) / 2;
|
||||
var me = this;
|
||||
var halfAngle = (me.startAngle + me.endAngle) / 2;
|
||||
var halfRadius = (me.innerRadius + me.outerRadius) / 2;
|
||||
return {
|
||||
x: vm.x + Math.cos(halfAngle) * halfRadius,
|
||||
y: vm.y + Math.sin(halfAngle) * halfRadius
|
||||
x: me.x + Math.cos(halfAngle) * halfRadius,
|
||||
y: me.y + Math.sin(halfAngle) * halfRadius
|
||||
};
|
||||
}
|
||||
|
||||
tooltipPosition() {
|
||||
var vm = this._view;
|
||||
var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2);
|
||||
var rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius;
|
||||
var me = this;
|
||||
var centreAngle = me.startAngle + ((me.endAngle - me.startAngle) / 2);
|
||||
var rangeFromCentre = (me.outerRadius - me.innerRadius) / 2 + me.innerRadius;
|
||||
|
||||
return {
|
||||
x: vm.x + (Math.cos(centreAngle) * rangeFromCentre),
|
||||
y: vm.y + (Math.sin(centreAngle) * rangeFromCentre)
|
||||
x: me.x + (Math.cos(centreAngle) * rangeFromCentre),
|
||||
y: me.y + (Math.sin(centreAngle) * rangeFromCentre)
|
||||
};
|
||||
}
|
||||
|
||||
draw(ctx) {
|
||||
var vm = this._view;
|
||||
var pixelMargin = (vm.borderAlign === 'inner') ? 0.33 : 0;
|
||||
var me = this;
|
||||
var options = me.options;
|
||||
var pixelMargin = (options.borderAlign === 'inner') ? 0.33 : 0;
|
||||
var arc = {
|
||||
x: vm.x,
|
||||
y: vm.y,
|
||||
innerRadius: vm.innerRadius,
|
||||
outerRadius: Math.max(vm.outerRadius - pixelMargin, 0),
|
||||
x: me.x,
|
||||
y: me.y,
|
||||
innerRadius: me.innerRadius,
|
||||
outerRadius: Math.max(me.outerRadius - pixelMargin, 0),
|
||||
pixelMargin: pixelMargin,
|
||||
startAngle: vm.startAngle,
|
||||
endAngle: vm.endAngle,
|
||||
fullCircles: Math.floor(vm.circumference / TAU)
|
||||
startAngle: me.startAngle,
|
||||
endAngle: me.endAngle,
|
||||
fullCircles: Math.floor(me.circumference / TAU)
|
||||
};
|
||||
var i;
|
||||
|
||||
ctx.save();
|
||||
|
||||
ctx.fillStyle = vm.backgroundColor;
|
||||
ctx.strokeStyle = vm.borderColor;
|
||||
ctx.fillStyle = options.backgroundColor;
|
||||
ctx.strokeStyle = options.borderColor;
|
||||
|
||||
if (arc.fullCircles) {
|
||||
arc.endAngle = arc.startAngle + TAU;
|
||||
@ -177,7 +176,7 @@ class Arc extends Element {
|
||||
for (i = 0; i < arc.fullCircles; ++i) {
|
||||
ctx.fill();
|
||||
}
|
||||
arc.endAngle = arc.startAngle + vm.circumference % TAU;
|
||||
arc.endAngle = arc.startAngle + me.circumference % TAU;
|
||||
}
|
||||
|
||||
ctx.beginPath();
|
||||
@ -186,8 +185,8 @@ class Arc extends Element {
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
if (vm.borderWidth) {
|
||||
drawBorder(ctx, vm, arc);
|
||||
if (options.borderWidth) {
|
||||
drawBorder(ctx, me, arc);
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
|
||||
@ -5,6 +5,7 @@ import Element from '../core/core.element';
|
||||
import helpers from '../helpers';
|
||||
|
||||
const defaultColor = defaults.global.defaultColor;
|
||||
const isPointInArea = helpers.canvas._isPointInArea;
|
||||
|
||||
defaults._set('global', {
|
||||
elements: {
|
||||
@ -18,48 +19,71 @@ defaults._set('global', {
|
||||
borderDashOffset: 0.0,
|
||||
borderJoinStyle: 'miter',
|
||||
capBezierPoints: true,
|
||||
fill: true, // do we fill in the area between the line and its base axis
|
||||
fill: true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function startAtGap(points, spanGaps) {
|
||||
let closePath = true;
|
||||
let previous = points.length && points[0]._view;
|
||||
let index, view;
|
||||
let previous = points.length && points[0];
|
||||
let index, point;
|
||||
|
||||
for (index = 1; index < points.length; ++index) {
|
||||
// If there is a gap in the (looping) line, start drawing from that gap
|
||||
view = points[index]._view;
|
||||
if (!view.skip && previous.skip) {
|
||||
point = points[index];
|
||||
if (!point.skip && previous.skip) {
|
||||
points = points.slice(index).concat(points.slice(0, index));
|
||||
closePath = spanGaps;
|
||||
break;
|
||||
}
|
||||
previous = view;
|
||||
previous = point;
|
||||
}
|
||||
|
||||
points.closePath = closePath;
|
||||
return points;
|
||||
}
|
||||
|
||||
function setStyle(ctx, vm) {
|
||||
ctx.lineCap = vm.borderCapStyle;
|
||||
ctx.setLineDash(vm.borderDash);
|
||||
ctx.lineDashOffset = vm.borderDashOffset;
|
||||
ctx.lineJoin = vm.borderJoinStyle;
|
||||
ctx.lineWidth = vm.borderWidth;
|
||||
ctx.strokeStyle = vm.borderColor;
|
||||
function setStyle(ctx, options) {
|
||||
ctx.lineCap = options.borderCapStyle;
|
||||
ctx.setLineDash(options.borderDash);
|
||||
ctx.lineDashOffset = options.borderDashOffset;
|
||||
ctx.lineJoin = options.borderJoinStyle;
|
||||
ctx.lineWidth = options.borderWidth;
|
||||
ctx.strokeStyle = options.borderColor;
|
||||
}
|
||||
|
||||
function normalPath(ctx, points, spanGaps, vm) {
|
||||
const steppedLine = vm.steppedLine;
|
||||
const lineMethod = steppedLine ? helpers.canvas._steppedLineTo : helpers.canvas._bezierCurveTo;
|
||||
function bezierCurveTo(ctx, previous, target, flip) {
|
||||
ctx.bezierCurveTo(
|
||||
flip ? previous.controlPointPreviousX : previous.controlPointNextX,
|
||||
flip ? previous.controlPointPreviousY : previous.controlPointNextY,
|
||||
flip ? target.controlPointNextX : target.controlPointPreviousX,
|
||||
flip ? target.controlPointNextY : target.controlPointPreviousY,
|
||||
target.x,
|
||||
target.y);
|
||||
}
|
||||
|
||||
function steppedLineTo(ctx, previous, target, flip, mode) {
|
||||
if (mode === 'middle') {
|
||||
const midpoint = (previous.x + target.x) / 2.0;
|
||||
ctx.lineTo(midpoint, flip ? target.y : previous.y);
|
||||
ctx.lineTo(midpoint, flip ? previous.y : target.y);
|
||||
} else if ((mode === 'after' && !flip) || (mode !== 'after' && flip)) {
|
||||
ctx.lineTo(previous.x, target.y);
|
||||
} else {
|
||||
ctx.lineTo(target.x, previous.y);
|
||||
}
|
||||
ctx.lineTo(target.x, target.y);
|
||||
}
|
||||
|
||||
function normalPath(ctx, points, spanGaps, options) {
|
||||
const steppedLine = options.steppedLine;
|
||||
const lineMethod = steppedLine ? steppedLineTo : bezierCurveTo;
|
||||
let move = true;
|
||||
let index, currentVM, previousVM;
|
||||
|
||||
for (index = 0; index < points.length; ++index) {
|
||||
currentVM = points[index]._view;
|
||||
currentVM = points[index];
|
||||
|
||||
if (currentVM.skip) {
|
||||
move = move || !spanGaps;
|
||||
@ -68,7 +92,7 @@ function normalPath(ctx, points, spanGaps, vm) {
|
||||
if (move) {
|
||||
ctx.moveTo(currentVM.x, currentVM.y);
|
||||
move = false;
|
||||
} else if (vm.tension || steppedLine) {
|
||||
} else if (options.tension || steppedLine) {
|
||||
lineMethod(ctx, previousVM, currentVM, false, steppedLine);
|
||||
} else {
|
||||
ctx.lineTo(currentVM.x, currentVM.y);
|
||||
@ -91,7 +115,7 @@ function fastPath(ctx, points, spanGaps) {
|
||||
let index, vm, truncX, x, y, prevX, minY, maxY, lastY;
|
||||
|
||||
for (index = 0; index < points.length; ++index) {
|
||||
vm = points[index]._view;
|
||||
vm = points[index];
|
||||
|
||||
// If point is skipped, we either move to next (not skipped) point
|
||||
// or line to it if spanGaps is true. `move` can already be true.
|
||||
@ -135,8 +159,64 @@ function fastPath(ctx, points, spanGaps) {
|
||||
}
|
||||
}
|
||||
|
||||
function useFastPath(vm) {
|
||||
return vm.tension === 0 && !vm.steppedLine && !vm.fill && !vm.borderDash.length;
|
||||
function useFastPath(options) {
|
||||
return options.tension === 0 && !options.steppedLine && !options.fill && !options.borderDash.length;
|
||||
}
|
||||
|
||||
function capControlPoint(pt, min, max) {
|
||||
return Math.max(Math.min(pt, max), min);
|
||||
}
|
||||
|
||||
function capBezierPoints(points, area) {
|
||||
var i, ilen, model;
|
||||
for (i = 0, ilen = points.length; i < ilen; ++i) {
|
||||
model = points[i];
|
||||
if (isPointInArea(model, area)) {
|
||||
if (i > 0 && isPointInArea(points[i - 1], area)) {
|
||||
model.controlPointPreviousX = capControlPoint(model.controlPointPreviousX, area.left, area.right);
|
||||
model.controlPointPreviousY = capControlPoint(model.controlPointPreviousY, area.top, area.bottom);
|
||||
}
|
||||
if (i < points.length - 1 && isPointInArea(points[i + 1], area)) {
|
||||
model.controlPointNextX = capControlPoint(model.controlPointNextX, area.left, area.right);
|
||||
model.controlPointNextY = capControlPoint(model.controlPointNextY, area.top, area.bottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateBezierControlPoints(points, options, area, loop) {
|
||||
var i, ilen, point, controlPoints;
|
||||
|
||||
// Only consider points that are drawn in case the spanGaps option is used
|
||||
if (options.spanGaps) {
|
||||
points = points.filter(function(pt) {
|
||||
return !pt.skip;
|
||||
});
|
||||
}
|
||||
|
||||
if (options.cubicInterpolationMode === 'monotone') {
|
||||
helpers.curve.splineCurveMonotone(points);
|
||||
} else {
|
||||
let prev = loop ? points[points.length - 1] : points[0];
|
||||
for (i = 0, ilen = points.length; i < ilen; ++i) {
|
||||
point = points[i];
|
||||
controlPoints = helpers.curve.splineCurve(
|
||||
prev,
|
||||
point,
|
||||
points[Math.min(i + 1, ilen - (loop ? 0 : 1)) % ilen],
|
||||
options.tension
|
||||
);
|
||||
point.controlPointPreviousX = controlPoints.previous.x;
|
||||
point.controlPointPreviousY = controlPoints.previous.y;
|
||||
point.controlPointNextX = controlPoints.next.x;
|
||||
point.controlPointNextY = controlPoints.next.y;
|
||||
prev = point;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.capBezierPoints) {
|
||||
capBezierPoints(points, area);
|
||||
}
|
||||
}
|
||||
|
||||
class Line extends Element {
|
||||
@ -145,10 +225,21 @@ class Line extends Element {
|
||||
super(props);
|
||||
}
|
||||
|
||||
draw(ctx) {
|
||||
updateControlPoints(chartArea) {
|
||||
const me = this;
|
||||
const vm = me._view;
|
||||
const spanGaps = vm.spanGaps;
|
||||
if (me._controlPointsUpdated) {
|
||||
return;
|
||||
}
|
||||
const options = me.options;
|
||||
if (options.tension && !options.steppedLine) {
|
||||
updateBezierControlPoints(me._children, options, chartArea, me._loop);
|
||||
}
|
||||
}
|
||||
|
||||
drawPath(ctx, area) {
|
||||
const me = this;
|
||||
const options = me.options;
|
||||
const spanGaps = options.spanGaps;
|
||||
let closePath = me._loop;
|
||||
let points = me._children;
|
||||
|
||||
@ -161,19 +252,30 @@ class Line extends Element {
|
||||
closePath = points.closePath;
|
||||
}
|
||||
|
||||
if (useFastPath(options)) {
|
||||
fastPath(ctx, points, spanGaps);
|
||||
} else {
|
||||
me.updateControlPoints(area);
|
||||
normalPath(ctx, points, spanGaps, options);
|
||||
}
|
||||
|
||||
return closePath;
|
||||
}
|
||||
|
||||
draw(ctx, area) {
|
||||
const me = this;
|
||||
|
||||
if (!me._children.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
|
||||
setStyle(ctx, vm);
|
||||
setStyle(ctx, me.options);
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
if (useFastPath(vm)) {
|
||||
fastPath(ctx, points, spanGaps);
|
||||
} else {
|
||||
normalPath(ctx, points, spanGaps, vm);
|
||||
}
|
||||
|
||||
if (closePath) {
|
||||
if (me.drawPath(ctx, area)) {
|
||||
ctx.closePath();
|
||||
}
|
||||
|
||||
|
||||
@ -29,62 +29,55 @@ class Point extends Element {
|
||||
}
|
||||
|
||||
inRange(mouseX, mouseY) {
|
||||
const vm = this._view;
|
||||
return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false;
|
||||
const options = this.options;
|
||||
return ((Math.pow(mouseX - this.x, 2) + Math.pow(mouseY - this.y, 2)) < Math.pow(options.hitRadius + options.radius, 2));
|
||||
}
|
||||
|
||||
inXRange(mouseX) {
|
||||
const vm = this._view;
|
||||
return vm ? (Math.abs(mouseX - vm.x) < vm.radius + vm.hitRadius) : false;
|
||||
const options = this.options;
|
||||
return (Math.abs(mouseX - this.x) < options.radius + options.hitRadius);
|
||||
}
|
||||
|
||||
inYRange(mouseY) {
|
||||
const vm = this._view;
|
||||
return vm ? (Math.abs(mouseY - vm.y) < vm.radius + vm.hitRadius) : false;
|
||||
const options = this.options;
|
||||
return (Math.abs(mouseY - this.y) < options.radius + options.hitRadius);
|
||||
}
|
||||
|
||||
getCenterPoint() {
|
||||
const vm = this._view;
|
||||
return {
|
||||
x: vm.x,
|
||||
y: vm.y
|
||||
};
|
||||
return {x: this.x, y: this.y};
|
||||
}
|
||||
|
||||
size() {
|
||||
const vm = this._view;
|
||||
const radius = vm.radius || 0;
|
||||
const borderWidth = vm.borderWidth || 0;
|
||||
const options = this.options || {};
|
||||
const radius = options.radius || 0;
|
||||
const borderWidth = radius && options.borderWidth || 0;
|
||||
return (radius + borderWidth) * 2;
|
||||
}
|
||||
|
||||
tooltipPosition() {
|
||||
const vm = this._view;
|
||||
const options = this.options;
|
||||
return {
|
||||
x: vm.x,
|
||||
y: vm.y,
|
||||
padding: vm.radius + vm.borderWidth
|
||||
x: this.x,
|
||||
y: this.y,
|
||||
padding: options.radius + options.borderWidth
|
||||
};
|
||||
}
|
||||
|
||||
draw(ctx, chartArea) {
|
||||
const vm = this._view;
|
||||
const pointStyle = vm.pointStyle;
|
||||
const rotation = vm.rotation;
|
||||
const radius = vm.radius;
|
||||
const x = vm.x;
|
||||
const y = vm.y;
|
||||
const me = this;
|
||||
const options = me.options;
|
||||
const radius = options.radius;
|
||||
|
||||
if (vm.skip || radius <= 0) {
|
||||
if (me.skip || radius <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clipping for Points.
|
||||
if (chartArea === undefined || helpers.canvas._isPointInArea(vm, chartArea)) {
|
||||
ctx.strokeStyle = vm.borderColor;
|
||||
ctx.lineWidth = vm.borderWidth;
|
||||
ctx.fillStyle = vm.backgroundColor;
|
||||
helpers.canvas.drawPoint(ctx, pointStyle, radius, x, y, rotation);
|
||||
if (chartArea === undefined || helpers.canvas._isPointInArea(me, chartArea)) {
|
||||
ctx.strokeStyle = options.borderColor;
|
||||
ctx.lineWidth = options.borderWidth;
|
||||
ctx.fillStyle = options.backgroundColor;
|
||||
helpers.canvas.drawPoint(ctx, options.pointStyle, radius, me.x, me.y, options.rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,31 +17,27 @@ defaults._set('global', {
|
||||
}
|
||||
});
|
||||
|
||||
function isVertical(vm) {
|
||||
return vm && vm.width !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get the bounds of the bar regardless of the orientation
|
||||
* @param bar {Chart.Element.Rectangle} the bar
|
||||
* @return {Bounds} bounds of the bar
|
||||
* @private
|
||||
*/
|
||||
function getBarBounds(vm) {
|
||||
function getBarBounds(bar) {
|
||||
var x1, x2, y1, y2, half;
|
||||
|
||||
if (isVertical(vm)) {
|
||||
half = vm.width / 2;
|
||||
x1 = vm.x - half;
|
||||
x2 = vm.x + half;
|
||||
y1 = Math.min(vm.y, vm.base);
|
||||
y2 = Math.max(vm.y, vm.base);
|
||||
if (bar.horizontal) {
|
||||
half = bar.height / 2;
|
||||
x1 = Math.min(bar.x, bar.base);
|
||||
x2 = Math.max(bar.x, bar.base);
|
||||
y1 = bar.y - half;
|
||||
y2 = bar.y + half;
|
||||
} else {
|
||||
half = vm.height / 2;
|
||||
x1 = Math.min(vm.x, vm.base);
|
||||
x2 = Math.max(vm.x, vm.base);
|
||||
y1 = vm.y - half;
|
||||
y2 = vm.y + half;
|
||||
half = bar.width / 2;
|
||||
x1 = bar.x - half;
|
||||
x2 = bar.x + half;
|
||||
y1 = Math.min(bar.y, bar.base);
|
||||
y2 = Math.max(bar.y, bar.base);
|
||||
}
|
||||
|
||||
return {
|
||||
@ -56,19 +52,19 @@ function swap(orig, v1, v2) {
|
||||
return orig === v1 ? v2 : orig === v2 ? v1 : orig;
|
||||
}
|
||||
|
||||
function parseBorderSkipped(vm) {
|
||||
var edge = vm.borderSkipped;
|
||||
function parseBorderSkipped(bar) {
|
||||
var edge = bar.options.borderSkipped;
|
||||
var res = {};
|
||||
|
||||
if (!edge) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (vm.horizontal) {
|
||||
if (vm.base > vm.x) {
|
||||
if (bar.horizontal) {
|
||||
if (bar.base > bar.x) {
|
||||
edge = swap(edge, 'left', 'right');
|
||||
}
|
||||
} else if (vm.base < vm.y) {
|
||||
} else if (bar.base < bar.y) {
|
||||
edge = swap(edge, 'bottom', 'top');
|
||||
}
|
||||
|
||||
@ -76,9 +72,9 @@ function parseBorderSkipped(vm) {
|
||||
return res;
|
||||
}
|
||||
|
||||
function parseBorderWidth(vm, maxW, maxH) {
|
||||
var value = vm.borderWidth;
|
||||
var skip = parseBorderSkipped(vm);
|
||||
function parseBorderWidth(bar, maxW, maxH) {
|
||||
var value = bar.options.borderWidth;
|
||||
var skip = parseBorderSkipped(bar);
|
||||
var t, r, b, l;
|
||||
|
||||
if (helpers.isObject(value)) {
|
||||
@ -98,11 +94,11 @@ function parseBorderWidth(vm, maxW, maxH) {
|
||||
};
|
||||
}
|
||||
|
||||
function boundingRects(vm) {
|
||||
var bounds = getBarBounds(vm);
|
||||
function boundingRects(bar) {
|
||||
var bounds = getBarBounds(bar);
|
||||
var width = bounds.right - bounds.left;
|
||||
var height = bounds.bottom - bounds.top;
|
||||
var border = parseBorderWidth(vm, width / 2, height / 2);
|
||||
var border = parseBorderWidth(bar, width / 2, height / 2);
|
||||
|
||||
return {
|
||||
outer: {
|
||||
@ -120,10 +116,10 @@ function boundingRects(vm) {
|
||||
};
|
||||
}
|
||||
|
||||
function inRange(vm, x, y) {
|
||||
function inRange(bar, x, y) {
|
||||
var skipX = x === null;
|
||||
var skipY = y === null;
|
||||
var bounds = !vm || (skipX && skipY) ? false : getBarBounds(vm);
|
||||
var bounds = !bar || (skipX && skipY) ? false : getBarBounds(bar);
|
||||
|
||||
return bounds
|
||||
&& (skipX || x >= bounds.left && x <= bounds.right)
|
||||
@ -137,12 +133,12 @@ class Rectangle extends Element {
|
||||
}
|
||||
|
||||
draw(ctx) {
|
||||
var vm = this._view;
|
||||
var rects = boundingRects(vm);
|
||||
var options = this.options;
|
||||
var rects = boundingRects(this);
|
||||
var outer = rects.outer;
|
||||
var inner = rects.inner;
|
||||
|
||||
ctx.fillStyle = vm.backgroundColor;
|
||||
ctx.fillStyle = options.backgroundColor;
|
||||
ctx.fillRect(outer.x, outer.y, outer.w, outer.h);
|
||||
|
||||
if (outer.w === inner.w && outer.h === inner.h) {
|
||||
@ -153,43 +149,36 @@ class Rectangle extends Element {
|
||||
ctx.beginPath();
|
||||
ctx.rect(outer.x, outer.y, outer.w, outer.h);
|
||||
ctx.clip();
|
||||
ctx.fillStyle = vm.borderColor;
|
||||
ctx.fillStyle = options.borderColor;
|
||||
ctx.rect(inner.x, inner.y, inner.w, inner.h);
|
||||
ctx.fill('evenodd');
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
inRange(mouseX, mouseY) {
|
||||
return inRange(this._view, mouseX, mouseY);
|
||||
return inRange(this, mouseX, mouseY);
|
||||
}
|
||||
|
||||
inXRange(mouseX) {
|
||||
return inRange(this._view, mouseX, null);
|
||||
return inRange(this, mouseX, null);
|
||||
}
|
||||
|
||||
inYRange(mouseY) {
|
||||
return inRange(this._view, null, mouseY);
|
||||
return inRange(this, null, mouseY);
|
||||
}
|
||||
|
||||
getCenterPoint() {
|
||||
var vm = this._view;
|
||||
var x, y;
|
||||
if (isVertical(vm)) {
|
||||
x = vm.x;
|
||||
y = (vm.y + vm.base) / 2;
|
||||
} else {
|
||||
x = (vm.x + vm.base) / 2;
|
||||
y = vm.y;
|
||||
}
|
||||
|
||||
return {x: x, y: y};
|
||||
const {x, y, base, horizontal} = this;
|
||||
return {
|
||||
x: horizontal ? (x + base) / 2 : x,
|
||||
y: horizontal ? y : (y + base) / 2
|
||||
};
|
||||
}
|
||||
|
||||
tooltipPosition() {
|
||||
var vm = this._view;
|
||||
return {
|
||||
x: vm.x,
|
||||
y: vm.y
|
||||
x: this.x,
|
||||
y: this.y
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ export function splineCurveMonotone(points) {
|
||||
|
||||
var pointsWithTangents = (points || []).map(function(point) {
|
||||
return {
|
||||
model: point._model,
|
||||
model: point,
|
||||
deltaK: 0,
|
||||
mK: 0
|
||||
};
|
||||
|
||||
@ -6,6 +6,7 @@ var Chart = require('./core/core.controller');
|
||||
Chart.helpers = require('./helpers/index');
|
||||
Chart._adapters = require('./core/core.adapters');
|
||||
Chart.Animation = require('./core/core.animation');
|
||||
Chart.Animator = require('./core/core.animator');
|
||||
Chart.animationService = require('./core/core.animations');
|
||||
Chart.controllers = require('./controllers/index');
|
||||
Chart.DatasetController = require('./core/core.datasetController');
|
||||
|
||||
@ -28,7 +28,7 @@ var mappers = {
|
||||
var length = points.length || 0;
|
||||
|
||||
return !length ? null : function(point, i) {
|
||||
return (i < length && points[i]._view) || null;
|
||||
return (i < length && points[i]) || null;
|
||||
};
|
||||
},
|
||||
|
||||
@ -55,7 +55,7 @@ var mappers = {
|
||||
|
||||
// @todo if (fill[0] === '#')
|
||||
function decodeFill(el, index, count) {
|
||||
var model = el._model || {};
|
||||
var model = el.options || {};
|
||||
var fillOption = model.fill;
|
||||
var fill = fillOption && typeof fillOption.target !== 'undefined' ? fillOption.target : fillOption;
|
||||
var target;
|
||||
@ -105,7 +105,7 @@ function decodeFill(el, index, count) {
|
||||
}
|
||||
|
||||
function computeLinearBoundary(source) {
|
||||
var model = source.el._model || {};
|
||||
var model = source.el || {};
|
||||
var scale = source.scale || {};
|
||||
var fill = source.fill;
|
||||
var target = null;
|
||||
@ -352,11 +352,11 @@ function clipAndFill(ctx, clippingPointsSets, fillingPointsSets, color, stepped,
|
||||
|
||||
function doFill(ctx, points, mapper, colors, el, area) {
|
||||
const count = points.length;
|
||||
const view = el._view;
|
||||
const options = el.options;
|
||||
const loop = el._loop;
|
||||
const span = view.spanGaps;
|
||||
const stepped = view.steppedLine;
|
||||
const tension = view.tension;
|
||||
const span = options.spanGaps;
|
||||
const stepped = options.steppedLine;
|
||||
const tension = options.tension;
|
||||
let curve0 = [];
|
||||
let curve1 = [];
|
||||
let len0 = 0;
|
||||
@ -369,8 +369,8 @@ function doFill(ctx, points, mapper, colors, el, area) {
|
||||
|
||||
for (i = 0, ilen = count; i < ilen; ++i) {
|
||||
index = i % count;
|
||||
p0 = points[index]._view;
|
||||
p1 = mapper(p0, index, view);
|
||||
p0 = points[index];
|
||||
p1 = mapper(p0, index);
|
||||
d0 = isDrawable(p0);
|
||||
d1 = isDrawable(p1);
|
||||
|
||||
@ -423,7 +423,7 @@ module.exports = {
|
||||
el = meta.dataset;
|
||||
source = null;
|
||||
|
||||
if (el && el._model && el instanceof elements.Line) {
|
||||
if (el && el.options && el instanceof elements.Line) {
|
||||
source = {
|
||||
visible: chart.isDatasetVisible(i),
|
||||
fill: decodeFill(el, i, count),
|
||||
@ -450,9 +450,19 @@ module.exports = {
|
||||
},
|
||||
|
||||
beforeDatasetsDraw: function(chart) {
|
||||
var metasets = chart._getSortedVisibleDatasetMetas();
|
||||
var ctx = chart.ctx;
|
||||
var meta, i, el, view, points, mapper, color, colors, fillOption;
|
||||
const metasets = chart._getSortedVisibleDatasetMetas();
|
||||
const area = chart.chartArea;
|
||||
const ctx = chart.ctx;
|
||||
var meta, i, el, options, points, mapper, color, colors, fillOption;
|
||||
|
||||
for (i = metasets.length - 1; i >= 0; --i) {
|
||||
meta = metasets[i].$filler;
|
||||
|
||||
if (!meta || !meta.visible) {
|
||||
continue;
|
||||
}
|
||||
meta.el.updateControlPoints(area);
|
||||
}
|
||||
|
||||
for (i = metasets.length - 1; i >= 0; --i) {
|
||||
meta = metasets[i].$filler;
|
||||
@ -462,11 +472,11 @@ module.exports = {
|
||||
}
|
||||
|
||||
el = meta.el;
|
||||
view = el._view;
|
||||
options = el.options;
|
||||
points = el._children || [];
|
||||
mapper = meta.mapper;
|
||||
fillOption = meta.el._model.fill;
|
||||
color = view.backgroundColor || defaults.global.defaultColor;
|
||||
fillOption = options.fill;
|
||||
color = options.backgroundColor || defaults.global.defaultColor;
|
||||
|
||||
colors = {above: color, below: color};
|
||||
if (fillOption && typeof fillOption === 'object') {
|
||||
@ -474,8 +484,8 @@ module.exports = {
|
||||
colors.below = fillOption.below || color;
|
||||
}
|
||||
if (mapper && points.length) {
|
||||
helpers.canvas.clipArea(ctx, chart.chartArea);
|
||||
doFill(ctx, points, mapper, colors, el, chart.chartArea);
|
||||
helpers.canvas.clipArea(ctx, area);
|
||||
doFill(ctx, points, mapper, colors, el, area);
|
||||
helpers.canvas.unclipArea(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,7 +58,7 @@ defaults._set('global', {
|
||||
return {
|
||||
text: datasets[meta.index].label,
|
||||
fillStyle: style.backgroundColor,
|
||||
hidden: !chart.isDatasetVisible(meta.index),
|
||||
hidden: !meta.visible,
|
||||
lineCap: style.borderCapStyle,
|
||||
lineDash: style.borderDash,
|
||||
lineDashOffset: style.borderDashOffset,
|
||||
|
||||
BIN
test/fixtures/controller.line/clip/default-y-max.png
vendored
BIN
test/fixtures/controller.line/clip/default-y-max.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
BIN
test/fixtures/controller.line/clip/default-y.png
vendored
BIN
test/fixtures/controller.line/clip/default-y.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
9
test/fixtures/core.tooltip/opacity.js
vendored
9
test/fixtures/core.tooltip/opacity.js
vendored
@ -82,14 +82,13 @@ module.exports = {
|
||||
event = {
|
||||
type: 'mousemove',
|
||||
target: canvas,
|
||||
clientX: rect.left + point._model.x,
|
||||
clientY: rect.top + point._model.y
|
||||
clientX: rect.left + point.x,
|
||||
clientY: rect.top + point.y
|
||||
};
|
||||
chart.handleEvent(event);
|
||||
chart.tooltip.handleEvent(event);
|
||||
chart.tooltip.transition(1);
|
||||
chart.tooltip._view.opacity = j / 10;
|
||||
chart.tooltip.draw();
|
||||
chart.tooltip.opacity = j / 10;
|
||||
chart.tooltip.draw(chart.ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -728,11 +728,11 @@ describe('Chart.controllers.bar', function() {
|
||||
{x: 89, y: 512},
|
||||
{x: 217, y: 0}
|
||||
].forEach(function(expected, i) {
|
||||
expect(meta.data[i]._model.x).toBeCloseToPixel(expected.x);
|
||||
expect(meta.data[i]._model.y).toBeCloseToPixel(expected.y);
|
||||
expect(meta.data[i]._model.base).toBeCloseToPixel(1024);
|
||||
expect(meta.data[i]._model.width).toBeCloseToPixel(46);
|
||||
expect(meta.data[i]._model).toEqual(jasmine.objectContaining({
|
||||
expect(meta.data[i].x).toBeCloseToPixel(expected.x);
|
||||
expect(meta.data[i].y).toBeCloseToPixel(expected.y);
|
||||
expect(meta.data[i].base).toBeCloseToPixel(1024);
|
||||
expect(meta.data[i].width).toBeCloseToPixel(46);
|
||||
expect(meta.data[i].options).toEqual(jasmine.objectContaining({
|
||||
backgroundColor: 'red',
|
||||
borderSkipped: 'top',
|
||||
borderColor: 'blue',
|
||||
@ -785,10 +785,10 @@ describe('Chart.controllers.bar', function() {
|
||||
var bar1 = meta.data[0];
|
||||
var bar2 = meta.data[1];
|
||||
|
||||
expect(bar1._model.x).toBeCloseToPixel(179);
|
||||
expect(bar1._model.y).toBeCloseToPixel(114);
|
||||
expect(bar2._model.x).toBeCloseToPixel(435);
|
||||
expect(bar2._model.y).toBeCloseToPixel(0);
|
||||
expect(bar1.x).toBeCloseToPixel(179);
|
||||
expect(bar1.y).toBeCloseToPixel(114);
|
||||
expect(bar2.x).toBeCloseToPixel(435);
|
||||
expect(bar2.y).toBeCloseToPixel(0);
|
||||
});
|
||||
|
||||
it('should update elements when the scales are stacked', function() {
|
||||
@ -829,10 +829,10 @@ describe('Chart.controllers.bar', function() {
|
||||
{b: 293, w: 92 / 2, x: 295, y: 146},
|
||||
{b: 293, w: 92 / 2, x: 422, y: 439}
|
||||
].forEach(function(values, i) {
|
||||
expect(meta0.data[i]._model.base).toBeCloseToPixel(values.b);
|
||||
expect(meta0.data[i]._model.width).toBeCloseToPixel(values.w);
|
||||
expect(meta0.data[i]._model.x).toBeCloseToPixel(values.x);
|
||||
expect(meta0.data[i]._model.y).toBeCloseToPixel(values.y);
|
||||
expect(meta0.data[i].base).toBeCloseToPixel(values.b);
|
||||
expect(meta0.data[i].width).toBeCloseToPixel(values.w);
|
||||
expect(meta0.data[i].x).toBeCloseToPixel(values.x);
|
||||
expect(meta0.data[i].y).toBeCloseToPixel(values.y);
|
||||
});
|
||||
|
||||
var meta1 = chart.getDatasetMeta(1);
|
||||
@ -843,10 +843,10 @@ describe('Chart.controllers.bar', function() {
|
||||
{b: 146, w: 92 / 2, x: 345, y: 146},
|
||||
{b: 439, w: 92 / 2, x: 473, y: 497}
|
||||
].forEach(function(values, i) {
|
||||
expect(meta1.data[i]._model.base).toBeCloseToPixel(values.b);
|
||||
expect(meta1.data[i]._model.width).toBeCloseToPixel(values.w);
|
||||
expect(meta1.data[i]._model.x).toBeCloseToPixel(values.x);
|
||||
expect(meta1.data[i]._model.y).toBeCloseToPixel(values.y);
|
||||
expect(meta1.data[i].base).toBeCloseToPixel(values.b);
|
||||
expect(meta1.data[i].width).toBeCloseToPixel(values.w);
|
||||
expect(meta1.data[i].x).toBeCloseToPixel(values.x);
|
||||
expect(meta1.data[i].y).toBeCloseToPixel(values.y);
|
||||
});
|
||||
});
|
||||
|
||||
@ -890,10 +890,10 @@ describe('Chart.controllers.bar', function() {
|
||||
{b: 1024, w: 92 / 2, x: 294, y: 922},
|
||||
{b: 1024, w: 92 / 2, x: 422.5, y: 0}
|
||||
].forEach(function(values, i) {
|
||||
expect(meta0.data[i]._model.base).toBeCloseToPixel(values.b);
|
||||
expect(meta0.data[i]._model.width).toBeCloseToPixel(values.w);
|
||||
expect(meta0.data[i]._model.x).toBeCloseToPixel(values.x);
|
||||
expect(meta0.data[i]._model.y).toBeCloseToPixel(values.y);
|
||||
expect(meta0.data[i].base).toBeCloseToPixel(values.b);
|
||||
expect(meta0.data[i].width).toBeCloseToPixel(values.w);
|
||||
expect(meta0.data[i].x).toBeCloseToPixel(values.x);
|
||||
expect(meta0.data[i].y).toBeCloseToPixel(values.y);
|
||||
});
|
||||
|
||||
var meta1 = chart.getDatasetMeta(1);
|
||||
@ -904,10 +904,10 @@ describe('Chart.controllers.bar', function() {
|
||||
{b: 922, w: 92 / 2, x: 345, y: 0},
|
||||
{b: 0, w: 92 / 2, x: 473.5, y: 0}
|
||||
].forEach(function(values, i) {
|
||||
expect(meta1.data[i]._model.base).toBeCloseToPixel(values.b);
|
||||
expect(meta1.data[i]._model.width).toBeCloseToPixel(values.w);
|
||||
expect(meta1.data[i]._model.x).toBeCloseToPixel(values.x);
|
||||
expect(meta1.data[i]._model.y).toBeCloseToPixel(values.y);
|
||||
expect(meta1.data[i].base).toBeCloseToPixel(values.b);
|
||||
expect(meta1.data[i].width).toBeCloseToPixel(values.w);
|
||||
expect(meta1.data[i].x).toBeCloseToPixel(values.x);
|
||||
expect(meta1.data[i].y).toBeCloseToPixel(values.y);
|
||||
});
|
||||
});
|
||||
|
||||
@ -949,10 +949,10 @@ describe('Chart.controllers.bar', function() {
|
||||
{b: 293, w: 92, x: 320, y: 146},
|
||||
{b: 293, w: 92, x: 448, y: 439}
|
||||
].forEach(function(values, i) {
|
||||
expect(meta0.data[i]._model.base).toBeCloseToPixel(values.b);
|
||||
expect(meta0.data[i]._model.width).toBeCloseToPixel(values.w);
|
||||
expect(meta0.data[i]._model.x).toBeCloseToPixel(values.x);
|
||||
expect(meta0.data[i]._model.y).toBeCloseToPixel(values.y);
|
||||
expect(meta0.data[i].base).toBeCloseToPixel(values.b);
|
||||
expect(meta0.data[i].width).toBeCloseToPixel(values.w);
|
||||
expect(meta0.data[i].x).toBeCloseToPixel(values.x);
|
||||
expect(meta0.data[i].y).toBeCloseToPixel(values.y);
|
||||
});
|
||||
|
||||
var meta1 = chart.getDatasetMeta(1);
|
||||
@ -963,10 +963,10 @@ describe('Chart.controllers.bar', function() {
|
||||
{b: 293, w: 92, x: 320, y: 293},
|
||||
{b: 293, w: 92, x: 448, y: 497}
|
||||
].forEach(function(values, i) {
|
||||
expect(meta1.data[i]._model.base).toBeCloseToPixel(values.b);
|
||||
expect(meta1.data[i]._model.width).toBeCloseToPixel(values.w);
|
||||
expect(meta1.data[i]._model.x).toBeCloseToPixel(values.x);
|
||||
expect(meta1.data[i]._model.y).toBeCloseToPixel(values.y);
|
||||
expect(meta1.data[i].base).toBeCloseToPixel(values.b);
|
||||
expect(meta1.data[i].width).toBeCloseToPixel(values.w);
|
||||
expect(meta1.data[i].x).toBeCloseToPixel(values.x);
|
||||
expect(meta1.data[i].y).toBeCloseToPixel(values.y);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1008,10 +1008,10 @@ describe('Chart.controllers.bar', function() {
|
||||
{b: 293, w: 92 / 2, x: 295, y: 146},
|
||||
{b: 293, w: 92 / 2, x: 422, y: 439}
|
||||
].forEach(function(values, i) {
|
||||
expect(meta0.data[i]._model.base).toBeCloseToPixel(values.b);
|
||||
expect(meta0.data[i]._model.width).toBeCloseToPixel(values.w);
|
||||
expect(meta0.data[i]._model.x).toBeCloseToPixel(values.x);
|
||||
expect(meta0.data[i]._model.y).toBeCloseToPixel(values.y);
|
||||
expect(meta0.data[i].base).toBeCloseToPixel(values.b);
|
||||
expect(meta0.data[i].width).toBeCloseToPixel(values.w);
|
||||
expect(meta0.data[i].x).toBeCloseToPixel(values.x);
|
||||
expect(meta0.data[i].y).toBeCloseToPixel(values.y);
|
||||
});
|
||||
|
||||
var meta1 = chart.getDatasetMeta(1);
|
||||
@ -1022,10 +1022,10 @@ describe('Chart.controllers.bar', function() {
|
||||
{b: 146, w: 92 / 2, x: 345, y: 146},
|
||||
{b: 439, w: 92 / 2, x: 473, y: 497}
|
||||
].forEach(function(values, i) {
|
||||
expect(meta1.data[i]._model.base).toBeCloseToPixel(values.b);
|
||||
expect(meta1.data[i]._model.width).toBeCloseToPixel(values.w);
|
||||
expect(meta1.data[i]._model.x).toBeCloseToPixel(values.x);
|
||||
expect(meta1.data[i]._model.y).toBeCloseToPixel(values.y);
|
||||
expect(meta1.data[i].base).toBeCloseToPixel(values.b);
|
||||
expect(meta1.data[i].width).toBeCloseToPixel(values.w);
|
||||
expect(meta1.data[i].x).toBeCloseToPixel(values.x);
|
||||
expect(meta1.data[i].y).toBeCloseToPixel(values.y);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1069,10 +1069,10 @@ describe('Chart.controllers.bar', function() {
|
||||
{b: 293, w: 92, x: 320, y: 146},
|
||||
{b: 293, w: 92, x: 448, y: 439}
|
||||
].forEach(function(values, i) {
|
||||
expect(meta0.data[i]._model.base).toBeCloseToPixel(values.b);
|
||||
expect(meta0.data[i]._model.width).toBeCloseToPixel(values.w);
|
||||
expect(meta0.data[i]._model.x).toBeCloseToPixel(values.x);
|
||||
expect(meta0.data[i]._model.y).toBeCloseToPixel(values.y);
|
||||
expect(meta0.data[i].base).toBeCloseToPixel(values.b);
|
||||
expect(meta0.data[i].width).toBeCloseToPixel(values.w);
|
||||
expect(meta0.data[i].x).toBeCloseToPixel(values.x);
|
||||
expect(meta0.data[i].y).toBeCloseToPixel(values.y);
|
||||
});
|
||||
|
||||
var meta = chart.getDatasetMeta(1);
|
||||
@ -1083,10 +1083,10 @@ describe('Chart.controllers.bar', function() {
|
||||
{b: 146, w: 92, x: 320, y: 146},
|
||||
{b: 439, w: 92, x: 448, y: 497}
|
||||
].forEach(function(values, i) {
|
||||
expect(meta.data[i]._model.base).toBeCloseToPixel(values.b);
|
||||
expect(meta.data[i]._model.width).toBeCloseToPixel(values.w);
|
||||
expect(meta.data[i]._model.x).toBeCloseToPixel(values.x);
|
||||
expect(meta.data[i]._model.y).toBeCloseToPixel(values.y);
|
||||
expect(meta.data[i].base).toBeCloseToPixel(values.b);
|
||||
expect(meta.data[i].width).toBeCloseToPixel(values.w);
|
||||
expect(meta.data[i].x).toBeCloseToPixel(values.x);
|
||||
expect(meta.data[i].y).toBeCloseToPixel(values.y);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1126,10 +1126,10 @@ describe('Chart.controllers.bar', function() {
|
||||
{x: 89, y: 256},
|
||||
{x: 217, y: 0}
|
||||
].forEach(function(values, i) {
|
||||
expect(meta.data[i]._model.base).toBeCloseToPixel(512);
|
||||
expect(meta.data[i]._model.width).toBeCloseToPixel(46);
|
||||
expect(meta.data[i]._model.x).toBeCloseToPixel(values.x);
|
||||
expect(meta.data[i]._model.y).toBeCloseToPixel(values.y);
|
||||
expect(meta.data[i].base).toBeCloseToPixel(512);
|
||||
expect(meta.data[i].width).toBeCloseToPixel(46);
|
||||
expect(meta.data[i].x).toBeCloseToPixel(values.x);
|
||||
expect(meta.data[i].y).toBeCloseToPixel(values.y);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1172,10 +1172,10 @@ describe('Chart.controllers.bar', function() {
|
||||
{b: 384, x: 89, y: 256},
|
||||
{b: 256, x: 217, y: 0}
|
||||
].forEach(function(values, i) {
|
||||
expect(meta.data[i]._model.base).toBeCloseToPixel(values.b);
|
||||
expect(meta.data[i]._model.width).toBeCloseToPixel(46);
|
||||
expect(meta.data[i]._model.x).toBeCloseToPixel(values.x);
|
||||
expect(meta.data[i]._model.y).toBeCloseToPixel(values.y);
|
||||
expect(meta.data[i].base).toBeCloseToPixel(values.b);
|
||||
expect(meta.data[i].width).toBeCloseToPixel(46);
|
||||
expect(meta.data[i].x).toBeCloseToPixel(values.x);
|
||||
expect(meta.data[i].y).toBeCloseToPixel(values.y);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1235,29 +1235,31 @@ describe('Chart.controllers.bar', function() {
|
||||
var bar = meta.data[0];
|
||||
|
||||
meta.controller.setHoverStyle(bar, 1, 0);
|
||||
expect(bar._model.backgroundColor).toBe('rgb(230, 0, 0)');
|
||||
expect(bar._model.borderColor).toBe('rgb(0, 0, 230)');
|
||||
expect(bar._model.borderWidth).toBe(2);
|
||||
expect(bar.options.backgroundColor).toBe('rgb(230, 0, 0)');
|
||||
expect(bar.options.borderColor).toBe('rgb(0, 0, 230)');
|
||||
expect(bar.options.borderWidth).toBe(2);
|
||||
|
||||
// Set a dataset style
|
||||
chart.data.datasets[1].hoverBackgroundColor = 'rgb(128, 128, 128)';
|
||||
chart.data.datasets[1].hoverBorderColor = 'rgb(0, 0, 0)';
|
||||
chart.data.datasets[1].hoverBorderWidth = 5;
|
||||
chart.update();
|
||||
|
||||
meta.controller.setHoverStyle(bar, 1, 0);
|
||||
expect(bar._model.backgroundColor).toBe('rgb(128, 128, 128)');
|
||||
expect(bar._model.borderColor).toBe('rgb(0, 0, 0)');
|
||||
expect(bar._model.borderWidth).toBe(5);
|
||||
expect(bar.options.backgroundColor).toBe('rgb(128, 128, 128)');
|
||||
expect(bar.options.borderColor).toBe('rgb(0, 0, 0)');
|
||||
expect(bar.options.borderWidth).toBe(5);
|
||||
|
||||
// Should work with array styles so that we can set per bar
|
||||
chart.data.datasets[1].hoverBackgroundColor = ['rgb(255, 255, 255)', 'rgb(128, 128, 128)'];
|
||||
chart.data.datasets[1].hoverBorderColor = ['rgb(9, 9, 9)', 'rgb(0, 0, 0)'];
|
||||
chart.data.datasets[1].hoverBorderWidth = [2.5, 5];
|
||||
chart.update();
|
||||
|
||||
meta.controller.setHoverStyle(bar, 1, 0);
|
||||
expect(bar._model.backgroundColor).toBe('rgb(255, 255, 255)');
|
||||
expect(bar._model.borderColor).toBe('rgb(9, 9, 9)');
|
||||
expect(bar._model.borderWidth).toBe(2.5);
|
||||
expect(bar.options.backgroundColor).toBe('rgb(255, 255, 255)');
|
||||
expect(bar.options.borderColor).toBe('rgb(9, 9, 9)');
|
||||
expect(bar.options.borderWidth).toBe(2.5);
|
||||
});
|
||||
|
||||
it('should remove a hover style from a bar', function() {
|
||||
@ -1293,17 +1295,17 @@ describe('Chart.controllers.bar', function() {
|
||||
chart.options.elements.rectangle.borderWidth = 3.14;
|
||||
|
||||
chart.update();
|
||||
expect(bar._model.backgroundColor).toBe('rgb(128, 128, 128)');
|
||||
expect(bar._model.borderColor).toBe('rgb(15, 15, 15)');
|
||||
expect(bar._model.borderWidth).toBe(3.14);
|
||||
expect(bar.options.backgroundColor).toBe('rgb(128, 128, 128)');
|
||||
expect(bar.options.borderColor).toBe('rgb(15, 15, 15)');
|
||||
expect(bar.options.borderWidth).toBe(3.14);
|
||||
meta.controller.setHoverStyle(bar, 1, 0);
|
||||
expect(bar._model.backgroundColor).toBe(helpers.getHoverColor('rgb(128, 128, 128)'));
|
||||
expect(bar._model.borderColor).toBe(helpers.getHoverColor('rgb(15, 15, 15)'));
|
||||
expect(bar._model.borderWidth).toBe(3.14);
|
||||
expect(bar.options.backgroundColor).toBe(helpers.getHoverColor('rgb(128, 128, 128)'));
|
||||
expect(bar.options.borderColor).toBe(helpers.getHoverColor('rgb(15, 15, 15)'));
|
||||
expect(bar.options.borderWidth).toBe(3.14);
|
||||
meta.controller.removeHoverStyle(bar);
|
||||
expect(bar._model.backgroundColor).toBe('rgb(128, 128, 128)');
|
||||
expect(bar._model.borderColor).toBe('rgb(15, 15, 15)');
|
||||
expect(bar._model.borderWidth).toBe(3.14);
|
||||
expect(bar.options.backgroundColor).toBe('rgb(128, 128, 128)');
|
||||
expect(bar.options.borderColor).toBe('rgb(15, 15, 15)');
|
||||
expect(bar.options.borderWidth).toBe(3.14);
|
||||
|
||||
// Should work with array styles so that we can set per bar
|
||||
chart.data.datasets[1].backgroundColor = ['rgb(255, 255, 255)', 'rgb(128, 128, 128)'];
|
||||
@ -1311,17 +1313,17 @@ describe('Chart.controllers.bar', function() {
|
||||
chart.data.datasets[1].borderWidth = [2.5, 5];
|
||||
|
||||
chart.update();
|
||||
expect(bar._model.backgroundColor).toBe('rgb(255, 255, 255)');
|
||||
expect(bar._model.borderColor).toBe('rgb(9, 9, 9)');
|
||||
expect(bar._model.borderWidth).toBe(2.5);
|
||||
expect(bar.options.backgroundColor).toBe('rgb(255, 255, 255)');
|
||||
expect(bar.options.borderColor).toBe('rgb(9, 9, 9)');
|
||||
expect(bar.options.borderWidth).toBe(2.5);
|
||||
meta.controller.setHoverStyle(bar, 1, 0);
|
||||
expect(bar._model.backgroundColor).toBe(helpers.getHoverColor('rgb(255, 255, 255)'));
|
||||
expect(bar._model.borderColor).toBe(helpers.getHoverColor('rgb(9, 9, 9)'));
|
||||
expect(bar._model.borderWidth).toBe(2.5);
|
||||
expect(bar.options.backgroundColor).toBe(helpers.getHoverColor('rgb(255, 255, 255)'));
|
||||
expect(bar.options.borderColor).toBe(helpers.getHoverColor('rgb(9, 9, 9)'));
|
||||
expect(bar.options.borderWidth).toBe(2.5);
|
||||
meta.controller.removeHoverStyle(bar);
|
||||
expect(bar._model.backgroundColor).toBe('rgb(255, 255, 255)');
|
||||
expect(bar._model.borderColor).toBe('rgb(9, 9, 9)');
|
||||
expect(bar._model.borderWidth).toBe(2.5);
|
||||
expect(bar.options.backgroundColor).toBe('rgb(255, 255, 255)');
|
||||
expect(bar.options.borderColor).toBe('rgb(9, 9, 9)');
|
||||
expect(bar.options.borderWidth).toBe(2.5);
|
||||
});
|
||||
|
||||
describe('Bar width', function() {
|
||||
@ -1351,7 +1353,7 @@ describe('Chart.controllers.bar', function() {
|
||||
for (var i = 0; i < chart.data.datasets.length; i++) {
|
||||
var bars = chart.getDatasetMeta(i).data;
|
||||
for (var j = xScale.min; j <= xScale.max; j++) {
|
||||
totalBarWidth += bars[j]._model.width;
|
||||
totalBarWidth += bars[j].width;
|
||||
}
|
||||
if (stacked) {
|
||||
break;
|
||||
@ -1425,7 +1427,7 @@ describe('Chart.controllers.bar', function() {
|
||||
for (var i = 0; i < chart.data.datasets.length; i++) {
|
||||
var bars = chart.getDatasetMeta(i).data;
|
||||
for (var j = yScale.min; j <= yScale.max; j++) {
|
||||
totalBarHeight += bars[j]._model.height;
|
||||
totalBarHeight += bars[j].height;
|
||||
}
|
||||
if (stacked) {
|
||||
break;
|
||||
@ -1525,8 +1527,8 @@ describe('Chart.controllers.bar', function() {
|
||||
|
||||
for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) {
|
||||
meta = chart.getDatasetMeta(i);
|
||||
expect(meta.data[0]._model.width).toBeCloseToPixel(expected);
|
||||
expect(meta.data[1]._model.width).toBeCloseToPixel(expected);
|
||||
expect(meta.data[0].width).toBeCloseToPixel(expected);
|
||||
expect(meta.data[1].width).toBeCloseToPixel(expected);
|
||||
}
|
||||
});
|
||||
|
||||
@ -1540,8 +1542,8 @@ describe('Chart.controllers.bar', function() {
|
||||
|
||||
for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) {
|
||||
meta = chart.getDatasetMeta(i);
|
||||
expect(meta.data[0]._model.width).toBeCloseToPixel(10);
|
||||
expect(meta.data[1]._model.width).toBeCloseToPixel(10);
|
||||
expect(meta.data[0].width).toBeCloseToPixel(10);
|
||||
expect(meta.data[1].width).toBeCloseToPixel(10);
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -1562,8 +1564,8 @@ describe('Chart.controllers.bar', function() {
|
||||
|
||||
var data = chart.getDatasetMeta(0).data;
|
||||
|
||||
expect(data[0]._model.base - minBarLength).toEqual(data[0]._model.y);
|
||||
expect(data[1]._model.base + minBarLength).toEqual(data[1]._model.y);
|
||||
expect(data[0].base - minBarLength).toEqual(data[0].y);
|
||||
expect(data[1].base + minBarLength).toEqual(data[1].y);
|
||||
});
|
||||
|
||||
it('minBarLength settings should be used on X axis on horizontalBar chart', function() {
|
||||
@ -1580,7 +1582,7 @@ describe('Chart.controllers.bar', function() {
|
||||
|
||||
var data = chart.getDatasetMeta(0).data;
|
||||
|
||||
expect(data[0]._model.base + minBarLength).toEqual(data[0]._model.x);
|
||||
expect(data[1]._model.base - minBarLength).toEqual(data[1]._model.x);
|
||||
expect(data[0].base + minBarLength).toEqual(data[0].x);
|
||||
expect(data[1].base - minBarLength).toEqual(data[1].x);
|
||||
});
|
||||
});
|
||||
|
||||
@ -138,15 +138,14 @@ describe('Chart.controllers.bubble', function() {
|
||||
{r: 2, x: 341, y: 486},
|
||||
{r: 1, x: 512, y: 0}
|
||||
].forEach(function(expected, i) {
|
||||
expect(meta.data[i]._model.radius).toBe(expected.r);
|
||||
expect(meta.data[i]._model.x).toBeCloseToPixel(expected.x);
|
||||
expect(meta.data[i]._model.y).toBeCloseToPixel(expected.y);
|
||||
expect(meta.data[i]._model).toEqual(jasmine.objectContaining({
|
||||
expect(meta.data[i].x).toBeCloseToPixel(expected.x);
|
||||
expect(meta.data[i].y).toBeCloseToPixel(expected.y);
|
||||
expect(meta.data[i].options).toEqual(jasmine.objectContaining({
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 1,
|
||||
hitRadius: 1,
|
||||
skip: false
|
||||
radius: expected.r
|
||||
}));
|
||||
});
|
||||
|
||||
@ -162,12 +161,11 @@ describe('Chart.controllers.bubble', function() {
|
||||
chart.update();
|
||||
|
||||
for (var i = 0; i < 4; ++i) {
|
||||
expect(meta.data[i]._model).toEqual(jasmine.objectContaining({
|
||||
expect(meta.data[i].options).toEqual(jasmine.objectContaining({
|
||||
backgroundColor: 'rgb(98, 98, 98)',
|
||||
borderColor: 'rgb(8, 8, 8)',
|
||||
borderWidth: 0.55,
|
||||
hitRadius: 3.3,
|
||||
skip: false
|
||||
hitRadius: 3.3
|
||||
}));
|
||||
}
|
||||
});
|
||||
@ -295,16 +293,16 @@ describe('Chart.controllers.bubble', function() {
|
||||
var point = chart.getDatasetMeta(0).data[0];
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mousemove', point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(49, 135, 221)');
|
||||
expect(point._model.borderColor).toBe('rgb(22, 89, 156)');
|
||||
expect(point._model.borderWidth).toBe(1);
|
||||
expect(point._model.radius).toBe(20 + 4);
|
||||
expect(point.options.backgroundColor).toBe('rgb(49, 135, 221)');
|
||||
expect(point.options.borderColor).toBe('rgb(22, 89, 156)');
|
||||
expect(point.options.borderWidth).toBe(1);
|
||||
expect(point.options.radius).toBe(20 + 4);
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mouseout', point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(point._model.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(point._model.borderWidth).toBe(2);
|
||||
expect(point._model.radius).toBe(20);
|
||||
expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(point.options.borderWidth).toBe(2);
|
||||
expect(point.options.radius).toBe(20);
|
||||
});
|
||||
|
||||
it ('should handle hover styles defined via dataset properties', function() {
|
||||
@ -321,16 +319,16 @@ describe('Chart.controllers.bubble', function() {
|
||||
chart.update();
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mousemove', point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(200, 100, 150)');
|
||||
expect(point._model.borderColor).toBe('rgb(150, 50, 100)');
|
||||
expect(point._model.borderWidth).toBe(8.4);
|
||||
expect(point._model.radius).toBe(20 + 4.2);
|
||||
expect(point.options.backgroundColor).toBe('rgb(200, 100, 150)');
|
||||
expect(point.options.borderColor).toBe('rgb(150, 50, 100)');
|
||||
expect(point.options.borderWidth).toBe(8.4);
|
||||
expect(point.options.radius).toBe(20 + 4.2);
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mouseout', point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(point._model.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(point._model.borderWidth).toBe(2);
|
||||
expect(point._model.radius).toBe(20);
|
||||
expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(point.options.borderWidth).toBe(2);
|
||||
expect(point.options.radius).toBe(20);
|
||||
});
|
||||
|
||||
it ('should handle hover styles defined via element options', function() {
|
||||
@ -347,16 +345,16 @@ describe('Chart.controllers.bubble', function() {
|
||||
chart.update();
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mousemove', point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(200, 100, 150)');
|
||||
expect(point._model.borderColor).toBe('rgb(150, 50, 100)');
|
||||
expect(point._model.borderWidth).toBe(8.4);
|
||||
expect(point._model.radius).toBe(20 + 4.2);
|
||||
expect(point.options.backgroundColor).toBe('rgb(200, 100, 150)');
|
||||
expect(point.options.borderColor).toBe('rgb(150, 50, 100)');
|
||||
expect(point.options.borderWidth).toBe(8.4);
|
||||
expect(point.options.radius).toBe(20 + 4.2);
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mouseout', point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(point._model.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(point._model.borderWidth).toBe(2);
|
||||
expect(point._model.radius).toBe(20);
|
||||
expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(point.options.borderWidth).toBe(2);
|
||||
expect(point.options.radius).toBe(20);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -78,6 +78,7 @@ describe('Chart.controllers.doughnut', function() {
|
||||
legend: false,
|
||||
title: false,
|
||||
animation: {
|
||||
duration: 0,
|
||||
animateRotate: true,
|
||||
animateScale: false
|
||||
},
|
||||
@ -106,14 +107,14 @@ describe('Chart.controllers.doughnut', function() {
|
||||
{c: 0},
|
||||
{c: 0}
|
||||
].forEach(function(expected, i) {
|
||||
expect(meta.data[i]._model.x).toBeCloseToPixel(256);
|
||||
expect(meta.data[i]._model.y).toBeCloseToPixel(256);
|
||||
expect(meta.data[i]._model.outerRadius).toBeCloseToPixel(256);
|
||||
expect(meta.data[i]._model.innerRadius).toBeCloseToPixel(192);
|
||||
expect(meta.data[i]._model.circumference).toBeCloseTo(expected.c, 8);
|
||||
expect(meta.data[i]._model).toEqual(jasmine.objectContaining({
|
||||
startAngle: Math.PI * -0.5,
|
||||
endAngle: Math.PI * -0.5,
|
||||
expect(meta.data[i].x).toBeCloseToPixel(256);
|
||||
expect(meta.data[i].y).toBeCloseToPixel(256);
|
||||
expect(meta.data[i].outerRadius).toBeCloseToPixel(256);
|
||||
expect(meta.data[i].innerRadius).toBeCloseToPixel(192);
|
||||
expect(meta.data[i].circumference).toBeCloseTo(expected.c, 8);
|
||||
expect(meta.data[i].startAngle).toBeCloseToPixel(Math.PI * -0.5);
|
||||
expect(meta.data[i].endAngle).toBeCloseToPixel(Math.PI * -0.5);
|
||||
expect(meta.data[i].options).toEqual(jasmine.objectContaining({
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderColor: 'rgb(0, 0, 255)',
|
||||
borderWidth: 2
|
||||
@ -128,14 +129,14 @@ describe('Chart.controllers.doughnut', function() {
|
||||
{c: 0, s: 2.2689280275, e: 2.2689280275},
|
||||
{c: 2.4434609527, s: 2.2689280275, e: 4.7123889803}
|
||||
].forEach(function(expected, i) {
|
||||
expect(meta.data[i]._model.x).toBeCloseToPixel(256);
|
||||
expect(meta.data[i]._model.y).toBeCloseToPixel(256);
|
||||
expect(meta.data[i]._model.outerRadius).toBeCloseToPixel(256);
|
||||
expect(meta.data[i]._model.innerRadius).toBeCloseToPixel(192);
|
||||
expect(meta.data[i]._model.circumference).toBeCloseTo(expected.c, 8);
|
||||
expect(meta.data[i]._model.startAngle).toBeCloseTo(expected.s, 8);
|
||||
expect(meta.data[i]._model.endAngle).toBeCloseTo(expected.e, 8);
|
||||
expect(meta.data[i]._model).toEqual(jasmine.objectContaining({
|
||||
expect(meta.data[i].x).toBeCloseToPixel(256);
|
||||
expect(meta.data[i].y).toBeCloseToPixel(256);
|
||||
expect(meta.data[i].outerRadius).toBeCloseToPixel(256);
|
||||
expect(meta.data[i].innerRadius).toBeCloseToPixel(192);
|
||||
expect(meta.data[i].circumference).toBeCloseTo(expected.c, 8);
|
||||
expect(meta.data[i].startAngle).toBeCloseTo(expected.s, 8);
|
||||
expect(meta.data[i].endAngle).toBeCloseTo(expected.e, 8);
|
||||
expect(meta.data[i].options).toEqual(jasmine.objectContaining({
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderColor: 'rgb(0, 0, 255)',
|
||||
borderWidth: 2
|
||||
@ -200,13 +201,13 @@ describe('Chart.controllers.doughnut', function() {
|
||||
{c: Math.PI / 8, s: Math.PI, e: Math.PI + Math.PI / 8},
|
||||
{c: 3 * Math.PI / 8, s: Math.PI + Math.PI / 8, e: Math.PI + Math.PI / 2}
|
||||
].forEach(function(expected, i) {
|
||||
expect(meta.data[i]._model.x).toBeCloseToPixel(512);
|
||||
expect(meta.data[i]._model.y).toBeCloseToPixel(512);
|
||||
expect(meta.data[i]._model.outerRadius).toBeCloseToPixel(512);
|
||||
expect(meta.data[i]._model.innerRadius).toBeCloseToPixel(384);
|
||||
expect(meta.data[i]._model.circumference).toBeCloseTo(expected.c, 8);
|
||||
expect(meta.data[i]._model.startAngle).toBeCloseTo(expected.s, 8);
|
||||
expect(meta.data[i]._model.endAngle).toBeCloseTo(expected.e, 8);
|
||||
expect(meta.data[i].x).toBeCloseToPixel(512);
|
||||
expect(meta.data[i].y).toBeCloseToPixel(512);
|
||||
expect(meta.data[i].outerRadius).toBeCloseToPixel(512);
|
||||
expect(meta.data[i].innerRadius).toBeCloseToPixel(384);
|
||||
expect(meta.data[i].circumference).toBeCloseTo(expected.c, 8);
|
||||
expect(meta.data[i].startAngle).toBeCloseTo(expected.s, 8);
|
||||
expect(meta.data[i].endAngle).toBeCloseTo(expected.e, 8);
|
||||
});
|
||||
});
|
||||
|
||||
@ -244,9 +245,9 @@ describe('Chart.controllers.doughnut', function() {
|
||||
{c: Math.PI / 8, s: Math.PI, e: Math.PI + Math.PI / 8},
|
||||
{c: 3 * Math.PI / 8, s: Math.PI + Math.PI / 8, e: Math.PI + Math.PI / 2}
|
||||
].forEach(function(expected, i) {
|
||||
expect(meta.data[i]._model.circumference).toBeCloseTo(expected.c, 8);
|
||||
expect(meta.data[i]._model.startAngle).toBeCloseTo(expected.s, 8);
|
||||
expect(meta.data[i]._model.endAngle).toBeCloseTo(expected.e, 8);
|
||||
expect(meta.data[i].circumference).toBeCloseTo(expected.c, 8);
|
||||
expect(meta.data[i].startAngle).toBeCloseTo(expected.s, 8);
|
||||
expect(meta.data[i].endAngle).toBeCloseTo(expected.e, 8);
|
||||
});
|
||||
});
|
||||
|
||||
@ -351,14 +352,14 @@ describe('Chart.controllers.doughnut', function() {
|
||||
var arc = chart.getDatasetMeta(0).data[0];
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mousemove', arc);
|
||||
expect(arc._model.backgroundColor).toBe('rgb(49, 135, 221)');
|
||||
expect(arc._model.borderColor).toBe('rgb(22, 89, 156)');
|
||||
expect(arc._model.borderWidth).toBe(2);
|
||||
expect(arc.options.backgroundColor).toBe('rgb(49, 135, 221)');
|
||||
expect(arc.options.borderColor).toBe('rgb(22, 89, 156)');
|
||||
expect(arc.options.borderWidth).toBe(2);
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mouseout', arc);
|
||||
expect(arc._model.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(arc._model.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(arc._model.borderWidth).toBe(2);
|
||||
expect(arc.options.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(arc.options.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(arc.options.borderWidth).toBe(2);
|
||||
});
|
||||
|
||||
it ('should handle hover styles defined via dataset properties', function() {
|
||||
@ -374,14 +375,14 @@ describe('Chart.controllers.doughnut', function() {
|
||||
chart.update();
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mousemove', arc);
|
||||
expect(arc._model.backgroundColor).toBe('rgb(200, 100, 150)');
|
||||
expect(arc._model.borderColor).toBe('rgb(150, 50, 100)');
|
||||
expect(arc._model.borderWidth).toBe(8.4);
|
||||
expect(arc.options.backgroundColor).toBe('rgb(200, 100, 150)');
|
||||
expect(arc.options.borderColor).toBe('rgb(150, 50, 100)');
|
||||
expect(arc.options.borderWidth).toBe(8.4);
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mouseout', arc);
|
||||
expect(arc._model.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(arc._model.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(arc._model.borderWidth).toBe(2);
|
||||
expect(arc.options.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(arc.options.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(arc.options.borderWidth).toBe(2);
|
||||
});
|
||||
|
||||
it ('should handle hover styles defined via element options', function() {
|
||||
@ -397,14 +398,14 @@ describe('Chart.controllers.doughnut', function() {
|
||||
chart.update();
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mousemove', arc);
|
||||
expect(arc._model.backgroundColor).toBe('rgb(200, 100, 150)');
|
||||
expect(arc._model.borderColor).toBe('rgb(150, 50, 100)');
|
||||
expect(arc._model.borderWidth).toBe(8.4);
|
||||
expect(arc.options.backgroundColor).toBe('rgb(200, 100, 150)');
|
||||
expect(arc.options.borderColor).toBe('rgb(150, 50, 100)');
|
||||
expect(arc.options.borderWidth).toBe(8.4);
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mouseout', arc);
|
||||
expect(arc._model.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(arc._model.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(arc._model.borderWidth).toBe(2);
|
||||
expect(arc.options.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(arc.options.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(arc.options.borderWidth).toBe(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -203,9 +203,9 @@ describe('Chart.controllers.line', function() {
|
||||
{x: 0, y: 512},
|
||||
{x: 171, y: 0}
|
||||
].forEach(function(expected, i) {
|
||||
expect(meta.data[i]._model.x).toBeCloseToPixel(expected.x);
|
||||
expect(meta.data[i]._model.y).toBeCloseToPixel(expected.y);
|
||||
expect(meta.data[i]._model).toEqual(jasmine.objectContaining({
|
||||
expect(meta.data[i].x).toBeCloseToPixel(expected.x);
|
||||
expect(meta.data[i].y).toBeCloseToPixel(expected.y);
|
||||
expect(meta.data[i].options).toEqual(jasmine.objectContaining({
|
||||
backgroundColor: 'red',
|
||||
borderColor: 'blue',
|
||||
}));
|
||||
@ -248,7 +248,7 @@ describe('Chart.controllers.line', function() {
|
||||
var meta = chart.getDatasetMeta(0);
|
||||
// 1 point
|
||||
var point = meta.data[0];
|
||||
expect(point._model.x).toBeCloseToPixel(0);
|
||||
expect(point.x).toBeCloseToPixel(0);
|
||||
|
||||
// 2 points
|
||||
chart.data.labels = ['One', 'Two'];
|
||||
@ -257,8 +257,8 @@ describe('Chart.controllers.line', function() {
|
||||
|
||||
var points = meta.data;
|
||||
|
||||
expect(points[0]._model.x).toBeCloseToPixel(0);
|
||||
expect(points[1]._model.x).toBeCloseToPixel(512);
|
||||
expect(points[0].x).toBeCloseToPixel(0);
|
||||
expect(points[1].x).toBeCloseToPixel(512);
|
||||
|
||||
// 3 points
|
||||
chart.data.labels = ['One', 'Two', 'Three'];
|
||||
@ -267,9 +267,9 @@ describe('Chart.controllers.line', function() {
|
||||
|
||||
points = meta.data;
|
||||
|
||||
expect(points[0]._model.x).toBeCloseToPixel(0);
|
||||
expect(points[1]._model.x).toBeCloseToPixel(256);
|
||||
expect(points[2]._model.x).toBeCloseToPixel(512);
|
||||
expect(points[0].x).toBeCloseToPixel(0);
|
||||
expect(points[1].x).toBeCloseToPixel(256);
|
||||
expect(points[2].x).toBeCloseToPixel(512);
|
||||
|
||||
// 4 points
|
||||
chart.data.labels = ['One', 'Two', 'Three', 'Four'];
|
||||
@ -278,10 +278,10 @@ describe('Chart.controllers.line', function() {
|
||||
|
||||
points = meta.data;
|
||||
|
||||
expect(points[0]._model.x).toBeCloseToPixel(0);
|
||||
expect(points[1]._model.x).toBeCloseToPixel(171);
|
||||
expect(points[2]._model.x).toBeCloseToPixel(340);
|
||||
expect(points[3]._model.x).toBeCloseToPixel(512);
|
||||
expect(points[0].x).toBeCloseToPixel(0);
|
||||
expect(points[1].x).toBeCloseToPixel(171);
|
||||
expect(points[2].x).toBeCloseToPixel(340);
|
||||
expect(points[3].x).toBeCloseToPixel(512);
|
||||
});
|
||||
|
||||
it('should update elements when the y scale is stacked', function() {
|
||||
@ -320,8 +320,8 @@ describe('Chart.controllers.line', function() {
|
||||
{x: 341, y: 146},
|
||||
{x: 512, y: 439}
|
||||
].forEach(function(values, i) {
|
||||
expect(meta0.data[i]._model.x).toBeCloseToPixel(values.x);
|
||||
expect(meta0.data[i]._model.y).toBeCloseToPixel(values.y);
|
||||
expect(meta0.data[i].x).toBeCloseToPixel(values.x);
|
||||
expect(meta0.data[i].y).toBeCloseToPixel(values.y);
|
||||
});
|
||||
|
||||
var meta1 = chart.getDatasetMeta(1);
|
||||
@ -332,8 +332,8 @@ describe('Chart.controllers.line', function() {
|
||||
{x: 341, y: 146},
|
||||
{x: 512, y: 497}
|
||||
].forEach(function(values, i) {
|
||||
expect(meta1.data[i]._model.x).toBeCloseToPixel(values.x);
|
||||
expect(meta1.data[i]._model.y).toBeCloseToPixel(values.y);
|
||||
expect(meta1.data[i].x).toBeCloseToPixel(values.x);
|
||||
expect(meta1.data[i].y).toBeCloseToPixel(values.y);
|
||||
});
|
||||
|
||||
});
|
||||
@ -383,8 +383,8 @@ describe('Chart.controllers.line', function() {
|
||||
{x: 341, y: 146},
|
||||
{x: 512, y: 439}
|
||||
].forEach(function(values, i) {
|
||||
expect(meta0.data[i]._model.x).toBeCloseToPixel(values.x);
|
||||
expect(meta0.data[i]._model.y).toBeCloseToPixel(values.y);
|
||||
expect(meta0.data[i].x).toBeCloseToPixel(values.x);
|
||||
expect(meta0.data[i].y).toBeCloseToPixel(values.y);
|
||||
});
|
||||
|
||||
var meta1 = chart.getDatasetMeta(1);
|
||||
@ -395,8 +395,8 @@ describe('Chart.controllers.line', function() {
|
||||
{x: 341, y: 146},
|
||||
{x: 512, y: 497}
|
||||
].forEach(function(values, i) {
|
||||
expect(meta1.data[i]._model.x).toBeCloseToPixel(values.x);
|
||||
expect(meta1.data[i]._model.y).toBeCloseToPixel(values.y);
|
||||
expect(meta1.data[i].x).toBeCloseToPixel(values.x);
|
||||
expect(meta1.data[i].y).toBeCloseToPixel(values.y);
|
||||
});
|
||||
|
||||
});
|
||||
@ -461,8 +461,8 @@ describe('Chart.controllers.line', function() {
|
||||
{x: 341, y: 146},
|
||||
{x: 512, y: 439}
|
||||
].forEach(function(values, i) {
|
||||
expect(meta0.data[i]._model.x).toBeCloseToPixel(values.x);
|
||||
expect(meta0.data[i]._model.y).toBeCloseToPixel(values.y);
|
||||
expect(meta0.data[i].x).toBeCloseToPixel(values.x);
|
||||
expect(meta0.data[i].y).toBeCloseToPixel(values.y);
|
||||
});
|
||||
|
||||
var meta1 = chart.getDatasetMeta(1);
|
||||
@ -473,8 +473,8 @@ describe('Chart.controllers.line', function() {
|
||||
{x: 341, y: 146},
|
||||
{x: 512, y: 497}
|
||||
].forEach(function(values, i) {
|
||||
expect(meta1.data[i]._model.x).toBeCloseToPixel(values.x);
|
||||
expect(meta1.data[i]._model.y).toBeCloseToPixel(values.y);
|
||||
expect(meta1.data[i].x).toBeCloseToPixel(values.x);
|
||||
expect(meta1.data[i].y).toBeCloseToPixel(values.y);
|
||||
});
|
||||
|
||||
});
|
||||
@ -515,8 +515,8 @@ describe('Chart.controllers.line', function() {
|
||||
{x: 341, y: 146},
|
||||
{x: 512, y: 439}
|
||||
].forEach(function(values, i) {
|
||||
expect(meta0.data[i]._model.x).toBeCloseToPixel(values.x);
|
||||
expect(meta0.data[i]._model.y).toBeCloseToPixel(values.y);
|
||||
expect(meta0.data[i].x).toBeCloseToPixel(values.x);
|
||||
expect(meta0.data[i].y).toBeCloseToPixel(values.y);
|
||||
});
|
||||
|
||||
var meta1 = chart.getDatasetMeta(1);
|
||||
@ -527,8 +527,8 @@ describe('Chart.controllers.line', function() {
|
||||
{x: 341, y: 146},
|
||||
{x: 512, y: 497}
|
||||
].forEach(function(values, i) {
|
||||
expect(meta1.data[i]._model.x).toBeCloseToPixel(values.x);
|
||||
expect(meta1.data[i]._model.y).toBeCloseToPixel(values.y);
|
||||
expect(meta1.data[i].x).toBeCloseToPixel(values.x);
|
||||
expect(meta1.data[i].y).toBeCloseToPixel(values.y);
|
||||
});
|
||||
|
||||
});
|
||||
@ -552,9 +552,9 @@ describe('Chart.controllers.line', function() {
|
||||
|
||||
var meta = chart.getDatasetMeta(0);
|
||||
|
||||
expect(meta.dataset._model.backgroundColor).toBe('rgb(98, 98, 98)');
|
||||
expect(meta.dataset._model.borderColor).toBe('rgb(8, 8, 8)');
|
||||
expect(meta.dataset._model.borderWidth).toBe(0.55);
|
||||
expect(meta.dataset.options.backgroundColor).toBe('rgb(98, 98, 98)');
|
||||
expect(meta.dataset.options.borderColor).toBe('rgb(8, 8, 8)');
|
||||
expect(meta.dataset.options.borderWidth).toBe(0.55);
|
||||
});
|
||||
|
||||
describe('dataset global defaults', function() {
|
||||
@ -595,19 +595,19 @@ describe('Chart.controllers.line', function() {
|
||||
}
|
||||
});
|
||||
|
||||
var model = chart.getDatasetMeta(0).dataset._model;
|
||||
var options = chart.getDatasetMeta(0).dataset.options;
|
||||
|
||||
expect(model.spanGaps).toBe(true);
|
||||
expect(model.tension).toBe(0.231);
|
||||
expect(model.backgroundColor).toBe('#add');
|
||||
expect(model.borderWidth).toBe('#daa');
|
||||
expect(model.borderColor).toBe('#dad');
|
||||
expect(model.borderCapStyle).toBe('round');
|
||||
expect(model.borderDash).toEqual([0]);
|
||||
expect(model.borderDashOffset).toBe(0.871);
|
||||
expect(model.borderJoinStyle).toBe('miter');
|
||||
expect(model.fill).toBe('start');
|
||||
expect(model.cubicInterpolationMode).toBe('monotone');
|
||||
expect(options.spanGaps).toBe(true);
|
||||
expect(options.tension).toBe(0.231);
|
||||
expect(options.backgroundColor).toBe('#add');
|
||||
expect(options.borderWidth).toBe('#daa');
|
||||
expect(options.borderColor).toBe('#dad');
|
||||
expect(options.borderCapStyle).toBe('round');
|
||||
expect(options.borderDash).toEqual([0]);
|
||||
expect(options.borderDashOffset).toBe(0.871);
|
||||
expect(options.borderJoinStyle).toBe('miter');
|
||||
expect(options.fill).toBe('start');
|
||||
expect(options.cubicInterpolationMode).toBe('monotone');
|
||||
});
|
||||
|
||||
it('should be overriden by user-supplied values', function() {
|
||||
@ -639,14 +639,14 @@ describe('Chart.controllers.line', function() {
|
||||
}
|
||||
});
|
||||
|
||||
var model = chart.getDatasetMeta(0).dataset._model;
|
||||
var options = chart.getDatasetMeta(0).dataset.options;
|
||||
|
||||
// dataset-level option overrides global default
|
||||
expect(model.spanGaps).toBe(true);
|
||||
expect(options.spanGaps).toBe(true);
|
||||
// chart-level default overrides global default
|
||||
expect(model.tension).toBe(0.345);
|
||||
expect(options.tension).toBe(0.345);
|
||||
// dataset-level option overrides chart-level default
|
||||
expect(model.backgroundColor).toBe('#dad');
|
||||
expect(options.backgroundColor).toBe('#dad');
|
||||
});
|
||||
});
|
||||
|
||||
@ -679,19 +679,19 @@ describe('Chart.controllers.line', function() {
|
||||
}
|
||||
});
|
||||
|
||||
var model = chart.getDatasetMeta(0).dataset._model;
|
||||
var options = chart.getDatasetMeta(0).dataset.options;
|
||||
|
||||
expect(model.spanGaps).toBe(true);
|
||||
expect(model.tension).toBe(0.231);
|
||||
expect(model.backgroundColor).toBe('#add');
|
||||
expect(model.borderWidth).toBe('#daa');
|
||||
expect(model.borderColor).toBe('#dad');
|
||||
expect(model.borderCapStyle).toBe('round');
|
||||
expect(model.borderDash).toEqual([0]);
|
||||
expect(model.borderDashOffset).toBe(0.871);
|
||||
expect(model.borderJoinStyle).toBe('miter');
|
||||
expect(model.fill).toBe('start');
|
||||
expect(model.cubicInterpolationMode).toBe('monotone');
|
||||
expect(options.spanGaps).toBe(true);
|
||||
expect(options.tension).toBe(0.231);
|
||||
expect(options.backgroundColor).toBe('#add');
|
||||
expect(options.borderWidth).toBe('#daa');
|
||||
expect(options.borderColor).toBe('#dad');
|
||||
expect(options.borderCapStyle).toBe('round');
|
||||
expect(options.borderDash).toEqual([0]);
|
||||
expect(options.borderDashOffset).toBe(0.871);
|
||||
expect(options.borderJoinStyle).toBe('miter');
|
||||
expect(options.fill).toBe('start');
|
||||
expect(options.cubicInterpolationMode).toBe('monotone');
|
||||
});
|
||||
|
||||
it('should obey the dataset options', function() {
|
||||
@ -717,19 +717,19 @@ describe('Chart.controllers.line', function() {
|
||||
}
|
||||
});
|
||||
|
||||
var model = chart.getDatasetMeta(0).dataset._model;
|
||||
var options = chart.getDatasetMeta(0).dataset.options;
|
||||
|
||||
expect(model.spanGaps).toBe(true);
|
||||
expect(model.tension).toBe(0.231);
|
||||
expect(model.backgroundColor).toBe('#add');
|
||||
expect(model.borderWidth).toBe('#daa');
|
||||
expect(model.borderColor).toBe('#dad');
|
||||
expect(model.borderCapStyle).toBe('round');
|
||||
expect(model.borderDash).toEqual([0]);
|
||||
expect(model.borderDashOffset).toBe(0.871);
|
||||
expect(model.borderJoinStyle).toBe('miter');
|
||||
expect(model.fill).toBe('start');
|
||||
expect(model.cubicInterpolationMode).toBe('monotone');
|
||||
expect(options.spanGaps).toBe(true);
|
||||
expect(options.tension).toBe(0.231);
|
||||
expect(options.backgroundColor).toBe('#add');
|
||||
expect(options.borderWidth).toBe('#daa');
|
||||
expect(options.borderColor).toBe('#dad');
|
||||
expect(options.borderCapStyle).toBe('round');
|
||||
expect(options.borderDash).toEqual([0]);
|
||||
expect(options.borderDashOffset).toBe(0.871);
|
||||
expect(options.borderJoinStyle).toBe('miter');
|
||||
expect(options.fill).toBe('start');
|
||||
expect(options.cubicInterpolationMode).toBe('monotone');
|
||||
});
|
||||
|
||||
it('should handle number of data point changes in update', function() {
|
||||
@ -790,16 +790,16 @@ describe('Chart.controllers.line', function() {
|
||||
var point = chart.getDatasetMeta(0).data[0];
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mousemove', point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(49, 135, 221)');
|
||||
expect(point._model.borderColor).toBe('rgb(22, 89, 156)');
|
||||
expect(point._model.borderWidth).toBe(1);
|
||||
expect(point._model.radius).toBe(4);
|
||||
expect(point.options.backgroundColor).toBe('rgb(49, 135, 221)');
|
||||
expect(point.options.borderColor).toBe('rgb(22, 89, 156)');
|
||||
expect(point.options.borderWidth).toBe(1);
|
||||
expect(point.options.radius).toBe(4);
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mouseout', point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(point._model.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(point._model.borderWidth).toBe(2);
|
||||
expect(point._model.radius).toBe(3);
|
||||
expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(point.options.borderWidth).toBe(2);
|
||||
expect(point.options.radius).toBe(3);
|
||||
});
|
||||
|
||||
it ('should handle hover styles defined via dataset properties', function() {
|
||||
@ -816,16 +816,16 @@ describe('Chart.controllers.line', function() {
|
||||
chart.update();
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mousemove', point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(200, 100, 150)');
|
||||
expect(point._model.borderColor).toBe('rgb(150, 50, 100)');
|
||||
expect(point._model.borderWidth).toBe(8.4);
|
||||
expect(point._model.radius).toBe(4.2);
|
||||
expect(point.options.backgroundColor).toBe('rgb(200, 100, 150)');
|
||||
expect(point.options.borderColor).toBe('rgb(150, 50, 100)');
|
||||
expect(point.options.borderWidth).toBe(8.4);
|
||||
expect(point.options.radius).toBe(4.2);
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mouseout', point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(point._model.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(point._model.borderWidth).toBe(2);
|
||||
expect(point._model.radius).toBe(3);
|
||||
expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(point.options.borderWidth).toBe(2);
|
||||
expect(point.options.radius).toBe(3);
|
||||
});
|
||||
|
||||
it ('should handle hover styles defined via element options', function() {
|
||||
@ -842,16 +842,16 @@ describe('Chart.controllers.line', function() {
|
||||
chart.update();
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mousemove', point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(200, 100, 150)');
|
||||
expect(point._model.borderColor).toBe('rgb(150, 50, 100)');
|
||||
expect(point._model.borderWidth).toBe(8.4);
|
||||
expect(point._model.radius).toBe(4.2);
|
||||
expect(point.options.backgroundColor).toBe('rgb(200, 100, 150)');
|
||||
expect(point.options.borderColor).toBe('rgb(150, 50, 100)');
|
||||
expect(point.options.borderWidth).toBe(8.4);
|
||||
expect(point.options.radius).toBe(4.2);
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mouseout', point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(point._model.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(point._model.borderWidth).toBe(2);
|
||||
expect(point._model.radius).toBe(3);
|
||||
expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(point.options.borderWidth).toBe(2);
|
||||
expect(point.options.radius).toBe(3);
|
||||
});
|
||||
|
||||
it ('should handle dataset hover styles defined via dataset properties', function() {
|
||||
@ -872,14 +872,14 @@ describe('Chart.controllers.line', function() {
|
||||
chart.update();
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mousemove', point);
|
||||
expect(dataset._model.backgroundColor).toBe('#000');
|
||||
expect(dataset._model.borderColor).toBe('#111');
|
||||
expect(dataset._model.borderWidth).toBe(12);
|
||||
expect(dataset.options.backgroundColor).toBe('#000');
|
||||
expect(dataset.options.borderColor).toBe('#111');
|
||||
expect(dataset.options.borderWidth).toBe(12);
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mouseout', point);
|
||||
expect(dataset._model.backgroundColor).toBe('#AAA');
|
||||
expect(dataset._model.borderColor).toBe('#BBB');
|
||||
expect(dataset._model.borderWidth).toBe(6);
|
||||
expect(dataset.options.backgroundColor).toBe('#AAA');
|
||||
expect(dataset.options.borderColor).toBe('#BBB');
|
||||
expect(dataset.options.borderWidth).toBe(6);
|
||||
});
|
||||
});
|
||||
|
||||
@ -899,7 +899,7 @@ describe('Chart.controllers.line', function() {
|
||||
var meta = chart.getDatasetMeta(0);
|
||||
var point = meta.data[0];
|
||||
|
||||
expect(point._model.borderWidth).toBe(0);
|
||||
expect(point.options.borderWidth).toBe(0);
|
||||
});
|
||||
|
||||
it('should allow an array as the point border width setting', function() {
|
||||
@ -916,9 +916,9 @@ describe('Chart.controllers.line', function() {
|
||||
});
|
||||
|
||||
var meta = chart.getDatasetMeta(0);
|
||||
expect(meta.data[0]._model.borderWidth).toBe(1);
|
||||
expect(meta.data[1]._model.borderWidth).toBe(2);
|
||||
expect(meta.data[2]._model.borderWidth).toBe(3);
|
||||
expect(meta.data[3]._model.borderWidth).toBe(4);
|
||||
expect(meta.data[0].options.borderWidth).toBe(1);
|
||||
expect(meta.data[1].options.borderWidth).toBe(2);
|
||||
expect(meta.data[2].options.borderWidth).toBe(3);
|
||||
expect(meta.data[3].options.borderWidth).toBe(4);
|
||||
});
|
||||
});
|
||||
|
||||
@ -108,13 +108,13 @@ describe('Chart.controllers.polarArea', function() {
|
||||
{o: 51, s: 0.5 * Math.PI, e: Math.PI},
|
||||
{o: 0, s: Math.PI, e: 1.5 * Math.PI}
|
||||
].forEach(function(expected, i) {
|
||||
expect(meta.data[i]._model.x).toBeCloseToPixel(256);
|
||||
expect(meta.data[i]._model.y).toBeCloseToPixel(259);
|
||||
expect(meta.data[i]._model.innerRadius).toBeCloseToPixel(0);
|
||||
expect(meta.data[i]._model.outerRadius).toBeCloseToPixel(expected.o);
|
||||
expect(meta.data[i]._model.startAngle).toBe(expected.s);
|
||||
expect(meta.data[i]._model.endAngle).toBe(expected.e);
|
||||
expect(meta.data[i]._model).toEqual(jasmine.objectContaining({
|
||||
expect(meta.data[i].x).toBeCloseToPixel(256);
|
||||
expect(meta.data[i].y).toBeCloseToPixel(259);
|
||||
expect(meta.data[i].innerRadius).toBeCloseToPixel(0);
|
||||
expect(meta.data[i].outerRadius).toBeCloseToPixel(expected.o);
|
||||
expect(meta.data[i].startAngle).toBe(expected.s);
|
||||
expect(meta.data[i].endAngle).toBe(expected.e);
|
||||
expect(meta.data[i].options).toEqual(jasmine.objectContaining({
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderWidth: 1.2
|
||||
@ -129,17 +129,17 @@ describe('Chart.controllers.polarArea', function() {
|
||||
chart.update();
|
||||
|
||||
for (var i = 0; i < 4; ++i) {
|
||||
expect(meta.data[i]._model.backgroundColor).toBe('rgb(128, 129, 130)');
|
||||
expect(meta.data[i]._model.borderColor).toBe('rgb(56, 57, 58)');
|
||||
expect(meta.data[i]._model.borderWidth).toBe(1.123);
|
||||
expect(meta.data[i].options.backgroundColor).toBe('rgb(128, 129, 130)');
|
||||
expect(meta.data[i].options.borderColor).toBe('rgb(56, 57, 58)');
|
||||
expect(meta.data[i].options.borderWidth).toBe(1.123);
|
||||
}
|
||||
|
||||
chart.update();
|
||||
|
||||
expect(meta.data[0]._model.x).toBeCloseToPixel(256);
|
||||
expect(meta.data[0]._model.y).toBeCloseToPixel(259);
|
||||
expect(meta.data[0]._model.innerRadius).toBeCloseToPixel(0);
|
||||
expect(meta.data[0]._model.outerRadius).toBeCloseToPixel(177);
|
||||
expect(meta.data[0].x).toBeCloseToPixel(256);
|
||||
expect(meta.data[0].y).toBeCloseToPixel(259);
|
||||
expect(meta.data[0].innerRadius).toBeCloseToPixel(0);
|
||||
expect(meta.data[0].outerRadius).toBeCloseToPixel(177);
|
||||
});
|
||||
|
||||
it('should update elements with start angle from options', function() {
|
||||
@ -176,13 +176,13 @@ describe('Chart.controllers.polarArea', function() {
|
||||
{o: 51, s: Math.PI, e: 1.5 * Math.PI},
|
||||
{o: 0, s: 1.5 * Math.PI, e: 2.0 * Math.PI}
|
||||
].forEach(function(expected, i) {
|
||||
expect(meta.data[i]._model.x).toBeCloseToPixel(256);
|
||||
expect(meta.data[i]._model.y).toBeCloseToPixel(259);
|
||||
expect(meta.data[i]._model.innerRadius).toBeCloseToPixel(0);
|
||||
expect(meta.data[i]._model.outerRadius).toBeCloseToPixel(expected.o);
|
||||
expect(meta.data[i]._model.startAngle).toBe(expected.s);
|
||||
expect(meta.data[i]._model.endAngle).toBe(expected.e);
|
||||
expect(meta.data[i]._model).toEqual(jasmine.objectContaining({
|
||||
expect(meta.data[i].x).toBeCloseToPixel(256);
|
||||
expect(meta.data[i].y).toBeCloseToPixel(259);
|
||||
expect(meta.data[i].innerRadius).toBeCloseToPixel(0);
|
||||
expect(meta.data[i].outerRadius).toBeCloseToPixel(expected.o);
|
||||
expect(meta.data[i].startAngle).toBe(expected.s);
|
||||
expect(meta.data[i].endAngle).toBe(expected.e);
|
||||
expect(meta.data[i].options).toEqual(jasmine.objectContaining({
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderWidth: 1.2
|
||||
@ -265,14 +265,14 @@ describe('Chart.controllers.polarArea', function() {
|
||||
var arc = chart.getDatasetMeta(0).data[0];
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mousemove', arc);
|
||||
expect(arc._model.backgroundColor).toBe('rgb(49, 135, 221)');
|
||||
expect(arc._model.borderColor).toBe('rgb(22, 89, 156)');
|
||||
expect(arc._model.borderWidth).toBe(2);
|
||||
expect(arc.options.backgroundColor).toBe('rgb(49, 135, 221)');
|
||||
expect(arc.options.borderColor).toBe('rgb(22, 89, 156)');
|
||||
expect(arc.options.borderWidth).toBe(2);
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mouseout', arc);
|
||||
expect(arc._model.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(arc._model.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(arc._model.borderWidth).toBe(2);
|
||||
expect(arc.options.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(arc.options.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(arc.options.borderWidth).toBe(2);
|
||||
});
|
||||
|
||||
it ('should handle hover styles defined via dataset properties', function() {
|
||||
@ -288,14 +288,14 @@ describe('Chart.controllers.polarArea', function() {
|
||||
chart.update();
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mousemove', arc);
|
||||
expect(arc._model.backgroundColor).toBe('rgb(200, 100, 150)');
|
||||
expect(arc._model.borderColor).toBe('rgb(150, 50, 100)');
|
||||
expect(arc._model.borderWidth).toBe(8.4);
|
||||
expect(arc.options.backgroundColor).toBe('rgb(200, 100, 150)');
|
||||
expect(arc.options.borderColor).toBe('rgb(150, 50, 100)');
|
||||
expect(arc.options.borderWidth).toBe(8.4);
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mouseout', arc);
|
||||
expect(arc._model.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(arc._model.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(arc._model.borderWidth).toBe(2);
|
||||
expect(arc.options.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(arc.options.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(arc.options.borderWidth).toBe(2);
|
||||
});
|
||||
|
||||
it ('should handle hover styles defined via element options', function() {
|
||||
@ -311,14 +311,14 @@ describe('Chart.controllers.polarArea', function() {
|
||||
chart.update();
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mousemove', arc);
|
||||
expect(arc._model.backgroundColor).toBe('rgb(200, 100, 150)');
|
||||
expect(arc._model.borderColor).toBe('rgb(150, 50, 100)');
|
||||
expect(arc._model.borderWidth).toBe(8.4);
|
||||
expect(arc.options.backgroundColor).toBe('rgb(200, 100, 150)');
|
||||
expect(arc.options.borderColor).toBe('rgb(150, 50, 100)');
|
||||
expect(arc.options.borderWidth).toBe(8.4);
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mouseout', arc);
|
||||
expect(arc._model.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(arc._model.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(arc._model.borderWidth).toBe(2);
|
||||
expect(arc.options.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(arc.options.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(arc.options.borderWidth).toBe(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -118,7 +118,7 @@ describe('Chart.controllers.radar', function() {
|
||||
meta.controller.reset(); // reset first
|
||||
|
||||
// Line element
|
||||
expect(meta.dataset._model).toEqual(jasmine.objectContaining({
|
||||
expect(meta.dataset.options).toEqual(jasmine.objectContaining({
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderCapStyle: 'round',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
@ -136,20 +136,19 @@ describe('Chart.controllers.radar', function() {
|
||||
{x: 256, y: 260, cppx: 256, cppy: 260, cpnx: 256, cpny: 260},
|
||||
{x: 256, y: 260, cppx: 256, cppy: 260, cpnx: 256, cpny: 260},
|
||||
].forEach(function(expected, i) {
|
||||
expect(meta.data[i]._model.x).toBeCloseToPixel(expected.x);
|
||||
expect(meta.data[i]._model.y).toBeCloseToPixel(expected.y);
|
||||
expect(meta.data[i]._model.controlPointPreviousX).toBeCloseToPixel(expected.cppx);
|
||||
expect(meta.data[i]._model.controlPointPreviousY).toBeCloseToPixel(expected.cppy);
|
||||
expect(meta.data[i]._model.controlPointNextX).toBeCloseToPixel(expected.cpnx);
|
||||
expect(meta.data[i]._model.controlPointNextY).toBeCloseToPixel(expected.cpny);
|
||||
expect(meta.data[i]._model).toEqual(jasmine.objectContaining({
|
||||
expect(meta.data[i].x).toBeCloseToPixel(expected.x);
|
||||
expect(meta.data[i].y).toBeCloseToPixel(expected.y);
|
||||
expect(meta.data[i].controlPointPreviousX).toBeCloseToPixel(expected.cppx);
|
||||
expect(meta.data[i].controlPointPreviousY).toBeCloseToPixel(expected.cppy);
|
||||
expect(meta.data[i].controlPointNextX).toBeCloseToPixel(expected.cpnx);
|
||||
expect(meta.data[i].controlPointNextY).toBeCloseToPixel(expected.cpny);
|
||||
expect(meta.data[i].options).toEqual(jasmine.objectContaining({
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 1,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
radius: 3,
|
||||
pointStyle: 'circle',
|
||||
skip: false,
|
||||
}));
|
||||
});
|
||||
|
||||
@ -162,20 +161,19 @@ describe('Chart.controllers.radar', function() {
|
||||
{x: 256, y: 260, cppx: 277, cppy: 260, cpnx: 250, cpny: 260},
|
||||
{x: 200, y: 260, cppx: 200, cppy: 264, cpnx: 200, cpny: 250},
|
||||
].forEach(function(expected, i) {
|
||||
expect(meta.data[i]._model.x).toBeCloseToPixel(expected.x);
|
||||
expect(meta.data[i]._model.y).toBeCloseToPixel(expected.y);
|
||||
expect(meta.data[i]._model.controlPointPreviousX).toBeCloseToPixel(expected.cppx);
|
||||
expect(meta.data[i]._model.controlPointPreviousY).toBeCloseToPixel(expected.cppy);
|
||||
expect(meta.data[i]._model.controlPointNextX).toBeCloseToPixel(expected.cpnx);
|
||||
expect(meta.data[i]._model.controlPointNextY).toBeCloseToPixel(expected.cpny);
|
||||
expect(meta.data[i]._model).toEqual(jasmine.objectContaining({
|
||||
expect(meta.data[i].x).toBeCloseToPixel(expected.x);
|
||||
expect(meta.data[i].y).toBeCloseToPixel(expected.y);
|
||||
expect(meta.data[i].controlPointPreviousX).toBeCloseToPixel(expected.cppx);
|
||||
expect(meta.data[i].controlPointPreviousY).toBeCloseToPixel(expected.cppy);
|
||||
expect(meta.data[i].controlPointNextX).toBeCloseToPixel(expected.cpnx);
|
||||
expect(meta.data[i].controlPointNextY).toBeCloseToPixel(expected.cpny);
|
||||
expect(meta.data[i].options).toEqual(jasmine.objectContaining({
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 1,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
radius: 3,
|
||||
pointStyle: 'circle',
|
||||
skip: false,
|
||||
}));
|
||||
});
|
||||
|
||||
@ -199,7 +197,7 @@ describe('Chart.controllers.radar', function() {
|
||||
|
||||
meta.controller._update();
|
||||
|
||||
expect(meta.dataset._model).toEqual(jasmine.objectContaining({
|
||||
expect(meta.dataset.options).toEqual(jasmine.objectContaining({
|
||||
backgroundColor: 'rgb(98, 98, 98)',
|
||||
borderCapStyle: 'butt',
|
||||
borderColor: 'rgb(8, 8, 8)',
|
||||
@ -218,16 +216,15 @@ describe('Chart.controllers.radar', function() {
|
||||
{x: 256, y: 260},
|
||||
{x: 200, y: 260},
|
||||
].forEach(function(expected, i) {
|
||||
expect(meta.data[i]._model.x).toBeCloseToPixel(expected.x);
|
||||
expect(meta.data[i]._model.y).toBeCloseToPixel(expected.y);
|
||||
expect(meta.data[i]._model).toEqual(jasmine.objectContaining({
|
||||
expect(meta.data[i].x).toBeCloseToPixel(expected.x);
|
||||
expect(meta.data[i].y).toBeCloseToPixel(expected.y);
|
||||
expect(meta.data[i].options).toEqual(jasmine.objectContaining({
|
||||
backgroundColor: 'rgb(128, 129, 130)',
|
||||
borderWidth: 1.123,
|
||||
borderColor: 'rgb(56, 57, 58)',
|
||||
hitRadius: 3.3,
|
||||
radius: 22,
|
||||
pointStyle: 'circle',
|
||||
skip: false,
|
||||
pointStyle: 'circle'
|
||||
}));
|
||||
});
|
||||
});
|
||||
@ -260,16 +257,16 @@ describe('Chart.controllers.radar', function() {
|
||||
var point = chart.getDatasetMeta(0).data[0];
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mousemove', point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(49, 135, 221)');
|
||||
expect(point._model.borderColor).toBe('rgb(22, 89, 156)');
|
||||
expect(point._model.borderWidth).toBe(1);
|
||||
expect(point._model.radius).toBe(4);
|
||||
expect(point.options.backgroundColor).toBe('rgb(49, 135, 221)');
|
||||
expect(point.options.borderColor).toBe('rgb(22, 89, 156)');
|
||||
expect(point.options.borderWidth).toBe(1);
|
||||
expect(point.options.radius).toBe(4);
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mouseout', point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(point._model.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(point._model.borderWidth).toBe(2);
|
||||
expect(point._model.radius).toBe(3);
|
||||
expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(point.options.borderWidth).toBe(2);
|
||||
expect(point.options.radius).toBe(3);
|
||||
});
|
||||
|
||||
it ('should handle hover styles defined via dataset properties', function() {
|
||||
@ -286,16 +283,16 @@ describe('Chart.controllers.radar', function() {
|
||||
chart.update();
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mousemove', point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(200, 100, 150)');
|
||||
expect(point._model.borderColor).toBe('rgb(150, 50, 100)');
|
||||
expect(point._model.borderWidth).toBe(8.4);
|
||||
expect(point._model.radius).toBe(4.2);
|
||||
expect(point.options.backgroundColor).toBe('rgb(200, 100, 150)');
|
||||
expect(point.options.borderColor).toBe('rgb(150, 50, 100)');
|
||||
expect(point.options.borderWidth).toBe(8.4);
|
||||
expect(point.options.radius).toBe(4.2);
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mouseout', point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(point._model.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(point._model.borderWidth).toBe(2);
|
||||
expect(point._model.radius).toBe(3);
|
||||
expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(point.options.borderWidth).toBe(2);
|
||||
expect(point.options.radius).toBe(3);
|
||||
});
|
||||
|
||||
it ('should handle hover styles defined via element options', function() {
|
||||
@ -312,16 +309,16 @@ describe('Chart.controllers.radar', function() {
|
||||
chart.update();
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mousemove', point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(200, 100, 150)');
|
||||
expect(point._model.borderColor).toBe('rgb(150, 50, 100)');
|
||||
expect(point._model.borderWidth).toBe(8.4);
|
||||
expect(point._model.radius).toBe(4.2);
|
||||
expect(point.options.backgroundColor).toBe('rgb(200, 100, 150)');
|
||||
expect(point.options.borderColor).toBe('rgb(150, 50, 100)');
|
||||
expect(point.options.borderWidth).toBe(8.4);
|
||||
expect(point.options.radius).toBe(4.2);
|
||||
|
||||
jasmine.triggerMouseEvent(chart, 'mouseout', point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(point._model.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(point._model.borderWidth).toBe(2);
|
||||
expect(point._model.radius).toBe(3);
|
||||
expect(point.options.backgroundColor).toBe('rgb(100, 150, 200)');
|
||||
expect(point.options.borderColor).toBe('rgb(50, 100, 150)');
|
||||
expect(point.options.borderWidth).toBe(2);
|
||||
expect(point.options.radius).toBe(3);
|
||||
});
|
||||
});
|
||||
|
||||
@ -339,7 +336,7 @@ describe('Chart.controllers.radar', function() {
|
||||
|
||||
var meta = chart.getDatasetMeta(0);
|
||||
var point = meta.data[0];
|
||||
expect(point._model.borderWidth).toBe(0);
|
||||
expect(point.options.borderWidth).toBe(0);
|
||||
});
|
||||
|
||||
it('should use the pointRadius setting over the radius setting', function() {
|
||||
@ -360,8 +357,8 @@ describe('Chart.controllers.radar', function() {
|
||||
|
||||
var meta0 = chart.getDatasetMeta(0);
|
||||
var meta1 = chart.getDatasetMeta(1);
|
||||
expect(meta0.data[0]._model.radius).toBe(10);
|
||||
expect(meta1.data[0]._model.radius).toBe(20);
|
||||
expect(meta0.data[0].options.radius).toBe(10);
|
||||
expect(meta1.data[0].options.radius).toBe(20);
|
||||
});
|
||||
|
||||
it('should return id for value scale', function() {
|
||||
|
||||
@ -21,8 +21,8 @@ describe('Chart.controllers.scatter', function() {
|
||||
jasmine.triggerMouseEvent(chart, 'mousemove', point);
|
||||
|
||||
// Title should be empty
|
||||
expect(chart.tooltip._view.title.length).toBe(0);
|
||||
expect(chart.tooltip._view.body[0].lines).toEqual(['(10, 15)']);
|
||||
expect(chart.tooltip.title.length).toBe(0);
|
||||
expect(chart.tooltip.body[0].lines).toEqual(['(10, 15)']);
|
||||
});
|
||||
|
||||
describe('showLines option', function() {
|
||||
@ -66,7 +66,6 @@ describe('Chart', function() {
|
||||
var callback = function() {};
|
||||
var defaults = Chart.defaults;
|
||||
|
||||
defaults.global.responsiveAnimationDuration = 42;
|
||||
defaults.global.hover.onHover = callback;
|
||||
defaults.line.spanGaps = true;
|
||||
defaults.line.hover.mode = 'x-axis';
|
||||
@ -79,11 +78,9 @@ describe('Chart', function() {
|
||||
expect(options.defaultFontSize).toBe(defaults.global.defaultFontSize);
|
||||
expect(options.showLines).toBe(defaults.line.showLines);
|
||||
expect(options.spanGaps).toBe(true);
|
||||
expect(options.responsiveAnimationDuration).toBe(42);
|
||||
expect(options.hover.onHover).toBe(callback);
|
||||
expect(options.hover.mode).toBe('x-axis');
|
||||
|
||||
defaults.global.responsiveAnimationDuration = 0;
|
||||
defaults.global.hover.onHover = null;
|
||||
defaults.line.spanGaps = false;
|
||||
defaults.line.hover.mode = 'index';
|
||||
@ -93,7 +90,6 @@ describe('Chart', function() {
|
||||
var callback = function() {};
|
||||
var defaults = Chart.defaults;
|
||||
|
||||
defaults.global.responsiveAnimationDuration = 42;
|
||||
defaults.global.hover.onHover = callback;
|
||||
defaults.line.hover.mode = 'x-axis';
|
||||
defaults.line.spanGaps = true;
|
||||
@ -101,7 +97,6 @@ describe('Chart', function() {
|
||||
var chart = acquireChart({
|
||||
type: 'line',
|
||||
options: {
|
||||
responsiveAnimationDuration: 4242,
|
||||
spanGaps: false,
|
||||
hover: {
|
||||
mode: 'dataset',
|
||||
@ -113,13 +108,11 @@ describe('Chart', function() {
|
||||
});
|
||||
|
||||
var options = chart.options;
|
||||
expect(options.responsiveAnimationDuration).toBe(4242);
|
||||
expect(options.showLines).toBe(defaults.global.showLines);
|
||||
expect(options.spanGaps).toBe(false);
|
||||
expect(options.hover.mode).toBe('dataset');
|
||||
expect(options.title.position).toBe('bottom');
|
||||
|
||||
defaults.global.responsiveAnimationDuration = 0;
|
||||
defaults.global.hover.onHover = null;
|
||||
defaults.line.hover.mode = 'index';
|
||||
defaults.line.spanGaps = false;
|
||||
@ -950,18 +943,18 @@ describe('Chart', function() {
|
||||
|
||||
// Verify that points are at their initial correct location,
|
||||
// then we will reset and see that they moved
|
||||
expect(meta.data[0]._model.y).toBeCloseToPixel(333);
|
||||
expect(meta.data[1]._model.y).toBeCloseToPixel(183);
|
||||
expect(meta.data[2]._model.y).toBeCloseToPixel(32);
|
||||
expect(meta.data[3]._model.y).toBeCloseToPixel(482);
|
||||
expect(meta.data[0].y).toBeCloseToPixel(333);
|
||||
expect(meta.data[1].y).toBeCloseToPixel(183);
|
||||
expect(meta.data[2].y).toBeCloseToPixel(32);
|
||||
expect(meta.data[3].y).toBeCloseToPixel(482);
|
||||
|
||||
chart.reset();
|
||||
|
||||
// For a line chart, the animation state is the bottom
|
||||
expect(meta.data[0]._model.y).toBeCloseToPixel(482);
|
||||
expect(meta.data[1]._model.y).toBeCloseToPixel(482);
|
||||
expect(meta.data[2]._model.y).toBeCloseToPixel(482);
|
||||
expect(meta.data[3]._model.y).toBeCloseToPixel(482);
|
||||
expect(meta.data[0].y).toBeCloseToPixel(482);
|
||||
expect(meta.data[1].y).toBeCloseToPixel(482);
|
||||
expect(meta.data[2].y).toBeCloseToPixel(482);
|
||||
expect(meta.data[3].y).toBeCloseToPixel(482);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1106,7 +1099,7 @@ describe('Chart', function() {
|
||||
chart.options.tooltips = newTooltipConfig;
|
||||
|
||||
chart.update();
|
||||
expect(chart.tooltip._options).toEqual(jasmine.objectContaining(newTooltipConfig));
|
||||
expect(chart.tooltip.options).toEqual(jasmine.objectContaining(newTooltipConfig));
|
||||
});
|
||||
|
||||
it ('should update the tooltip on update', function() {
|
||||
@ -1283,46 +1276,4 @@ describe('Chart', function() {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('controller.update', function() {
|
||||
beforeEach(function() {
|
||||
this.chart = acquireChart({
|
||||
type: 'doughnut',
|
||||
options: {
|
||||
animation: {
|
||||
easing: 'linear',
|
||||
duration: 500
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.addAnimationSpy = spyOn(Chart.animationService, 'addAnimation');
|
||||
});
|
||||
|
||||
it('should add an animation with the default options', function() {
|
||||
this.chart.update();
|
||||
|
||||
expect(this.addAnimationSpy).toHaveBeenCalledWith(
|
||||
this.chart,
|
||||
jasmine.objectContaining({easing: 'linear'}),
|
||||
500,
|
||||
undefined
|
||||
);
|
||||
});
|
||||
|
||||
it('should add an animation with the provided options', function() {
|
||||
this.chart.update({
|
||||
duration: 800,
|
||||
easing: 'easeOutBounce',
|
||||
lazy: false,
|
||||
});
|
||||
|
||||
expect(this.addAnimationSpy).toHaveBeenCalledWith(
|
||||
this.chart,
|
||||
jasmine.objectContaining({easing: 'easeOutBounce'}),
|
||||
800,
|
||||
false
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,51 +0,0 @@
|
||||
// Test the core element functionality
|
||||
describe('Core element tests', function() {
|
||||
it ('should transition model properties', function() {
|
||||
var element = new Chart.Element({
|
||||
_model: {
|
||||
numberProp: 0,
|
||||
numberProp2: 100,
|
||||
_underscoreProp: 0,
|
||||
stringProp: 'abc',
|
||||
objectProp: {
|
||||
myObject: true
|
||||
},
|
||||
colorProp: 'rgb(0, 0, 0)'
|
||||
}
|
||||
});
|
||||
|
||||
// First transition clones model into view
|
||||
element.transition(0.25);
|
||||
|
||||
expect(element._view).toEqual(element._model);
|
||||
expect(element._view).not.toBe(element._model);
|
||||
expect(element._view.objectProp).toBe(element._model.objectProp); // not cloned
|
||||
|
||||
element._model.numberProp = 100;
|
||||
element._model.numberProp2 = 250;
|
||||
element._model._underscoreProp = 200;
|
||||
element._model.stringProp = 'def';
|
||||
element._model.newStringProp = 'newString';
|
||||
element._model.colorProp = 'rgb(255, 255, 0)';
|
||||
|
||||
element.transition(0.25);
|
||||
|
||||
expect(element._view).toEqual({
|
||||
numberProp: 25,
|
||||
numberProp2: 137.5,
|
||||
_underscoreProp: 0, // underscore props are not transition to a new value
|
||||
stringProp: 'def',
|
||||
newStringProp: 'newString',
|
||||
objectProp: {
|
||||
myObject: true
|
||||
},
|
||||
colorProp: 'rgb(64, 64, 0)',
|
||||
});
|
||||
|
||||
// Final transition clones model into view
|
||||
element.transition(1);
|
||||
|
||||
expect(element._view).toEqual(element._model);
|
||||
expect(element._view).not.toBe(element._model);
|
||||
});
|
||||
});
|
||||
@ -33,8 +33,8 @@ describe('Core.Interaction', function() {
|
||||
type: 'click',
|
||||
chart: chart,
|
||||
native: true, // needed otherwise things its a DOM event
|
||||
x: point._model.x,
|
||||
y: point._model.y,
|
||||
x: point.x,
|
||||
y: point.y,
|
||||
};
|
||||
|
||||
var elements = Chart.Interaction.modes.point(chart, evt, {}).map(item => item.element);
|
||||
@ -88,8 +88,8 @@ describe('Core.Interaction', function() {
|
||||
type: 'click',
|
||||
chart: chart,
|
||||
native: true, // needed otherwise things its a DOM event
|
||||
x: point._model.x,
|
||||
y: point._model.y,
|
||||
x: point.x,
|
||||
y: point.y,
|
||||
};
|
||||
|
||||
var elements = Chart.Interaction.modes.index(chart, evt, {intersect: true}).map(item => item.element);
|
||||
@ -223,8 +223,8 @@ describe('Core.Interaction', function() {
|
||||
type: 'click',
|
||||
chart: chart,
|
||||
native: true, // needed otherwise things its a DOM event
|
||||
x: point._model.x,
|
||||
y: point._model.y
|
||||
x: point.x,
|
||||
y: point.y
|
||||
};
|
||||
|
||||
var elements = Chart.Interaction.modes.dataset(chart, evt, {intersect: true});
|
||||
@ -365,8 +365,8 @@ describe('Core.Interaction', function() {
|
||||
|
||||
// Halfway between 2 mid points
|
||||
var pt = {
|
||||
x: meta0.data[1]._view.x,
|
||||
y: (meta0.data[1]._view.y + meta1.data[1]._view.y) / 2
|
||||
x: meta0.data[1].x,
|
||||
y: (meta0.data[1].y + meta1.data[1].y) / 2
|
||||
};
|
||||
|
||||
var evt = {
|
||||
@ -391,8 +391,8 @@ describe('Core.Interaction', function() {
|
||||
|
||||
// At 'Point 2', 10
|
||||
var pt = {
|
||||
x: meta0.data[1]._view.x,
|
||||
y: meta0.data[0]._view.y
|
||||
x: meta0.data[1].x,
|
||||
y: meta0.data[0].y
|
||||
};
|
||||
|
||||
var evt = {
|
||||
@ -415,8 +415,8 @@ describe('Core.Interaction', function() {
|
||||
|
||||
// Haflway between 'Point 1' and 'Point 2', y=10
|
||||
var pt = {
|
||||
x: (meta0.data[0]._view.x + meta0.data[1]._view.x) / 2,
|
||||
y: meta0.data[0]._view.y
|
||||
x: (meta0.data[0].x + meta0.data[1].x) / 2,
|
||||
y: meta0.data[0].y
|
||||
};
|
||||
|
||||
var evt = {
|
||||
@ -440,8 +440,8 @@ describe('Core.Interaction', function() {
|
||||
|
||||
// 'Point 1', y = 30
|
||||
var pt = {
|
||||
x: meta0.data[0]._view.x,
|
||||
y: meta0.data[2]._view.y
|
||||
x: meta0.data[0].x,
|
||||
y: meta0.data[2].y
|
||||
};
|
||||
|
||||
var evt = {
|
||||
@ -464,8 +464,8 @@ describe('Core.Interaction', function() {
|
||||
|
||||
// 'Point 1', y = 40
|
||||
var pt = {
|
||||
x: meta0.data[0]._view.x,
|
||||
y: meta0.data[1]._view.y
|
||||
x: meta0.data[0].x,
|
||||
y: meta0.data[1].y
|
||||
};
|
||||
|
||||
var evt = {
|
||||
@ -514,8 +514,8 @@ describe('Core.Interaction', function() {
|
||||
type: 'click',
|
||||
chart: chart,
|
||||
native: true, // needed otherwise things its a DOM event
|
||||
x: point._view.x + 15,
|
||||
y: point._view.y
|
||||
x: point.x + 15,
|
||||
y: point.y
|
||||
};
|
||||
|
||||
// Nothing intersects so find nothing
|
||||
@ -526,8 +526,8 @@ describe('Core.Interaction', function() {
|
||||
type: 'click',
|
||||
chart: chart,
|
||||
native: true,
|
||||
x: point._view.x,
|
||||
y: point._view.y
|
||||
x: point.x,
|
||||
y: point.y
|
||||
};
|
||||
elements = Chart.Interaction.modes.nearest(chart, evt, {intersect: true}).map(item => item.element);
|
||||
expect(elements).toEqual([point]);
|
||||
@ -547,8 +547,8 @@ describe('Core.Interaction', function() {
|
||||
|
||||
// Halfway between 2 mid points
|
||||
var pt = {
|
||||
x: meta0.data[1]._view.x,
|
||||
y: meta0.data[1]._view.y
|
||||
x: meta0.data[1].x,
|
||||
y: meta0.data[1].y
|
||||
};
|
||||
|
||||
var evt = {
|
||||
@ -577,8 +577,8 @@ describe('Core.Interaction', function() {
|
||||
|
||||
// Halfway between 2 mid points
|
||||
var pt = {
|
||||
x: meta0.data[1]._view.x,
|
||||
y: meta0.data[1]._view.y
|
||||
x: meta0.data[1].x,
|
||||
y: meta0.data[1].y
|
||||
};
|
||||
|
||||
var evt = {
|
||||
@ -626,8 +626,8 @@ describe('Core.Interaction', function() {
|
||||
|
||||
// Halfway between 2 mid points
|
||||
var pt = {
|
||||
x: meta0.data[1]._view.x,
|
||||
y: meta0.data[1]._view.y
|
||||
x: meta0.data[1].x,
|
||||
y: meta0.data[1].y
|
||||
};
|
||||
|
||||
var evt = {
|
||||
@ -660,8 +660,8 @@ describe('Core.Interaction', function() {
|
||||
|
||||
// Halfway between 2 mid points
|
||||
var pt = {
|
||||
x: meta0.data[1]._view.x,
|
||||
y: meta0.data[1]._view.y
|
||||
x: meta0.data[1].x,
|
||||
y: meta0.data[1].y
|
||||
};
|
||||
|
||||
var evt = {
|
||||
@ -718,8 +718,8 @@ describe('Core.Interaction', function() {
|
||||
|
||||
// Halfway between 2 mid points
|
||||
var pt = {
|
||||
x: meta0.data[1]._view.x,
|
||||
y: meta0.data[1]._view.y
|
||||
x: meta0.data[1].x,
|
||||
y: meta0.data[1].y
|
||||
};
|
||||
|
||||
var evt = {
|
||||
@ -752,8 +752,8 @@ describe('Core.Interaction', function() {
|
||||
|
||||
// Halfway between 2 mid points
|
||||
var pt = {
|
||||
x: meta0.data[1]._view.x,
|
||||
y: meta0.data[1]._view.y
|
||||
x: meta0.data[1].x,
|
||||
y: meta0.data[1].y
|
||||
};
|
||||
|
||||
var evt = {
|
||||
|
||||
@ -69,7 +69,7 @@ describe('Core.Tooltip', function() {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
clientX: rect.left + point._model.x,
|
||||
clientX: rect.left + point.x,
|
||||
clientY: 0
|
||||
});
|
||||
|
||||
@ -80,46 +80,55 @@ describe('Core.Tooltip', function() {
|
||||
var tooltip = chart.tooltip;
|
||||
var globalDefaults = Chart.defaults.global;
|
||||
|
||||
expect(tooltip._view).toEqual(jasmine.objectContaining({
|
||||
// Positioning
|
||||
xPadding: 6,
|
||||
yPadding: 6,
|
||||
xAlign: 'left',
|
||||
yAlign: 'center',
|
||||
expect(tooltip.options.xPadding).toEqual(6);
|
||||
expect(tooltip.options.yPadding).toEqual(6);
|
||||
expect(tooltip.xAlign).toEqual('left');
|
||||
expect(tooltip.yAlign).toEqual('center');
|
||||
|
||||
expect(tooltip.options).toEqual(jasmine.objectContaining({
|
||||
// Body
|
||||
bodyFontColor: '#fff',
|
||||
_bodyFontFamily: globalDefaults.defaultFontFamily,
|
||||
_bodyFontStyle: globalDefaults.defaultFontStyle,
|
||||
_bodyAlign: 'left',
|
||||
bodyFontFamily: globalDefaults.defaultFontFamily,
|
||||
bodyFontStyle: globalDefaults.defaultFontStyle,
|
||||
bodyAlign: 'left',
|
||||
bodyFontSize: globalDefaults.defaultFontSize,
|
||||
bodySpacing: 2,
|
||||
}));
|
||||
|
||||
expect(tooltip.options).toEqual(jasmine.objectContaining({
|
||||
// Title
|
||||
titleFontColor: '#fff',
|
||||
_titleFontFamily: globalDefaults.defaultFontFamily,
|
||||
_titleFontStyle: 'bold',
|
||||
titleFontFamily: globalDefaults.defaultFontFamily,
|
||||
titleFontStyle: 'bold',
|
||||
titleFontSize: globalDefaults.defaultFontSize,
|
||||
_titleAlign: 'left',
|
||||
titleAlign: 'left',
|
||||
titleSpacing: 2,
|
||||
titleMarginBottom: 6,
|
||||
}));
|
||||
|
||||
expect(tooltip.options).toEqual(jasmine.objectContaining({
|
||||
// Footer
|
||||
footerFontColor: '#fff',
|
||||
_footerFontFamily: globalDefaults.defaultFontFamily,
|
||||
_footerFontStyle: 'bold',
|
||||
footerFontFamily: globalDefaults.defaultFontFamily,
|
||||
footerFontStyle: 'bold',
|
||||
footerFontSize: globalDefaults.defaultFontSize,
|
||||
_footerAlign: 'left',
|
||||
footerAlign: 'left',
|
||||
footerSpacing: 2,
|
||||
footerMarginTop: 6,
|
||||
}));
|
||||
|
||||
expect(tooltip.options).toEqual(jasmine.objectContaining({
|
||||
// Appearance
|
||||
caretSize: 5,
|
||||
caretPadding: 2,
|
||||
cornerRadius: 6,
|
||||
backgroundColor: 'rgba(0,0,0,0.8)',
|
||||
multiKeyBackground: '#fff',
|
||||
displayColors: true
|
||||
}));
|
||||
|
||||
expect(tooltip).toEqual(jasmine.objectContaining({
|
||||
opacity: 1,
|
||||
legendColorBackground: '#fff',
|
||||
displayColors: true,
|
||||
|
||||
// Text
|
||||
title: ['Point 2'],
|
||||
@ -135,7 +144,6 @@ describe('Core.Tooltip', function() {
|
||||
}],
|
||||
afterBody: [],
|
||||
footer: [],
|
||||
caretPadding: 2,
|
||||
labelColors: [{
|
||||
borderColor: globalDefaults.defaultColor,
|
||||
backgroundColor: globalDefaults.defaultColor
|
||||
@ -145,8 +153,8 @@ describe('Core.Tooltip', function() {
|
||||
}]
|
||||
}));
|
||||
|
||||
expect(tooltip._view.x).toBeCloseToPixel(267);
|
||||
expect(tooltip._view.y).toBeCloseToPixel(155);
|
||||
expect(tooltip.x).toBeCloseToPixel(267);
|
||||
expect(tooltip.y).toBeCloseToPixel(155);
|
||||
});
|
||||
|
||||
it('Should only display if intersecting if intersect is set', function() {
|
||||
@ -185,7 +193,7 @@ describe('Core.Tooltip', function() {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
clientX: rect.left + point._model.x,
|
||||
clientX: rect.left + point.x,
|
||||
clientY: 0
|
||||
});
|
||||
|
||||
@ -194,46 +202,9 @@ describe('Core.Tooltip', function() {
|
||||
|
||||
// Check and see if tooltip was displayed
|
||||
var tooltip = chart.tooltip;
|
||||
var globalDefaults = Chart.defaults.global;
|
||||
|
||||
expect(tooltip._view).toEqual(jasmine.objectContaining({
|
||||
// Positioning
|
||||
xPadding: 6,
|
||||
yPadding: 6,
|
||||
|
||||
// Body
|
||||
bodyFontColor: '#fff',
|
||||
_bodyFontFamily: globalDefaults.defaultFontFamily,
|
||||
_bodyFontStyle: globalDefaults.defaultFontStyle,
|
||||
_bodyAlign: 'left',
|
||||
bodyFontSize: globalDefaults.defaultFontSize,
|
||||
bodySpacing: 2,
|
||||
|
||||
// Title
|
||||
titleFontColor: '#fff',
|
||||
_titleFontFamily: globalDefaults.defaultFontFamily,
|
||||
_titleFontStyle: 'bold',
|
||||
titleFontSize: globalDefaults.defaultFontSize,
|
||||
_titleAlign: 'left',
|
||||
titleSpacing: 2,
|
||||
titleMarginBottom: 6,
|
||||
|
||||
// Footer
|
||||
footerFontColor: '#fff',
|
||||
_footerFontFamily: globalDefaults.defaultFontFamily,
|
||||
_footerFontStyle: 'bold',
|
||||
footerFontSize: globalDefaults.defaultFontSize,
|
||||
_footerAlign: 'left',
|
||||
footerSpacing: 2,
|
||||
footerMarginTop: 6,
|
||||
|
||||
// Appearance
|
||||
caretSize: 5,
|
||||
cornerRadius: 6,
|
||||
backgroundColor: 'rgba(0,0,0,0.8)',
|
||||
expect(tooltip).toEqual(jasmine.objectContaining({
|
||||
opacity: 0,
|
||||
legendColorBackground: '#fff',
|
||||
displayColors: true,
|
||||
}));
|
||||
});
|
||||
});
|
||||
@ -274,8 +245,8 @@ describe('Core.Tooltip', function() {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
clientX: rect.left + point._model.x,
|
||||
clientY: rect.top + point._model.y
|
||||
clientX: rect.left + point.x,
|
||||
clientY: rect.top + point.y
|
||||
});
|
||||
|
||||
// Manually trigger rather than having an async test
|
||||
@ -285,46 +256,55 @@ describe('Core.Tooltip', function() {
|
||||
var tooltip = chart.tooltip;
|
||||
var globalDefaults = Chart.defaults.global;
|
||||
|
||||
expect(tooltip._view).toEqual(jasmine.objectContaining({
|
||||
// Positioning
|
||||
xPadding: 6,
|
||||
yPadding: 6,
|
||||
xAlign: 'left',
|
||||
yAlign: 'center',
|
||||
expect(tooltip.options.xPadding).toEqual(6);
|
||||
expect(tooltip.options.yPadding).toEqual(6);
|
||||
expect(tooltip.xAlign).toEqual('left');
|
||||
expect(tooltip.yAlign).toEqual('center');
|
||||
|
||||
expect(tooltip.options).toEqual(jasmine.objectContaining({
|
||||
// Body
|
||||
bodyFontColor: '#fff',
|
||||
_bodyFontFamily: globalDefaults.defaultFontFamily,
|
||||
_bodyFontStyle: globalDefaults.defaultFontStyle,
|
||||
_bodyAlign: 'left',
|
||||
bodyFontFamily: globalDefaults.defaultFontFamily,
|
||||
bodyFontStyle: globalDefaults.defaultFontStyle,
|
||||
bodyAlign: 'left',
|
||||
bodyFontSize: globalDefaults.defaultFontSize,
|
||||
bodySpacing: 2,
|
||||
}));
|
||||
|
||||
expect(tooltip.options).toEqual(jasmine.objectContaining({
|
||||
// Title
|
||||
titleFontColor: '#fff',
|
||||
_titleFontFamily: globalDefaults.defaultFontFamily,
|
||||
_titleFontStyle: 'bold',
|
||||
titleFontFamily: globalDefaults.defaultFontFamily,
|
||||
titleFontStyle: 'bold',
|
||||
titleFontSize: globalDefaults.defaultFontSize,
|
||||
_titleAlign: 'left',
|
||||
titleAlign: 'left',
|
||||
titleSpacing: 2,
|
||||
titleMarginBottom: 6,
|
||||
}));
|
||||
|
||||
expect(tooltip.options).toEqual(jasmine.objectContaining({
|
||||
// Footer
|
||||
footerFontColor: '#fff',
|
||||
_footerFontFamily: globalDefaults.defaultFontFamily,
|
||||
_footerFontStyle: 'bold',
|
||||
footerFontFamily: globalDefaults.defaultFontFamily,
|
||||
footerFontStyle: 'bold',
|
||||
footerFontSize: globalDefaults.defaultFontSize,
|
||||
_footerAlign: 'left',
|
||||
footerAlign: 'left',
|
||||
footerSpacing: 2,
|
||||
footerMarginTop: 6,
|
||||
}));
|
||||
|
||||
expect(tooltip.options).toEqual(jasmine.objectContaining({
|
||||
// Appearance
|
||||
caretSize: 5,
|
||||
caretPadding: 2,
|
||||
cornerRadius: 6,
|
||||
backgroundColor: 'rgba(0,0,0,0.8)',
|
||||
multiKeyBackground: '#fff',
|
||||
displayColors: true
|
||||
}));
|
||||
|
||||
expect(tooltip).toEqual(jasmine.objectContaining({
|
||||
opacity: 1,
|
||||
legendColorBackground: '#fff',
|
||||
displayColors: true,
|
||||
|
||||
// Text
|
||||
title: ['Point 2'],
|
||||
@ -336,7 +316,6 @@ describe('Core.Tooltip', function() {
|
||||
}],
|
||||
afterBody: [],
|
||||
footer: [],
|
||||
caretPadding: 2,
|
||||
labelTextColors: ['#fff'],
|
||||
labelColors: [{
|
||||
borderColor: globalDefaults.defaultColor,
|
||||
@ -344,8 +323,8 @@ describe('Core.Tooltip', function() {
|
||||
}]
|
||||
}));
|
||||
|
||||
expect(tooltip._view.x).toBeCloseToPixel(267);
|
||||
expect(tooltip._view.y).toBeCloseToPixel(312);
|
||||
expect(tooltip.x).toBeCloseToPixel(267);
|
||||
expect(tooltip.y).toBeCloseToPixel(312);
|
||||
});
|
||||
|
||||
it('Should display information from user callbacks', function() {
|
||||
@ -421,8 +400,8 @@ describe('Core.Tooltip', function() {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
clientX: rect.left + point._model.x,
|
||||
clientY: rect.top + point._model.y
|
||||
clientX: rect.left + point.x,
|
||||
clientY: rect.top + point.y
|
||||
});
|
||||
|
||||
// Manually trigger rather than having an async test
|
||||
@ -432,45 +411,54 @@ describe('Core.Tooltip', function() {
|
||||
var tooltip = chart.tooltip;
|
||||
var globalDefaults = Chart.defaults.global;
|
||||
|
||||
expect(tooltip._view).toEqual(jasmine.objectContaining({
|
||||
// Positioning
|
||||
xPadding: 6,
|
||||
yPadding: 6,
|
||||
xAlign: 'center',
|
||||
yAlign: 'top',
|
||||
expect(tooltip.options.xPadding).toEqual(6);
|
||||
expect(tooltip.options.yPadding).toEqual(6);
|
||||
expect(tooltip.xAlign).toEqual('center');
|
||||
expect(tooltip.yAlign).toEqual('top');
|
||||
|
||||
expect(tooltip.options).toEqual(jasmine.objectContaining({
|
||||
// Body
|
||||
bodyFontColor: '#fff',
|
||||
_bodyFontFamily: globalDefaults.defaultFontFamily,
|
||||
_bodyFontStyle: globalDefaults.defaultFontStyle,
|
||||
_bodyAlign: 'left',
|
||||
bodyFontFamily: globalDefaults.defaultFontFamily,
|
||||
bodyFontStyle: globalDefaults.defaultFontStyle,
|
||||
bodyAlign: 'left',
|
||||
bodyFontSize: globalDefaults.defaultFontSize,
|
||||
bodySpacing: 2,
|
||||
}));
|
||||
|
||||
expect(tooltip.options).toEqual(jasmine.objectContaining({
|
||||
// Title
|
||||
titleFontColor: '#fff',
|
||||
_titleFontFamily: globalDefaults.defaultFontFamily,
|
||||
_titleFontStyle: 'bold',
|
||||
titleFontFamily: globalDefaults.defaultFontFamily,
|
||||
titleFontStyle: 'bold',
|
||||
titleFontSize: globalDefaults.defaultFontSize,
|
||||
_titleAlign: 'left',
|
||||
titleAlign: 'left',
|
||||
titleSpacing: 2,
|
||||
titleMarginBottom: 6,
|
||||
}));
|
||||
|
||||
expect(tooltip.options).toEqual(jasmine.objectContaining({
|
||||
// Footer
|
||||
footerFontColor: '#fff',
|
||||
_footerFontFamily: globalDefaults.defaultFontFamily,
|
||||
_footerFontStyle: 'bold',
|
||||
footerFontFamily: globalDefaults.defaultFontFamily,
|
||||
footerFontStyle: 'bold',
|
||||
footerFontSize: globalDefaults.defaultFontSize,
|
||||
_footerAlign: 'left',
|
||||
footerAlign: 'left',
|
||||
footerSpacing: 2,
|
||||
footerMarginTop: 6,
|
||||
}));
|
||||
|
||||
expect(tooltip.options).toEqual(jasmine.objectContaining({
|
||||
// Appearance
|
||||
caretSize: 5,
|
||||
caretPadding: 2,
|
||||
cornerRadius: 6,
|
||||
backgroundColor: 'rgba(0,0,0,0.8)',
|
||||
multiKeyBackground: '#fff',
|
||||
}));
|
||||
|
||||
expect(tooltip).toEqual(jasmine.objectContaining({
|
||||
opacity: 1,
|
||||
legendColorBackground: '#fff',
|
||||
|
||||
// Text
|
||||
title: ['beforeTitle', 'title', 'afterTitle'],
|
||||
@ -486,7 +474,6 @@ describe('Core.Tooltip', function() {
|
||||
}],
|
||||
afterBody: ['afterBody'],
|
||||
footer: ['beforeFooter', 'footer', 'afterFooter'],
|
||||
caretPadding: 2,
|
||||
labelTextColors: ['labelTextColor', 'labelTextColor'],
|
||||
labelColors: [{
|
||||
borderColor: globalDefaults.defaultColor,
|
||||
@ -497,8 +484,8 @@ describe('Core.Tooltip', function() {
|
||||
}]
|
||||
}));
|
||||
|
||||
expect(tooltip._view.x).toBeCloseToPixel(214);
|
||||
expect(tooltip._view.y).toBeCloseToPixel(190);
|
||||
expect(tooltip.x).toBeCloseToPixel(214);
|
||||
expect(tooltip.y).toBeCloseToPixel(190);
|
||||
});
|
||||
|
||||
it('Should allow sorting items', function() {
|
||||
@ -539,8 +526,8 @@ describe('Core.Tooltip', function() {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
clientX: rect.left + point0._model.x,
|
||||
clientY: rect.top + point0._model.y
|
||||
clientX: rect.left + point0.x,
|
||||
clientY: rect.top + point0.y
|
||||
});
|
||||
|
||||
// Manually trigger rather than having an async test
|
||||
@ -550,7 +537,7 @@ describe('Core.Tooltip', function() {
|
||||
var tooltip = chart.tooltip;
|
||||
var globalDefaults = Chart.defaults.global;
|
||||
|
||||
expect(tooltip._view).toEqual(jasmine.objectContaining({
|
||||
expect(tooltip).toEqual(jasmine.objectContaining({
|
||||
// Positioning
|
||||
xAlign: 'left',
|
||||
yAlign: 'center',
|
||||
@ -578,8 +565,8 @@ describe('Core.Tooltip', function() {
|
||||
}]
|
||||
}));
|
||||
|
||||
expect(tooltip._view.x).toBeCloseToPixel(267);
|
||||
expect(tooltip._view.y).toBeCloseToPixel(155);
|
||||
expect(tooltip.x).toBeCloseToPixel(267);
|
||||
expect(tooltip.y).toBeCloseToPixel(155);
|
||||
});
|
||||
|
||||
it('Should allow reversing items', function() {
|
||||
@ -618,8 +605,8 @@ describe('Core.Tooltip', function() {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
clientX: rect.left + point0._model.x,
|
||||
clientY: rect.top + point0._model.y
|
||||
clientX: rect.left + point0.x,
|
||||
clientY: rect.top + point0.y
|
||||
});
|
||||
|
||||
// Manually trigger rather than having an async test
|
||||
@ -629,7 +616,7 @@ describe('Core.Tooltip', function() {
|
||||
var tooltip = chart.tooltip;
|
||||
var globalDefaults = Chart.defaults.global;
|
||||
|
||||
expect(tooltip._view).toEqual(jasmine.objectContaining({
|
||||
expect(tooltip).toEqual(jasmine.objectContaining({
|
||||
// Positioning
|
||||
xAlign: 'left',
|
||||
yAlign: 'center',
|
||||
@ -657,8 +644,8 @@ describe('Core.Tooltip', function() {
|
||||
}]
|
||||
}));
|
||||
|
||||
expect(tooltip._view.x).toBeCloseToPixel(267);
|
||||
expect(tooltip._view.y).toBeCloseToPixel(155);
|
||||
expect(tooltip.x).toBeCloseToPixel(267);
|
||||
expect(tooltip.y).toBeCloseToPixel(155);
|
||||
});
|
||||
|
||||
it('Should follow dataset order', function() {
|
||||
@ -698,8 +685,8 @@ describe('Core.Tooltip', function() {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
clientX: rect.left + point0._model.x,
|
||||
clientY: rect.top + point0._model.y
|
||||
clientX: rect.left + point0.x,
|
||||
clientY: rect.top + point0.y
|
||||
});
|
||||
|
||||
// Manually trigger rather than having an async test
|
||||
@ -709,7 +696,7 @@ describe('Core.Tooltip', function() {
|
||||
var tooltip = chart.tooltip;
|
||||
var globalDefaults = Chart.defaults.global;
|
||||
|
||||
expect(tooltip._view).toEqual(jasmine.objectContaining({
|
||||
expect(tooltip).toEqual(jasmine.objectContaining({
|
||||
// Positioning
|
||||
xAlign: 'left',
|
||||
yAlign: 'center',
|
||||
@ -737,8 +724,8 @@ describe('Core.Tooltip', function() {
|
||||
}]
|
||||
}));
|
||||
|
||||
expect(tooltip._view.x).toBeCloseToPixel(267);
|
||||
expect(tooltip._view.y).toBeCloseToPixel(155);
|
||||
expect(tooltip.x).toBeCloseToPixel(267);
|
||||
expect(tooltip.y).toBeCloseToPixel(155);
|
||||
});
|
||||
|
||||
it('should filter items from the tooltip using the callback', function() {
|
||||
@ -781,8 +768,8 @@ describe('Core.Tooltip', function() {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
clientX: rect.left + point0._model.x,
|
||||
clientY: rect.top + point0._model.y
|
||||
clientX: rect.left + point0.x,
|
||||
clientY: rect.top + point0.y
|
||||
});
|
||||
|
||||
// Manually trigger rather than having an async test
|
||||
@ -792,7 +779,7 @@ describe('Core.Tooltip', function() {
|
||||
var tooltip = chart.tooltip;
|
||||
var globalDefaults = Chart.defaults.global;
|
||||
|
||||
expect(tooltip._view).toEqual(jasmine.objectContaining({
|
||||
expect(tooltip).toEqual(jasmine.objectContaining({
|
||||
// Positioning
|
||||
xAlign: 'left',
|
||||
yAlign: 'center',
|
||||
@ -850,8 +837,8 @@ describe('Core.Tooltip', function() {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
clientX: rect.left + point0._model.x,
|
||||
clientY: rect.top + point0._model.y
|
||||
clientX: rect.left + point0.x,
|
||||
clientY: rect.top + point0.y
|
||||
});
|
||||
|
||||
// Manually trigger rather than having an async test
|
||||
@ -860,7 +847,7 @@ describe('Core.Tooltip', function() {
|
||||
// Check and see if tooltip was displayed
|
||||
var tooltip = chart.tooltip;
|
||||
|
||||
expect(tooltip._model).toEqual(jasmine.objectContaining({
|
||||
expect(tooltip.options).toEqual(jasmine.objectContaining({
|
||||
// Positioning
|
||||
caretPadding: 10,
|
||||
}));
|
||||
@ -901,11 +888,11 @@ describe('Core.Tooltip', function() {
|
||||
// Check and see if tooltip was displayed
|
||||
var tooltip = chart.tooltip;
|
||||
|
||||
expect(tooltip._view instanceof Object).toBe(true);
|
||||
expect(tooltip._view.dataPoints instanceof Array).toBe(true);
|
||||
expect(tooltip._view.dataPoints.length).toBe(1);
|
||||
expect(tooltip instanceof Object).toBe(true);
|
||||
expect(tooltip.dataPoints instanceof Array).toBe(true);
|
||||
expect(tooltip.dataPoints.length).toBe(1);
|
||||
|
||||
var tooltipItem = tooltip._view.dataPoints[0];
|
||||
var tooltipItem = tooltip.dataPoints[0];
|
||||
|
||||
expect(tooltipItem.index).toBe(pointIndex);
|
||||
expect(tooltipItem.datasetIndex).toBe(datasetIndex);
|
||||
@ -957,8 +944,8 @@ describe('Core.Tooltip', function() {
|
||||
view: window,
|
||||
bubbles: false,
|
||||
cancelable: true,
|
||||
clientX: rect.left + firstPoint._model.x,
|
||||
clientY: rect.top + firstPoint._model.y
|
||||
clientX: rect.left + firstPoint.x,
|
||||
clientY: rect.top + firstPoint.y
|
||||
});
|
||||
|
||||
var tooltip = chart.tooltip;
|
||||
@ -1022,8 +1009,8 @@ describe('Core.Tooltip', function() {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
clientX: rect.left + point._model.x,
|
||||
clientY: rect.top + point._model.y
|
||||
clientX: rect.left + point.x,
|
||||
clientY: rect.top + point.y
|
||||
});
|
||||
|
||||
// Manually trigger rather than having an async test
|
||||
@ -1063,6 +1050,9 @@ describe('Core.Tooltip', function() {
|
||||
animation: {
|
||||
// without this slice center point is calculated wrong
|
||||
animateRotate: false
|
||||
},
|
||||
tooltips: {
|
||||
animation: false
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1091,14 +1081,15 @@ describe('Core.Tooltip', function() {
|
||||
chart.update();
|
||||
node.dispatchEvent(mouseOutEvent);
|
||||
node.dispatchEvent(mouseMoveEvent);
|
||||
var model = chart.tooltip._model;
|
||||
expect(model.x).toBeGreaterThanOrEqual(0);
|
||||
if (model.width <= chart.width) {
|
||||
expect(model.x + model.width).toBeLessThanOrEqual(chart.width);
|
||||
var tooltip = chart.tooltip;
|
||||
expect(tooltip.dataPoints.length).toBe(1);
|
||||
expect(tooltip.x).toBeGreaterThanOrEqual(0);
|
||||
if (tooltip.width <= chart.width) {
|
||||
expect(tooltip.x + tooltip.width).toBeLessThanOrEqual(chart.width);
|
||||
}
|
||||
expect(model.caretX).toBeCloseToPixel(tooltipPosition.x);
|
||||
expect(tooltip.caretX).toBeCloseToPixel(tooltipPosition.x);
|
||||
// if tooltip is longer than chart area then all tests done
|
||||
if (model.width > chart.width) {
|
||||
if (tooltip.width > chart.width) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1176,8 +1167,8 @@ describe('Core.Tooltip', function() {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
clientX: rect.left + point._model.x,
|
||||
clientY: rect.top + point._model.y
|
||||
clientX: rect.left + point.x,
|
||||
clientY: rect.top + point.y
|
||||
});
|
||||
|
||||
// Manually trigger rather than having an async test
|
||||
@ -1187,45 +1178,54 @@ describe('Core.Tooltip', function() {
|
||||
var tooltip = chart.tooltip;
|
||||
var globalDefaults = Chart.defaults.global;
|
||||
|
||||
expect(tooltip._view).toEqual(jasmine.objectContaining({
|
||||
// Positioning
|
||||
xPadding: 6,
|
||||
yPadding: 6,
|
||||
xAlign: 'center',
|
||||
yAlign: 'top',
|
||||
expect(tooltip.options.xPadding).toEqual(6);
|
||||
expect(tooltip.options.yPadding).toEqual(6);
|
||||
expect(tooltip.xAlign).toEqual('center');
|
||||
expect(tooltip.yAlign).toEqual('top');
|
||||
|
||||
expect(tooltip.options).toEqual(jasmine.objectContaining({
|
||||
// Body
|
||||
bodyFontColor: '#fff',
|
||||
_bodyFontFamily: globalDefaults.defaultFontFamily,
|
||||
_bodyFontStyle: globalDefaults.defaultFontStyle,
|
||||
_bodyAlign: 'left',
|
||||
bodyFontFamily: globalDefaults.defaultFontFamily,
|
||||
bodyFontStyle: globalDefaults.defaultFontStyle,
|
||||
bodyAlign: 'left',
|
||||
bodyFontSize: globalDefaults.defaultFontSize,
|
||||
bodySpacing: 2,
|
||||
}));
|
||||
|
||||
expect(tooltip.options).toEqual(jasmine.objectContaining({
|
||||
// Title
|
||||
titleFontColor: '#fff',
|
||||
_titleFontFamily: globalDefaults.defaultFontFamily,
|
||||
_titleFontStyle: 'bold',
|
||||
titleFontFamily: globalDefaults.defaultFontFamily,
|
||||
titleFontStyle: 'bold',
|
||||
titleFontSize: globalDefaults.defaultFontSize,
|
||||
_titleAlign: 'left',
|
||||
titleAlign: 'left',
|
||||
titleSpacing: 2,
|
||||
titleMarginBottom: 6,
|
||||
}));
|
||||
|
||||
expect(tooltip.options).toEqual(jasmine.objectContaining({
|
||||
// Footer
|
||||
footerFontColor: '#fff',
|
||||
_footerFontFamily: globalDefaults.defaultFontFamily,
|
||||
_footerFontStyle: 'bold',
|
||||
footerFontFamily: globalDefaults.defaultFontFamily,
|
||||
footerFontStyle: 'bold',
|
||||
footerFontSize: globalDefaults.defaultFontSize,
|
||||
_footerAlign: 'left',
|
||||
footerAlign: 'left',
|
||||
footerSpacing: 2,
|
||||
footerMarginTop: 6,
|
||||
}));
|
||||
|
||||
expect(tooltip.options).toEqual(jasmine.objectContaining({
|
||||
// Appearance
|
||||
caretSize: 5,
|
||||
caretPadding: 2,
|
||||
cornerRadius: 6,
|
||||
backgroundColor: 'rgba(0,0,0,0.8)',
|
||||
multiKeyBackground: '#fff',
|
||||
}));
|
||||
|
||||
expect(tooltip).toEqual(jasmine.objectContaining({
|
||||
opacity: 1,
|
||||
legendColorBackground: '#fff',
|
||||
|
||||
// Text
|
||||
title: ['beforeTitle', 'newline', 'title', 'newline', 'afterTitle', 'newline'],
|
||||
@ -1241,7 +1241,6 @@ describe('Core.Tooltip', function() {
|
||||
}],
|
||||
afterBody: ['afterBody', 'newline'],
|
||||
footer: ['beforeFooter', 'newline', 'footer', 'newline', 'afterFooter', 'newline'],
|
||||
caretPadding: 2,
|
||||
labelTextColors: ['labelTextColor', 'labelTextColor'],
|
||||
labelColors: [{
|
||||
borderColor: globalDefaults.defaultColor,
|
||||
@ -1262,45 +1261,51 @@ describe('Core.Tooltip', function() {
|
||||
y: 100,
|
||||
width: 100,
|
||||
height: 100,
|
||||
xPadding: 5,
|
||||
yPadding: 5,
|
||||
xAlign: 'left',
|
||||
yAlign: 'top',
|
||||
|
||||
// Body
|
||||
bodyFontColor: '#fff',
|
||||
_bodyFontFamily: globalDefaults.defaultFontFamily,
|
||||
_bodyFontStyle: globalDefaults.defaultFontStyle,
|
||||
_bodyAlign: body,
|
||||
bodyFontSize: globalDefaults.defaultFontSize,
|
||||
bodySpacing: 2,
|
||||
options: {
|
||||
xPadding: 5,
|
||||
yPadding: 5,
|
||||
|
||||
// Title
|
||||
titleFontColor: '#fff',
|
||||
_titleFontFamily: globalDefaults.defaultFontFamily,
|
||||
_titleFontStyle: 'bold',
|
||||
titleFontSize: globalDefaults.defaultFontSize,
|
||||
_titleAlign: title,
|
||||
titleSpacing: 2,
|
||||
titleMarginBottom: 6,
|
||||
// Body
|
||||
bodyFontColor: '#fff',
|
||||
bodyFontFamily: globalDefaults.defaultFontFamily,
|
||||
bodyFontStyle: globalDefaults.defaultFontStyle,
|
||||
bodyAlign: body,
|
||||
bodyFontSize: globalDefaults.defaultFontSize,
|
||||
bodySpacing: 2,
|
||||
|
||||
// Footer
|
||||
footerFontColor: '#fff',
|
||||
_footerFontFamily: globalDefaults.defaultFontFamily,
|
||||
_footerFontStyle: 'bold',
|
||||
footerFontSize: globalDefaults.defaultFontSize,
|
||||
_footerAlign: footer,
|
||||
footerSpacing: 2,
|
||||
footerMarginTop: 6,
|
||||
// Title
|
||||
titleFontColor: '#fff',
|
||||
titleFontFamily: globalDefaults.defaultFontFamily,
|
||||
titleFontStyle: 'bold',
|
||||
titleFontSize: globalDefaults.defaultFontSize,
|
||||
titleAlign: title,
|
||||
titleSpacing: 2,
|
||||
titleMarginBottom: 6,
|
||||
|
||||
// Appearance
|
||||
caretSize: 5,
|
||||
cornerRadius: 6,
|
||||
borderColor: '#aaa',
|
||||
borderWidth: 1,
|
||||
backgroundColor: 'rgba(0,0,0,0.8)',
|
||||
// Footer
|
||||
footerFontColor: '#fff',
|
||||
footerFontFamily: globalDefaults.defaultFontFamily,
|
||||
footerFontStyle: 'bold',
|
||||
footerFontSize: globalDefaults.defaultFontSize,
|
||||
footerAlign: footer,
|
||||
footerSpacing: 2,
|
||||
footerMarginTop: 6,
|
||||
|
||||
// Appearance
|
||||
caretSize: 5,
|
||||
cornerRadius: 6,
|
||||
caretPadding: 2,
|
||||
borderColor: '#aaa',
|
||||
borderWidth: 1,
|
||||
backgroundColor: 'rgba(0,0,0,0.8)',
|
||||
multiKeyBackground: '#fff',
|
||||
displayColors: false
|
||||
|
||||
},
|
||||
opacity: 1,
|
||||
legendColorBackground: '#fff',
|
||||
|
||||
// Text
|
||||
title: ['title'],
|
||||
@ -1312,7 +1317,6 @@ describe('Core.Tooltip', function() {
|
||||
}],
|
||||
afterBody: [],
|
||||
footer: ['footer'],
|
||||
caretPadding: 2,
|
||||
labelTextColors: ['#fff'],
|
||||
labelColors: [{
|
||||
borderColor: 'rgb(255, 0, 0)',
|
||||
@ -1348,16 +1352,19 @@ describe('Core.Tooltip', function() {
|
||||
|
||||
var mockContext = window.createMockContext();
|
||||
var tooltip = new Chart.Tooltip({
|
||||
_options: globalDefaults.tooltips,
|
||||
_chart: {
|
||||
ctx: mockContext,
|
||||
options: {
|
||||
tooltips: {
|
||||
animation: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('Should go left', function() {
|
||||
mockContext.resetCalls();
|
||||
tooltip._view = makeView('left', 'left', 'left');
|
||||
tooltip.draw();
|
||||
Chart.helpers.merge(tooltip, makeView('left', 'left', 'left'));
|
||||
tooltip.draw(mockContext);
|
||||
|
||||
expect(mockContext.getCalls()).toEqual(Array.prototype.concat(drawBody, [
|
||||
{name: 'setTextAlign', args: ['left']},
|
||||
@ -1376,8 +1383,8 @@ describe('Core.Tooltip', function() {
|
||||
|
||||
it('Should go right', function() {
|
||||
mockContext.resetCalls();
|
||||
tooltip._view = makeView('right', 'right', 'right');
|
||||
tooltip.draw();
|
||||
Chart.helpers.merge(tooltip, makeView('right', 'right', 'right'));
|
||||
tooltip.draw(mockContext);
|
||||
|
||||
expect(mockContext.getCalls()).toEqual(Array.prototype.concat(drawBody, [
|
||||
{name: 'setTextAlign', args: ['right']},
|
||||
@ -1396,8 +1403,8 @@ describe('Core.Tooltip', function() {
|
||||
|
||||
it('Should center', function() {
|
||||
mockContext.resetCalls();
|
||||
tooltip._view = makeView('center', 'center', 'center');
|
||||
tooltip.draw();
|
||||
Chart.helpers.merge(tooltip, makeView('center', 'center', 'center'));
|
||||
tooltip.draw(mockContext);
|
||||
|
||||
expect(mockContext.getCalls()).toEqual(Array.prototype.concat(drawBody, [
|
||||
{name: 'setTextAlign', args: ['center']},
|
||||
@ -1416,8 +1423,8 @@ describe('Core.Tooltip', function() {
|
||||
|
||||
it('Should allow mixed', function() {
|
||||
mockContext.resetCalls();
|
||||
tooltip._view = makeView('right', 'center', 'left');
|
||||
tooltip.draw();
|
||||
Chart.helpers.merge(tooltip, makeView('right', 'center', 'left'));
|
||||
tooltip.draw(mockContext);
|
||||
|
||||
expect(mockContext.getCalls()).toEqual(Array.prototype.concat(drawBody, [
|
||||
{name: 'setTextAlign', args: ['right']},
|
||||
|
||||
@ -13,20 +13,15 @@ describe('Arc element tests', function() {
|
||||
});
|
||||
|
||||
it ('should determine if in range', function() {
|
||||
// Mock out the arc as if the controller put it there
|
||||
var arc = new Chart.elements.Arc({
|
||||
_datasetIndex: 2,
|
||||
_index: 1
|
||||
});
|
||||
|
||||
// Mock out the view as if the controller put it there
|
||||
arc._view = {
|
||||
startAngle: 0,
|
||||
endAngle: Math.PI / 2,
|
||||
x: 0,
|
||||
y: 0,
|
||||
innerRadius: 5,
|
||||
outerRadius: 10,
|
||||
};
|
||||
});
|
||||
|
||||
expect(arc.inRange(2, 2)).toBe(false);
|
||||
expect(arc.inRange(7, 0)).toBe(true);
|
||||
@ -36,20 +31,15 @@ describe('Arc element tests', function() {
|
||||
});
|
||||
|
||||
it ('should get the tooltip position', function() {
|
||||
// Mock out the arc as if the controller put it there
|
||||
var arc = new Chart.elements.Arc({
|
||||
_datasetIndex: 2,
|
||||
_index: 1
|
||||
});
|
||||
|
||||
// Mock out the view as if the controller put it there
|
||||
arc._view = {
|
||||
startAngle: 0,
|
||||
endAngle: Math.PI / 2,
|
||||
x: 0,
|
||||
y: 0,
|
||||
innerRadius: 0,
|
||||
outerRadius: Math.sqrt(2),
|
||||
};
|
||||
});
|
||||
|
||||
var pos = arc.tooltipPosition();
|
||||
expect(pos.x).toBeCloseTo(0.5);
|
||||
@ -57,20 +47,15 @@ describe('Arc element tests', function() {
|
||||
});
|
||||
|
||||
it ('should get the center', function() {
|
||||
// Mock out the arc as if the controller put it there
|
||||
var arc = new Chart.elements.Arc({
|
||||
_datasetIndex: 2,
|
||||
_index: 1
|
||||
});
|
||||
|
||||
// Mock out the view as if the controller put it there
|
||||
arc._view = {
|
||||
startAngle: 0,
|
||||
endAngle: Math.PI / 2,
|
||||
x: 0,
|
||||
y: 0,
|
||||
innerRadius: 0,
|
||||
outerRadius: Math.sqrt(2),
|
||||
};
|
||||
});
|
||||
|
||||
var center = arc.getCenterPoint();
|
||||
expect(center.x).toBeCloseTo(0.5, 6);
|
||||
|
||||
@ -13,21 +13,15 @@ describe('Chart.elements.Point', function() {
|
||||
});
|
||||
|
||||
it ('Should correctly identify as in range', function() {
|
||||
// Mock out the point as if we were made by the controller
|
||||
var point = new Chart.elements.Point({
|
||||
_datasetIndex: 2,
|
||||
_index: 1
|
||||
});
|
||||
|
||||
// Safely handles if these are called before the viewmodel is instantiated
|
||||
expect(point.inRange(5)).toBe(false);
|
||||
|
||||
// Attach a view object as if we were the controller
|
||||
point._view = {
|
||||
radius: 2,
|
||||
hitRadius: 3,
|
||||
options: {
|
||||
radius: 2,
|
||||
hitRadius: 3,
|
||||
},
|
||||
x: 10,
|
||||
y: 15
|
||||
};
|
||||
});
|
||||
|
||||
expect(point.inRange(10, 15)).toBe(true);
|
||||
expect(point.inRange(10, 10)).toBe(false);
|
||||
@ -36,18 +30,15 @@ describe('Chart.elements.Point', function() {
|
||||
});
|
||||
|
||||
it ('should get the correct tooltip position', function() {
|
||||
// Mock out the point as if we were made by the controller
|
||||
var point = new Chart.elements.Point({
|
||||
_datasetIndex: 2,
|
||||
_index: 1
|
||||
});
|
||||
|
||||
// Attach a view object as if we were the controller
|
||||
point._view = {
|
||||
radius: 2,
|
||||
borderWidth: 6,
|
||||
options: {
|
||||
radius: 2,
|
||||
borderWidth: 6,
|
||||
},
|
||||
x: 10,
|
||||
y: 15
|
||||
};
|
||||
});
|
||||
|
||||
expect(point.tooltipPosition()).toEqual({
|
||||
x: 10,
|
||||
@ -57,34 +48,31 @@ describe('Chart.elements.Point', function() {
|
||||
});
|
||||
|
||||
it('should get the correct center point', function() {
|
||||
// Mock out the point as if we were made by the controller
|
||||
var point = new Chart.elements.Point({
|
||||
_datasetIndex: 2,
|
||||
_index: 1
|
||||
});
|
||||
|
||||
// Attach a view object as if we were the controller
|
||||
point._view = {
|
||||
radius: 2,
|
||||
options: {
|
||||
radius: 2,
|
||||
},
|
||||
x: 10,
|
||||
y: 10
|
||||
};
|
||||
});
|
||||
|
||||
expect(point.getCenterPoint()).toEqual({x: 10, y: 10});
|
||||
});
|
||||
|
||||
it ('should not draw if skipped', function() {
|
||||
var mockContext = window.createMockContext();
|
||||
var point = new Chart.elements.Point();
|
||||
|
||||
// Attach a view object as if we were the controller
|
||||
point._view = {
|
||||
radius: 2,
|
||||
hitRadius: 3,
|
||||
// Mock out the point as if we were made by the controller
|
||||
var point = new Chart.elements.Point({
|
||||
options: {
|
||||
radius: 2,
|
||||
hitRadius: 3,
|
||||
},
|
||||
x: 10,
|
||||
y: 15,
|
||||
ctx: mockContext,
|
||||
skip: true
|
||||
};
|
||||
});
|
||||
|
||||
point.draw(mockContext);
|
||||
|
||||
|
||||
@ -14,20 +14,11 @@ describe('Rectangle element tests', function() {
|
||||
|
||||
it('Should correctly identify as in range', function() {
|
||||
var rectangle = new Chart.elements.Rectangle({
|
||||
_datasetIndex: 2,
|
||||
_index: 1
|
||||
});
|
||||
|
||||
// Safely handles if these are called before the viewmodel is instantiated
|
||||
expect(rectangle.inRange(5)).toBe(false);
|
||||
|
||||
// Attach a view object as if we were the controller
|
||||
rectangle._view = {
|
||||
base: 0,
|
||||
width: 4,
|
||||
x: 10,
|
||||
y: 15
|
||||
};
|
||||
});
|
||||
|
||||
expect(rectangle.inRange(10, 15)).toBe(true);
|
||||
expect(rectangle.inRange(10, 10)).toBe(true);
|
||||
@ -36,17 +27,11 @@ describe('Rectangle element tests', function() {
|
||||
|
||||
// Test when the y is below the base (negative bar)
|
||||
var negativeRectangle = new Chart.elements.Rectangle({
|
||||
_datasetIndex: 2,
|
||||
_index: 1
|
||||
});
|
||||
|
||||
// Attach a view object as if we were the controller
|
||||
negativeRectangle._view = {
|
||||
base: 0,
|
||||
width: 4,
|
||||
x: 10,
|
||||
y: -15
|
||||
};
|
||||
});
|
||||
|
||||
expect(negativeRectangle.inRange(10, -16)).toBe(false);
|
||||
expect(negativeRectangle.inRange(10, 1)).toBe(false);
|
||||
@ -55,17 +40,11 @@ describe('Rectangle element tests', function() {
|
||||
|
||||
it('should get the correct tooltip position', function() {
|
||||
var rectangle = new Chart.elements.Rectangle({
|
||||
_datasetIndex: 2,
|
||||
_index: 1
|
||||
});
|
||||
|
||||
// Attach a view object as if we were the controller
|
||||
rectangle._view = {
|
||||
base: 0,
|
||||
width: 4,
|
||||
x: 10,
|
||||
y: 15
|
||||
};
|
||||
});
|
||||
|
||||
expect(rectangle.tooltipPosition()).toEqual({
|
||||
x: 10,
|
||||
@ -74,17 +53,11 @@ describe('Rectangle element tests', function() {
|
||||
|
||||
// Test when the y is below the base (negative bar)
|
||||
var negativeRectangle = new Chart.elements.Rectangle({
|
||||
_datasetIndex: 2,
|
||||
_index: 1
|
||||
});
|
||||
|
||||
// Attach a view object as if we were the controller
|
||||
negativeRectangle._view = {
|
||||
base: -10,
|
||||
width: 4,
|
||||
x: 10,
|
||||
y: -15
|
||||
};
|
||||
});
|
||||
|
||||
expect(negativeRectangle.tooltipPosition()).toEqual({
|
||||
x: 10,
|
||||
@ -94,17 +67,11 @@ describe('Rectangle element tests', function() {
|
||||
|
||||
it('should get the center', function() {
|
||||
var rectangle = new Chart.elements.Rectangle({
|
||||
_datasetIndex: 2,
|
||||
_index: 1
|
||||
});
|
||||
|
||||
// Attach a view object as if we were the controller
|
||||
rectangle._view = {
|
||||
base: 0,
|
||||
width: 4,
|
||||
x: 10,
|
||||
y: 15
|
||||
};
|
||||
});
|
||||
|
||||
expect(rectangle.getCenterPoint()).toEqual({x: 10, y: 7.5});
|
||||
});
|
||||
|
||||
@ -22,8 +22,8 @@ describe('Default Configs', function() {
|
||||
chart.tooltip.update();
|
||||
|
||||
// Title is always blank
|
||||
expect(chart.tooltip._model.title).toEqual([]);
|
||||
expect(chart.tooltip._model.body).toEqual([{
|
||||
expect(chart.tooltip.title).toEqual([]);
|
||||
expect(chart.tooltip.body).toEqual([{
|
||||
before: [],
|
||||
lines: ['My dataset: (10, 12, 5)'],
|
||||
after: []
|
||||
@ -50,8 +50,8 @@ describe('Default Configs', function() {
|
||||
chart.tooltip.update();
|
||||
|
||||
// Title is always blank
|
||||
expect(chart.tooltip._model.title).toEqual([]);
|
||||
expect(chart.tooltip._model.body).toEqual([{
|
||||
expect(chart.tooltip.title).toEqual([]);
|
||||
expect(chart.tooltip.body).toEqual([{
|
||||
before: [],
|
||||
lines: ['label2: 20'],
|
||||
after: []
|
||||
@ -76,8 +76,8 @@ describe('Default Configs', function() {
|
||||
chart.tooltip.update();
|
||||
|
||||
// Title is always blank
|
||||
expect(chart.tooltip._model.title).toEqual([]);
|
||||
expect(chart.tooltip._model.body).toEqual([{
|
||||
expect(chart.tooltip.title).toEqual([]);
|
||||
expect(chart.tooltip.body).toEqual([{
|
||||
before: [],
|
||||
lines: [
|
||||
'row1: 20',
|
||||
@ -196,8 +196,8 @@ describe('Default Configs', function() {
|
||||
chart.tooltip.update();
|
||||
|
||||
// Title is always blank
|
||||
expect(chart.tooltip._model.title).toEqual([]);
|
||||
expect(chart.tooltip._model.body).toEqual([{
|
||||
expect(chart.tooltip.title).toEqual([]);
|
||||
expect(chart.tooltip.body).toEqual([{
|
||||
before: [],
|
||||
lines: ['label2: 20'],
|
||||
after: []
|
||||
|
||||
@ -49,163 +49,135 @@ describe('Curve helper tests', function() {
|
||||
|
||||
it('should spline curves with monotone cubic interpolation', function() {
|
||||
var dataPoints = [
|
||||
{_model: {x: 0, y: 0, skip: false}},
|
||||
{_model: {x: 3, y: 6, skip: false}},
|
||||
{_model: {x: 9, y: 6, skip: false}},
|
||||
{_model: {x: 12, y: 60, skip: false}},
|
||||
{_model: {x: 15, y: 60, skip: false}},
|
||||
{_model: {x: 18, y: 120, skip: false}},
|
||||
{_model: {x: null, y: null, skip: true}},
|
||||
{_model: {x: 21, y: 180, skip: false}},
|
||||
{_model: {x: 24, y: 120, skip: false}},
|
||||
{_model: {x: 27, y: 125, skip: false}},
|
||||
{_model: {x: 30, y: 105, skip: false}},
|
||||
{_model: {x: 33, y: 110, skip: false}},
|
||||
{_model: {x: 33, y: 110, skip: false}},
|
||||
{_model: {x: 36, y: 170, skip: false}}
|
||||
{x: 0, y: 0, skip: false},
|
||||
{x: 3, y: 6, skip: false},
|
||||
{x: 9, y: 6, skip: false},
|
||||
{x: 12, y: 60, skip: false},
|
||||
{x: 15, y: 60, skip: false},
|
||||
{x: 18, y: 120, skip: false},
|
||||
{x: null, y: null, skip: true},
|
||||
{x: 21, y: 180, skip: false},
|
||||
{x: 24, y: 120, skip: false},
|
||||
{x: 27, y: 125, skip: false},
|
||||
{x: 30, y: 105, skip: false},
|
||||
{x: 33, y: 110, skip: false},
|
||||
{x: 33, y: 110, skip: false},
|
||||
{x: 36, y: 170, skip: false}
|
||||
];
|
||||
helpers.splineCurveMonotone(dataPoints);
|
||||
expect(dataPoints).toEqual([{
|
||||
_model: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
skip: false,
|
||||
controlPointNextX: 1,
|
||||
controlPointNextY: 2
|
||||
}
|
||||
x: 0,
|
||||
y: 0,
|
||||
skip: false,
|
||||
controlPointNextX: 1,
|
||||
controlPointNextY: 2
|
||||
},
|
||||
{
|
||||
_model: {
|
||||
x: 3,
|
||||
y: 6,
|
||||
skip: false,
|
||||
controlPointPreviousX: 2,
|
||||
controlPointPreviousY: 6,
|
||||
controlPointNextX: 5,
|
||||
controlPointNextY: 6
|
||||
}
|
||||
x: 3,
|
||||
y: 6,
|
||||
skip: false,
|
||||
controlPointPreviousX: 2,
|
||||
controlPointPreviousY: 6,
|
||||
controlPointNextX: 5,
|
||||
controlPointNextY: 6
|
||||
},
|
||||
{
|
||||
_model: {
|
||||
x: 9,
|
||||
y: 6,
|
||||
skip: false,
|
||||
controlPointPreviousX: 7,
|
||||
controlPointPreviousY: 6,
|
||||
controlPointNextX: 10,
|
||||
controlPointNextY: 6
|
||||
}
|
||||
x: 9,
|
||||
y: 6,
|
||||
skip: false,
|
||||
controlPointPreviousX: 7,
|
||||
controlPointPreviousY: 6,
|
||||
controlPointNextX: 10,
|
||||
controlPointNextY: 6
|
||||
},
|
||||
{
|
||||
_model: {
|
||||
x: 12,
|
||||
y: 60,
|
||||
skip: false,
|
||||
controlPointPreviousX: 11,
|
||||
controlPointPreviousY: 60,
|
||||
controlPointNextX: 13,
|
||||
controlPointNextY: 60
|
||||
}
|
||||
x: 12,
|
||||
y: 60,
|
||||
skip: false,
|
||||
controlPointPreviousX: 11,
|
||||
controlPointPreviousY: 60,
|
||||
controlPointNextX: 13,
|
||||
controlPointNextY: 60
|
||||
},
|
||||
{
|
||||
_model: {
|
||||
x: 15,
|
||||
y: 60,
|
||||
skip: false,
|
||||
controlPointPreviousX: 14,
|
||||
controlPointPreviousY: 60,
|
||||
controlPointNextX: 16,
|
||||
controlPointNextY: 60
|
||||
}
|
||||
x: 15,
|
||||
y: 60,
|
||||
skip: false,
|
||||
controlPointPreviousX: 14,
|
||||
controlPointPreviousY: 60,
|
||||
controlPointNextX: 16,
|
||||
controlPointNextY: 60
|
||||
},
|
||||
{
|
||||
_model: {
|
||||
x: 18,
|
||||
y: 120,
|
||||
skip: false,
|
||||
controlPointPreviousX: 17,
|
||||
controlPointPreviousY: 100
|
||||
}
|
||||
x: 18,
|
||||
y: 120,
|
||||
skip: false,
|
||||
controlPointPreviousX: 17,
|
||||
controlPointPreviousY: 100
|
||||
},
|
||||
{
|
||||
_model: {
|
||||
x: null,
|
||||
y: null,
|
||||
skip: true
|
||||
}
|
||||
x: null,
|
||||
y: null,
|
||||
skip: true
|
||||
},
|
||||
{
|
||||
_model: {
|
||||
x: 21,
|
||||
y: 180,
|
||||
skip: false,
|
||||
controlPointNextX: 22,
|
||||
controlPointNextY: 160
|
||||
}
|
||||
x: 21,
|
||||
y: 180,
|
||||
skip: false,
|
||||
controlPointNextX: 22,
|
||||
controlPointNextY: 160
|
||||
},
|
||||
{
|
||||
_model: {
|
||||
x: 24,
|
||||
y: 120,
|
||||
skip: false,
|
||||
controlPointPreviousX: 23,
|
||||
controlPointPreviousY: 120,
|
||||
controlPointNextX: 25,
|
||||
controlPointNextY: 120
|
||||
}
|
||||
x: 24,
|
||||
y: 120,
|
||||
skip: false,
|
||||
controlPointPreviousX: 23,
|
||||
controlPointPreviousY: 120,
|
||||
controlPointNextX: 25,
|
||||
controlPointNextY: 120
|
||||
},
|
||||
{
|
||||
_model: {
|
||||
x: 27,
|
||||
y: 125,
|
||||
skip: false,
|
||||
controlPointPreviousX: 26,
|
||||
controlPointPreviousY: 125,
|
||||
controlPointNextX: 28,
|
||||
controlPointNextY: 125
|
||||
}
|
||||
x: 27,
|
||||
y: 125,
|
||||
skip: false,
|
||||
controlPointPreviousX: 26,
|
||||
controlPointPreviousY: 125,
|
||||
controlPointNextX: 28,
|
||||
controlPointNextY: 125
|
||||
},
|
||||
{
|
||||
_model: {
|
||||
x: 30,
|
||||
y: 105,
|
||||
skip: false,
|
||||
controlPointPreviousX: 29,
|
||||
controlPointPreviousY: 105,
|
||||
controlPointNextX: 31,
|
||||
controlPointNextY: 105
|
||||
}
|
||||
x: 30,
|
||||
y: 105,
|
||||
skip: false,
|
||||
controlPointPreviousX: 29,
|
||||
controlPointPreviousY: 105,
|
||||
controlPointNextX: 31,
|
||||
controlPointNextY: 105
|
||||
},
|
||||
{
|
||||
_model: {
|
||||
x: 33,
|
||||
y: 110,
|
||||
skip: false,
|
||||
controlPointPreviousX: 32,
|
||||
controlPointPreviousY: 110,
|
||||
controlPointNextX: 33,
|
||||
controlPointNextY: 110
|
||||
}
|
||||
x: 33,
|
||||
y: 110,
|
||||
skip: false,
|
||||
controlPointPreviousX: 32,
|
||||
controlPointPreviousY: 110,
|
||||
controlPointNextX: 33,
|
||||
controlPointNextY: 110
|
||||
},
|
||||
{
|
||||
_model: {
|
||||
x: 33,
|
||||
y: 110,
|
||||
skip: false,
|
||||
controlPointPreviousX: 33,
|
||||
controlPointPreviousY: 110,
|
||||
controlPointNextX: 34,
|
||||
controlPointNextY: 110
|
||||
}
|
||||
x: 33,
|
||||
y: 110,
|
||||
skip: false,
|
||||
controlPointPreviousX: 33,
|
||||
controlPointPreviousY: 110,
|
||||
controlPointNextX: 34,
|
||||
controlPointNextY: 110
|
||||
},
|
||||
{
|
||||
_model: {
|
||||
x: 36,
|
||||
y: 170,
|
||||
skip: false,
|
||||
controlPointPreviousX: 35,
|
||||
controlPointPreviousY: 150
|
||||
}
|
||||
x: 36,
|
||||
y: 170,
|
||||
skip: false,
|
||||
controlPointPreviousX: 35,
|
||||
controlPointPreviousY: 150
|
||||
}]);
|
||||
});
|
||||
});
|
||||
|
||||
@ -149,7 +149,7 @@ describe('Legend block tests', function() {
|
||||
datasetIndex: 1
|
||||
}, {
|
||||
text: 'dataset3',
|
||||
fillStyle: 'green',
|
||||
fillStyle: 'rgba(0,0,0,0.1)',
|
||||
hidden: false,
|
||||
lineCap: 'butt',
|
||||
lineDash: [],
|
||||
@ -198,7 +198,7 @@ describe('Legend block tests', function() {
|
||||
|
||||
expect(chart.legend.legendItems).toEqual([{
|
||||
text: 'dataset3',
|
||||
fillStyle: 'green',
|
||||
fillStyle: 'rgba(0,0,0,0.1)',
|
||||
hidden: false,
|
||||
lineCap: 'butt',
|
||||
lineDash: [],
|
||||
|
||||
@ -113,8 +113,6 @@ function _resolveElementPoint(el) {
|
||||
point = el.getCenterPoint();
|
||||
} else if (el.x !== undefined && el.y !== undefined) {
|
||||
point = el;
|
||||
} else if (el._model && el._model.x !== undefined && el._model.y !== undefined) {
|
||||
point = el._model;
|
||||
}
|
||||
}
|
||||
return point;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user