canvas思维导图连线需绑定节点世界坐标、按场景选三种类型、响应状态变化、隔离移动端手势。关键在于坐标统一转换、动态样式更新与手势精准识别,确保连线随节点动、交互变、缩放稳。

Canvas 绘制交互式思维导图时,连线不是静态装饰,而是承载逻辑关系、支持动态响应的核心元素。关键不在“画线”,而在“线如何随节点动、随交互变、随缩放稳”。以下四点是落地时真正影响体验的逻辑要点:
连线必须绑定节点世界坐标,而非画布像素坐标
节点拖拽或缩放时,如果连线直接用 node.x/node.y(即未经过 viewTransform 反算的原始值)绘制,就会漂移或断裂。正确做法是:所有坐标运算前统一转换——
起始点 = ((startNode.x - offsetX) / scale),
结束点 = ((endNode.x - offsetX) / scale)。
这样即使画布放大2倍、平移300px,连线仍精准锚定在节点中心。
三种连线类型按场景选,不混用
-
直线连线:适用于父子级直连(如中心主题→一级分支),调用
moveTo() → lineTo() → stroke()即可,性能最高; -
折线连线:用于绕开密集区域(如两个同级节点间需避开中间节点),插入1–2个偏移控制点,例如
lineTo(x+60, y); lineTo(x+60, y2); lineTo(x2, y2); -
贝塞尔曲线:适合表达非对称关系(如“影响”“依赖”),用
quadraticCurveTo(cx, cy, ex, ey),控制点建议设为起点与终点中垂线上方1/3处,视觉更自然。
连线要响应节点状态变化
不能只画一次。当节点被选中、高亮、折叠或编辑时,连线应同步更新样式:
- 选中某节点时,与其相连的所有线宽从1.5px增至2.5px,颜色变主色;
- 折叠子分支后,对应连线应设为
ctx.setLineDash([4, 4])显示虚线,并降低透明度(ctx.globalAlpha = 0.6); - 鼠标悬停在线上时,需用
isPointInStroke()判断命中(注意传入反算后的坐标),再临时加粗并显示关系标签。
移动端手势必须隔离处理
双指缩放和单指拖拽共存时,若未区分手势类型,连线会抖动或错位:
- 监听
touchstart,记录 touches 长度,≥2 则标记为缩放手势,禁用节点拖拽; - 缩放过程中,仅更新
viewTransform.scale和offsetX/Y,不重绘节点位置; - 所有 touchmove 事件末尾加
e.preventDefault(),防止页面滚动干扰画布操作。











