目录
  1. 1. 弧度
    1. 1.1. 什么是弧度?
    2. 1.2. 弧度怎么去描述?
    3. 1.3. 一个角度等于多少弧度?
  2. 2. 体验曲线的绘制
  3. 3. 绘制圆弧
    1. 3.1. arc()方法
    2. 3.2. 绘制四分之一弧
    3. 3.3. 绘制扇形
    4. 3.4. 绘制一个等分成n块扇形的圆
    5. 3.5. 绘制饼图
    6. 3.6. 画布中心绘制文字
      1. 3.6.1. textAlign()方法
      2. 3.6.2. textBaseline()方法
    7. 3.7. 绘制完整饼状图表
canvas理解曲线的绘制

弧度

什么是弧度?

弧度是一种长度的描述单位

弧度怎么去描述?

一个弧度就是一个半径的长度

一个圆有多少个弧度 $2 * π$

一个角度等于多少弧度?

一个角度等于$ π/180$

体验曲线的绘制

1.体验曲线的绘制

2.线是由点构成的

3.曲线可以由数学公式得来

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
canvas {
border: 1px solid #ccc;
}
</style>
</head>
<body>
<canvas width="600" height="400"></canvas>
<script>
var myCanvas = document.querySelector('canvas');
var ctx = myCanvas.getContext('2d');

for(var i = 1 ; i < 600 ; i ++){
var x = i;
var y = 50*Math.sin(x/10) + 100;
ctx.lineTo(x,y);
}
ctx.stroke();

</script>
</body>
</html>

绘制圆弧

arc()方法

arc() 方法创建弧/曲线(用于创建圆或部分圆)。

提示:如需通过 arc() 来创建圆,请把起始角设置为 0,结束角设置为 $2*Math.PI。$

提示:请使用 stroke()fill()方法在画布上绘制实际的弧。

context.arc(x,y,r,sAngle,eAngle,counterclockwise);
x 圆的中心的 x 坐标。
y 圆的中心的 y 坐标。
r 圆的半径。
sAngle 起始角,以弧度计。(弧的圆形的三点钟位置是 0 度)。
eAngle 结束角,以弧度计。
counterclockwise 可选。规定应该逆时针还是顺时针绘图。False = 顺时针,true = 逆时针。

绘制四分之一弧

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
canvas {
border: 1px solid #ccc;
}
</style>
</head>

<body>
<canvas width="600" height="400"></canvas>
<script>
var myCanvas = document.querySelector('canvas');
var ctx = myCanvas.getContext('2d');

/*在中心位置画一个半径150px的圆弧左下角*/
var w = ctx.canvas.width;
var h = ctx.canvas.height;
ctx.arc(w / 2, h / 2, 150, Math.PI, Math.PI / 2, true)
ctx.stroke();
</script>
</body>

</html>

绘制扇形

绘制扇形填充得设置起点为圆心位置

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
canvas {
border: 1px solid #ccc;
}
</style>
</head>
<body>
<canvas width="600" height="400"></canvas>
<script>
var myCanvas = document.querySelector('canvas');
var ctx = myCanvas.getContext('2d');

/*在中心位置画一个半径150px的圆弧右上角*/
var w = ctx.canvas.width;
var h = ctx.canvas.height;

/*把起点放到圆心位置*/
ctx.moveTo(w/2,h/2);

ctx.arc(w/2,h/2,150,0,-Math.PI/2,true);
ctx.fill();


</script>
</body>
</html>

绘制一个等分成n块扇形的圆

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
canvas {
border: 1px solid #ccc;
}
</style>
</head>

<body>
<canvas width="600" height="400"></canvas>
<script>
var myCanvas = document.querySelector('canvas');
var ctx = myCanvas.getContext('2d');

var w = ctx.canvas.width;
var h = ctx.canvas.height;

/*分成几等分*/
var num = 360;
/*一份多少弧度*/
var angle = Math.PI * 2 / num;

