需求

前面的几篇文章介绍了如何绘制网格图、坐标系、坐标系中的点,那么本篇章将这些步骤方法,以js原型面向对象的方式开发,编写出一个折线图的示例。

构建对象的思路

为了更加好方便地使用绘画折线图的方法,应该要将其各个绘制写成对应的对象方法。那么构建对象方法有很多种,本篇将使用prototype属性构建绘画折线图的对象。

如果需要构建一个绘画折线图的对象,基于前面几篇绘制网格图、坐标系、坐标系中的点,可以将其中的基本参数、基本方法都设置到这个绘画折线图的对象中。

定义内容如下:

  1. 构建一个绘制折线图的对象 LineChart
  2. LineChart对象首先要有绘制网格图、坐标系、坐标系中的点相关的基本参数,罗列如下:
    2.1 画笔工具 var ctx = myCanvas.getContext('2d');
    2.2 绘制网格图需要的基本参数:网格大小 girdSize、Canvas的width、height
    2.3 绘制坐标系需要的基本参数:坐标系箭头三角形大小 arrowSize、坐标系距离边界的间隙 space
    2.4 绘制坐标系中点的基本参数:点的大小dotSize、点的坐标(应该由后台传参坐标,不应该写死。)
  3. LineChart对象除了基本参数,还要将各种绘制方法定义到对象中,如下:
    3.1 绘制网格图的方法 drawGrid
    3.2 绘制坐标系的方法 drawCoordinates
    3.3 绘制坐标中点的方法 drawPoints
    3.4 绘制将坐标点连成折线的方法 drawLinePath

好了,有了上面的定义内容,就可以开始下面的定义方法。

