实现canvas连线

Posted zhongxk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实现canvas连线相关的知识,希望对你有一定的参考价值。

如图:

技术分享图片

简单说明下,每个点都可以连接,但是不能重复连接同一个点,当连接到最后一个点的时候,会自动连接第一个点(首尾相连)。

 

var canvas = document.querySelector(‘#canvas‘)
var ctx = canvas.getContext(‘2d‘)

  

画点

 

使用数组保存点的位置,遍历数组将点画出来

技术分享图片
 1 var points = [{x: 300,y: 98, isConnect: false},{x: 217,y: 264, isConnect: false},{x: 295,y: 359, isConnect: false},{x: 372,y: 508, isConnect: false},{x: 511,y: 385, isConnect: false},{x: 497,y: 203, isConnect: false}]
 2 
 3 function drawPoint () {
 4   for (var i = 0, len = points.length; i < len; i++) {
 5       ctx.save()
 6       ctx.beginPath()
 7       ctx.arc(points[i].x, points[i].y, 10, 0, 2 * Math.PI)
 8       ctx.fill()
 9       ctx.restore()
10   } 
11 }
View Code

画线

画线这部分涉及到交互,所以我们需要添加事件,设置drawing,当点击的时候才能开始画线

 1 var mouse = { //用来保存鼠标移动的位置
 2       start: {x: 0, y: 0},
 3       end: {x: 0, y: 0}
 4     }
 5 var drawing = false; //判断是否可以画线
 6     function drawLine (pos1, pos2) {
 7       ctx.save()
 8       ctx.beginPath()
 9       ctx.moveTo(pos1.x, pos1.y)
10       ctx.lineTo(pos2.x, pos2.y)
11       ctx.stroke()
12       ctx.closePath()
13       ctx.restore()
14     }
15 
16     canvas.addEventListener(‘mousedown‘, function(e) {
17 
18       mouse.start.x = e.pageX
19       mouse.start.y = e.pageY
20       drawing = true
21     })
22 
23     canvas.addEventListener(‘mousemove‘, function(e) {
24 
25       mouse.end.x = e.pageX
26       mouse.end.y = e.pageY
27       ctx.clearRect(0, 0, canvas.width, canvas.height) //清除画布
28 29       if (drawing) {
30         drawLine(mouse.start, mouse.end)
31       }
32 
33     })

“吸附”点

我们现在是可以在任意一点开始画线,但是我们的需求是,靠近某个点才能开始画线

怎么判断靠近某个点呢?使用勾股定理,计算两点的距离(一个点是原点, 另一个点是鼠标位置)小于一个值(dis)时,我们判定被这个点“吸附”了,然后开始画线。

写一个方法计算距离:

1 function distance (pos1, pos2) {
2   return Math.sqrt(Math.pow(pos1.x - pos2.x, 2) + Math.pow(pos1.y - pos2.y, 2))    
3 }

判断是否被”吸附“, 并且”吸附“过的点不能再连接:

 1 function adsorption (mouse) {
 2 
 3    for (var i = 0, len = points.length; i < len; i++) {
 4         
 5       if (!points[i].isConnect && distance(mouse, points[i]) <= dis) {
 6 
 7           points[i].isConnect = true
 8           drawing = true
 9 
10       }
11 
12    }
13 }
14 ...
15 //修改下事件
16 // canvas.addEventListener(‘mousedown‘, function(e) {
17 
18 //   mouse.start.x = e.pageX
19 //   mouse.start.y = e.pageY
20 
21  // })
22 
23 canvas.addEventListener(‘mousemove‘, function(e) {
24 
25   mouse.end.x = e.pageX
26   mouse.end.y = e.pageY
27   ctx.clearRect(0, 0, canvas.width, canvas.height)
28   adsorption(mouse.end)
29   drawPoint()
30   if (drawing) {
31     drawLine(mouse.start, mouse.end)
32   }
33 
34 })

到这里,鼠标靠近点的时候,就可以画线了,但是并不是我们预想的那样,应该从点开始画线

这是因为在drawLine传值的是mouse.start,我们只需要把mouse.start换成点的位置就可以了,那么如何换成点的位置呢?

可以用一个数组保存连接过的点:

 1 var savePoints = []
 2 ...
 3 //修改adsorption
 4 function adsorption (mouse) {
 5 
 6    for (var i = 0, len = points.length; i < len; i++) {
 7         
 8       if (!points[i].isConnect && distance(mouse, points[i]) <= dis) {
 9 
10           points[i].isConnect = true
11           drawing = true
12           savePoints.push(points[i])  
13 
14      }
15 
16    }
17 }
18 ...
19 //修改mouse事件
20 canvas.addEventListener(‘mousemove‘, function(e) {
21 
22       ...
23       if (drawing) {
24         drawLine(savePoints[savePoints.length - 1], mouse.end)
25       }
26 
27 })

我们发现每次靠近一个点的时候,都是从这个点开始连线的,之前连接的线并没有画出来,clearRect清除了之前连的线

可以利用保存过的点,把之前连过的线画出来:

 1  ...
 2  function drawOldLine () {
 3    for (var i = 0, len = savePoints.length - 1; i < len; i++) {
 4      drawLine(savePoints[i], savePoints[i + 1])
 5    }
 6 }
 7 ...
 8 //修改mousemove事件
 9 ...
10 if (_this.drawing) {
11 
12    ...
13    drawOldLine()
14 
15 }

好了,我们可以看到,每个点都可以连接,跟我们预想的一样,现在就差最后一步了

首尾相连,简单的思路就是,保存过的数组savePoints里的第一个点和最后一个点连线:

1 function autoLine () {
2       ctx.clearRect(0, 0, canvas.width, canvas.height)
3       drawOldLine()
4       drawPoint()
5       drawLine(savePoints[savePoints.length - 1], savePoints[0])
6       drawing = false
7 }

到这里,已经完成了连线功能。

大家可以尝试一下封装成插件,以后可以方便地使用以及拓展。

 

以上是关于实现canvas连线的主要内容,如果未能解决你的问题,请参考以下文章

关于canvas粒子特效实现分析

使用jsPlumb插件实现动态连线功能

自己定义View时,用到Paint Canvas的一些温故,简单的帧动画(动画一 ,&quot;掏粪男孩Gif&quot;顺便再提提onWindowFocusChanged)(代码片段

ZRender实现粒子网格动画实战

canvas绘制样式

带着canvas去流浪绘制雷达图