/*原点坐标*/
var x0 = w / 2;
var y0 = h / 2;

/*获取随机颜色*/
var getRandomColor = function () {
var r = Math.floor(Math.random() * 256);
var g = Math.floor(Math.random() * 256);
var b = Math.floor(Math.random() * 256);
return 'rgb(' + r + ',' + g + ',' + b + ')';
}


for (var i = 0; i < num; i++) {
/*起始弧度*/
var startAngle = i * angle
/*结束弧度*/
var endAngle = (i + 1) * angle
ctx.beginPath()
ctx.moveTo(x0, y0)
ctx.arc(x0, y0, 150, startAngle, endAngle)
/*随机颜色*/
ctx.fillStyle = getRandomColor();
ctx.fill()
}
</script>
</body>

</html>

绘制饼图

通过刚才学会了绘制一个区分不同块扇形的圆,那么绘制饼图只需要简单延伸即可

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
canvas {
border: 1px solid #ccc;
}
</style>
</head>
<body>
<canvas width="600" height="400"></canvas>
<script>
var myCanvas = document.querySelector('canvas');
var ctx = myCanvas.getContext('2d');

/*1.根据37期的年龄分布绘制饼图*/
/*2.准备统计的数据*/
/*15-20岁 6个*/
/*20-25岁 30个*/
/*25-30岁 10个*/
/*30-35岁 8个*/
var data = [6, 30, 10, 8];
/*3.在饼图表示出来*/
/*4.需要把数据转出弧度*/
var angleList = [];
var total = 0;
data.forEach(function (item, i) {
total += item;
});
console.log(total);
/*第二是转换成弧度的时候就可以去绘制扇形 减少一次遍历*/
data.forEach(function (item, i) {
var angle = Math.PI * 2 * (item/total);
angleList.push(angle);
});
console.log(angleList);
/*5.根据弧度绘制扇形*/

var w = ctx.canvas.width;
var h = ctx.canvas.height;
var x0 = w/2;
var y0 = h/2;
/*获取随机颜色*/
var getRandomColor = function () {
var r = Math.floor(Math.random() * 256);
var g = Math.floor(Math.random() * 256);
var b = Math.floor(Math.random() * 256);
return 'rgb(' + r + ',' + g + ',' + b + ')';
}


var startAngle = 0;
angleList.forEach(function (item,i) {
/*上一次绘制的结束弧度等于当前次的起始弧度*/
var endAngle = startAngle + item;
ctx.beginPath();
ctx.moveTo(x0,y0);
ctx.arc(x0,y0,150,startAngle,endAngle);
ctx.fillStyle = getRandomColor();
ctx.fill();
/*记录当前的结束位置作为下一次的起始位置*/
startAngle = endAngle;
});

</script>
</body>
</html>

画布中心绘制文字

textAlign()方法

textAlign属性根据锚点,设置或返回文本内容的当前对齐方式。

通常,文本会从指定位置开始,不过,如果您设置为 textAlign="right" 并将文本放置到位置 150,那么会在位置 150 结束。

context.textAlign="center|end|left|right|start";
描述
start 默认。文本在指定的位置开始。
end 文本在指定的位置结束。
center 文本的中心被放置在指定的位置。
left 文本左对齐。
right 文本右对齐。

textBaseline()方法

textBaseline属性设置或返回在绘制文本时的当前文本基线。

context.textBaseline="alphabetic|top|hanging|middle|ideographic|bottom";
描述
alphabetic 默认。文本基线是普通的字母基线。
top 文本基线是 em 方框的顶端。。
hanging 文本基线是悬挂基线。
middle 文本基线是 em 方框的正中。
ideographic 文本基线是表意基线。
bottom 文本基线是 em 方框的底端。
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
canvas {
border: 1px solid #ccc;
display: block;
margin: 100px auto;
}
</style>
</head>