构建对象的具体代码

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
canvas{
border: 1px solid #cccccc;
margin-top: 100px;
margin-left: 100px;
}
</style>
<script type="text/javascript">
window.onload = function () {

/*
1. 构建一个绘制折线图的对象 LineChart
2. LineChart对象首先要有绘制网格图、坐标系、坐标系中的点相关的基本参数,罗列如下:
2.1 画笔工具 var ctx = myCanvas.getContext('2d');
2.2 绘制网格图需要的基本参数:网格大小 girdSize、Canvas的width、height
2.3 绘制坐标系需要的基本参数:坐标系箭头三角形大小 arrowSize、坐标系距离边界的间隙 space
2.4 绘制坐标系中点的基本参数:点的大小dotSize、点的坐标(应该由后台传参坐标,不应该写死。)
3. LineChart对象除了基本参数,还要将各种绘制方法定义到对象中,如下:
3.1 绘制网格图的方法 drawGrid
3.2 绘制坐标系的方法 drawCoordinates
3.3 绘制坐标中点的方法 drawPoints
3.4 绘制将坐标点连成折线的方法 drawLinePath
*/

// 1. 定义绘制折线图对象
var LineChart = function (ctx) {
/*获取绘图工具*/
this.ctx = ctx || document.querySelector('canvas').getContext('2d');
/*画布的大小*/
this.canvasWidth = this.ctx.canvas.width;
this.canvasHeight = this.ctx.canvas.height;
/*网格的大小*/
this.gridSize = 10;
/*坐标系的间距*/
this.space = 20;
/*坐标原点*/
this.x0 = this.space;
this.y0 = this.canvasHeight - this.space;
/*箭头的大小*/
this.arrowSize = 10;
/*绘制点*/
this.dotSize = 10;
/*点的坐标 和数据有关系 数据可视化*/
};

// 2. 定义LineChart对象的初始化方法
LineChart.prototype.init = function (data) {
this.drawGrid(); // 绘制网格
this.drawCoordinates(); // 绘制坐标系
this.drawPoints(data); // 绘制点
this.drawLinePath(data); // 绘制点与点之间折线的轨迹
};

// 2. 定义绘制网格的对象方法 drawGrid
LineChart.prototype.drawGrid = function () {

this.ctx.strokeStyle = "#ccc"; // 设置每个线条的颜色

// 采用遍历的方式,绘画x轴的线条
var xLineTotals = Math.floor(this.canvasHeight / this.gridSize); // 计算需要绘画的x轴条数
for (var i = 0; i < xLineTotals; i++) {
// console.log(this.gridSize * i - 0.5);
// console.log(this.girdSize * i - 0.5);
this.ctx.beginPath(); // 开启路径,设置不同的样式
this.ctx.moveTo(0, this.gridSize * i - 0.5); // -0.5是为了解决像素模糊问题
this.ctx.lineTo(this.canvasWidth, this.gridSize * i - 0.5);
this.ctx.stroke();
}

// 采用遍历的方式,绘画y轴的线条
var yLineTotals = Math.floor(this.canvasWidth / this.gridSize); // 计算需要绘画y轴的条数
for (var j = 0; j < yLineTotals; j++) {
this.ctx.beginPath(); // 开启路径,设置不同的样式
this.ctx.moveTo(this.gridSize * j, 0);
this.ctx.lineTo(this.gridSize * j, this.canvasHeight);
this.ctx.stroke();
}
};

// 3. 定义绘制坐标系方法
LineChart.prototype.drawCoordinates = function () {

// 计算坐标系y轴的最远坐标点(x1,y1)以及对应三角形的坐标点左边(x2,y2)\右边(x3,y3)
var x1 = this.space;
var y1 = this.space;

var x2 = Math.floor(x1 - this.arrowSize/2);
var y2 = Math.floor(y1 + this.arrowSize);

var x3 = Math.floor(x1 + this.arrowSize/2);
var y3 = Math.floor(y1 + this.arrowSize);

// 绘画y轴的线条
this.ctx.beginPath();
this.ctx.beginPath();
this.ctx.moveTo(this.x0,this.y0); // 原点
this.ctx.lineTo(x1,y1); // y轴最远点

// 绘画y轴三角形
this.ctx.lineTo(x2,y2); // 三角形左边点
this.ctx.lineTo(x3,y3); // 三角形右边点
this.ctx.lineTo(x1,y1); // 回到y轴最远点

// 填充以及描边y轴
this.ctx.strokeStyle = "#000";
this.ctx.fill();
this.ctx.stroke();

// 计算坐标系x轴的最远坐标点(x4,y4)以及对应三角形的坐标点上边(x5,y5)\下边(x6,y6)
var x4 = this.canvasWidth - this.space;
var y4 = this.canvasHeight - this.space;

var x5 = Math.floor(x4 - this.arrowSize);
var y5 = Math.floor(y4 - this.arrowSize/2);

var x6 = Math.floor(x4 - this.arrowSize);
var y6 = Math.floor(y4 + this.arrowSize/2);

// 9.绘制x轴线条
this.ctx.beginPath();
this.ctx.moveTo(this.x0,this.y0); // 原点
this.ctx.lineTo(x4,y4); // x轴最远点

// 10.绘制三角形
this.ctx.lineTo(x5,y5); // 三角形的上边
this.ctx.lineTo(x6,y6); // 三角形的下边
this.ctx.lineTo(x4,y4); // 回到x轴最远点

// 11.填充以及描边
this.ctx.strokeStyle = "#000";
this.ctx.fill();
this.ctx.stroke();
};

// 4. 定义绘制坐标系多点的方法
LineChart.prototype.drawPoints = function (data) {

/*
1. 设置坐标点的中心圆点位置(x0,y0)
2. 设置坐标点的大小 dotSize
3. 计算坐标点的上下左右四角的点坐标
*/

// 获取画笔ctx
ctx = this.ctx;

// 设置坐标点的大小 dotSize
var dotSize = this.dotSize;

// 4.遍历点的坐标,以及绘画点
data.forEach(function (item,i) {
console.log("i = " + i + ", x = " + item.x + ", y = " + item.y);

// 1. 设置坐标点的中心圆点位置(x0,y0)
var x0 = item.x;
var y0 = item.y;
console.log("坐标点的重点原点位置 x0 = " + x0 + ", y0 = " + y0);

// 2.计算坐标点的上下左右四角的点坐标: 左上(x1,y1) 左下(x2,y2) 右上(x3,y3) 右下(x4,y4)

var x1 = Math.floor(x0 - dotSize/2);
var y1 = Math.floor(y0 - dotSize/2);

var x2 = Math.floor(x0 - dotSize/2);
var y2 = Math.floor(y0 + dotSize/2);

var x3 = Math.floor(x0 + dotSize/2);
var y3 = Math.floor(y0 - dotSize/2);

var x4 = Math.floor(x0 + dotSize/2);
var y4 = Math.floor(y0 + dotSize/2);

console.log("左上 x1 = " + x1 + ", y1 = " + y1);
console.log("左下 x2 = " + x2 + ", y2 = " + y2);
console.log("右上 x3 = " + x3 + ", y3 = " + y3);
console.log("右下 x4 = " + x4 + ", y4 = " + y4);

// 3.绘画坐标点

ctx.beginPath();
ctx.beginPath();
ctx.moveTo(x1,y1); // 左上点
ctx.lineTo(x2,y2); // 左下点
ctx.lineTo(x4,y4); // 右下点
ctx.lineTo(x3,y3); // 右上点
ctx.closePath();

// 4.填充以及描边y轴
ctx.fill();
});
};

// 5. 定义绘制坐标系多点的折现
LineChart.prototype.drawLinePath = function (data) {

/*获取绘图工具*/
var ctx = this.ctx;

// 设置坐标系与边界的间隙大小
var space = this.space;

// 2. 获取Canvas的width、height
var canvasWidth = this.canvasWidth;
var canvasHeight = this.canvasHeight;

// 3.计算坐标系的原点坐标(x0,y0)
var x0 = this.space;
var y0 = canvasHeight - space;

/*
遍历绘画多点连接的折线
1. 第一个点与坐标系原点连成一条线
2. 从第二个点开始与上一个点连成一条线,所以需要记录上一个点的坐标
*/

// 记录上一个点坐标
var prev_point_x = null;
var prev_point_y = null;

data.forEach(function (item,i) {
console.log("绘制折线: i = " + i + ", x = " + item.x + ", y = " + item.y);

if (i===0){
console.log("坐标系的原点坐标:x0 = " + x0 + ", y0 = " + y0);
console.log("第一个点的坐标: x = " + item.x + ", y = " + item.y);

// 第一个点与坐标系原点连成一条线
ctx.beginPath();
ctx.moveTo(x0,y0); // 坐标系原点
ctx.lineTo(item.x,item.y); // 第一个点
ctx.stroke();

// 记录当前的点为下一个点的坐标的出发点坐标
prev_point_x = item.x;
prev_point_y = item.y;

}else{ // 从第二个点开始与上一个点连成一条线,所以需要记录上一个点的坐标

ctx.beginPath();
ctx.moveTo(prev_point_x,prev_point_y); // 设置上一个点的坐标为出发点
ctx.lineTo(item.x, item.y); // 设置当前点为终点
ctx.stroke();

// 记录当前的点为下一个点的坐标的出发点坐标
prev_point_x = item.x;
prev_point_y = item.y;

}

})

};

// 定义需要绘制的点坐标
var points = [
{
x: 30,
y: 80,
},
{
x: 40,
y: 120,
},
{
x: 100,
y: 200,
},
{
x: 150,
y: 300,
},
{
x: 250,
y: 100,
},
{
x: 300,
y: 200,
},
{
x: 350,
y: 50,
}
];

// 创建绘制折线图
var linechart = new LineChart();
linechart.init(points);
}
</script>
</head>
<body>
<canvas id="myCanvas" width="600" height="400"></canvas>
</body>
</html>

浏览器显示效果如下:


Canvas 绘制折线图 - 使用prototype属性构建对象_折线

Canvas 绘制折线图 - 使用prototype属性构建对象_折线图_02