对单调的画布说拜拜👋🏻

开始前在这里贴一下我们的项目地址和官网,欢迎大家访问和star⭐️~

项目地址:github.com/didi/LogicF...

官网地址:logicflow.cn/

前言

众所周知,LogicFlow是基于SVG实现的画布,由于没有特别设计过,画布主题默认是这样的👇🏻

虽然现在功能够用,但视觉上确实逐渐跟不上潮流了。

更关键的是,如果你想自定义一套风格统一的画布主题,至少需要经过 4 步操作,涉及多个 API,配置繁琐且易出错:

「修改元素样式 -> 设置画布背景 -> 配置网格 -> 重写边箭头方法调整边箭头样式 -> 其他改动点」

🙋:那有没有通过一套配置完成整个画布主题的配置的办法?

👨🏻:有的,朋友,有的

做了什么

为了能带来更美观的画布、让用户能更方便地配置自定义主题,从2.0.14版本开始LogicFlow对主题模块做了全面升级,让开发者能更便捷地调整主题。具体包括三个方面:

  1. 新增3套内置主题,满足多种审美风格
  2. 主题配置能力增强:支持多边形圆角、箭头样式、背景和网格统一设置
  3. 支持用户配置自定义主题,一行代码切换画布主题

这里主要为大家分享一下这次优化的实现思路,以供有需要的朋友参考。

如何实现

LogicFlow 的主题模块本质是对画布各元素样式的统一配置。当前支持配置的元素与属性如下:

目前我们对外提供了两种配置主题的方式:

  • 初始化配置中传入 style 参数

当创建 LogicFlow 实例时,传入的 style 会被构造函数读取并传给 GraphModel。GraphModel 在初始化时会调用 setupTheme 方法,将传入的 style 与默认主题合并后,存入 theme 字段中。

在画布渲染阶段,视图组件会从各自的 model 中读取 graphModel.theme,并将样式应用到对应的 SVG 元素上,完成样式展示。

  • 运行时调用 setTheme() 方法

调用 setTheme 方法时,LogicFlow 会触发 GraphModel 的 setTheme 方法,将当前主题与传入的样式合并后再次调用 setupTheme,生成更新后的主题并存入 theme 字段。

得益于内部使用的 MobX 响应式机制,theme 的变更会自动触发视图层的更新,使样式即时生效。

实现步骤

Step 1 新增主题映射与切换方法

新增主题映射非常简单,只需参考现有的配置结构,新增三套主题样式并加入映射表即可。

接着为 setTheme 方法新增一个控制主题字段的可选参数 themeMode:

当调用 setTheme(theme, themeMode) 时,内部流程如下:

  1. 优先根据传入的 themeMode 查找对应的预设主题;
  2. 将预设主题与当前基础样式合并;
  3. 如果还传入了 theme(即自定义样式),则继续合并;
  4. 最终生成的主题配置会更新到 theme 中并回显至视图。

这样就实现了预设主题 + 自定义主题的灵活组合。

Step 2 样式合并机制

引入主题模式后,我们需要处理三类样式来源:

  • 基础样式(LogicFlow 内置默认样式)
  • 主题样式(通过 themeMode 引入的预设样式)
  • 自定义样式(用户通过 style 或 setTheme 设置)

这也引出了一个关键问题:

「样式的优先级该如何处理?如何确保高优先级的样式不被覆盖?」

在引入主题模式之前,样式优先级是这样的:

setTheme 设置的样式 > 初始化时通过 style 设置的样式 > 内置基础样式

但在支持主题模式后,如果不做处理,任何一次 setTheme 的调用都会导致之前的样式被完全覆盖,无论是主题样式还是用户定制样式。

为了解决这个问题,我们明确了新的样式优先级:

setTheme 的自定义样式 > style 设置的自定义样式 > 主题样式 > 基础样式

为了实现这一机制,我们新增了一个 customStyle 字段,专门用来存储用户的自定义样式:

  • 初始化时,customStyle 会保存用户传入的 style;
  • 每次调用 setTheme 时,会将传入的自定义样式与已有的 customStyle 合并,再与主题样式及基础样式合并生成最终的 theme;
  • 合并后的 customStyle 会重新存储,等待下一次更新。

通过这样的机制,我们实现了主题样式与用户样式的隔离,保证用户配置的高优先级样式在切换主题时依然生效、不会被覆盖。

Step 3 构建自定义主题

在支持内置主题切换的基础上,我们还希望给用户更多自由 ------ 能否定义属于自己的主题? 为此,我们新增了 LogicFlow.addThemeMode 静态方法,允许用户注册自定义主题。

该方法接受两个参数:

  • themeMode:主题名称
  • config:该主题的样式配置对象

用户只需调用 LogicFlow.addThemeMode('myTheme', customThemeConfig); 即可将自定义主题注册进框架,并像使用内置主题一样通过 setTheme 切换。

内存管理

需要注意的是:不论是内置的 4 套主题,还是用户注册的自定义主题,都是通过静态方式全局存储的。

这意味着这些配置在页面生命周期内会一直存在内存中。

