阅读视图

发现新文章,点击刷新页面。

LogicFlow 小地图性能优化:从「实时克隆」到「占位缩略块」!🚀

写在开头

Hi,各位朋友们好呀!😋

今是2026年03月10日,虽迟但到,时间飞快,又过去一个月了。

灵魂一问:你养虾了吗?🦞

最近 OpenClaw 很火呢,但...它真能给你带来实际作用吗?🤔
小编也养了一只,但目前好像除了提供点"情绪价值",其他场景的还没派上用场,生产力也还在观察中。

二月过了个年,这个年小编过得非常开心的,从各个方面。🥳 然后,也给辛苦一年的自己买了个小礼物:换了台电脑——MacBook Air M4 24+512。

猜猜小编花了多少钱拿下的?评论区有答案。

言归正传,今天要分享的内容依旧是关于 LogicFlow 库的,给其小地图插件增加缩略块模式,效果如下,请诸君按需食用哈。

image.png

需求背景 💡

在最近的项目里,小编基于 LogicFlow 做了流程图页面,节点类型不少,而且很多是自定义 HTML 节点,内容里有文本、图片、视频、音频等富媒体。

画布上用了官方推荐的小地图插件,功能没问题,但小地图是实时同步主画布的:主画布渲染一份节点,小地图再渲染一份,内容一样。节点一多,加上拖拽、缩放、批量操作,两边都要更新,有点一个页面干两份活的意思,几十上百个节点时性能压力就很明显。

主画布可以靠局部渲染缓解,小地图那块就没辙了,如果节点再显示图片、视频这类资源,一进页面就要全量加载,非常容易卡顿。

这次目标很明确:给小地图开发一种缩略块模式——用轻量占位块代替真实节点渲染,缓解性能问题。具体来说🤔:

  1. 保留定位导航能力
  2. 不再同步创建真实节点内容
  3. 用轻量占位块表达节点位置和大小
  4. 与现有 miniMap 配置兼容

实现过程 ⚡

以下改造思路和实现均基于 LogicFlow 官方 MiniMap 源码,插件整体代码并不算多,可以仔细瞧瞧:传送门

第1️⃣步:明确改造策略——继承官方 MiniMap

小编没有另起炉灶,从零开始,而是直接继承官方 MiniMap,只改关键实现点。

这样做的好处是:

  • 官方行为仍可复用(例如视口更新、定位等)
  • 后续升级 LogicFlow 时,迁移成本更低

🍊 为什么选择「继承 + 局部重写」❓

因为咱们真正的痛点不是功能不够,只是渲染太重。只要把渲染部分调整一下,就能快速拿到收益,不必把整个插件推倒从零开始。

import { MiniMap } from "@logicflow/extension";

/**
 * 自定义小地图:继承官方 MiniMap,通过 placeholderMode 支持「占位块」与「实时克隆」双模式
 */
class CustomMiniMap extends MiniMap {
  constructor({ lf, LogicFlow, options }) {
    const { placeholderMode = true, ...restOptions } = options || {};
    const hasRestOptions = Object.keys(restOptions).length > 0;
    // 将 placeholderMode 以外的配置透传给官方 MiniMap
    super({ lf, LogicFlow, options: hasRestOptions ? restOptions : undefined });
    this.placeholderMode = placeholderMode;  // 默认开启占位块模式
  }
}

第2️⃣步:增加 placeholderMode,支持双模式切换

这一步是整个方案的开关:

  • placeholderMode: true:占位块模式(默认)
  • placeholderMode: false:实时模式(回退到官方行为)

也就是说,咱们不是把官方逻辑「干掉」,而是给它加了个性能开关。

/**
 * 重写 setView:根据 placeholderMode 决定走官方渲染还是轻量占位块渲染
 */
setView(reRender = true) {
  if (!this.placeholderMode) {
    return MiniMap.prototype.setView.call(this, reRender);  // 回退到官方实时克隆
  }
  // placeholderMode === true 时,走轻量占位块渲染逻辑(此处省略具体实现)
}

第3️⃣步:把真实节点数据转换为占位块数据

⏰ 关键点❗❗❗

小地图不再吃原始节点类型,而是统一转换成一个占位节点类型: minimap:placeholder

转换时只保留导航必需信息:

  • id
  • x / y
  • width / height
  • 少量 properties(用于占位模型读取)
const MINIMAP_PLACEHOLDER_TYPE = "minimap:placeholder";

/**
 * 将原始节点数据转换为占位块数据,仅保留定位、尺寸等导航必需信息
 * @param {Object} data - { nodes, edges }
 * @returns {Object} 转换后的 { nodes, edges },节点类型统一为 minimap:placeholder
 */
_resetDataWithPlaceholder(data) {
  const nodes = data.nodes.map((node) => {
    // 优先从 properties 取尺寸,再 fallback 到节点顶层,默认 200
    const width = Number(node.properties?.width) || Number(node.width) || 200;
    const height = Number(node.properties?.height) || Number(node.height) || 200;
    return {
      id: node.id,
      type: MINIMAP_PLACEHOLDER_TYPE,
      x: node.x,
      y: node.y,
      width,
      height,
      properties: { width, height, _originalType: node.type },
    };
  });

  return {
    nodes,
    edges: this.showEdge ? data.edges.map((e) => ({ ...e, text: undefined })) : [],
  };
}

💡 小贴士:这里优先从 properties.width/height 取尺寸,再 fallback 到节点顶层尺寸,这个细节非常重要,能保证小地图占位块尺寸更贴近主画布真实节点。

第4️⃣步:注册轻量占位节点视图与模型

占位节点本身非常轻,只渲染一个 rect,不挂任何复杂内容。

import { h, RectNode, RectNodeModel } from "@logicflow/core";

/**
 * 轻量占位节点视图:只渲染一个圆角矩形,不挂载任何子节点或富媒体内容
 */
class MinimapPlaceholderView extends RectNode {
  getShape() {
    const { x, y, width, height } = this.props.model;
    return h("g", {}, [
      h("rect", {
        x: x - width / 2,   // LogicFlow 节点以中心点为坐标,rect 需偏移
        y: y - height / 2,
        rx: 10,
        ry: 10,
        width,
        height,
      }),
    ]);
  }
}

这样小地图的渲染成本就从创建一堆真实节点内容,降到了画几个轻量矩形块。

第5️⃣步:接入现有使用的地方

在业务页面里,小编是直接替换 MiniMap 的来源,不改既有交互入口:

// 仅改 import 来源,其余用法与官方 MiniMap 一致
import { CustomMiniMap as MiniMap } from "./plugins/CustomMiniMap";

LogicFlow.use(MiniMap);

再加上 CustomMiniMap.pluginName = "miniMap",可以继续复用原有 pluginsOptions.miniMap 配置,不需要大动干戈改业务代码,这点非常香。😁

完整源码

传送门

总结

这次改造的核心就一句话:小地图有时可能并不需要真实还原,只需要正确导航就行。

通过二次改造增加小地图新模式后,咱们拿到了几个关键收益:

  • 小地图渲染负担显著下降
  • 节点规模上来后,交互更稳
  • 依然保留官方 MiniMap 的主要能力




至此,本篇文章就写完啦,撒花撒花。

image.png

希望本文对你有所帮助,如有任何疑问,期待你的留言哦。
老样子,点赞+评论=你会了,收藏=你精通了。

❌