本文只是一个paper.js
的使用注意事项,可以算是踩坑指南,不是翻译文档,有问题可以留言交流。
前言
最近在搞一个图形框选工具,支持矩形、椭圆、多边形框选,同时需要限定范围,写本篇目的是看国内中文资料很少,将这次踩坑指南记录一下,便于大家交流;具体操作为首先在一张图片框选一个范围作为限定范围,然后第二个人再次进行框选,只能在第一个人指定的方位框选,限定范围和框选范围均支持三种类型,如下图所示中间透明区域即为限定范围,绿色即为框选范围(图片来自网络)
方案选择
fabric.js:这个框架支持鼠标进行矩形和椭圆形的框选以及变换,我尝试在这个框架的基础上进行多边形框选,以及限定范围的处理,发现本框架扩展较差,不太适合此场景
原生js:尝试原生,能很快的实现想要的功能,但是对于边界的检测,图形的交叉检测自己写有点费劲
paper.js,two.js:均为二维图形绘制库,对比了两个库github的star,以及示例,选择了paper.js
paper.js踩坑
js调用与PaperScript调用区别
首先要注意的是,关于使用PaperScript
与js
调用他的api
的区别,我直接使用的js
来进行调用,主要需要注意的点如下(paperScript代码不放)
- 需要调用方法
paper.setup(canvas)
或者new Project(canvas)
来创建一个空的project
和view
-
需要在元素加载完毕后,再创建
paper project
,也就是需要window.onload = function() { var canvas = document.getElementById('myCanvas'); paper.setup(canvas); }
-
关于工具,对于
PaperScript
的工具使用则可以直接使用事件,使用js需要自己创建工具,如var tool = new Tool(); var path; tool.onMouseDown = function(event) { path = new Path(); path.strokeColor = 'black'; path.add(event.point); } tool.onMouseDrag = function(event) { path.add(event.point); }
-
关于运算,很多官方示例给出的为
+
,-
,*
,/
,实际上我们使用js操作会出现报错,此时我们应该采用向量的add
,subtract
,multiply
,divide
方法来进行代替,如下var vector = point2 - point1; // paperScript写法 var vector = point2.subtract(point1); // js写法
参考链接:http://paperjs.org/tutorials/...
向量的概念
向量是这里边很重要的一个概念,理解了向量的概念对于绘图以及操作动画轨迹我认为是很重要的一个功能(具体可以看下方资料),此处我只说一点,就是Point
本身其实就是代表一个向量,如图
point1
和point2
均为向量,这个其实代表了他们的相对于远点也就是canvas左上角的向量值
如果我们想把point1
移动到point2
那么,其实首先向右移动60,然后向下移动50
那么此时我们有一个更简单的方法,就是通过向量
var vector = point2 - point1;
// = { x: 110, y: 200 } - { x: 50, y: 50 }
// = { x: 60, y: 150 }
这样做减法,我们就得到了一个向量,也就是说point1
和point2
是绝对位置,而vector
则为相对位置,通过这个方式我们得到了vector
,此时我们可以得到他的长度和角度,帮助我们完成一些必要的运算
console.log(vector.length);
// 161.55494
console.log(vector.angle);
// 68.19859
通过向量,我们则可以对点的位置进行操作和处理
参考中文资料:https://www.microheart.me/pap...
参考官网资料:http://paperjs.org/tutorials/...
绘制层级
存在图层的概念,类似于PS工具的层级关系
-
PaperScope1
-
project1(操作对象)
-
layer1(图层)
- Path(路径)
- Group(组)
- Shape(图形)
- layer2
-
- project2
-
- PaperScope2
但是此处有几个点需要注意
- 当图形实例化时,默认情况是自动会加入到当前活跃的对象(
paper.project
)中活跃的图层(project.activeLayer
)当中,如果需要设置,需要自己处理配置
paper.settings.insertItems // 是否将新建的Item插入到活跃的图层中
- 对于图形和路径,虽然都存在椭圆和矩形等形状,但是他们的一些属性操作是不同的,最容易被坑的就是
size
属性,这个对于Shape
是有的,但是Path
没有,一定注意下图的Properties
的不同,避免踩坑
- 实例化
Project
后会默认加到全局的paper.projects
当中,并作为一个被激活的project
,如果存在多个project
,请处理处理多个project的活跃关系,避免出现想要往一个project里边加,但是却导致加到另外一个里边,激活一个对象的方法为(如果insertItems
为默认值true
,这个问题易出现)
project.activate(); // 使用当前对象绘制图形
绘制工具
paper.js的工具就是处理鼠标和键盘事件,同时当实例化Tools
时会加入到全局,如果存在多个Tools
也应该注意,避免多个监听事件使用出现问题
var tool1 = new Tools();
var tool2 = new Tools();
tool1.onMouseUp = () => {
console.log('tool2');
};
tool2.onMouseUp = () => {
console.log('tool2');
}
tool1
和tool2
均会放在paper.tools
当中,同一时间只能有一个工具生效,也就是上面两个onMouseUp
同时只能有一个回调被使用到,激活某一个工具,如下
tool1.activate();
碰撞检测
这个东西在图形处理的时候很有用,这里说一下官网支持的一些东西
- 支持检测图形,图形边界和图形的选中边界
- 支持检测某个点在图形的什么位置
- 只是检测两个图形的是否相交以及相交点的位置
点检测
点检测方法为hitTest
,示例为
project.hitTest(point[, options])
其中point
即为paper.js
实例化的一个点,比如new Point(15, 20)
则检测[15, 20]这个店是否命中了某个图形,命中的位置为什么,命中的对象结构参照HitResult
类
其中options
为一个对象,代表对检测的一些控制,下面列出一部分
- tolerance 检测灵敏度,默认为
paper.settings.hitTolerance
- fill 图形上
- stroke 图形边界
- segments 是否检测路径Path中每一段segment的控制点
- bounds 矩形的边界
- selected 只响应已经选中的店
路径相交检测
aPath
是否与bPath
相交,返回一个布尔值
aPath.intersects(bPath);
获取aPath
和bPath
相交的点,并返回相交的点集合
aPath.getIntersections(bPath)
动画(我没用到,略过)
其他建议
- 需要理解
canvas
原生的一些内容能够帮助更好的绘图,比如两次绘制之间关系(paperjs为blendMode
,原生为globalCompositeOperation
),参照:https://developer.mozilla.org... - 理解原生的裁剪(原生为
ctx.clip()
,paper.js
为使用clipMask
属性),使用这个时候后续图形绘制的显示将仅能展示在此裁剪路径当中 -
下面几个事件处理很有用,可以注意一下,可以看下方代码使用
- removeOn(options)
- removeOnMove()
- removeOnDown()
- removeOnDrag()
-
removeOnUp()
在鼠标拖拽时,不断清空上一次的绘制,然后绘制一个新的,这样就能做出鼠标操作绘制出矩形和椭圆形的功能了tools.onMouseDrag = (event) => { var path = new Path.Circle({ center: event.point, radius: 10, fillColor: 'black' }); path.removeOnDrag(); }
- 路径还有很多操作前后端
segment
段的方法,等待自己去探索使用
结束语
paper.js
还有很多有意思的功能,只是需要注意上面的一些坑,虽然中文资料不多,但是逐步看看官方文档,慢慢也就能看懂了
官网API地址:http://paperjs.org/reference/...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。