🎯 用 Vue + SVG 实现一个「蛇形时间轴」组件,打造高颜值事件流程图

🎯 用 Vue + SVG 实现一个「蛇形时间轴」组件,打造高颜值事件流程图

在数据可视化或大屏项目中,我们常常需要展示一系列的事件流程,比如飞行轨迹、操作日志、任务执行顺序等。本文将带你一步步实现一个基于 Vue + SVG蛇形排列时间轴组件,支持动态数据渲染、自适应布局与美观样式。

📌 效果预览

先来看一下最终效果(简化描述):

  • 每行最多显示 5 个节点;
  • 偶数行从左往右排布,奇数行从右往左,形成"蛇形"布局;
  • 节点之间用带箭头的线段连接;
  • 每个节点包含时间和标签信息;
  • 样式美观,适配深色背景大屏风格。

🧩 组件结构概览

这是一个标准的 Vue 单文件组件(SFC),由以下几个部分组成:

<template> 部分

使用 SVG 渲染图形元素:

  • 箭头定义(<marker>
  • 连线(<line>
  • 节点圆点(<circle>
  • 时间文本(<text>
  • 标签文本(<text>

📊 <script> 部分

  • 定义了原始事件数据 dataList

  • 设置每行最大节点数 maxPerRow

  • 使用计算属性动态生成:

    • 节点坐标(蛇形排列)
    • 连线路径(两端缩进避免重叠)
    • SVG 宽高(根据数据长度自动调整)

🎨 <style scoped> 部分

  • 使用背景图片和文字渐变效果打造科技感外观;
  • 标题栏使用 -webkit-background-clip: text 技术实现渐变文字。

🔍 关键技术点详解

1️⃣ 蛇形布局算法

kotlin 复制代码
深色版本
const row = Math.floor(idx / this.maxPerRow)
const col = idx % this.maxPerRow
if (row % 2 === 0) {
  x = leftMargin + col * this.nodeGapX
} else {
  x = leftMargin + (this.maxPerRow - 1 - col) * this.nodeGapX
}

通过判断当前是偶数行还是奇数行,控制节点的排列方向,实现蛇形布局。


2️⃣ 动态连线绘制

使用向量数学方法计算两点之间的连线,并在两端留出一定间隙,避免覆盖节点:

ini 复制代码
深色版本
const dx = x2 - x1
const dy = y2 - y1
const len = Math.sqrt(dx * dx + dy * dy)
const ratioStart = gap / len
const ratioEnd = (len - gap) / len

3️⃣ SVG 自适应宽高

kotlin 复制代码
深色版本
svgWidth() {
  return this.maxPerRow * this.nodeGapX + 100
},
svgHeight() {
  return Math.ceil(this.dataList.length / this.maxPerRow) * this.nodeGapY + 40
}

根据数据长度和每行节点数,自动计算 SVG 容器尺寸。

💡 可扩展性建议

虽然该组件已经能很好地满足基础需求,但还可以进一步增强功能和灵活性:

功能 实现方式
✅ 支持点击事件 <circle> 添加 @click 事件
🎨 主题定制 将颜色提取为 props 或 CSS 变量
📱 响应式适配 使用百分比宽度或监听窗口变化
🎥 动画过渡 添加 SVG 动画或 Vue transition

📦 如何复用这个组件?

你可以将它封装成一个通用组件,接收如下 props:

yaml 复制代码
深色版本
props: {
  dataList: { type: Array, required: true },
  maxPerRow: { type: Number, default: 5 },
  nodeGapX: { type: Number, default: 200 },
  nodeGapY: { type: Number, default: 100 },
  themeColor: { type: String, default: '#fff' }
}

这样就可以在多个页面中复用,只需传入不同的事件数据即可。

🧠 源码(示例)