圆形
在canvas中,我们使用arc()方法来画一个圆
语法:
- cxt.beginPath();
- cxt.arc(x,y,r,开始角度,结束角度,anticlockwise);
- cxt.closePath();
其中x和y代表圆心坐标,r为半径;开始角度和结束角度都以“弧度”为单位,例如180°应该写成Math.PI;anticlockwise是一个布尔值,当为true时,逆时针方向绘制,默认值为false,顺时针方向绘制。
学习完绘制完圆之后,可以尝试canvas中最常见的图形操作:描边(stroke)和填充(fill)
语法:
-
cxt.strokeStyle = "属性值";
-
cxt.stroke();
-
cxt.fillStyle = "属性值";
-
cxt.fill();
预备代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<canvas id = "canvas" width = "300" height = "300" style = "border: 1px dashed gray;"></canvas>
</body>
<script>
window.onload = function() {
//写逻辑
}
</script>
</html>
效果图为:
let canvas = document.getElementById('canvas');
let cxt = canvas.getContext('2d');
cxt.beginPath();
cxt.arc(100,100,100,0,90 * Math.PI / 180);
cxt.closePath();
cxt.lineWidth = 5;
cxt.strokeStyle = "yellow";
cxt.stroke();
cxt.fillStyle = "black";
cxt.fill();
效果图为:
弧线
在canvas中,如果想画弧线,常见的方法有两种:arc()、arcTo()
语法:
- cxt.beginPath();
- cxt.arc(x,y,r,开始角度,结束角度,anticlockwise);
- cxt.strokeStyle = "属性值";
- cxt.stroke();
必须要注意的是,“使用arc()方法绘制圆”,需要closePath()来关闭路径,而“使用arc()方法画弧线”不需要,原因是弧线不是闭合图形
同时,stroke()和fill()这两个方法只能用来绘制当前路径,不能同时绘制多个路径
let canvas = document.getElementById('canvas');
let cxt = canvas.getContext('2d');
cxt.moveTo(0,100);
cxt.lineTo(100,100);
cxt.stroke();
cxt.beginPath();
cxt.moveTo(100,100);
cxt.arc(100,100,100,0,90 * Math.PI / 180);
cxt.closePath();
cxt.strokeStyle = "yellow";
cxt.stroke();
效果图为:
如果删除了第一个cxt.stroke(),预览效果如下所示:
语法:
- cxt.arcTo(x1,y1,x2,y2,r);
(x1,y1)表示控制点的坐标,(x2,y2)表示结束点的坐标,r表示圆弧的半径,借用一张网上的图片
练习:绘制扇形
昨天晚上准备更这一期学习内容的时候,准备做一下扇形,当时想到了之前校企实训用的echarts的饼状图,就想着自己也尝试输入数据,然后就可以生成一个扇形统计图,花了几个小时,最终也是简单实现了一些功能。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<canvas id = "canvas" width = "300" height = "300" style = "border: 1px dashed gray;"></canvas>
</body>
<script>
window.onload = function() {
//写逻辑
let canvas = document.getElementById('canvas');
let cxt = canvas.getContext('2d');
let arr = [
{name:'苹果',amount:2},
{name:'柿子',amount:2},
{name:'橘子',amount:2},
// {name:'柚子',amount:4},
];
let colorArr = createColor(arr.length); // 随机颜色合集
let array = [0 * Math.PI / 180]; // 角度合集
let angle; // 鼠标点的位置的夹角
let line1;
function createPie(x,y,r,arr){
let sum = 0;
let h = 20;
let hrect = 12;
for(let i = 0;i < arr.length;i++){
let obj = arr[i];
sum += obj.amount;
}
for(let i = 0;i < arr.length;i++){ // 判断弧度
let obj = arr[i];
let number = (obj.amount / sum) * Math.PI * 2 + array[i];
array.push(number);
}
console.log(array);
for(let i = 0;i < array.length - 1;i++){ // 绘制扇形
cxt.beginPath();
cxt.moveTo(x,y);
cxt.arc(x,y,r,array[i],array[i+1] );
cxt.closePath();
cxt.fillStyle = colorArr[i];
cxt.fill();
}
for(let i = 0;i < arr.length;i++){ // 数据列表
let obj = arr[i];
cxt.fillStyle = colorArr[i];
cxt.fillRect(canvas.width / 1.5, hrect , 40 , 10);
let text = `${obj.name}:${obj.amount}`;
cxt.font = "bold 10px 楷体";
cxt.fillStyle = colorArr[i];
cxt.fillText(text,canvas.width / 1.5 + 50, h);
h += 20;
hrect += 20;
}
}
createPie(canvas.width / 3 , canvas.height / 2 , 80 , arr);
canvas.onclick = function(e){ // 点击饼状图局部放大(没有实现再次点击变回原来的样式)
//console.log(e.offsetX,e.offsetY);
let clickX = e.offsetX;
let clickY = e.offsetY;
let x = canvas.width / 3;
let y = canvas.height / 2;
let r = 80;
let calx = clickX;
let caly = y;
line1 = getDistance(clickX,clickY,x,y); // 斜边
let line2 = getDistance(clickX,clickY,calx,caly);
let line3 = getDistance(x,y,calx,caly);
angle = Math.acos((Math.pow(line1,2) + Math.pow(line3,2) - Math.pow(line2,2)) / (2 * line1 * line3));
console.log(angle);
if(clickX > x && clickY > y){
// 在第一象限
}
else if(clickX < x && clickY > y){
// 在第二象限
angle = Math.PI - angle ;
}
else if(clickX < x && clickY < y){
// 在第三象限
angle += Math.PI;
}
else {
// 在第四象限
angle = Math.PI * 2 - angle;
}
for(let i = 0;i < array.length;i++){
if(angle > array[i] && angle < array[i+1] && line1 <= r){
console.log(colorArr[i]);
cxt.beginPath();
cxt.moveTo(x,y);
cxt.arc(x,y,r+20,array[i],array[i+1] );
cxt.closePath();
cxt.fillStyle = colorArr[i];
cxt.fill();
}
}
}
function getDistance(x1,y1,x2,y2){
return Math.sqrt(Math.pow(x1-x2,2) + Math.pow(y1-y2,2));
}
function createColor(len){ // 随机生成颜色列表
let arr = [];
while(arr.length < len){
let r = Math.floor(Math.random() * 255);
let g = Math.floor(Math.random() * 255);
let b = Math.floor(Math.random() * 255);
arr.push(`rgb(${r}, ${g}, ${b})`);
}
return [...new Set(arr)];
}
}
</script>
</html>
效果图为:
封面制作网站 ColorFu
gif制作软件ScreenToGif - Record your screen, edit and save as a gif, video or other formats
文章内容参考莫振杰 著《HTML5 CANVAS开发详解》,感兴趣的同学可以阅读一下这本书,如有错误,欢迎指正!!