<body>
<canvas width="600" height="400"></canvas>
<script>
var myCanvas = document.querySelector('canvas');
var ctx = myCanvas.getContext('2d');

/*1.在画布的中心绘制一段文字*/
/*2.申明一段文字*/
var str = '您饿了么';
/*3.确定画布的中心*/
var w = ctx.canvas.width;
var h = ctx.canvas.height;
/*4.画一个十字架在画布的中心*/
ctx.beginPath();
ctx.moveTo(0, h / 2 - 0.5);
ctx.lineTo(w, h / 2 - 0.5);
ctx.moveTo(w / 2 - 0.5, 0);
ctx.lineTo(w / 2 - 0.5, h);
ctx.strokeStyle = '#eee';
ctx.stroke();
/*5.绘制文本*/
ctx.beginPath();
ctx.strokeStyle = '#000';
var x0 = w / 2;
var y0 = h / 2;
/*注意:起点位置在文字的左下角*/
/*有文本的属性 尺寸 字体 左右对齐方式 垂直对齐的方式*/
ctx.font = '40px Microsoft YaHei';
/*左右对齐方式 (center left right start end) 基准起始坐标*/
ctx.textAlign = 'center';
/*垂直对齐的方式 基线 baseline(top,bottom,middle) 基准起始坐标*/
ctx.textBaseline = 'middle';
ctx.fillText(str, x0, y0);
/*6.画一个下划线和文字一样长*/
ctx.beginPath();
/*获取文本的宽度*/
var width = ctx.measureText(str).width;
/*绘制下划线*/
ctx.moveTo(x0 - width / 2, y0 + 20);
ctx.lineTo(x0 + width / 2, y0 + 20);
ctx.stroke();
</script>
</body>

</html>

绘制完整饼状图表

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
canvas {
border: 1px solid #ccc;
display: block;
margin: 100px auto;
}
</style>
</head>
<body>
<canvas width="600" height="400"></canvas>
<script>
/*var myCanvas = document.querySelector('canvas');
var ctx = myCanvas.getContext('2d');*/

/*1.绘制饼状态图*/
/*1.1 根据数据绘制一个饼图*/
/*1.2 绘制标题 从扇形的弧中心伸出一条线在画一条横线在横线的上面写上文字标题*/
/*1.3 在画布的左上角 绘制说明 一个和扇形一样颜色的矩形 旁边就是文字说明*/

