| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 | 'use strict';module.exports = function(Chart) {	var helpers = Chart.helpers;	var globalDefaults = Chart.defaults.global;	Chart.defaults.global.elements.line = {		tension: 0.4,		backgroundColor: globalDefaults.defaultColor,		borderWidth: 3,		borderColor: globalDefaults.defaultColor,		borderCapStyle: 'butt',		borderDash: [],		borderDashOffset: 0.0,		borderJoinStyle: 'miter',		capBezierPoints: true,		fill: true, // do we fill in the area between the line and its base axis	};	Chart.elements.Line = Chart.Element.extend({		draw: function() {			var me = this;			var vm = me._view;			var spanGaps = vm.spanGaps;			var fillPoint = vm.scaleZero;			var loop = me._loop;			// Handle different fill modes for cartesian lines			if (!loop) {				if (vm.fill === 'top') {					fillPoint = vm.scaleTop;				} else if (vm.fill === 'bottom') {					fillPoint = vm.scaleBottom;				}			}			var ctx = me._chart.ctx;			ctx.save();			// Helper function to draw a line to a point			function lineToPoint(previousPoint, point) {				var pointVM = point._view;				if (point._view.steppedLine === true) {					ctx.lineTo(pointVM.x, previousPoint._view.y);					ctx.lineTo(pointVM.x, pointVM.y);				} else if (point._view.tension === 0) {					ctx.lineTo(pointVM.x, pointVM.y);				} else {					ctx.bezierCurveTo(						previousPoint._view.controlPointNextX,						previousPoint._view.controlPointNextY,						pointVM.controlPointPreviousX,						pointVM.controlPointPreviousY,						pointVM.x,						pointVM.y					);				}			}			var points = me._children.slice(); // clone array			var lastDrawnIndex = -1;			// If we are looping, adding the first point again			if (loop && points.length) {				points.push(points[0]);			}			var index, current, previous, currentVM;			// Fill Line			if (points.length && vm.fill) {				ctx.beginPath();				for (index = 0; index < points.length; ++index) {					current = points[index];					previous = helpers.previousItem(points, index);					currentVM = current._view;					// First point moves to it's starting position no matter what					if (index === 0) {						if (loop) {							ctx.moveTo(fillPoint.x, fillPoint.y);						} else {							ctx.moveTo(currentVM.x, fillPoint);						}						if (!currentVM.skip) {							lastDrawnIndex = index;							ctx.lineTo(currentVM.x, currentVM.y);						}					} else {						previous = lastDrawnIndex === -1 ? previous : points[lastDrawnIndex];						if (currentVM.skip) {							// Only do this if this is the first point that is skipped							if (!spanGaps && lastDrawnIndex === (index - 1)) {								if (loop) {									ctx.lineTo(fillPoint.x, fillPoint.y);								} else {									ctx.lineTo(previous._view.x, fillPoint);								}							}						} else {							if (lastDrawnIndex !== (index - 1)) {								// There was a gap and this is the first point after the gap. If we've never drawn a point, this is a special case.								// If the first data point is NaN, then there is no real gap to skip								if (spanGaps && lastDrawnIndex !== -1) {									// We are spanning the gap, so simple draw a line to this point									lineToPoint(previous, current);								} else if (loop) {									ctx.lineTo(currentVM.x, currentVM.y);								} else {									ctx.lineTo(currentVM.x, fillPoint);									ctx.lineTo(currentVM.x, currentVM.y);								}							} else {								// Line to next point								lineToPoint(previous, current);							}							lastDrawnIndex = index;						}					}				}				if (!loop && lastDrawnIndex !== -1) {					ctx.lineTo(points[lastDrawnIndex]._view.x, fillPoint);				}				ctx.fillStyle = vm.backgroundColor || globalDefaults.defaultColor;				ctx.closePath();				ctx.fill();			}			// Stroke Line Options			var globalOptionLineElements = globalDefaults.elements.line;			ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle;			// IE 9 and 10 do not support line dash			if (ctx.setLineDash) {				ctx.setLineDash(vm.borderDash || globalOptionLineElements.borderDash);			}			ctx.lineDashOffset = vm.borderDashOffset || globalOptionLineElements.borderDashOffset;			ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle;			ctx.lineWidth = vm.borderWidth || globalOptionLineElements.borderWidth;			ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor;			// Stroke Line			ctx.beginPath();			lastDrawnIndex = -1;			for (index = 0; index < points.length; ++index) {				current = points[index];				previous = helpers.previousItem(points, index);				currentVM = current._view;				// First point moves to it's starting position no matter what				if (index === 0) {					if (!currentVM.skip) {						ctx.moveTo(currentVM.x, currentVM.y);						lastDrawnIndex = index;					}				} else {					previous = lastDrawnIndex === -1 ? previous : points[lastDrawnIndex];					if (!currentVM.skip) {						if ((lastDrawnIndex !== (index - 1) && !spanGaps) || lastDrawnIndex === -1) {							// There was a gap and this is the first point after the gap							ctx.moveTo(currentVM.x, currentVM.y);						} else {							// Line to next point							lineToPoint(previous, current);						}						lastDrawnIndex = index;					}				}			}			ctx.stroke();			ctx.restore();		}	});};
 |