图形模块化1
图形选择,是可视化交互中必然会遇到的,它在可视化方面的面试中出现概率是最高的。
我在这里会从两个方向来说,分别是svg和canvas。
至于普通DOM 的选择,我就不消多说了。
因为svg 的选择是最简单的,所以咱们先说svg。
一、图形选择-svg
svg 的选择方式和普通DOM 的选择方式是一样的。
比如画一个三角形,然后为其正常添加鼠标划入划出事件:
在实际的工作中,我们可能会对复杂图形做出交互选择。
就比如图片里有一座酷似大象的山,我们把鼠标划到山上的时候,要做出一些相应的提示。
这个时候,我们可以用Illustrator 来绘制山体轮廓。
在绘制完成后,ctrl+shift+S 另存为svg 文件即可。
在另存为的时候,还会弹出svg 配置窗口:
在上面的窗口里面,我们可以点击“SVG 代码”按钮,查看相应的SVG代码:
从SVG代码中可以看出,图层的名称就是SVG 元素的id。
有了SVG 文件之后,我们就需要将其导入HTML 页面里。
因为这个文件是用Adobe 的Illustrator 软件生成的,所咱们就用Adobe 官方推荐的方式导入svg 文件:
二、svg绘图面对的两种问题
使用 标签的src 属性引入了svg 文件后,我们就需要为svg 中的元素添加鼠标事件了,这个过程需要考虑两个问题:
- svg 文件的引入是个异步事件,我们需要将在svg 文件引入成功后在获取svg 中的元素。
- svg 中的元素中的元素无法直接用当前页面的document 获取,svg 文件有自己的document 对象。
第1个问题:
可用为window 或embed 添加onload 事件来解决,如:
第2个问题:
要先用embed.getSVGDocument() 方法获取svg 自己的document 对象,然后再使用此document对象获取SVG 中的元素。
完整代码:
页面效果:
svg 绘图时,如果图形数量非常大,其渲染速度就会非常慢,而且它还不适合做图像处理。
这时,就需要选择canvas 了。
既然选择canvas,那我们就必须考虑如何选择canvas 中的图形了。
接下来,我具体给大家说多边形网格方法:
canvas 内置的isPointInPath(x,y) 方法。
多边形网格化方法。
三、图形选择-isPointInPath(x,y)
isPointInPath(x,y) 是canvas 2d中的内置方法,它可以判断一个点位是否在路径中。
isPointInPath(x,y) 面向的对象是路径,所以对文字、fillRect()、strokeRect()不好使。
首先,咱们先回顾一下路径的基本概念:
在我们使用canvas 的getContext(‘2d’) 方法获取canvas 上下文对象ctx 的时候, ctx上便挂载了一个空的路径集合。
在ctx.beginPath() 之后,所绘制的所有路径都会被添加到这个路径集合里。
isPointInPath(x,y) 方法判断的就是x、y 点是否在这个路径集合的所有路径里。
这个路径可以不用画出来,只要路径集合里有路径即可。
注意,在下一次ctx.beginPath() 时,路径集合会被置空。
接下来我们看一下isPointInPath 的使用方法。
我用三个点画了一条折线,没有将其闭合:
ctx.isPointInPath(250,100) 返回了true,就是点(250,100) 在刚才的3个点围成的闭合路径之中。
简单总结一下:
- 网路径集合中绘制了一条由3 个点组成的折线,未将其闭合(是否闭合无所谓)。
- 检测点(250,100) 是在上面的3 个点围成的图形中的,所以ctx.isPointInPath(250,100) 为true。
- ctx.isPointInPath(250,100) 方法是在绘图之前执行的,这说明isPointInPath(x,y)方法的使用并不需要把路径实际画出来。
这时候,大家可能会想:
如果我把鼠标点作为检测点,鼠标每次移动都要判断其是否在图形中,是不是每次鼠标移动都要把路径再画一遍?
这个答案要视情况而定:
路径集合没有被清空,那鼠标移动时都可以正常检测:
可是当我在画完路径后再画点东西时,用beginPath()方法把以前的路径给清空了;
画出了一个圆,那我们就无法再对以前的路径进行isPointInPath() 判断了。
例如:
这就是后一种情况:
路径集合被清空时,可以把绘制路径的步骤封装到一个方法里;
在鼠标移动时,执行此方法,把路径集合先清空,再放入我们需要检测的路径:
到这里,我们就可以做一些简单的图形选择的项目了。
但是在面对大一点的项目是,还是建议大家用模块的思想将上面功能模块化。
摘至开课吧前端团队,阅读后颇有收获分享至此,希望对大家有所帮助~