var PieChart = function (ctx) {
/*绘制工具*/
this.ctx = ctx || document.querySelector('canvas').getContext('2d');
/*绘制饼图的中心*/
this.w = this.ctx.canvas.width;
this.h = this.ctx.canvas.height;
/*圆心*/
this.x0 = this.w / 2 + 60;
this.y0 = this.h / 2;
/*半径*/
this.radius = 150;
/*伸出去的线的长度*/
this.outLine = 20;
/*说明的矩形大小*/
this.rectW = 30;
this.rectH = 16;
this.space = 20;
}
PieChart.prototype.init = function (data) {
/*1.准备数据*/
this.drawPie(data);
};
PieChart.prototype.drawPie = function (data) {
var that = this;
/*1.转化弧度*/
var angleList = this.transformAngle(data);
/*2.绘制饼图*/
var startAngle = 0;
angleList.forEach(function (item, i) {
/*当前的结束弧度要等于下一次的起始弧度*/
var endAngle = startAngle + item.angle;
that.ctx.beginPath();
that.ctx.moveTo(that.x0, that.y0);
that.ctx.arc(that.x0, that.y0, that.radius, startAngle, endAngle);
var color = that.ctx.fillStyle = that.getRandomColor();
that.ctx.fill();
/*下一次要使用当前的这一次的结束角度*/
/*绘制标题*/
that.drawTitle(startAngle, item.angle, color , item.title);
/*绘制说明*/
that.drawDesc(i,item.title);
startAngle = endAngle;
});
};
PieChart.prototype.drawTitle = function (startAngle, angle ,color , title) {
/*1.确定伸出去的线 通过圆心点 通过伸出去的点 确定这个线*/
/*2.确定伸出去的点 需要确定伸出去的线的长度*/
/*3.固定伸出去的线的长度*/
/*4.计算这个点的坐标*/
/*5.需要根据角度和斜边的长度*/
/*5.1 使用弧度 当前扇形的起始弧度 + 对应的弧度的一半 */
/*5.2 半径+伸出去的长度 */
/*5.3 outX = x0 + cos(angle) * ( r + outLine)*/
/*5.3 outY = y0 + sin(angle) * ( r + outLine)*/
/*斜边*/
var edge = this.radius + this.outLine;
/*x轴方向的直角边*/
var edgeX = Math.cos(startAngle + angle / 2) * edge;
/*y轴方向的直角边*/
var edgeY = Math.sin(startAngle + angle / 2) * edge;
/*计算出去的点坐标*/
var outX = this.x0 + edgeX;
var outY = this.y0 + edgeY;
this.ctx.beginPath();
this.ctx.moveTo(this.x0, this.y0);
this.ctx.lineTo(outX, outY);
this.ctx.strokeStyle = color;
/*画文字和下划线*/
/*线的方向怎么判断 伸出去的点在X0的左边 线的方向就是左边*/
/*线的方向怎么判断 伸出去的点在X0的右边 线的方向就是右边*/
/*结束的点坐标 和文字大小*/
this.ctx.font = '14px Microsoft YaHei';
var textWidth = this.ctx.measureText(title).width ;
if(outX > this.x0){
/*右*/
this.ctx.lineTo(outX + textWidth,outY);
this.ctx.textAlign = 'left';
}else{
/*左*/
this.ctx.lineTo(outX - textWidth,outY);
this.ctx.textAlign = 'right';
}
this.ctx.stroke();
this.ctx.textBaseline = 'bottom';
this.ctx.fillText(title,outX,outY);

};
PieChart.prototype.drawDesc = function (index,title) {
/*绘制说明*/
/*矩形的大小*/
/*距离上和左边的间距*/
/*矩形之间的间距*/
this.ctx.fillRect(this.space,this.space + index * (this.rectH + 10),this.rectW,this.rectH);
/*绘制文字*/
this.ctx.beginPath();
this.ctx.textAlign = 'left';
this.ctx.textBaseline = 'top';
this.ctx.font = '12px Microsoft YaHei';
this.ctx.fillText(title,this.space + this.rectW + 10 , this.space + index * (this.rectH + 10));
};
PieChart.prototype.transformAngle = function (data) {
/*返回的数据内容包含弧度的*/
var total = 0;
data.forEach(function (item, i) {
total += item.num;
});
/*计算弧度 并且追加到当前的对象内容*/
data.forEach(function (item, i) {
var angle = item.num / total * Math.PI * 2;
item.angle = angle;
});
return data;
};
PieChart.prototype.getRandomColor = function () {
var r = Math.floor(Math.random() * 256);
var g = Math.floor(Math.random() * 256);
var b = Math.floor(Math.random() * 256);
return 'rgb(' + r + ',' + g + ',' + b + ')';
};

var data = [
{
title: '15-20岁',
num: 6
},
{
title: '20-25岁',
num: 30
},
{
title: '25-30岁',
num: 10
},
{
title: '30以上',
num: 8
}
];

var pieChart = new PieChart();
pieChart.init(data);

</script>
</body>
</html>

文章作者: Jachie Xie
文章链接: https://xjc5772.github.io/2020-07/31/%E5%AD%A6%E4%B9%A0/%E5%89%8D%E7%AB%AF%E5%AD%A6%E4%B9%A0/H5/canvas%E7%90%86%E8%A7%A3%E6%9B%B2%E7%BA%BF%E7%9A%84%E7%BB%98%E5%88%B6/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 XJC&Blog
打赏
  • 微信
  • 支付宝

评论