前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >简简单单实现画笔工具,轻松绘制丝滑曲线

简简单单实现画笔工具,轻松绘制丝滑曲线

作者头像
前端西瓜哥
发布2024-06-03 15:25:56
920
发布2024-06-03 15:25:56
举报

大家好,我是前端西瓜哥。

最近照着 Figma 做了个简单的画笔功能,实现起来还是比较简单的。

我正在开发的 suika 图形编辑器: https://github.com/F-star/suika 线上体验: https://blog.fstars.wang/app/suika/

绘制流程

首先是监听按下鼠标,我们记录好此时鼠标的位置,作为路径的起点,并记录此时是 “拖拽状态”。

然后按住鼠标不放,进行拖拽。

我们监听鼠标移动事件,如果是 “拖拽状态”,我们通过鼠标事件拿到最新的鼠标位置,保存起来。

鼠标移动事件会在鼠标移动时按较小的间隔不断触发,于是我们能拿到一个个的点。

我们将这些点按顺序连起来,然后渲染到画布上,这样就在画布上绘制出了线条。

最后鼠标释放,这条线段就正式被绘制出来了,我们退出 “拖拽状态”,并把新增一个路径对象的数据添加到历史记录。

对离散点做曲线拟合

我们是无法从浏览器的 API 拿到曲线的,能拿到的只是一堆的点。

浏览器会在鼠标移动时按照特定的频率触发鼠标事件。

移动得慢,会拿到密集的点,移动得快,就会拿到稀疏的点。

它的采样频率比较适中,如果希望提高采样率,单位时间内捕获更多的点,但那是不可能的,因为浏览器做了限制。

如果高采样率很重要,可以考虑做桌面应用。

但不管如何,最后我们可以拿到一条折线,但和我们真实世界中用画笔绘制出的光滑线条有很大出入。

所以这里需要对离散的采样点做光滑化处理,最终转换为点更少的曲线表达。

这种操作称为 曲线拟合(Curve Fitting)

算法

这里我就想到了 paper.js 的 path.simplify(tolerance)。该方法的作用就是曲线拟合,将一个复杂的 path 简化为数据量更少形状更平滑的 path。

tolerance 是光滑程度,越大就越光滑,但同时也越不像原来的路径形状。

它使用的是一种叫做 Schneider algorithm 的曲线拟合算法,并在其上做了一些改进。

该算法的原理不是本文讨论的重点,感兴趣的可以去找一篇发布于 1990 年,名为《An Algorithm for Automatically Fitting Digitized Curves》的文章,并收录在一本名为《Graphics Gems》的书中。

关注公众号,回复 ”曲线拟合“,获取《Graphics Gems》电子书

paper.js 的方法很好,但它的这个算法是和 paper.js 对象耦合在一起的,我不好抽出来,有一些工作量。

最后我找到一个 fit-curve 库,正是基于 Schneider algorithm 的实现。

https://github.com/soswow/fit-curve

其用法为:

代码语言:javascript
复制
import fitCurve from 'fit-curve';

const points = [[0, 0], [10, 10], [10, 0], [20, 0]]; // 需要处理的有序点集
const error = 50; // error 越大,曲线越光滑

const bezierCurves = fitCurve(points, error);
// bezierCurves[0] 为 [[0, 0], [20.27317402, 20.27317402], [-1.24665147, 0], [20, 0]]
// 代表的是三阶贝塞尔曲线:[起点, 控制点1,控制点2, 终点]

然后我们在鼠标释放的时候,对折线线条应用该算法,就能得到一个平滑的曲线。

这里我给 error 设置非常小的值,让曲线更接近原来的形状,同时也能有效减少点的数量。

曲线拟合算法还有其它的实现,比如 RDP algorithm,读者可以都尝试一下,看看哪个效果更好。

更进阶的,可以像 paper.js 一样尝试去改进算法,甚至融合创造新的算法。

其它

这里的画笔工具,思路是在绘制折线后做一个曲线拟合,将线条做平滑处理。

还有一种做法是在绘制过程中就进行曲线拟合(也叫防抖),甚至可以引入压感动态改变线的局部粗细,这样更接近像是 Photoshop 这类基于位图的画笔工具形态。

结尾

我是前端西瓜哥,欢迎关注我,学习更多图形编辑器知识。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-05-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端西瓜哥 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 绘制流程
  • 对离散点做曲线拟合
  • 算法
  • 其它
  • 结尾
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档