You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Vega v5节点图中绘制多色平行连接线?

Vega v5 多属性连接线配置方案

核心思路

  • 拆分链接数据:将每个包含多个共同属性的链接,拆分为多条对应单个属性的链接记录,每条记录标记属性类型/索引。
  • 坐标偏移计算:根据属性索引,对源、目标节点的坐标施加微小偏移,让同组线条平行分开,避免重叠。
  • 条件着色:基于属性类型/索引设置不同的stroke颜色,同时保留原有的hover交互逻辑。

具体实现步骤

1. 数据预处理(添加数据转换)

在你的links数据源后添加flatten转换,把共同属性数组拆成独立条目:

"data": [
  // 你的nodes数据...
  {
    "name": "links",
    // 替换为你的链接数据源(inline或url)
    "transform": [
      // 假设共同属性存储在datum.commonProps数组中
      {"type": "flatten", "fields": ["commonProps"], "as": ["linkProp"]},
      // 给同节点对的拆分链接添加索引,用于计算偏移
      {"type": "window", "ops": ["row_number"], "as": ["propIndex"], "groupby": ["source", "target"]}
    ]
  }
]

2. 计算偏移后的坐标(修改path的transform)

在linkpath转换前,添加formula转换计算偏移后的源/目标坐标,确保线条平行无分叉:

"transform": [
  // 计算连线的方向向量
  {
    "type": "formula",
    "expr": "datum.target.x - datum.source.x",
    "as": "dx"
  },
  {
    "type": "formula",
    "expr": "datum.target.y - datum.source.y",
    "as": "dy"
  },
  {
    "type": "formula",
    "expr": "sqrt(datum.dx*datum.dx + datum.dy*datum.dy)",
    "as": "dist"
  },
  // 计算垂直于连线的单位偏移向量
  {
    "type": "formula",
    "expr": "datum.dist != 0 ? -datum.dy / datum.dist : 0",
    "as": "offsetX"
  },
  {
    "type": "formula",
    "expr": "datum.dist != 0 ? datum.dx / datum.dist : 1",
    "as": "offsetY"
  },
  // 根据属性索引计算偏移量(正负交替避免重叠)
  {
    "type": "formula",
    "expr": "(datum.propIndex - 1.5) * 5", // 5为偏移像素,可按需调整
    "as": "offsetAmount"
  },
  // 生成偏移后的源/目标坐标
  {
    "type": "formula",
    "expr": "datum.source.x + datum.offsetX * datum.offsetAmount",
    "as": "sourceXOffset"
  },
  {
    "type": "formula",
    "expr": "datum.source.y + datum.offsetY * datum.offsetAmount",
    "as": "sourceYOffset"
  },
  {
    "type": "formula",
    "expr": "datum.target.x + datum.offsetX * datum.offsetAmount",
    "as": "targetXOffset"
  },
  {
    "type": "formula",
    "expr": "datum.target.y + datum.offsetY * datum.offsetAmount",
    "as": "targetYOffset"
  },
  // 使用偏移后的坐标生成路径
  {
    "type": "linkpath",
    "require": {"signal": "force"},
    "shape": "line",
    "orient": "horizontal",
    "sourceX": "datum.sourceXOffset", 
    "sourceY": "datum.sourceYOffset",
    "targetX": "datum.targetXOffset", 
    "targetY": "datum.targetYOffset"
  }
]

3. 配置条件着色与交互

修改stroke信号,根据属性类型设置颜色,同时保留原hover逻辑:

"encode": {
  "update": {
    "stroke": {
      "signal": "// 优先处理hover高亮\n(datum.source.datum.filmId == hoverLinkSource && datum.target.datum.filmId == hoverLinkTarget) || datum.source.datum.filmId == hoverNode || datum.target.datum.filmId == hoverNode ? '#0aa4b5' : \n// 根据属性类型设置颜色\ndatum.linkProp == 'genre' ? '#ff4d4f' : \ndatum.linkProp == 'director' ? '#52c41a' : \n// 默认颜色\n'black'"
    },
    "strokeWidth": {"value": 2}, // 减小宽度避免线条重叠
    "cursor": {"value": "pointer"},
    "tooltip": {
      "signal": "{'title': 'Film Link', 'Film 1': datum.source.datum.title, 'Film 2': datum.target.datum.title, 'Link Type': datum.linkProp}"
    }
  }
}

4. 解决路径分叉问题

  • 确保偏移量基于原始连线的垂直方向计算,保证多条线条平行。
  • 偏移像素值不要过大,避免线条远离节点。
  • 绑定linkpath的require信号到force布局,确保布局稳定后再生成路径。

完整修改后的Path图层示例

{
  "type": "path",
  "from": {"data": "links"},
  "interactive": true,
  "encode": {
    "update": {
      "stroke": {
        "signal": "(datum.source.datum.filmId == hoverLinkSource && datum.target.datum.filmId == hoverLinkTarget) || datum.source.datum.filmId == hoverNode || datum.target.datum.filmId == hoverNode ? '#0aa4b5' : datum.linkProp == 'genre' ? '#ff4d4f' : datum.linkProp == 'director' ? '#52c41a' : 'black'"
      },
      "strokeWidth": {"value": 2},
      "cursor": {"value": "pointer"},
      "tooltip": {"signal": "{'title': 'Film Link', 'Film 1': datum.source.datum.title, 'Film 2': datum.target.datum.title, 'Link Type': datum.linkProp}"}
    }
  },
  "transform": [
    {
      "type": "formula",
      "expr": "datum.target.x - datum.source.x",
      "as": "dx"
    },
    {
      "type": "formula",
      "expr": "datum.target.y - datum.source.y",
      "as": "dy"
    },
    {
      "type": "formula",
      "expr": "sqrt(datum.dx*datum.dx + datum.dy*datum.dy)",
      "as": "dist"
    },
    {
      "type": "formula",
      "expr": "datum.dist != 0 ? -datum.dy / datum.dist : 0",
      "as": "offsetX"
    },
    {
      "type": "formula",
      "expr": "datum.dist != 0 ? datum.dx / datum.dist : 1",
      "as": "offsetY"
    },
    {
      "type": "formula",
      "expr": "(datum.propIndex - 1.5) * 5",
      "as": "offsetAmount"
    },
    {
      "type": "formula",
      "expr": "datum.source.x + datum.offsetX * datum.offsetAmount",
      "as": "sourceXOffset"
    },
    {
      "type": "formula",
      "expr": "datum.source.y + datum.offsetY * datum.offsetAmount",
      "as": "sourceYOffset"
    },
    {
      "type": "formula",
      "expr": "datum.target.x + datum.offsetX * datum.offsetAmount",
      "as": "targetXOffset"
    },
    {
      "type": "formula",
      "expr": "datum.target.y + datum.offsetY * datum.offsetAmount",
      "as": "targetYOffset"
    },
    {
      "type": "linkpath",
      "require": {"signal": "force"},
      "shape": "line",
      "orient": "horizontal",
      "sourceX": "datum.sourceXOffset", 
      "sourceY": "datum.sourceYOffset",
      "targetX": "datum.targetXOffset", 
      "targetY": "datum.targetYOffset"
    }
  ]
}

内容的提问来源于stack exchange,提问作者Brian Lim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 22:27:48