(function (){
"use strict";
var root = this, Chart = root.Chart, helpers = Chart.helpers;
var defaultConfig = {
scaleShowGridLines: true ,
scaleGridLineColor: "rgba(0,0,0,.05)",
scaleGridLineWidth: 1,
scaleShowHorizontalLines: true ,
scaleShowVerticalLines: true ,
bezierCurve: true ,
bezierCurveTension: 0.4,
pointDot: true ,
pointDotRadius: 4,
pointDotStrokeWidth: 1,
pointHitDetectionRadius: 20,
datasetStroke: true ,
datasetStrokeWidth: 2,
datasetFill: true ,
legendTemplate: "
-legend\"><% for (var i=0; i- \"><%if(datasets[i].label){%><%=datasets[i].label%><%}%>
<%}%>
",
offsetGridLines: false }
;
Chart.Type.extend({
name: "Line",
defaults: defaultConfig,
initialize: function (data){
this.PointClass = Chart.Point.extend({
offsetGridLines: this.options.offsetGridLines,
strokeWidth: this.options.pointDotStrokeWidth,
radius: this.options.pointDotRadius,
display: this.options.pointDot,
hitDetectionRadius: this.options.pointHitDetectionRadius,
ctx: this.chart.ctx,
inRange: function (mouseX){
return (Math.pow(mouseX - this.x, 2) < Math.pow(this.radius + this.hitDetectionRadius, 2));
}
}
);
this.datasets = [] ;
if (this.options.showTooltips) {
helpers.bindEvents(this, this.options.tooltipEvents, function (evt){
var activePoints = (evt.type !== 'mouseout')? this.getPointsAtEvent(evt): [] ;
this.eachPoints(function (point){
point.restore(['fillColor', 'strokeColor'] );
}
);
helpers.each(activePoints, function (activePoint){
activePoint.fillColor = activePoint.highlightFill;
activePoint.strokeColor = activePoint.highlightStroke;
}
);
this.showTooltip(activePoints);
}
);
}
helpers.each(data.datasets, function (dataset){
var datasetObject = {
label: dataset.label || null ,
fillColor: dataset.fillColor,
strokeColor: dataset.strokeColor,
pointColor: dataset.pointColor,
pointStrokeColor: dataset.pointStrokeColor,
points: [] }
;
this.datasets.push(datasetObject);
helpers.each(dataset.data, function (dataPoint, index){
datasetObject.points.push(new this.PointClass({
value: dataPoint,
label: data.labels[index],
datasetLabel: dataset.label,
strokeColor: dataset.pointStrokeColor,
fillColor: dataset.pointColor,
highlightFill: dataset.pointHighlightFill || dataset.pointColor,
highlightStroke: dataset.pointHighlightStroke || dataset.pointStrokeColor}
));
}
, this);
this.buildScale(data.labels);
this.eachPoints(function (point, index){
helpers.extend(point, {
x: this.scale.calculateX(index),
y: this.scale.endPoint}
);
point.save();
}
, this);
}
, this);
this.render();
}
,
update: function (){
this.scale.update();
helpers.each(this.activeElements, function (activeElement){
activeElement.restore(['fillColor', 'strokeColor'] );
}
);
this.eachPoints(function (point){
point.save();
}
);
this.render();
}
,
eachPoints: function (callback){
helpers.each(this.datasets, function (dataset){
helpers.each(dataset.points, callback, this);
}
, this);
}
,
getPointsAtEvent: function (e){
var pointsArray = [] , eventPosition = helpers.getRelativePosition(e);
helpers.each(this.datasets, function (dataset){
helpers.each(dataset.points, function (point){
if (point.inRange(eventPosition.x, eventPosition.y)) pointsArray.push(point);
}
);
}
, this);
return pointsArray;
}
,
buildScale: function (labels){
var self = this;
var dataTotal = function (){
var values = [] ;
self.eachPoints(function (point){
values.push(point.value);
}
);
return values;
}
;
var scaleOptions = {
templateString: this.options.scaleLabel,
height: this.chart.height,
width: this.chart.width,
ctx: this.chart.ctx,
textColor: this.options.scaleFontColor,
offsetGridLines: this.options.offsetGridLines,
fontSize: this.options.scaleFontSize,
fontStyle: this.options.scaleFontStyle,
fontFamily: this.options.scaleFontFamily,
valuesCount: _AN_Read_length('length', labels),
beginAtZero: this.options.scaleBeginAtZero,
integersOnly: this.options.scaleIntegersOnly,
calculateYRange: function (currentHeight){
var updatedRanges = helpers.calculateScaleRange(dataTotal(), currentHeight, this.fontSize, this.beginAtZero, this.integersOnly);
helpers.extend(this, updatedRanges);
}
,
xLabels: labels,
font: helpers.fontString(this.options.scaleFontSize, this.options.scaleFontStyle, this.options.scaleFontFamily),
lineWidth: this.options.scaleLineWidth,
lineColor: this.options.scaleLineColor,
showHorizontalLines: this.options.scaleShowHorizontalLines,
showVerticalLines: this.options.scaleShowVerticalLines,
gridLineWidth: (this.options.scaleShowGridLines)? this.options.scaleGridLineWidth: 0,
gridLineColor: (this.options.scaleShowGridLines)? this.options.scaleGridLineColor: "rgba(0,0,0,0)",
padding: (this.options.showScale)? 0: this.options.pointDotRadius + this.options.pointDotStrokeWidth,
showLabels: this.options.scaleShowLabels,
display: this.options.showScale}
;
if (this.options.scaleOverride) {
helpers.extend(scaleOptions, {
calculateYRange: helpers.noop,
steps: this.options.scaleSteps,
stepValue: this.options.scaleStepWidth,
min: this.options.scaleStartValue,
max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)}
);
}
this.scale = new Chart.Scale(scaleOptions);
}
,
addData: function (valuesArray, label){
helpers.each(valuesArray, function (value, datasetIndex){
this.datasets[datasetIndex].points.push(new this.PointClass({
value: value,
label: label,
x: this.scale.calculateX(this.scale.valuesCount + 1),
y: this.scale.endPoint,
strokeColor: this.datasets[datasetIndex].pointStrokeColor,
fillColor: this.datasets[datasetIndex].pointColor}
));
}
, this);
this.scale.addXLabel(label);
this.update();
}
,
removeData: function (){
this.scale.removeXLabel();
helpers.each(this.datasets, function (dataset){
dataset.points.shift();
}
, this);
this.update();
}
,
reflow: function (){
var newScaleProps = helpers.extend({
height: this.chart.height,
width: this.chart.width}
);
this.scale.update(newScaleProps);
}
,
draw: function (ease){
var easingDecimal = ease || 1;
_AN_Call_clear("clear", this);
var ctx = this.chart.ctx;
var hasValue = function (item){
return item.value !== null ;
}
, nextPoint = function (point, collection, index){
return helpers.findNextWhere(collection, hasValue, index) || point;
}
, previousPoint = function (point, collection, index){
return helpers.findPreviousWhere(collection, hasValue, index) || point;
}
;
this.scale.draw(easingDecimal);
helpers.each(this.datasets, function (dataset){
var pointsWithValues = helpers.where(dataset.points, hasValue);
helpers.each(dataset.points, function (point, index){
if (point.hasValue()) {
point.transition({
y: this.scale.calculateY(point.value),
x: this.scale.calculateX(index)}
, easingDecimal);
}
}
, this);
if (this.options.bezierCurve) {
helpers.each(pointsWithValues, function (point, index){
var tension = (index > 0 && index < _AN_Read_length("length", pointsWithValues) - 1)? this.options.bezierCurveTension: 0;
point.controlPoints = helpers.splineCurve(previousPoint(point, pointsWithValues, index), point, nextPoint(point, pointsWithValues, index), tension);
if (point.controlPoints.outer.y > this.scale.endPoint) {
point.controlPoints.outer.y = this.scale.endPoint;
}
else if (point.controlPoints.outer.y < this.scale.startPoint) {
point.controlPoints.outer.y = this.scale.startPoint;
}
if (point.controlPoints.inner.y > this.scale.endPoint) {
point.controlPoints.inner.y = this.scale.endPoint;
}
else if (point.controlPoints.inner.y < this.scale.startPoint) {
point.controlPoints.inner.y = this.scale.startPoint;
}
}
, this);
}
ctx.lineWidth = this.options.datasetStrokeWidth;
ctx.strokeStyle = dataset.strokeColor;
ctx.beginPath();
helpers.each(pointsWithValues, function (point, index){
if (index === 0) {
ctx.moveTo(point.x, point.y);
}
else {
if (this.options.bezierCurve) {
var previous = previousPoint(point, pointsWithValues, index);
ctx.bezierCurveTo(previous.controlPoints.outer.x, previous.controlPoints.outer.y, point.controlPoints.inner.x, point.controlPoints.inner.y, point.x, point.y);
}
else {
ctx.lineTo(point.x, point.y);
}
}
}
, this);
ctx.stroke();
if (this.options.datasetFill && _AN_Read_length("length", pointsWithValues) > 0) {
ctx.lineTo(pointsWithValues[_AN_Read_length("length", pointsWithValues) - 1].x, this.scale.endPoint);
ctx.lineTo(pointsWithValues[0].x, this.scale.endPoint);
ctx.fillStyle = dataset.fillColor;
ctx.closePath();
ctx.fill();
}
helpers.each(pointsWithValues, function (point){
point.draw();
}
);
}
, this);
}
}
);
}
).call(this);