图形编辑器基于Paper.js教程26:如何在canvas上实现无线网格的功能,高性能,共用网格线

最近在重构TC的UI部分,新版的设计中有一个无限网格线的功能,简单理解就是你的画布上,每隔10px就有一条垂直线或水平线,参考 啄木鸟激光的 软件 LaserPecker
如下图:
在这里插入图片描述
主要有两个大特性,
1: 拖动画布时,无论往哪个方向拖动,无论拖动多少距离,画布上都充满了网格,无止境
2: 缩放画布时,依然保持满屏的网格线,在不同的缩放比下,可能网格的间隔会改变

这个需求是想表达创作是无止境的,不受限于屏幕大小,网格线所在的地方,就是你创作的地方。但可能对密集恐惧症的不太友好。

这个功能最大的难点是 性能。因为在小视图的情况下,画布上的网格线有可能非常多,每一条线都是一个对象,100条垂直线,100条水平线,还没开始创作,200多个对象,就已经吃了浏览器100多M的内存,这要是再导入一个700万像素的图片,内存随时都可能溢出。

针对这个需求,我们有一个很简单的实现方案,就是在拖动画布的事件,缩放画布的事件里 将先前的网格线清空,然后再创建新的网格线,创建的网格线,只需要创建视图内的网格线即可。
在paperjs中 可以很简单地获取到当前视图的四个顶点paper.view.bounds

根据顶点的坐标来确定创建网格线的起点和终点, 需要注意的是,网格线的起点并不一定是视图的起点,因为视图的起点就是就是左上角,有可能是不能被 网格线的间隔整除。 比如视图的起点是27,17,而你的网格线间隔是10,那么你画网格线的起点可以是 30,20,也有是20,10。需要找到距离起点最近的网格线开始画。如果你以视图的起点为网格线的起点,那么你在拖动画布时,网格线是不会动的,因为它始终以画布左上角为起点。这是开发者容易犯的一个错误。

在拖动时清空之前的网格,重新创建网格,这里面的性能消耗,不用说你也知道开销很大。特别是遇到比较卡的电脑。

于是我就想能否创建一个比视图稍微大一点的网格,然后在移动画布时网格页按照某种规律进行移动,共用网格,不必清空网格,重新创建。

于是为了一下AI,结果给的方案很不靠谱,最后还是我自己思考。

假设我们的canvas 大小是100100,那么我们的视图就是100100。网格线按10px的分割。

我们创建网格线时按照 120* 120来创建,就是在视图外多创建两条网格线,我们称之为边界缓冲线。

默认情况下,我们拖动画布往左拉动,那么画布上所有的元素都会往左移动,网格线也不例外。

如下图:
请添加图片描述

那么当我们往左拖动画布的距离超过了一个网格线间隔,我们就让网格线整体往右移动一个网格线间隔。比如你此次拖动往左移动了17px,那么网格线整体就向右移动10px

基于上面的思想,我们可以在移动画布的事件里,累计一次拖动的移动距离,当移动的距离超够网格间隔时,就向相反方向移动网格,并将累计的距离减去网格间隔,进行继续累加。

在拖动画布时的事件里,可以这样处理

    tool.onMouseDrag = (event) => {
      if (dragging && lastPoint) {
        lastViewCenter = paper.view.center;
        const delta = lastPoint.subtract(event.point);
        if (!moveGridDelta) {
          moveGridDelta = delta
        } else {
          moveGridDelta = moveGridDelta.add(delta);
        }
        paper.view.center = paper.view.center.add(delta);

        lastPoint = event.point.add(paper.view.center.subtract(lastViewCenter));

        // 如果moveGridDelta的任意一边超过了gridSpacing,则更新网格线,移动网格线
        if (Math.abs(moveGridDelta.x) > gridSpacing || Math.abs(moveGridDelta.y) > gridSpacing) {
          moveGridDelta = moveGrid(moveGridDelta, gridSpacing, gridLinesGroup)
        }
      }
    };

核心函数是 moveGrid 函数。
看一下最后的效果图:

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拿我格子衫来

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值