mirror of
https://github.com/chartjs/Chart.js.git
synced 2025-12-08 20:36:08 +00:00
Dataset effective type is now stored under meta.type, allowing many charts to share the same dataset but with different types. Also move dataset.bar flag to meta.bar.
315 lines
12 KiB
JavaScript
315 lines
12 KiB
JavaScript
"use strict";
|
|
|
|
module.exports = function(Chart) {
|
|
|
|
var helpers = Chart.helpers;
|
|
|
|
Chart.defaults.line = {
|
|
showLines: true,
|
|
|
|
hover: {
|
|
mode: "label"
|
|
},
|
|
|
|
scales: {
|
|
xAxes: [{
|
|
type: "category",
|
|
id: 'x-axis-0'
|
|
}],
|
|
yAxes: [{
|
|
type: "linear",
|
|
id: 'y-axis-0'
|
|
}]
|
|
}
|
|
};
|
|
|
|
|
|
Chart.controllers.line = Chart.DatasetController.extend({
|
|
addElements: function() {
|
|
var meta = this.getMeta();
|
|
meta.dataset = meta.dataset || new Chart.elements.Line({
|
|
_chart: this.chart.chart,
|
|
_datasetIndex: this.index,
|
|
_points: meta.data
|
|
});
|
|
|
|
helpers.each(this.getDataset().data, function(value, index) {
|
|
meta.data[index] = meta.data[index] || new Chart.elements.Point({
|
|
_chart: this.chart.chart,
|
|
_datasetIndex: this.index,
|
|
_index: index
|
|
});
|
|
}, this);
|
|
},
|
|
|
|
addElementAndReset: function(index) {
|
|
var point = new Chart.elements.Point({
|
|
_chart: this.chart.chart,
|
|
_datasetIndex: this.index,
|
|
_index: index
|
|
});
|
|
|
|
// Add to the points array and reset it
|
|
this.getMeta().data.splice(index, 0, point);
|
|
this.updateElement(point, index, true);
|
|
|
|
// Make sure bezier control points are updated
|
|
if (this.chart.options.showLines && this.chart.options.elements.line.tension !== 0)
|
|
this.updateBezierControlPoints();
|
|
},
|
|
|
|
update: function update(reset) {
|
|
var meta = this.getMeta();
|
|
var line = meta.dataset;
|
|
var points = meta.data;
|
|
|
|
var yScale = this.getScaleForId(meta.yAxisID);
|
|
var xScale = this.getScaleForId(meta.xAxisID);
|
|
var scaleBase;
|
|
|
|
if (yScale.min < 0 && yScale.max < 0) {
|
|
scaleBase = yScale.getPixelForValue(yScale.max);
|
|
} else if (yScale.min > 0 && yScale.max > 0) {
|
|
scaleBase = yScale.getPixelForValue(yScale.min);
|
|
} else {
|
|
scaleBase = yScale.getPixelForValue(0);
|
|
}
|
|
|
|
// Update Line
|
|
if (this.chart.options.showLines) {
|
|
// Utility
|
|
line._scale = yScale;
|
|
line._datasetIndex = this.index;
|
|
// Data
|
|
line._children = points;
|
|
// Model
|
|
|
|
// Compatibility: If the properties are defined with only the old name, use those values
|
|
if ((this.getDataset().tension !== undefined) && (this.getDataset().lineTension === undefined))
|
|
{
|
|
this.getDataset().lineTension = this.getDataset().tension;
|
|
}
|
|
|
|
line._model = {
|
|
// Appearance
|
|
tension: line.custom && line.custom.tension ? line.custom.tension : helpers.getValueOrDefault(this.getDataset().lineTension, this.chart.options.elements.line.tension),
|
|
backgroundColor: line.custom && line.custom.backgroundColor ? line.custom.backgroundColor : (this.getDataset().backgroundColor || this.chart.options.elements.line.backgroundColor),
|
|
borderWidth: line.custom && line.custom.borderWidth ? line.custom.borderWidth : (this.getDataset().borderWidth || this.chart.options.elements.line.borderWidth),
|
|
borderColor: line.custom && line.custom.borderColor ? line.custom.borderColor : (this.getDataset().borderColor || this.chart.options.elements.line.borderColor),
|
|
borderCapStyle: line.custom && line.custom.borderCapStyle ? line.custom.borderCapStyle : (this.getDataset().borderCapStyle || this.chart.options.elements.line.borderCapStyle),
|
|
borderDash: line.custom && line.custom.borderDash ? line.custom.borderDash : (this.getDataset().borderDash || this.chart.options.elements.line.borderDash),
|
|
borderDashOffset: line.custom && line.custom.borderDashOffset ? line.custom.borderDashOffset : (this.getDataset().borderDashOffset || this.chart.options.elements.line.borderDashOffset),
|
|
borderJoinStyle: line.custom && line.custom.borderJoinStyle ? line.custom.borderJoinStyle : (this.getDataset().borderJoinStyle || this.chart.options.elements.line.borderJoinStyle),
|
|
fill: line.custom && line.custom.fill ? line.custom.fill : (this.getDataset().fill !== undefined ? this.getDataset().fill : this.chart.options.elements.line.fill),
|
|
// Scale
|
|
scaleTop: yScale.top,
|
|
scaleBottom: yScale.bottom,
|
|
scaleZero: scaleBase
|
|
};
|
|
line.pivot();
|
|
}
|
|
|
|
// Update Points
|
|
helpers.each(points, function(point, index) {
|
|
this.updateElement(point, index, reset);
|
|
}, this);
|
|
|
|
if (this.chart.options.showLines && this.chart.options.elements.line.tension !== 0)
|
|
this.updateBezierControlPoints();
|
|
},
|
|
|
|
getPointBackgroundColor: function(point, index) {
|
|
var backgroundColor = this.chart.options.elements.point.backgroundColor;
|
|
var dataset = this.getDataset();
|
|
|
|
if (point.custom && point.custom.backgroundColor) {
|
|
backgroundColor = point.custom.backgroundColor;
|
|
} else if (dataset.pointBackgroundColor) {
|
|
backgroundColor = helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, backgroundColor);
|
|
} else if (dataset.backgroundColor) {
|
|
backgroundColor = dataset.backgroundColor;
|
|
}
|
|
|
|
return backgroundColor;
|
|
},
|
|
getPointBorderColor: function(point, index) {
|
|
var borderColor = this.chart.options.elements.point.borderColor;
|
|
var dataset = this.getDataset();
|
|
|
|
if (point.custom && point.custom.borderColor) {
|
|
borderColor = point.custom.borderColor;
|
|
} else if (dataset.pointBorderColor) {
|
|
borderColor = helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderColor, index, borderColor);
|
|
} else if (dataset.borderColor) {
|
|
borderColor = dataset.borderColor;
|
|
}
|
|
|
|
return borderColor;
|
|
},
|
|
getPointBorderWidth: function(point, index) {
|
|
var borderWidth = this.chart.options.elements.point.borderWidth;
|
|
var dataset = this.getDataset();
|
|
|
|
if (point.custom && point.custom.borderWidth !== undefined) {
|
|
borderWidth = point.custom.borderWidth;
|
|
} else if (dataset.pointBorderWidth !== undefined) {
|
|
borderWidth = helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, borderWidth);
|
|
} else if (dataset.borderWidth !== undefined) {
|
|
borderWidth = dataset.borderWidth;
|
|
}
|
|
|
|
return borderWidth;
|
|
},
|
|
|
|
updateElement: function(point, index, reset) {
|
|
var meta = this.getMeta();
|
|
var yScale = this.getScaleForId(meta.yAxisID);
|
|
var xScale = this.getScaleForId(meta.xAxisID);
|
|
var scaleBase;
|
|
|
|
if (yScale.min < 0 && yScale.max < 0) {
|
|
scaleBase = yScale.getPixelForValue(yScale.max);
|
|
} else if (yScale.min > 0 && yScale.max > 0) {
|
|
scaleBase = yScale.getPixelForValue(yScale.min);
|
|
} else {
|
|
scaleBase = yScale.getPixelForValue(0);
|
|
}
|
|
|
|
// Utility
|
|
point._chart = this.chart.chart;
|
|
point._xScale = xScale;
|
|
point._yScale = yScale;
|
|
point._datasetIndex = this.index;
|
|
point._index = index;
|
|
|
|
// Desired view properties
|
|
|
|
// Compatibility: If the properties are defined with only the old name, use those values
|
|
if ((this.getDataset().radius !== undefined) && (this.getDataset().pointRadius === undefined))
|
|
{
|
|
this.getDataset().pointRadius = this.getDataset().radius;
|
|
}
|
|
if ((this.getDataset().hitRadius !== undefined) && (this.getDataset().pointHitRadius === undefined))
|
|
{
|
|
this.getDataset().pointHitRadius = this.getDataset().hitRadius;
|
|
}
|
|
|
|
point._model = {
|
|
x: xScale.getPixelForValue(this.getDataset().data[index], index, this.index, this.chart.isCombo),
|
|
y: reset ? scaleBase : this.calculatePointY(this.getDataset().data[index], index, this.index, this.chart.isCombo),
|
|
// Appearance
|
|
radius: point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.getDataset().pointRadius, index, this.chart.options.elements.point.radius),
|
|
pointStyle: point.custom && point.custom.pointStyle ? point.custom.pointStyle : helpers.getValueAtIndexOrDefault(this.getDataset().pointStyle, index, this.chart.options.elements.point.pointStyle),
|
|
backgroundColor: this.getPointBackgroundColor(point, index),
|
|
borderColor: this.getPointBorderColor(point, index),
|
|
borderWidth: this.getPointBorderWidth(point, index),
|
|
// Tooltip
|
|
hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().pointHitRadius, index, this.chart.options.elements.point.hitRadius)
|
|
};
|
|
|
|
point._model.skip = point.custom && point.custom.skip ? point.custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
|
|
},
|
|
|
|
calculatePointY: function(value, index, datasetIndex, isCombo) {
|
|
var meta = this.getMeta();
|
|
var xScale = this.getScaleForId(meta.xAxisID);
|
|
var yScale = this.getScaleForId(meta.yAxisID);
|
|
|
|
if (yScale.options.stacked) {
|
|
|
|
var sumPos = 0,
|
|
sumNeg = 0;
|
|
|
|
for (var i = 0; i < datasetIndex; i++) {
|
|
var ds = this.chart.data.datasets[i];
|
|
var dsMeta = this.chart.getDatasetMeta(i);
|
|
if (dsMeta.type === 'line' && helpers.isDatasetVisible(ds)) {
|
|
if (ds.data[index] < 0) {
|
|
sumNeg += ds.data[index] || 0;
|
|
} else {
|
|
sumPos += ds.data[index] || 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (value < 0) {
|
|
return yScale.getPixelForValue(sumNeg + value);
|
|
} else {
|
|
return yScale.getPixelForValue(sumPos + value);
|
|
}
|
|
}
|
|
|
|
return yScale.getPixelForValue(value);
|
|
},
|
|
|
|
updateBezierControlPoints: function() {
|
|
// Update bezier control points
|
|
var meta = this.getMeta();
|
|
helpers.each(meta.data, function(point, index) {
|
|
var controlPoints = helpers.splineCurve(
|
|
helpers.previousItem(meta.data, index)._model,
|
|
point._model,
|
|
helpers.nextItem(meta.data, index)._model,
|
|
meta.dataset._model.tension
|
|
);
|
|
|
|
// Prevent the bezier going outside of the bounds of the graph
|
|
point._model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, this.chart.chartArea.right), this.chart.chartArea.left);
|
|
point._model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, this.chart.chartArea.bottom), this.chart.chartArea.top);
|
|
|
|
point._model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, this.chart.chartArea.right), this.chart.chartArea.left);
|
|
point._model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, this.chart.chartArea.bottom), this.chart.chartArea.top);
|
|
|
|
// Now pivot the point for animation
|
|
point.pivot();
|
|
}, this);
|
|
},
|
|
|
|
draw: function(ease) {
|
|
var meta = this.getMeta();
|
|
var easingDecimal = ease || 1;
|
|
|
|
// Transition Point Locations
|
|
helpers.each(meta.data, function(point) {
|
|
point.transition(easingDecimal);
|
|
});
|
|
|
|
// Transition and Draw the line
|
|
if (this.chart.options.showLines)
|
|
meta.dataset.transition(easingDecimal).draw();
|
|
|
|
// Draw the points
|
|
helpers.each(meta.data, function(point) {
|
|
point.draw();
|
|
});
|
|
},
|
|
|
|
setHoverStyle: function(point) {
|
|
// Point
|
|
var dataset = this.chart.data.datasets[point._datasetIndex];
|
|
var index = point._index;
|
|
|
|
point._model.radius = point.custom && point.custom.hoverRadius ? point.custom.hoverRadius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
|
|
point._model.backgroundColor = point.custom && point.custom.hoverBackgroundColor ? point.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.color(point._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
|
|
point._model.borderColor = point.custom && point.custom.hoverBorderColor ? point.custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.color(point._model.borderColor).saturate(0.5).darken(0.1).rgbString());
|
|
point._model.borderWidth = point.custom && point.custom.hoverBorderWidth ? point.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, point._model.borderWidth);
|
|
},
|
|
|
|
removeHoverStyle: function(point) {
|
|
var dataset = this.chart.data.datasets[point._datasetIndex];
|
|
var index = point._index;
|
|
|
|
// Compatibility: If the properties are defined with only the old name, use those values
|
|
if ((this.getDataset().radius !== undefined) && (this.getDataset().pointRadius === undefined))
|
|
{
|
|
this.getDataset().pointRadius = this.getDataset().radius;
|
|
}
|
|
|
|
point._model.radius = point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.getDataset().pointRadius, index, this.chart.options.elements.point.radius);
|
|
point._model.backgroundColor = this.getPointBackgroundColor(point, index);
|
|
point._model.borderColor = this.getPointBorderColor(point, index);
|
|
point._model.borderWidth = this.getPointBorderWidth(point, index);
|
|
}
|
|
});
|
|
};
|