_index: index,
_chart: this.chart,
_model: {
- x: 0, //xScale.getPixelForValue(null, index, true),
- y: 0, //this.chartArea.bottom,
+ x: 0,
+ y: 0,
},
}));
}, this);
// The line chart onlty supports a single x axis because the x axis is always a dataset axis
- dataset.xAxisID = this.options.scales.xAxes[0].id;
+ if (!dataset.xAxisID) {
+ dataset.xAxisID = this.options.scales.xAxes[0].id;
+ }
if (!dataset.yAxisID) {
dataset.yAxisID = this.options.scales.yAxes[0].id;
// Desired view properties
_model: {
- x: xScale.getPixelForValue(null, index, true), // value not used in dataset scale, but we want a consistent API between scales
+ x: xScale.getPointPixelForValue(this.data.datasets[datasetIndex].data[index], index, datasetIndex),
y: yScalePoint,
// Appearance
// Desired view properties
_model: {
- x: xScale.getPixelForValue(null, index, true), // value not used in dataset scale, but we want a consistent API between scales
+ x: xScale.getPointPixelForValue(this.data.datasets[datasetIndex].data[index], index, datasetIndex),
y: yScale.getPointPixelForValue(this.data.datasets[datasetIndex].data[index], index, datasetIndex),
// Appearance
this.render(animationDuration);
},
buildScale: function() {
- var self = this;
-
// Map of scale ID to scale object so we can lookup later
this.scales = {};
- // Build the x axis. The line chart only supports a single x axis
- var ScaleClass = Chart.scales.getScaleConstructor(this.options.scales.xAxes[0].type);
- var xScale = new ScaleClass({
- ctx: this.chart.ctx,
- options: this.options.scales.xAxes[0],
- data: this.data,
- id: this.options.scales.xAxes[0].id,
- });
- this.scales[xScale.id] = xScale;
+ // Build the x axes
+ helpers.each(this.options.scales.xAxes, function(xAxisOptions) {
+ var ScaleClass = Chart.scales.getScaleConstructor(xAxisOptions.type);
+ var scale = new ScaleClass({
+ ctx: this.chart.ctx,
+ options: xAxisOptions,
+ data: this.data,
+ id: xAxisOptions.id,
+ });
+
+ this.scales[scale.id] = scale;
+ }, this);
- // Build up all the y scales
+ // Build the y axes
helpers.each(this.options.scales.yAxes, function(yAxisOptions) {
var ScaleClass = Chart.scales.getScaleConstructor(yAxisOptions.type);
var scale = new ScaleClass({
// scale numbers
beginAtZero: false,
- integersOnly: false,
override: null,
// label settings
// scale numbers
beginAtZero: false,
- integersOnly: false,
override: null,
// label settings
// Events
helpers.bindEvents(this, this.options.events, this.events);
- //Custom Point Defaults
+ // Create a new line and its points for each dataset and piece of data
helpers.each(this.data.datasets, function(dataset, datasetIndex) {
dataset.metaDataset = new Chart.Line({
_chart: this.chart,
_index: index,
_chart: this.chart,
_model: {
- x: 0, //xScale.getPixelForValue(null, index, true),
- y: 0, //this.chartArea.bottom,
+ x: 0,
+ y: 0,
},
}));
// Desired view properties
_model: {
- x: xScale.getPixelForValue(this.data.datasets[datasetIndex].data[index].x), // value not used in dataset scale, but we want a consistent API between scales
+ x: xScale.getPointPixelForValue(this.data.datasets[datasetIndex].data[index], index, datasetIndex),
y: yScalePoint,
// Appearance
tension: point.custom && point.custom.tension ? point.custom.tension : this.options.elements.line.tension,
- radius: point.custom && point.custom.radius ? point.custom.pointRadius : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointRadius, index, this.options.elements.point.radius),
+ radius: point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].radius, index, this.options.elements.point.radius),
backgroundColor: point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBackgroundColor, index, this.options.elements.point.backgroundColor),
borderColor: point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBorderColor, index, this.options.elements.point.borderColor),
borderWidth: point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBorderWidth, index, this.options.elements.point.borderWidth),
- skip: (this.data.datasets[datasetIndex].data[index] === null) || (this.data.datasets[datasetIndex].data[index].x === null) || (this.data.datasets[datasetIndex].data[index].y === null),
+ skip: this.data.datasets[datasetIndex].data[index] === null,
// Tooltip
- hoverRadius: point.custom && point.custom.hoverRadius ? point.custom.hoverRadius : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointHitRadius, index, this.options.elements.point.hitRadius),
+ hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].hitRadius, index, this.options.elements.point.hitRadius),
},
});
}, this);
point.pivot();
}, this);
},
- update: function() {
+ update: function(animationDuration) {
Chart.scaleService.fitScalesForChart(this, this.chart.width, this.chart.height);
// Update the lines
// Model
_model: {
// Appearance
- tension: dataset.tension || this.options.elements.line.tension,
- backgroundColor: dataset.backgroundColor || this.options.elements.line.backgroundColor,
- borderWidth: dataset.borderWidth || this.options.elements.line.borderWidth,
- borderColor: dataset.borderColor || this.options.elements.line.borderColor,
- fill: dataset.fill !== undefined ? dataset.fill : this.options.elements.line.fill, // use the value from the dataset if it was provided. else fall back to the default
+ tension: dataset.metaDataset.custom && dataset.metaDataset.custom.tension ? dataset.metaDataset.custom.tension : (dataset.tension || this.options.elements.line.tension),
+ backgroundColor: dataset.metaDataset.custom && dataset.metaDataset.custom.backgroundColor ? dataset.metaDataset.custom.backgroundColor : (dataset.backgroundColor || this.options.elements.line.backgroundColor),
+ borderWidth: dataset.metaDataset.custom && dataset.metaDataset.custom.borderWidth ? dataset.metaDataset.custom.borderWidth : (dataset.borderWidth || this.options.elements.line.borderWidth),
+ borderColor: dataset.metaDataset.custom && dataset.metaDataset.custom.borderColor ? dataset.metaDataset.custom.borderColor : (dataset.borderColor || this.options.elements.line.borderColor),
+ fill: dataset.metaDataset.custom && dataset.metaDataset.custom.fill ? dataset.metaDataset.custom.fill : (dataset.fill !== undefined ? dataset.fill : this.options.elements.line.fill),
skipNull: dataset.skipNull !== undefined ? dataset.skipNull : this.options.elements.line.skipNull,
drawNull: dataset.drawNull !== undefined ? dataset.drawNull : this.options.elements.line.drawNull,
// Scale
// Desired view properties
_model: {
- x: xScale.getPixelForValue(this.data.datasets[datasetIndex].data[index].x),
- y: yScale.getPixelForValue(this.data.datasets[datasetIndex].data[index].y),
+ x: xScale.getPointPixelForValue(this.data.datasets[datasetIndex].data[index], index, datasetIndex),
+ y: yScale.getPointPixelForValue(this.data.datasets[datasetIndex].data[index], index, datasetIndex),
// Appearance
tension: point.custom && point.custom.tension ? point.custom.tension : this.options.elements.line.tension,
- radius: point.custom && point.custom.radius ? point.custom.pointRadius : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointRadius, index, this.options.elements.point.radius),
+ radius: point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].radius, index, this.options.elements.point.radius),
backgroundColor: point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBackgroundColor, index, this.options.elements.point.backgroundColor),
borderColor: point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBorderColor, index, this.options.elements.point.borderColor),
borderWidth: point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBorderWidth, index, this.options.elements.point.borderWidth),
- skip: (this.data.datasets[datasetIndex].data[index] === null) || (this.data.datasets[datasetIndex].data[index].x === null) || (this.data.datasets[datasetIndex].data[index].y === null),
+ skip: this.data.datasets[datasetIndex].data[index] === null,
// Tooltip
- hoverRadius: point.custom && point.custom.hoverRadius ? point.custom.hoverRadius : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointHitRadius, index, this.options.elements.point.hitRadius),
+ hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].hitRadius, index, this.options.elements.point.hitRadius),
},
});
}, this);
point.pivot();
}, this);
- this.render();
+ this.render(animationDuration);
},
buildScale: function() {
// Map of scale ID to scale object so we can lookup later
this.scales = {};
+ // Build the x axes
helpers.each(this.options.scales.xAxes, function(xAxisOptions) {
var ScaleClass = Chart.scales.getScaleConstructor(xAxisOptions.type);
var scale = new ScaleClass({
this.scales[scale.id] = scale;
}, this);
+ // Build the y axes
helpers.each(this.options.scales.yAxes, function(yAxisOptions) {
var ScaleClass = Chart.scales.getScaleConstructor(yAxisOptions.type);
var scale = new ScaleClass({
this.tooltip.transition(easingDecimal).draw();
},
events: function(e) {
- // If exiting chart
- if (e.type == 'mouseout') {
- return this;
- }
-
this.lastActive = this.lastActive || [];
// Find Active Elements
- this.active = function() {
- switch (this.options.hover.mode) {
- case 'single':
- return this.getElementAtEvent(e);
- case 'label':
- return this.getElementsAtEvent(e);
- case 'dataset':
- return this.getDatasetAtEvent(e);
- default:
- return e;
- }
- }.call(this);
+ if (e.type == 'mouseout') {
+ this.active = [];
+ } else {
+ this.active = function() {
+ switch (this.options.hover.mode) {
+ case 'single':
+ return this.getElementAtEvent(e);
+ case 'label':
+ return this.getElementsAtEvent(e);
+ case 'dataset':
+ return this.getDatasetAtEvent(e);
+ default:
+ return e;
+ }
+ }.call(this);
+ }
// On Hover hook
if (this.options.hover.onHover) {
this.options.hover.onHover.call(this, this.active);
}
+ if (e.type == 'mouseup' || e.type == 'click') {
+ if (this.options.onClick) {
+ this.options.onClick.call(this, e, this.active);
+ }
+ }
+
var dataset;
var index;
// Remove styling for last active (even if it may still be active)
dataset = this.data.datasets[this.lastActive[0]._datasetIndex];
index = this.lastActive[0]._index;
- this.lastActive[0]._model.radius = this.lastActive[0].custom && this.lastActive[0].custom.radius ? this.lastActive[0].custom.pointRadius : helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, this.options.elements.point.radius);
+ this.lastActive[0]._model.radius = this.lastActive[0].custom && this.lastActive[0].custom.radius ? this.lastActive[0].custom.radius : helpers.getValueAtIndexOrDefault(dataset.radius, index, this.options.elements.point.radius);
this.lastActive[0]._model.backgroundColor = this.lastActive[0].custom && this.lastActive[0].custom.backgroundColor ? this.lastActive[0].custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, this.options.elements.point.backgroundColor);
this.lastActive[0]._model.borderColor = this.lastActive[0].custom && this.lastActive[0].custom.borderColor ? this.lastActive[0].custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, this.options.elements.point.borderColor);
this.lastActive[0]._model.borderWidth = this.lastActive[0].custom && this.lastActive[0].custom.borderWidth ? this.lastActive[0].custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, this.options.elements.point.borderWidth);
dataset = this.data.datasets[this.lastActive[i]._datasetIndex];
index = this.lastActive[i]._index;
- this.lastActive[i]._model.radius = this.lastActive[i].custom && this.lastActive[i].custom.radius ? this.lastActive[i].custom.pointRadius : helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, this.options.elements.point.radius);
+ this.lastActive[i]._model.radius = this.lastActive[i].custom && this.lastActive[i].custom.radius ? this.lastActive[i].custom.radius : helpers.getValueAtIndexOrDefault(dataset.radius, index, this.options.elements.point.radius);
this.lastActive[i]._model.backgroundColor = this.lastActive[i].custom && this.lastActive[i].custom.backgroundColor ? this.lastActive[i].custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, this.options.elements.point.backgroundColor);
this.lastActive[i]._model.borderColor = this.lastActive[i].custom && this.lastActive[i].custom.borderColor ? this.lastActive[i].custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, this.options.elements.point.borderColor);
this.lastActive[i]._model.borderWidth = this.lastActive[i].custom && this.lastActive[i].custom.borderWidth ? this.lastActive[i].custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, this.options.elements.point.borderWidth);
dataset = this.data.datasets[this.active[0]._datasetIndex];
index = this.active[0]._index;
- this.active[0]._model.radius = this.active[0].custom && this.active[0].custom.hoverRadius ? this.active[0].custom.hoverRadius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.active[0]._model.radius + 1);
+ this.active[0]._model.radius = this.active[0].custom && this.active[0].custom.radius ? this.active[0].custom.radius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.options.elements.point.hoverRadius);
this.active[0]._model.backgroundColor = this.active[0].custom && this.active[0].custom.hoverBackgroundColor ? this.active[0].custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.color(this.active[0]._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
this.active[0]._model.borderColor = this.active[0].custom && this.active[0].custom.hoverBorderColor ? this.active[0].custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.color(this.active[0]._model.borderColor).saturate(0.5).darken(0.1).rgbString());
this.active[0]._model.borderWidth = this.active[0].custom && this.active[0].custom.hoverBorderWidth ? this.active[0].custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, this.active[0]._model.borderWidth);
dataset = this.data.datasets[this.active[i]._datasetIndex];
index = this.active[i]._index;
- this.active[i]._model.radius = this.active[i].custom && this.active[i].custom.hoverRadius ? this.active[i].custom.hoverRadius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.active[i]._model.radius + 1);
+ this.active[i]._model.radius = this.active[i].custom && this.active[i].custom.radius ? this.active[i].custom.radius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.options.elements.point.hoverRadius);
this.active[i]._model.backgroundColor = this.active[i].custom && this.active[i].custom.hoverBackgroundColor ? this.active[i].custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.color(this.active[i]._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
this.active[i]._model.borderColor = this.active[i].custom && this.active[i].custom.hoverBorderColor ? this.active[i].custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.color(this.active[i]._model.borderColor).saturate(0.5).darken(0.1).rgbString());
this.active[i]._model.borderWidth = this.active[i].custom && this.active[i].custom.hoverBorderWidth ? this.active[i].custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, this.active[i]._model.borderWidth);
(this.lastActive.length && this.active.length && changed)) {
this.stop();
- this.render(this.options.hoverAnimationDuration);
+ this.render(this.options.hover.animationDuration);
}
}
isHorizontal: function() {
return this.options.position == "top" || this.options.position == "bottom";
},
- getPixelForValue: function(value, index, includeOffset) {
+ getPixelForValue: function(value, index, datasetIndex, includeOffset) {
// This must be called after fit has been run so that
// this.left, this.top, this.right, and this.bottom have been defined
if (this.isHorizontal()) {
return this.top + (index * (this.height / this.data.labels.length));
}
},
-
+ getPointPixelForValue: function(value, index, datasetIndex) {
+ return this.getPixelForValue(value, index, datasetIndex, true);
+ },
// Functions needed for bar charts
calculateBaseWidth: function() {
- return (this.getPixelForValue(null, 1, true) - this.getPixelForValue(null, 0, true)) - (2 * this.options.categorySpacing);
+ return (this.getPixelForValue(null, 1, 0, true) - this.getPixelForValue(null, 0, 0, true)) - (2 * this.options.categorySpacing);
},
calculateBarWidth: function(datasetCount) {
//The padding between datasets is to the right of each bar, providing that there are more than 1 dataset
},
calculateBarX: function(datasetCount, datasetIndex, elementIndex) {
var xWidth = this.calculateBaseWidth(),
- xAbsolute = this.getPixelForValue(null, elementIndex, true) - (xWidth / 2),
+ xAbsolute = this.getPixelForValue(null, elementIndex, datasetIndex, true) - (xWidth / 2),
barWidth = this.calculateBarWidth(datasetCount);
if (this.options.stacked) {
var isRotated = this.labelRotation !== 0;
helpers.each(this.data.labels, function(label, index) {
- var xLineValue = this.getPixelForValue(label, index, false); // xvalues for grid lines
- var xLabelValue = this.getPixelForValue(label, index, true); // x values for labels (need to consider offsetLabel option)
+ var xLineValue = this.getPixelForValue(label, index, null, false); // xvalues for grid lines
+ var xLabelValue = this.getPixelForValue(label, index, null, true); // x values for labels (need to consider offsetLabel option)
if (this.options.gridLines.show) {
if (index === 0) {