原生CANVAS语法实现的封装折线图和饼图
Posted 我是真的不会前端
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原生CANVAS语法实现的封装折线图和饼图相关的知识,希望对你有一定的参考价值。
介绍
首先canvas是html5的一种新标签,代表一个画布,可以在上面进行绘画、动画等操作。画布默认大小是300*150。
canvas标签本生就是一个只是画布,可以导出为透明背景的png图片。要实现上面有文字、线条等呈现,需要使用js实现。总之,画布上一切的呈现,都需要使用js来实现。
画布大小不能使用样式控制,用样式调整的是一个可视区域,其实真实的大小,还是一样的,只是在画布上画内容的话,会等比例放大。调整画布大小,需要在标签上直接添加width和height属性。
canvas标签也是可以放文字的,只是当canvas标签不被浏览器支持的时候,会显示,例如ie8。
基本使用
-
获取canvas元素
var canvas = document.querySelector('canvas')
-
获取这个元素的工具箱 - 上下文
工具箱中包含了很多工具:直线工具、弧形工具、文本工具、矩形工具… 我们需要依赖这些工具进行绘画
语法:
var ctx = canvas.getContext('2d')
-
画图形
默认情况下,canvas选中的工具是直线工具,要画一条直线的话,需要先将画笔放到一个指定像素点
ctx.moveTo(x轴坐标,y轴坐标)
然后以线的形式,将画笔移动到终点:
ctx.lineTo(200,100)
此时应该已经有线了,但是页面中并没有出现,因为我们前面两个步骤描述的是画笔走的路径,这个路径需要进行填充:
ctx.fill
也可以进行描边:
ctx.strock()
默认是黑色,线的宽度是1px
此时在画布中出现了一条线,但是发现线的粗细不是1px,颜色也不是黑色。这是因为,canvas绘制线条,会将线条的中心点跟坐标点的位置进行对齐,这样的话,不管是线的开始对准坐标点还是线的结束对准中心点都不合适,所以浏览器干脆将线强行拉伸到 坐标点-1~坐标点+1,也就是本来1px的线,被强制拉伸到了2px,这样的话,颜色也就浅了。
我们可以将线的宽度设置为2px做验证,因为2px就不用被拉伸了:
ctx.lineWith = 2 // 值是数字
ctx.lineTo(200,100)
//结果就是2px宽的线,纯黑色了。基于这个问题,我们以后在绘图的时候,尽量将像素设置为双数。
1 :简单封装的一个折线图
html和css
<html>
<head>
<meta charset="UTF-8">
<title>document</title>
</head>
<style>
canvas{
border:1px solid #000;
}
</style>
<body>
<canvas class="linechart" width=600 height=300></canvas>
</body>
javascript封装的源码
// 定义一个类
class LineChart{
constructor(classname,data){
// 画布标签获取到
this.canvas = document.querySelector('.'+classname)
// 工具箱
this.ctx = this.canvas.getContext('2d')
// 定义画布大小
this.canvasWidth = this.ctx.canvas.width
this.canvasHeight = this.ctx.canvas.height
// 定义坐标轴到画布边缘的间隙
this.space = 20
// 定义原点
this.originX = 0
this.originY = 0
// 定义箭头三角形的高 和 点 的长度
this.length = 10
// 将数据绑定成类的属性
this.data = data
// 定义画布中的数据
this.canvasData = null;
}
// 定义一个初始化方法
init(){
// 获取原点
this.getOrigin()
// 创建坐标轴 - x、y
this.createAxisX()
this.createAxisY()
// 转换数据
this.convert(this.data)
// 描每个点
// this.setPoint(data)
// 描所有点
this.setPoints(this.canvasData)
// 连线
this.connectLine(this.canvasData)
}
connectLine(data){
for(let i=0;i<data.length-1;i++){
this.ctx.beginPath()
// 放画笔
this.ctx.moveTo(data[i].x,data[i].y)
// 画线
this.ctx.lineTo(data[i+1].x,data[i+1].y)
this.ctx.closePath()
this.ctx.stroke()
}
}
// 描所有点的方法
setPoints(data){
data.forEach(point=>{
this.setPoint(point)
})
}
// 描一个点的方法
setPoint(data){
this.ctx.beginPath()
// 放画笔位置
this.ctx.moveTo(data.x-this.length/2,data.y-this.length/2)
// 画线
this.ctx.lineTo(data.x+this.length/2,data.y-this.length/2)
this.ctx.lineTo(data.x+this.length/2,data.y+this.length/2)
this.ctx.lineTo(data.x-this.length/2,data.y+this.length/2)
this.ctx.lineTo(data.x-this.length/2,data.y-this.length/2)
this.ctx.closePath()
this.ctx.stroke()
this.ctx.fill()
}
// 转换数据的方法
convert(){
// 将坐标轴的数据转成画布的数据
// 遍历数据
this.canvasData = this.data.map(point=>{
return {
x:point.x+this.space,
y:this.canvasHeight - this.space - point.y
}
})
}
// 创建y轴
createAxisY(){
this.ctx.beginPath()
// 将画笔放到原点
this.ctx.moveTo(this.originX,this.originY)
// 画线
this.ctx.lineTo(this.originX,this.space)
// 画箭头
this.ctx.lineTo(this.originX-this.length/2,this.space + this.length)
this.ctx.lineTo(this.originX+this.length/2,this.space + this.length)
this.ctx.lineTo(this.originX,this.space)
this.ctx.closePath()
this.ctx.stroke()
this.ctx.fill()
}
// 获取原点的方法
getOrigin(){
this.originX = this.space;
this.originY = this.canvasHeight - this.space
}
// 定义创建x坐标轴的方法
createAxisX(){
this.ctx.beginPath()
// 将画笔放到原点
this.ctx.moveTo(this.originX,this.originY)
// 画线
this.ctx.lineTo(this.canvasWidth - this.space,this.originY)
// 画箭头
this.ctx.lineTo(this.canvasWidth-this.space-this.length,this.originY-this.length/2)
this.ctx.lineTo(this.canvasWidth-this.space-this.length,this.originY+this.length/2)
this.ctx.lineTo(this.canvasWidth - this.space,this.originY)
this.ctx.closePath()
this.ctx.stroke()
this.ctx.fill()
}
}
调用方法
var lc = new LineChart('linechart',[
{
x:0, //写入每个坐标点的位置
y:0
},
{
x:100,
y:100
},
{
x:200,
y:120
},
{
x:300,
y:220
},
{
x:400,
y:150
},
])
lc.init()
效果
是不是简陋了点,现在封装一个好看点的饼图
Demo2:封装一个圆饼图
html和css
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>document</title>
</head>
<body>
<style>
canvas{
border:1px solid #000
}
</style>
<canvas width=900 height=500 class="pie"></canvas>
</body>
javascript封装的源码
class Pie{
constructor(classname,data){
// 将数据绑定在属性上
this.data = data
// 获取canvas节点
this.canvas = document.querySelector('.'+classname)
// 获取工具箱
this.ctx = this.canvas.getContext('2d');
// 定义圆心
this.x = this.ctx.canvas.width / 2 + 200;
this.y = this.ctx.canvas.height / 2;
// 定义半径
this.r = 150
// 定义延伸线的长度
this.R = this.r + 40
// 定义数据总量
this.total = this.data.reduce((a,b)=>{
if(typeof a === 'number'){
return a + b.num
}else{
return this.data[0].num + b.num
}
})
}
// 初始化方法
init(){
// 数据处理方法
this.convertData()
// 画饼的方法
this.drawPie()
}
// 数据处理方法
convertData(){
this.data.forEach(v=>{
v.arc = v.num/this.total*2 * Math.PI
})
}
// 画饼的方法
drawPie(){
// 初始弧度
var startArc = 0
this.data.forEach((v,index)=>{
this.ctx.beginPath()
this.ctx.moveTo(this.x,this.y)
var endArc = startArc + v.arc
this.ctx.arc(this.x,this.y,this.r,startArc,endArc)
startArc = endArc
var color = this.getColor()
this.ctx.fillStyle = color
this.ctx.fill()
// 画延伸线
this.outLine(v.arc,endArc,color,v.title)
// 画说明方块
this.descSquare(index)
})
}
// 画说明方块的方法
descSquare(index){
var squareWidth = 50;
var squareHeight = 30;
var squareLeft = 20;
var squareTop = 20
// 画小方块
this.ctx.fillRect(squareLeft,squareTop*(index+1)+squareHeight*index,squareWidth,squareHeight)
// 计算文字的开始坐标
var textX = squareLeft + squareWidth + squareLeft
var textY = squareTop*(index+1)+squareHeight*index+squareHeight/2
this.ctx.textBaseline = 'middle';
this.ctx.textAlign = 'left';
var percent = (this.data[index].num / this.total).toFixed(2) * 100 + '%'
this.ctx.fillText(this.data[index].title+' ' + percent,textX,textY)
}
// 画延伸线的方法
outLine(currentArc,endArc,color,title){
// 获取到需要画线的这个弧度
var arc = endArc - currentArc/2
// 计算这条线的终点x和y
var endX = Math.cos(arc) * this.R + this.x
var endY = Math.sin(arc) * this.R + this.y
this.ctx.moveTo(this.x,this.y)
this.ctx.lineTo(endX,endY)
this.ctx.strokeStyle = color
// 获取文字长度
this.ctx.font = '16px 楷体'
var textWidth = this.ctx.measureText(title).width
if(endX<this.x){
var textX = endX - textWidth
this.ctx.textAlign = 'left';
}else{
var textX = endX + textWidth
this.ctx.textAlign = 'right';
}
this.ctx.textBaseline = 'bottom';
this.ctx.lineTo(textX,endY)
// 写字
this.ctx.strokeText(title,textX,endY-3)
this.ctx.stroke()
}
// 获取随机颜色的方法
getColor(){
return `rgb(${Math.floor(Math.random()*256)},${Math.floor(Math.random()*256)},${Math.floor(Math.random()*256)})`
}
}
调用方法
var data = [
{
title:"15 ~ 20 岁",
num:我是刚学c#的,老师安排了任务,用c#winformchart画柱状图,折线图和饼图,恳请帮帮忙,