(function( w ) {
/*
* constructor { LineChart } 折线图构造函数
* param { ctx: Context } 绘图上下文
* param { paddingArr: Array } 折线图到画布四边的距离,存储顺序为上右下左
* param { arrowArr: Array } 折线图中箭头的宽和高
* param { data: Array } 存储了折线图中所需的数据
* */
function LineChart( ctx, data, paddingArr, arrowArr ) {
this.ctx = ctx;
this.paddingArr = paddingArr || [ 20, 20, 20, 20 ];

this.arrowArr = arrowArr || [ 10, 20 ];
this.arrowWidth = this.arrowArr[0];
this.arrowHeight = this.arrowArr[1];

this.data = data;

// 计算上顶点的坐标
this.vertexTop = {
x: this.paddingArr[ 3 ],
y: this.paddingArr[ 0 ]
};

// 计算原点的坐标
this.origin = {
x: this.paddingArr[ 3 ],
y: this.ctx.canvas.height - this.paddingArr[ 2 ]
};

// 计算右顶点的坐标
this.vertexRight = {
x: this.ctx.canvas.width - this.paddingArr[ 1 ],
y: this.ctx.canvas.height - this.paddingArr[ 2 ]
};

// 根据数据得到对应的坐标
this.processData();
}

// 置换原型
LineChart.prototype = {

constructor: LineChart,

// 绘制折线图
draw: function() {
this.drawCoordinate();
this.drawArrow();
this.drawPoint();
this.drawLine();
},

// 绘制坐标轴中的两条线
drawCoordinate: function() {
this.ctx.beginPath();
this.ctx.moveTo( this.vertexTop.x, this.vertexTop.y );
this.ctx.lineTo( this.origin.x, this.origin.y );
this.ctx.lineTo( this.vertexRight.x, this.vertexRight.y );
this.ctx.stroke();
},

// 绘制坐标轴中的两个箭头
drawArrow: function() {

// 先绘制上面箭头
this.ctx.beginPath();
this.ctx.moveTo( this.vertexTop.x, this.vertexTop.y );
this.ctx.lineTo( this.vertexTop.x - this.arrowWidth / 2, this.vertexTop.y + this.arrowHeight );
this.ctx.lineTo( this.vertexTop.x, this.vertexTop.y + this.arrowHeight / 2 );
this.ctx.lineTo( this.vertexTop.x + this.arrowWidth / 2, this.vertexTop.y + this.arrowHeight );
this.ctx.closePath();
this.ctx.stroke();

// 再绘制右面箭头
this.ctx.beginPath();
this.ctx.moveTo( this.vertexRight.x, this.vertexRight.y );
this.ctx.lineTo( this.vertexRight.x - this.arrowHeight, this.vertexRight.y - this.arrowWidth / 2 );
this.ctx.lineTo( this.vertexRight.x - this.arrowHeight / 2, this.vertexRight.y );
this.ctx.lineTo( this.vertexRight.x - this.arrowHeight, this.vertexRight.y + this.arrowWidth / 2 );
this.ctx.closePath();
this.ctx.stroke();
},

// 把传入进来的数据转化为对应画布的坐标
processData: function() {

// 计算x轴可表示的刻度范围
this.rangeX = this.ctx.canvas.width - this.paddingArr[3] - this.paddingArr[1] - this.arrowArr[1];
// 计算单位数据占用多少x轴
this.unitX = this.rangeX / (this.data.length - 1);

// 计算y轴可表示的刻度范围
this.rangeY = this.ctx.canvas.height - this.paddingArr[0] - this.paddingArr[2] - this.arrowArr[1];
// 计算单位数据占用多少y轴
this.unitY = this.rangeY / Math.max.apply( null, this.data );

// 用来存储转换后的坐标数据
this.processArr = [];

// 遍历所有的数据,依次转换为对应的坐标
for( var i = 0, len = this.data.length; i < len; i++ ) {
/*
* 数据转化为相当于画布的坐标:
* canvasX = this.origin.x + this.unitX * i
* canvasY = this.origin.y - this.unitY * y
* */
this.processArr.push( this.origin.x + this.unitX * i );
this.processArr.push( this.origin.y - this.unitY * this.data[ i ] );
}
},

// 根据数据绘制相应的点
drawPoint: function() {
var r = 4;

// 遍历所有的坐标,依次绘制点
for( var i = 0, len = this.processArr.length; i < len; i+=2 ) {
this.ctx.beginPath();
this.ctx.arc( this.processArr[ i ], this.processArr[ i + 1 ], r, 0, Math.PI*2 );
this.ctx.fill();
}
},

// 根据数据绘制折线
drawLine: function() {
this.ctx.beginPath();
for( var i = 0, len = this.processArr.length; i < len; i+=2 ) {
this.ctx.lineTo( this.processArr[ i ], this.processArr[ i + 1 ] );
}
this.ctx.stroke();
}
};

// 给原型添加一个绘制折线图的方法
jQuery.fn.extend({

// 在第一个元素中,按照指定的数据绘制折线图
lineChart: function( data ) {

/*
* 实现思路:
* 1、动态创建canvas元素,并且获取绘图环境
* 2、获取第一个元素的大小,按照这个大小动态设置画布的大小
* 3、创建折线图对象,调用draw方法绘制
* 4、把绘制好的画布添加到第一个元素中
* */

// 获取第一个元素
var $first = this.first();

// 根据元素的大小动态设置画布的大小
var $cvs = $('<canvas></canvas>').attr({
width: parseInt( $first.css( 'width' ) ),
height: parseInt( $first.css( 'height' ) ),
});
var ctx = $cvs.get(0).getContext( '2d' );

// 在画布中绘制折线图
var lineChart = new LineChart( ctx, data );
lineChart.draw();

// 把绘制好的画布添加到第一个元素中
$first.append( $cvs );
}
});

}( window ));