2016-02-12 04:30:53 +01:00
|
|
|
"use strict";
|
|
|
|
|
|
|
|
module.exports = function(Chart) {
|
|
|
|
|
2016-02-14 23:06:00 +01:00
|
|
|
var helpers = Chart.helpers;
|
2016-05-14 05:07:39 +02:00
|
|
|
var globalDefaults = Chart.defaults.global;
|
2016-02-14 23:06:00 +01:00
|
|
|
|
|
|
|
Chart.defaults.global.elements.line = {
|
|
|
|
tension: 0.4,
|
2016-05-14 05:07:39 +02:00
|
|
|
backgroundColor: globalDefaults.defaultColor,
|
2016-02-14 23:06:00 +01:00
|
|
|
borderWidth: 3,
|
2016-05-14 05:07:39 +02:00
|
|
|
borderColor: globalDefaults.defaultColor,
|
2016-02-14 23:06:00 +01:00
|
|
|
borderCapStyle: 'butt',
|
|
|
|
borderDash: [],
|
|
|
|
borderDashOffset: 0.0,
|
|
|
|
borderJoinStyle: 'miter',
|
|
|
|
fill: true // do we fill in the area between the line and its base axis
|
|
|
|
};
|
|
|
|
|
|
|
|
Chart.elements.Line = Chart.Element.extend({
|
|
|
|
lineToNextPoint: function(previousPoint, point, nextPoint, skipHandler, previousSkipHandler) {
|
2016-06-04 20:14:16 +02:00
|
|
|
var me = this;
|
|
|
|
var ctx = me._chart.ctx;
|
2016-06-07 09:15:26 +02:00
|
|
|
var spanGaps = me._view ? me._view.spanGaps : false;
|
2016-02-14 23:06:00 +01:00
|
|
|
|
2016-06-07 09:15:26 +02:00
|
|
|
if (point._view.skip && !spanGaps) {
|
2016-06-04 20:14:16 +02:00
|
|
|
skipHandler.call(me, previousPoint, point, nextPoint);
|
2016-06-07 09:15:26 +02:00
|
|
|
} else if (previousPoint._view.skip && !spanGaps) {
|
2016-06-04 20:14:16 +02:00
|
|
|
previousSkipHandler.call(me, previousPoint, point, nextPoint);
|
2016-02-14 23:06:00 +01:00
|
|
|
} else if (point._view.tension === 0) {
|
|
|
|
ctx.lineTo(point._view.x, point._view.y);
|
|
|
|
} else {
|
|
|
|
// Line between points
|
|
|
|
ctx.bezierCurveTo(
|
|
|
|
previousPoint._view.controlPointNextX,
|
|
|
|
previousPoint._view.controlPointNextY,
|
|
|
|
point._view.controlPointPreviousX,
|
|
|
|
point._view.controlPointPreviousY,
|
|
|
|
point._view.x,
|
|
|
|
point._view.y
|
|
|
|
);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
draw: function() {
|
2016-06-04 20:14:16 +02:00
|
|
|
var me = this;
|
2016-02-14 23:06:00 +01:00
|
|
|
|
2016-06-04 20:14:16 +02:00
|
|
|
var vm = me._view;
|
|
|
|
var ctx = me._chart.ctx;
|
|
|
|
var first = me._children[0];
|
|
|
|
var last = me._children[me._children.length - 1];
|
2016-02-14 23:06:00 +01:00
|
|
|
|
|
|
|
function loopBackToStart(drawLineToCenter) {
|
|
|
|
if (!first._view.skip && !last._view.skip) {
|
|
|
|
// Draw a bezier line from last to first
|
|
|
|
ctx.bezierCurveTo(
|
|
|
|
last._view.controlPointNextX,
|
|
|
|
last._view.controlPointNextY,
|
|
|
|
first._view.controlPointPreviousX,
|
|
|
|
first._view.controlPointPreviousY,
|
|
|
|
first._view.x,
|
|
|
|
first._view.y
|
|
|
|
);
|
|
|
|
} else if (drawLineToCenter) {
|
|
|
|
// Go to center
|
2016-06-04 20:14:16 +02:00
|
|
|
ctx.lineTo(me._view.scaleZero.x, me._view.scaleZero.y);
|
2016-02-14 23:06:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.save();
|
|
|
|
|
|
|
|
// If we had points and want to fill this line, do so.
|
2016-06-04 20:14:16 +02:00
|
|
|
if (me._children.length > 0 && vm.fill) {
|
2016-02-14 23:06:00 +01:00
|
|
|
// Draw the background first (so the border is always on top)
|
|
|
|
ctx.beginPath();
|
|
|
|
|
2016-06-04 20:14:16 +02:00
|
|
|
helpers.each(me._children, function(point, index) {
|
|
|
|
var previous = helpers.previousItem(me._children, index);
|
|
|
|
var next = helpers.nextItem(me._children, index);
|
2016-02-14 23:06:00 +01:00
|
|
|
|
|
|
|
// First point moves to it's starting position no matter what
|
|
|
|
if (index === 0) {
|
2016-06-04 20:14:16 +02:00
|
|
|
if (me._loop) {
|
2016-02-14 23:06:00 +01:00
|
|
|
ctx.moveTo(vm.scaleZero.x, vm.scaleZero.y);
|
|
|
|
} else {
|
|
|
|
ctx.moveTo(point._view.x, vm.scaleZero);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (point._view.skip) {
|
2016-06-04 20:14:16 +02:00
|
|
|
if (!me._loop) {
|
|
|
|
ctx.moveTo(next._view.x, me._view.scaleZero);
|
2016-02-14 23:06:00 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ctx.lineTo(point._view.x, point._view.y);
|
|
|
|
}
|
|
|
|
} else {
|
2016-06-04 20:14:16 +02:00
|
|
|
me.lineToNextPoint(previous, point, next, function(previousPoint, point, nextPoint) {
|
|
|
|
if (me._loop) {
|
2016-02-14 23:06:00 +01:00
|
|
|
// Go to center
|
2016-06-04 20:14:16 +02:00
|
|
|
ctx.lineTo(me._view.scaleZero.x, me._view.scaleZero.y);
|
2016-02-14 23:06:00 +01:00
|
|
|
} else {
|
2016-06-04 20:14:16 +02:00
|
|
|
ctx.lineTo(previousPoint._view.x, me._view.scaleZero);
|
|
|
|
ctx.moveTo(nextPoint._view.x, me._view.scaleZero);
|
2016-02-14 23:06:00 +01:00
|
|
|
}
|
|
|
|
}, function(previousPoint, point) {
|
|
|
|
// If we skipped the last point, draw a line to ourselves so that the fill is nice
|
|
|
|
ctx.lineTo(point._view.x, point._view.y);
|
|
|
|
});
|
|
|
|
}
|
2016-06-04 20:14:16 +02:00
|
|
|
}, me);
|
2016-02-14 23:06:00 +01:00
|
|
|
|
|
|
|
// For radial scales, loop back around to the first point
|
2016-06-04 20:14:16 +02:00
|
|
|
if (me._loop) {
|
2016-02-14 23:06:00 +01:00
|
|
|
loopBackToStart(true);
|
|
|
|
} else {
|
|
|
|
//Round off the line by going to the base of the chart, back to the start, then fill.
|
2016-06-04 20:14:16 +02:00
|
|
|
ctx.lineTo(me._children[me._children.length - 1]._view.x, vm.scaleZero);
|
|
|
|
ctx.lineTo(me._children[0]._view.x, vm.scaleZero);
|
2016-02-14 23:06:00 +01:00
|
|
|
}
|
|
|
|
|
2016-05-14 05:07:39 +02:00
|
|
|
ctx.fillStyle = vm.backgroundColor || globalDefaults.defaultColor;
|
2016-02-14 23:06:00 +01:00
|
|
|
ctx.closePath();
|
|
|
|
ctx.fill();
|
|
|
|
}
|
|
|
|
|
2016-05-14 05:07:39 +02:00
|
|
|
var globalOptionLineElements = globalDefaults.elements.line;
|
2016-02-14 23:06:00 +01:00
|
|
|
// Now draw the line between all the points with any borders
|
2016-05-14 05:07:39 +02:00
|
|
|
ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle;
|
2016-02-14 23:06:00 +01:00
|
|
|
|
|
|
|
// IE 9 and 10 do not support line dash
|
|
|
|
if (ctx.setLineDash) {
|
2016-05-14 05:07:39 +02:00
|
|
|
ctx.setLineDash(vm.borderDash || globalOptionLineElements.borderDash);
|
2016-02-14 23:06:00 +01:00
|
|
|
}
|
|
|
|
|
2016-05-14 05:07:39 +02:00
|
|
|
ctx.lineDashOffset = vm.borderDashOffset || globalOptionLineElements.borderDashOffset;
|
|
|
|
ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle;
|
|
|
|
ctx.lineWidth = vm.borderWidth || globalOptionLineElements.borderWidth;
|
|
|
|
ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor;
|
2016-02-14 23:06:00 +01:00
|
|
|
ctx.beginPath();
|
|
|
|
|
2016-06-04 20:14:16 +02:00
|
|
|
helpers.each(me._children, function(point, index) {
|
|
|
|
var previous = helpers.previousItem(me._children, index);
|
|
|
|
var next = helpers.nextItem(me._children, index);
|
2016-02-14 23:06:00 +01:00
|
|
|
|
|
|
|
if (index === 0) {
|
|
|
|
ctx.moveTo(point._view.x, point._view.y);
|
|
|
|
} else {
|
2016-06-04 20:14:16 +02:00
|
|
|
me.lineToNextPoint(previous, point, next, function(previousPoint, point, nextPoint) {
|
2016-02-14 23:06:00 +01:00
|
|
|
ctx.moveTo(nextPoint._view.x, nextPoint._view.y);
|
|
|
|
}, function(previousPoint, point) {
|
|
|
|
// If we skipped the last point, move up to our point preventing a line from being drawn
|
|
|
|
ctx.moveTo(point._view.x, point._view.y);
|
|
|
|
});
|
|
|
|
}
|
2016-06-04 20:14:16 +02:00
|
|
|
}, me);
|
2016-02-14 23:06:00 +01:00
|
|
|
|
2016-06-04 20:14:16 +02:00
|
|
|
if (me._loop && me._children.length > 0) {
|
2016-02-14 23:06:00 +01:00
|
|
|
loopBackToStart();
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.stroke();
|
|
|
|
ctx.restore();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|