![c33d7c2756d2ae8b4ff1014b71b849e8.png](https://img-blog.csdnimg.cn/img_convert/c33d7c2756d2ae8b4ff1014b71b849e8.png)
要想在canvas 2D中绘制虚线有很多种方法,可以自己使用算法实现,也可以使用原生的API。
一、自己使用算法实现虚线绘制
大概思路是:
- 求出虚线段的个数
- 再逐一生成虚线段的路径
这里只使用了勾股定理这一个数学公式。
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>虚线绘制1</title>
</head>
<body>
<canvas id="canvas" width="300" height="200"></canvas>
<script>
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
function drawDashedLine(x1, y1, x2, y2, dashLength = 5){
let deltaX = x2 - x1;
let deltaY = y2 - y1;
// 求虚线段的个数
let dashNums = Math.floor(
Math.sqrt(deltaX*deltaX + deltaY*deltaY) / dashLength
);
// 生成虚线段的路径
context.beginPath();
for(let i = 0; i < dashNums; i++){
let nextX = x1 + (deltaX / dashNums) * i;
let nextY = y1 + (deltaY / dashNums) * i;
if(i % 2 === 0){
context.moveTo(nextX, nextY);
}else{
context.lineTo(nextX, nextY);
}
}
context.stroke
// 绘制虚线段
context.stroke();
}
drawDashedLine(0, 0, canvas.width, canvas.height, 6);
</script>
</body>
</html>
效果:
![88d32374595c5bea2180060194254435.png](https://img-blog.csdnimg.cn/img_convert/88d32374595c5bea2180060194254435.png)
二、在绘图环境中扩展虚线API
如果能将上面自己实现的虚线绘制功能绑定到Canvas 2D的绘图环境对象中那不是更好吗?
可以使用元编程来完成!
由于虚线的起始点是通过调用moveTo()方法来确定的,所以在Canvas2D的绘图环境对象中增加一个生成虚线路径的函数的主要难点是:在这个函数中不能取得这个起始点的数据。
所以重点是确保生成虚线路径的函数中能访问到起始点数据。
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>虚线绘制2</title>
</head>
<body>
<canvas id="canvas" width="300" height="200"></canvas>
<script>
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
// 另存一份moveTo函数
const moveToFunction = CanvasRenderingContext2D.prototype.moveTo;
// 在原型对象中开辟一个变量用于存储传入moveTo()的参数值
CanvasRenderingContext2D.prototype.moveToLocation = {};
// 重新定义moveTo方法
CanvasRenderingContext2D.prototype.moveTo = function(x, y){
moveToFunction.call(context, x, y);
this.moveToLocation.x = x;
this.moveToLocation.y = y;
console.log(1);
}
// 在绘图环境中扩展dashedLineTo()方法
CanvasRenderingContext2D.prototype.dashedLineTo = function drawDashedLine(x, y, dashLength = 5){
let deltaX = x - this.moveToLocation.x;
let deltaY = y - this.moveToLocation.y;
// 求虚线段的个数
let dashNums = Math.floor(
Math.sqrt(deltaX*deltaX + deltaY*deltaY) / dashLength
);
// 生成虚线段的路径
let startX = this.moveToLocation.x;
let startY = this.moveToLocation.y;
for(let i = 0; i < dashNums; i++){
let nextX = startX + (deltaX / dashNums) * i;
let nextY = startY + (deltaY / dashNums) * i;
if(i % 2 === 0){
context.moveTo(nextX, nextY);
}else{
context.lineTo(nextX, nextY);
}
}
this.moveTo(x, y);
}
context.moveTo(0, 0);
context.dashedLineTo(canvas.width, canvas.height);
context.stroke();
</script>
</body>
</html>
效果:
![d75fce48fdecfb483195ef64924e516a.png](https://img-blog.csdnimg.cn/img_convert/d75fce48fdecfb483195ef64924e516a.png)
三、使用原生API绘制虚线
canvas2D已经有原生API支持生成虚线路径了。
setLineDash(segments)方法用于指定在填充时使用虚线模式。
segments参数是一个数组,一组描述交替绘制线段和间距(坐标空间单位)长度的数字。 如果数组元素的数量是奇数, 数组的元素会被复制并重复。例如, [5, 15, 25]
会变成[5, 15, 25, 5, 15, 25]。
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>虚线绘制3</title>
</head>
<body>
<canvas id="canvas" width="300" height="200"></canvas>
<script>
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
// 设置填充线时使用虚线模式
context.setLineDash([5, 5]);
context.moveTo(0, 0);
context.lineTo(canvas.width, canvas.height);
context.stroke();
</script>
</body>
</html>
效果:
![3ca86181d7034a71490976995bed87ed.png](https://img-blog.csdnimg.cn/img_convert/3ca86181d7034a71490976995bed87ed.png)