携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第24天,点击查看活动详情
一、前言
由于项目需求,想要开发一个展示项目历程的功能,一开始想到的是用 element ui 的时间线来实现,但是我发现 element ui 已经让我审美疲劳了,我不想再用了,机缘巧合下我发现 ECharts 有一个关系图,似乎能用这个方式来实现,抱着试一试的态度,在一顿猛如虎的操作下,还真别说真的能实现,所以想给大家也安利一下,有需要优化的地方,欢迎大家提出来。不废话了,上代码。
二、ECharts 实现项目历程
代码如下:
<template>
<div class="app-container">
<!-- 图表容器 -->
<div id="routeCanvas" style="width: 100%; height: 800px; background-color: black;" />
</div>
</template>
<script>
import { EleResize } from '@/utils/esresize' // 图表自适应
export default {
name: 'App',
data() {
return {
// 图片
symbols: [
require('../../assets/test/start.png'),
require('../../assets/test/through.png'),
require('../../assets/test/check.png'),
require('../../assets/test/update.png'),
require('../../assets/test/check2.png')
],
// 颜色
colors: ['pink', 'skyblue', 'green', 'orange', 'white'],
// 连线标签
linkLabels: [
'1', '2', '3', '4', '5', '6', '7', '8', '9', '10',
'11', '12', '13', '14', '15', '16', '17', '18', '19', '20',
'21', '22', '23', '24', '25', '26', '27', '28', '29', '30',
'31', '32', '33', '34', '35', '36', '37', '38', '39', '40'
],
// 步骤
stepList: ['提交合同', '审核合同', '调整合同', '生成合同'],
// 关系图数据
jsonData: {
'1': [{
'finished_time': '2022-07-18 16:16:22',
'finished_step_id': 0,
'id': 378,
'operator': '巨蟹座不吃鱼'
},
{
'finished_time': '2022-07-18 16:16:45',
'finished_step_id': 1,
'id': 379,
'operator': '巨蟹座不吃鱼'
},
{
'finished_time': '2022-07-18 16:16:48',
'finished_step_id': 2,
'id': 380,
'operator': '巨蟹座不吃鱼'
},
{
'finished_time': '2022-07-18 16:46:53',
'finished_step_id': 3,
'id': 381,
'operator': '巨蟹座不吃鱼'
}],
'2': [{
'finished_time': '2022-07-18 17:02:55',
'finished_step_id': 1,
'id': 382,
'operator': '巨蟹座不吃鱼'
},
{
'finished_time': '2022-07-18 17:02:58',
'finished_step_id': 2,
'id': 383,
'operator': '巨蟹座不吃鱼'
},
{
'finished_time': '2022-07-19 09:35:44',
'finished_step_id': 3,
'id': 384,
'operator': '巨蟹座不吃鱼'
}],
'3': [{
'finished_time': '2022-07-19 09:36:38',
'finished_step_id': 2,
'id': 385,
'operator': '巨蟹座不吃鱼'
},
{
'finished_time': '2022-07-20 11:14:05',
'finished_step_id': 3,
'id': 387,
'operator': '巨蟹座不吃鱼'
}],
'4': [{
'finished_time': '2022-07-20 11:14:18',
'finished_step_id': 1,
'id': 388,
'operator': '巨蟹座不吃鱼'
},
{
'finished_time': '2022-07-20 11:14:21',
'finished_step_id': 2,
'id': 389,
'operator': '巨蟹座不吃鱼'
},
{
'finished_time': '2022-07-22 14:06:22',
'finished_step_id': 3,
'id': 390,
'operator': '巨蟹座不吃鱼'
}],
'5': [{
'finished_time': '2022-07-22 14:59:01',
'finished_step_id': 1,
'id': 391,
'operator': '巨蟹座不吃鱼'
},
{
'finished_time': '2022-07-22 14:59:04',
'finished_step_id': 2,
'id': 392,
'operator': '巨蟹座不吃鱼'
},
{
'finished_time': '2022-07-22 16:01:01',
'finished_step_id': 3,
'id': 393,
'operator': '巨蟹座不吃鱼'
},
{
'finished_time': '2022-07-22 16:16:53',
'finished_step_id': 4,
'id': 394,
'operator': '巨蟹座不吃鱼'
}]
}
}
},
created() {
//初始化调用
this.formateChartsData()
},
methods: {
// 数据处理
formateChartsData() {
// 初始化
var chartData = []
var chartLink = []
var x = 400
var y = 0
// 单独拼接开始
chartData.push({
name: '开始' + '\n' + this.jsonData['1'][0]['finished_time'], // 显示的标签
x: x, // x位置
y: 0, // y位置
symbol: 'image://' + this.symbols[0], // 开始图片
symbolSize: 40, // 图片大小
value: this.jsonData['1'][0]['operator'], // 提示框中的展示的名字
label: { // 标签样式
color: 'red',
fontWeight: 'bold'
}
})
// 拼接其他轮次
if (this.jsonData['1'].length > 1) {
for (var iter_num in this.jsonData) { // iter_item:轮次
// 1.拼接轮次
y += 400
chartData.push({
name: '第' + iter_num + '轮:',
x: 0,
y: y,
symbol: 'rect',
symbolSize: 0,
label: {
color: this.colors[Number(iter_num) - 1],
fontSize: '16px',
fontWeight: 'bold'
}
})
// 2.拼接每轮次的步骤
for (var node_num in this.jsonData[iter_num]) { // node_num:步骤
if (this.jsonData[iter_num][node_num]['finished_step_id'] === 0) { // 跳过开始
continue
} else {
chartData.push({
name: this.stepList[this.jsonData[iter_num][node_num]['finished_step_id'] - 1] + '\n' + this.jsonData[iter_num][node_num]['finished_time'],
x: iter_num === '1' ? (x + 700 * (node_num - 1)) : (x + 700 * node_num), // 计算每个步骤的x位置
y: y,
symbol: 'image://' + this.symbols[this.jsonData[iter_num][node_num]['finished_step_id']],
symbolSize: 40,
value: this.jsonData[iter_num][node_num]['operator'],
label: {
color: this.colors[Number(iter_num) - 1],
fontWeight: 'bold'
}
})
}
}
}
// 3.拼接每个步骤之间的连线chartLink
for (var i = 0; i < chartData.length - 1; i++) {
if (chartData[i]['name'].indexOf('第') === -1) {
chartLink.push({
source: i,
target: chartData[i + 1]['name'].indexOf('第') === -1 && chartData[i]['name'] !== '开始' ? i + 1 : i + 2,
symbolSize: [2, 10],
lineStyle: {
width: 1,
curveness: 0
},
label: {
show: false, // 连线标签是否展示
formatter: this.linkLabels[i]
}
})
}
}
}
// 画图
this.$nextTick(() => {
this.initCharts(document.getElementById('routeCanvas'), '项目历程示例', chartData, chartLink)
})
},
// 画图方法
initCharts(domName, projectName, chartData, chartLink) {
var myChart
if (myChart !== null && myChart !== '' && myChart !== undefined) {
myChart.dispose() // 图表销毁
}
myChart = this.$echarts.init(domName)
// 图表自适应
var listener = function() {
myChart.resize()
}
EleResize.on(domName, listener)
var option = {
title: { // 标题
text: projectName.split('*#*')[0],
top: 10,
left: 'center',
textStyle: {
fontSize: 30,
color: '#fff'
}
},
tooltip: { // 提示框
trigger: 'item',
backgroundColor: 'rgba(255, 255, 255, 0.9)'
},
animationDurationUpdate: 1500,
animationEasingUpdate: 'quinticInOut',
series: [// 数据
{
type: 'graph',
layout: 'none',
roam: true,
label: {
show: true,
position: 'bottom'
},
edgeSymbol: ['circle', 'arrow'],
edgeSymbolSize: [4, 10],
edgeLabel: {
fontSize: 20
},
animationDelay: function(idx) {
return idx * 200
},
data: chartData,
links: chartLink,
lineStyle: {
opacity: 0.9,
width: 2,
curveness: 0
}
}
]
}
// 清除图表
myChart.clear()
// 绘制图表
option && myChart.setOption(option)
}
}
}
</script>
页面渲染效果如下: