最近发现了一个很特别的 canvas lib, paper.js.
它的官方 demo 比较特别, 比较偏向特效上的呈现, 比如 Voronoi 图, 蝌蚪运动(看起来很像...), 以及根据音波做图像呈现等, 不过 example 有点掉 san, 谨慎观看.
没想到十年前玩过的 Staggering Beauty 就是用 paper.js 做的.
我对 Paper.js 的看法
这是我使用第一天的感受, 仅说明一下个人看法.
paper.js 在使用上很像 data -driven 的 canvas 绘制库. 开发者需要操作的是 point path 的数据, 而不是去操作图形本身.
例如, point 表示位置, 但是 point 并不表示形状. 开发中需要做的事情, 是将一个 shape, 比如 circle 和 point 绑定在一起, 和 threejs 有那么点相似.
另外目前看, paperjs 没有 scene 的概念, 只要声明的形状都会呈现在画布上.
paper.js 的官方例子, 看得出它的目标更多是运用在一些特效上, 和完整的 canvas 引擎还是有区别的. 不过用它来做一个 bezier 曲线编辑应该足够.
besizer 曲线编辑
这是第一版, 最终是希望做成 PS 钢笔工具那样的效果.
下面这条去曲线由两段 bezier 曲线构成. 红色是控制点, 蓝色是曲线的锚点.
这个例子是三阶 bezier 曲线, 因为一条曲线有两个控制点. 同时第一段的结束点是第二段曲线的开始点. 现在说一下 paper.js 的能力以及实现思路.
paper.js 本身提供了 hitTest 能力, 所以不需要自己去寻找鼠标选中的 shape. 另外 paper.js 虽然没有 bezier Path 类和方法, 但是提供 handleout handlein 这两个向量来绘制 bezier 曲线.
绘制
下图可以看到, path 由多个 segments(段) 组成, 相邻的两个点构成一段(当然可以自己定义).
- 通过 handleout 和 handlein 来控制贝塞尔曲线
- Point: Segment 的主要部分是一个点,表示曲线开始点 or 结束点。
- 每一个起点都有 handleIn 每一个结束点都有 handleOut
- HandleIn: 一个向量,是控制点和开始点构成的向量, 其值为 controlPoint - startPoint 它定义-了曲线接近控制点时的形状。
- HandleOut: 一个向量,是控制点和结束点构成的向量, 其值为 controlPoint - endPoint 它定义了曲线远离控制点的形状。
// Set the control handles for the curve
bezierPath.segments[0].handleOut = controlPoint1.subtract(startPoint);
bezierPath.segments[1].handleIn = controlPoint2.subtract(endPoint);
事件 & data-driven
当我们拖动控制点, 也就是拖动 Circle Shape 时, 修改 handle position 数据, handle 自己更新. 同时修改 handleLine(辅助线) segments 第二个值, 也就是修改了辅助线 controlPoint 的坐标
var handleLine = new paper.Path({
segments: [endPoint, controlPoint],
});
var handle = new Path.Circle({
center: point,
});
handle.on('mousedrag', function (event) {
handle.position = handle.position.add(event.delta);
handleLine && (handleLine.segments[1].point = handle.position);
});
结束, 不用将 shape 添加到场景中, 也不用调用 paper.onframe 或者 raf 来绘制, 直接绑定事件 --> 修改数据. 结果就能呈现.