写在前面

最近在换工作,投了特别喜欢的一家公司,正在等意向(更新后续,目前成功入职了,十分感恩),等待时间是不能浪费的,所以我打算先熟悉一下公司的技术。echarts就是其中之一,之前有用过Echarts,但是这家公司的业务是需要高度自定义的。那么就开始吧!

项目链接在这儿👉https://github.com/Ra-Liz/vue-echarts-test

以下的练手项目使用vue3搭建。(顺便回顾了vue3,没想到上手这么快)

一个简单的自定义饼图

image-20240730112451189

思路:

  1. 使用ref绑定图容器
  2. 初始化echart画布
  3. 配置画布内元素
    1. 标题、工具文本、整体样式
    2. 数据排序、细节样式
  4. 挂载监听器
  5. 测试数据实时更新逻辑
    1. btn绑定回调,watch监听数据变化
    2. 优化函数声明,分块,拼接
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
<template>
<div class="w-full h-full">
<button class="w-1/2 h-20 rounded bg-blue-200 hover:bg-blue-400" @click="handleChangeData">
点击更新数据
</button>
<div id="chart" ref="chartContainer" class="w-1/2 h-1/2 bg-pink-200"></div>
</div>
</template>

<script setup>
import * as echarts from 'echarts'
import { onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'

const fakeData = reactive([
{ value: 335, name: 'Direct' },
{ value: 310, name: 'Email' },
{ value: 274, name: 'Union Ads' },
{ value: 235, name: 'Video Ads' },
{ value: 400, name: 'Search Engine' }
])

const chartContainer = ref(null)
let myChart = null

const initChart = () => {
if (chartContainer.value) {
myChart = echarts.init(chartContainer.value)
setChartOptions()
}
}

const setChartOptions = () => {
if (myChart) {
const option = {
backgroundColor: '#2c343c',
title: {
text: 'Customized Pie',
left: 'center',
top: 20,
textStyle: {
color: '#ccc'
}
},
tooltip: {
trigger: 'item'
},
visualMap: {
show: false,
min: 80,
max: 600,
inRange: {
colorLightness: [0, 1]
}
},
series: [
{
name: 'Access From',
type: 'pie',
radius: '55%',
center: ['50%', '50%'],
data: fakeData.sort((a, b) => a.value - b.value),
roseType: 'radius',
label: {
color: 'rgba(255, 255, 255, 0.3)'
},
labelLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.3)'
},
smooth: 0.2,
length: 10,
length2: 20
},
itemStyle: {
color: '#c23531',
shadowBlur: 200,
shadowColor: 'rgba(0, 0, 0, 0.5)'
},
animationType: 'scale',
animationEasing: 'elasticOut',
animationDelay: (idx) => Math.random() * 200
}
]
}
myChart.setOption(option)
}
}

const handleChangeData = () => {
fakeData.forEach((item) => {
item.value = Math.floor(Math.random() * 500)
})
}

onMounted(() => {
initChart()
window.addEventListener('resize', () => myChart && myChart.resize())
})

onBeforeUnmount(() => {
window.removeEventListener('resize', () => myChart && myChart.resize())
if (myChart) {
myChart.dispose()
}
})

watch(
fakeData,
() => {
setChartOptions()
},
{ deep: true }
)
</script>

自定义柱状图趋势

image-20240730112509879

思路:

  1. 同上
  2. 使用api….进行样式自定义
  3. 使用分区缩放
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
<template>
<div class="w-full h-full">
<h1 class="text-3xl text-black">Test 2</h1>
<div ref="containerRef" class="w-1/2 h-1/2 rounded bg-blue-300"></div>
</div>
</template>

<script setup lang="ts">
import { ref, onMounted, nextTick } from 'vue'
import * as echarts from 'echarts'

let myChart: echarts.ECharts | null = null
const containerRef = ref<HTMLDivElement | null>(null)

const originYear: number = 2020
const years: number = 10
const cnt: number = 7
const legendData: string[] = ['trend']
const xAxisData: string[] = []
const customData: any[] = []
const encodeY: any = []
const dataList: any = []

for (let i = 0; i < cnt; i++) {
legendData.push(`${originYear + i}`)
dataList.push([])
encodeY.push(1 + i)
}

for (let i = 0; i < years; i++) {
xAxisData.push('category' + i)

const customVal = [i]
customData.push(customVal)

let val = Math.random() * 1000
for (let j = 0; j < dataList.length; j++) {
let value =
j === 0
? echarts.number.round(val, 2)
: echarts.number.round(Math.max(0, dataList[j - 1][i] + (Math.random() - 0.5) * 200), 2)
dataList[j].push(value)
customVal.push(value)
}
}

const initChart = () => {
if (containerRef.value) {
myChart = echarts.init(containerRef.value)
setChartOptions()
}
}

const setChartOptions = async () => {
if (myChart) {
const options = {
tooltip: {
trigger: 'axis'
},
legend: {
data: legendData
},
dataZoom: [
{
type: 'slider',
start: 50,
end: 70
},
{
type: 'inside',
start: 50,
end: 70
}
],
xAxis: {
type: 'category',
data: xAxisData
},
yAxis: {},
series: [
{
name: 'trend',
type: 'custom',
renderItem: (params: any, api: any) => {
let xValue = api.value(0)
let currentSeriesIndices = api.currentSeriesIndices()
let barLayout = api.barLayout({
barGap: '30%',
barCategoryGap: '20%',
count: currentSeriesIndices.length - 1
})
let points = []

for (let i = 0; i < currentSeriesIndices.length; i++) {
let seriesIndex = currentSeriesIndices[i]
if (seriesIndex !== params.seriesIndex) {
let point = api.coord([xValue, api.value(seriesIndex)])
point[0] += barLayout[i - 1].offsetCenter
point[1] -= 20
points.push(point)
}
}

let style = api.style({
stroke: api.visual('color'),
fill: 'none'
})
return {
type: 'polyline',
shape: {
points: points
},
style: style
}
},
data: customData,
encode: {
x: 0,
y: encodeY
},
z: 100
},
...dataList.map((data: any, index: any) => {
return {
type: 'bar',
animation: false,
name: legendData[index + 1],
data: data
}
})
]
}

myChart.setOption(options)
}
}

onMounted(() => {
nextTick(() => {
if (containerRef.value) {
console.log(containerRef.value)
initChart()
}
})
})
</script>

自定义绘制风场