为避免潜在的内存泄漏问题,我们还提供了两个辅助方法:

  • LogicFlow.removeThemeMode(themeMode):移除指定主题
  • LogicFlow.clearThemeMode():清空所有注册的自定义主题

通过这两个方法,用户可以按需清理主题配置,确保资源使用更可控。

Step 4 细节增强

圆角多边形

在 SVG 中,像矩形这样的图形可以直接通过 radius 设置圆角,但 多边形(如菱形、五边形)原生并不支持圆角配置。为了让所有几何图形在视觉风格上保持一致,我们对多边形进行了封装,支持圆角渲染。

实现思路简述如下:

  1. 遍历多边形的所有顶点;
  2. 对每个顶点,使用前后点形成的向量计算圆角的起点和终点;
  3. 使用路径命令画出从前一点到圆角起点的直线;
  4. 再以当前顶点为控制点、起终点为端点绘制二次贝塞尔曲线,形成圆角;
  5. 依次处理所有顶点,最终形成带圆角的平滑多边形路径。

箭头样式配置化

默认情况下,LogicFlow 边的箭头样式为实心箭头。如果想换成其他形态(如线条箭头或菱形箭头),此前需要用户手动重写逻辑,门槛较高。

为简化这一过程,我们新增了以下三种内置箭头样式,并提供了 startArrowType 和 endArrowType 两个主题配置项,一行配置即可定制起终点箭头样式。

  • 线条箭头
  • 圆形箭头
  • 菱形箭头

这些箭头本质上都是 SVG 路径,遵循相同的绘制逻辑,支持如下参数:

  • offset:箭头长度
  • verticalLength:箭头高度
  • refX/refY:箭头参考点位置,影响箭头在边上的相对位置

此外,我们还引入了两个 SVG 样式相关配置:

  • strokeLinecap:定义线段的端点样式,效果与SVG stroke-linecap 属性相同(如 round、square)
  • strokeLinejoin:定义线段连接处的样式,效果与SVG stroke-linejoin 属性相同(如 bevel、round)

通过它们可以进一步提升箭头在不同背景和缩放下的视觉表现。

背景、网格统一配置

在 2.0.14 之前,用户配置画布背景和网格时,必须通过专门的 API:

  • background、grid 初始化参数
  • updateBackgroundOption() / updateGridOptions() 方法

这对主题统一配置带来了不便。

为了解决这一问题,我们在新版本中支持通过 style 和 setTheme 配置背景与网格,将其纳入主题体系中。

配置方式保持不变,原有的 background 和 grid 参数依然生效;新的方式只是提供了一种更便捷的统一配置路径。

注意优先级差异:

初始化阶段,background/grid 参数的优先级高于 style 中的同类配置;

运行时阶段,setTheme、updateBackgroundOption 和 updateGridOptions 优先级等同。

总结:如何为SVG画布及其元素增加主题?

在构建流程图编辑器时,我们常常希望画布及其图形元素能根据不同的主题(如浅色、深色等)进行风格切换,同时又允许用户自定义细节样式。为了实现可维护、可扩展的主题系统,或许可以参考LogicFlow这样的一套通用解决方案:

  • 统一配置边界: 尽量将所有可视属性统一纳入主题样式的管理范围内;
  • 设计统一的样式注入机制: 内部维护一个样式模型,并设计样式作用到元素的生效链路,将主题样式以对象形式注入到画布及其子元素的样式计算中;
  • 构建样式合并规则: 根据实际的样式来源和更新时机,约定一个固定的合并样式规则,必要的情况下可以把不同优先级的样式分开存储,方便组合;
  • 提供用户自定义配置的能力: 提供统一的API/参数,支持用户根据自己的诉求灵活调整主题和样式;

如果这篇文章对你有帮助,欢迎关注我们的账号,我们会持续输出干货文章。也希望您能为我们的项目点上 Star,这对我们非常重要,感恩的心~

项目地址传送门:github.com/didi/LogicF...

相关推荐
周杰伦_Jay21 小时前
【大模型数据标注】核心技术与优秀开源框架
人工智能·机器学习·eureka·开源·github
玄魂1 天前
如何查看、生成 github 开源项目star 图表
前端·开源·echarts
隐语SecretFlow1 天前
【隐语Secreflow】如何配置 Kuscia 对请求进行 Path Rewrit
架构·开源
hh.h.1 天前
开源鸿蒙生态下Flutter的发展前景分析
flutter·开源·harmonyos
吴敬悦1 天前
私有的 GitHub Package 怎么拉取?
npm·github
文心快码BaiduComate1 天前
给 AI 装上“员工手册”:如何用Rules 给文心快码 (Comate) 赋能提效?
前端·程序员·前端框架
小胖霞1 天前
全栈系列(15)github Actions自动化部署前端vue
前端·node.js·github
一RTOS一1 天前
光亚鸿道携手AGIROS开源社区,共筑中国具身智能机器人操作系统新生态
机器人·开源·鸿道实时操作系统·国产嵌入式操作系统选型·具身智能操作系统选型
刘发财1 天前
前端一行代码生成数千页PDF,dompdf.js新增分页功能
前端·typescript·开源