你以为节点丢了,其实是被裁掉了

我在搭一个 BPMN 工作流编辑器,用的是 bpmn-js。

那天我打开画布,看到默认的三个元素——开始事件、审核任务、结束事件。但我手动拖了一个排他网关和一个注释框进去,保存后刷新页面,它们不见了。

我发了截图给你,红色边框的注释框里显示了一个「[」,旁边有个 X 菱形网关,还有一些虚线。我以为是渲染出了 bug。

我用 CDP 检查了实际页面,结果是这样:

1
2
3
4
5
6
viewportSize:     1384 x 805   (整个浏览器窗口)
canvasRect: 1004 x 687 (画布可见区域)
djsContainerSize: 1004 x 687 (bpmn-js 容器)
djsOverflow: hidden (溢出被裁剪)
shapeCount: 5 (开始 + 任务 + 结束 + 2个标签)
scrollbars: horizontal=no, vertical=no

画布上只有 5 个元素——开始、任务、结束和两个标签。你截图里多出来的 X 网关和红色注释框,不在 CDP 查到的 DOM 里。

这意味着那些元素是你手动拖到画布上的,但没有被保存到默认 XML。刷新页面后,只有 XML 里的元素会被加载。

但更关键的是:那些元素即使被加载了,也会被画布裁掉。

什么是无限画布

bpmn-js 的画布容器设置了 overflow: hidden。这意味着画布不会显示滚动条,也不会显示画布边界。

你可以把元素拖到画布可见区域之外——它们不会消失,只是被裁剪了。

你想看到它们?用鼠标中键拖动来平移画布,或者按住 Shift 加鼠标拖动。用 Ctrl 加滚轮缩放。

没有滚动条。没有边界线。没有”当前你看到哪里”的指示器。

这就是无限画布设计。

代价:你不知道自己在哪

无限画布设计的好处很明显——你可以画任意大的流程图,不需要担心画布边界。一个审批流程可能有几十个节点、几十条连线,如果画布有边界,你的流程就会被迫缩小或者换页。

但代价是:你失去了位置感。

我那次看到截图里有红色注释框和 X 网关,以为渲染出错了。其实不是——那些元素是被拖到了画布外面,被 overflow: hidden 裁掉了。

我问的是:”节点少吗?还是因为样式的问题,没显示全?没滚动条吗?”

答案很简单:

  • 节点不少——DOM 里有 5 个元素
  • 不是样式问题——是溢出裁剪
  • 确实没有滚动条——因为这是无限画布设计

三个问题,三个答案,但第一个问题的”答案”本身就是一个问题。

我以为节点丢了,因为无限画布给了我一种”所有内容都应该在这里”的错觉。但实际上,画布上显示的东西只是”当前视口”里的内容。你把元素拖到了视口外面,它就看不见了——但你没有任何提示告诉你”这里还有东西”。

固定画布 vs 无限画布:一个被低估的 trade-off

大多数工具的画布是有边界的。Word 有页面边缘,Excel 有单元格网格,VS Code 有滚动条,浏览器有窗口边界。

当你看到边界,你知道:

  • 内容在哪里结束
  • 滚动条的位置告诉你当前在看第几行/第几列
  • 你永远不会”丢东西”——因为画布会提醒你”这里还有内容”

但 bpmn-js、Figma、Excalidraw 这类工具选择了无限画布。

无限画布省掉了滚动条的 UI 复杂度,省掉了画布边界的视觉噪音。当你画一个 100 节点的流程图时,你不需要缩小视图到 20% 才能看到全貌——你可以把每个节点都正常大小,然后用平移来查看不同区域。

但代价是空间感知消失了。

一个实际例子

我在 BPMN 编辑器里遇到了这个问题。我拖了一个注释框到画布的右下角,但那个位置刚好在 1004×687 的可见区域之外。我刷新页面后,注释框没了。

我以为是 bug。我花了几分钟检查 DOM、检查 CSS、检查渲染逻辑,才意识到:

注释框还在画布里,只是被裁掉了。

如果我用的是一种有滚动条的工具——比如 Word 或传统 IDE——我一眼就能看到右侧或底部有滚动条,拉一下就能看到被裁掉的内容。

但 bpmn-js 没有滚动条。它给你一个无限的空间,代价是你必须自己知道”我在这里,那里还有东西”。

怎么解决

bpmn-js 提供了几种方式来应对这个问题:

  1. 鼠标中键拖动——平移画布,看到被裁掉的内容
  2. Shift + 鼠标拖动——同上
  3. Ctrl + 滚轮——缩放,缩小后所有元素都能显示在视口内
  4. F2 键——重置视图,自动缩放并居中显示所有元素
  5. 双击空白处——触发 zoom-fit,同上

但这些都不是”一眼就能看到”的。你需要知道这些快捷键,或者在 UI 上放一个”适应视图”按钮。

我后来决定加一个工具栏按钮,一键 zoom-fit。这样用户不用记快捷键,也不用猜”是不是有东西被裁掉了”。

无限画布适合什么

无限画布不是万能的。它适合:

  • 内容大小不可预测的场景(流程图可能有 5 个节点,也可能有 500 个)
  • 空间位置很重要的场景(你拖元素到不同位置是有意义的——比如 BPMN 的布局反映流程走向)
  • 内容不会被”意外丢失”的场景(元素不会因为超出边界而消失,只是被裁剪)

固定画布+滚动条适合:

  • 内容大小可预测的场景(一页 Word 文档、一张 Excel 表格)
  • 用户需要知道”当前位置”的场景(第 50 行、第 3 页)
  • 内容不会因为超出边界而”看起来消失”的场景

没有对错,只有适合不适合。

bpmn-js 选择无限画布,是因为 BPMN 流程图的规模不可预测。一个审批流程可能只有 3 个节点,也可能有几十个节点跨多页。如果用固定画布,大流程图会被迫缩小到看不清,或者被迫分页——而分页在 BPMN 里意味着把流程切断了。

但它也应该提供足够的视觉提示,让用户知道”画布外面还有东西”。

设计工具的人,需要为用户的困惑负责

我那次花了很长时间在检查 DOM、检查 CSS、检查渲染逻辑——我才意识到问题不是 bug,而是设计。

用户看到截图里有红色注释框和 X 网关,然后刷新后看不见了。用户的第一反应是”出错了”,不是”哦,那是无限画布设计,元素被裁掉了”。

这不是用户的错。这是工具没有提供足够的空间感知。

无限画布设计省掉了滚动条,但如果你不加”适应视图”按钮、不加小地图、不加缩略图预览——用户就只能靠猜。

猜的成本是时间。而我花了二十分钟在猜”是不是有东西被裁掉了”。

如果当时工具栏上有一个”适应视图”按钮,或者右下角有一个小地图显示当前视口在画布里的位置——这二十分钟就不会花。

结论

无限画布是一个合理的设计选择,但它有一个被低估的代价:用户会失去空间感知。

当你选择无限画布,你也在选择让用户用”快捷键+记忆”来替代”滚动条+视觉提示”。

如果你的工具选择了无限画布,你需要提供足够的补偿:

  • 一个”适应视图”按钮(让用户一键看到所有内容)
  • 一个小地图或缩略图(让用户知道当前位置)
  • 至少一个视觉提示(比如画布边缘的渐变色,暗示”外面还有东西”)

否则,你的用户会在画布外面迷路——而他们的第一反应是”你的工具有 bug”。