mirror of
https://github.com/chartjs/Chart.js.git
synced 2026-03-25 01:26:53 +01:00
328 lines
11 KiB
JavaScript
328 lines
11 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 lineElementOptions = this.chart.options.elements.line;
|
|
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
|
|
|
|
var dataset = this.getDataset();
|
|
var custom = line.custom || {};
|
|
// Compatibility: If the properties are defined with only the old name, use those values
|
|
if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
|
|
dataset.lineTension = dataset.tension;
|
|
}
|
|
|
|
line._model = {
|
|
// Appearance
|
|
tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.lineTension, lineElementOptions.tension),
|
|
backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
|
|
borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
|
|
borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
|
|
borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
|
|
borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
|
|
borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
|
|
borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
|
|
fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.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 && lineElementOptions.tension !== 0) {
|
|
this.updateBezierControlPoints();
|
|
}
|
|
},
|
|
|
|
getPointBackgroundColor: function(point, index) {
|
|
var backgroundColor = this.chart.options.elements.point.backgroundColor;
|
|
var dataset = this.getDataset();
|
|
var custom = point.custom || {};
|
|
|
|
if (custom.backgroundColor) {
|
|
backgroundColor = 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();
|
|
var custom = point.custom || {};
|
|
|
|
if (custom.borderColor) {
|
|
borderColor = custom.borderColor;
|
|
} else if (dataset.pointBorderColor) {
|
|
borderColor = helpers.getValueAtIndexOrDefault(dataset.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();
|
|
var custom = point.custom || {};
|
|
|
|
if (custom.borderWidth) {
|
|
borderWidth = custom.borderWidth;
|
|
} else if (dataset.pointBorderWidth) {
|
|
borderWidth = helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, borderWidth);
|
|
} else if (dataset.borderWidth) {
|
|
borderWidth = dataset.borderWidth;
|
|
}
|
|
|
|
return borderWidth;
|
|
},
|
|
|
|
updateElement: function(point, index, reset) {
|
|
var meta = this.getMeta();
|
|
var custom = point.custom || {};
|
|
var dataset = this.getDataset();
|
|
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 ((dataset.radius !== undefined) && (dataset.pointRadius === undefined))
|
|
{
|
|
dataset.pointRadius = dataset.radius;
|
|
}
|
|
if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined))
|
|
{
|
|
dataset.pointHitRadius = dataset.hitRadius;
|
|
}
|
|
|
|
point._model = {
|
|
x: xScale.getPixelForValue(dataset.data[index], index, this.index, this.chart.isCombo),
|
|
y: reset ? scaleBase : this.calculatePointY(dataset.data[index], index, this.index, this.chart.isCombo),
|
|
// Appearance
|
|
radius: custom.radius ? custom.radius : helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, this.chart.options.elements.point.radius),
|
|
pointStyle: custom.pointStyle ? custom.pointStyle : helpers.getValueAtIndexOrDefault(dataset.pointStyle, index, this.chart.options.elements.point.pointStyle),
|
|
backgroundColor: this.getPointBackgroundColor(point, index),
|
|
borderColor: this.getPointBorderColor(point, index),
|
|
borderWidth: this.getPointBorderWidth(point, index),
|
|
tension: meta.dataset._model ? meta.dataset._model.tension : 0,
|
|
// Tooltip
|
|
hitRadius: custom.hitRadius ? custom.hitRadius : helpers.getValueAtIndexOrDefault(dataset.pointHitRadius, index, this.chart.options.elements.point.hitRadius)
|
|
};
|
|
|
|
point._model.skip = custom.skip ? 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' && this.chart.isDatasetVisible(i)) {
|
|
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;
|
|
var custom = point.custom || {};
|
|
var model = point._model;
|
|
|
|
model.radius = custom.hoverRadius ? custom.hoverRadius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
|
|
model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
|
|
model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
|
|
model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
|
|
},
|
|
|
|
removeHoverStyle: function(point) {
|
|
var dataset = this.chart.data.datasets[point._datasetIndex];
|
|
var index = point._index;
|
|
var custom = point.custom || {};
|
|
var model = point._model;
|
|
|
|
// Compatibility: If the properties are defined with only the old name, use those values
|
|
if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined))
|
|
{
|
|
dataset.pointRadius = dataset.radius;
|
|
}
|
|
|
|
model.radius = custom.radius ? custom.radius : helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, this.chart.options.elements.point.radius);
|
|
model.backgroundColor = this.getPointBackgroundColor(point, index);
|
|
model.borderColor = this.getPointBorderColor(point, index);
|
|
model.borderWidth = this.getPointBorderWidth(point, index);
|
|
}
|
|
});
|
|
};
|