echarts.ts
// 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
import * as echarts from 'echarts/core'
/** 引入柱状图and折线图图表,图表后缀都为 Chart */
import { BarChart, LineChart } from 'echarts/charts'
// 引入提示框,标题,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component
import {
TitleComponent,
TooltipComponent,
GridComponent,
// 数据集组件
DatasetComponent,
// 内置数据转换器组件 (filter, sort)
TransformComponent,
LegendComponent
} from 'echarts/components'
// 标签自动布局,全局过渡动画等特性
import { LabelLayout, UniversalTransition } from 'echarts/features'
// 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
import { CanvasRenderer } from 'echarts/renderers'
// 注册必须的组件
echarts.use([
TitleComponent,
TooltipComponent,
GridComponent,
DatasetComponent,
TransformComponent,
LegendComponent,
BarChart,
LabelLayout,
UniversalTransition,
CanvasRenderer,
LineChart
])
// 导出
export default echarts
main.ts
import echarts from '@/utils/echarts'
import App from './App.vue'
const app = createApp(App)
app.config.globalProperties.$echarts = echarts
组件中使用
import { getCurrentInstance } from 'vue'
const { proxy }: any = getCurrentInstance()
myChart.value = markRaw(proxy.$echarts.init(container.value))
举例echarts组件
<template>
<div class="echart-main">
<div class="echart-nav">
<div class="echart-title">
<strong>{{ title }}</strong>
</div>
<slot name="title" />
</div>
<div v-if="props.isError" class="moment">指标采集失败,请刷新或联系管理员排查</div>
<div v-if="!props.isError && props.chartData.length === 0" class="moment">暂无数据</div>
<div class="echart" ref="container" v-if="props.chartData.length > 0" />
</div>
</template>
<script setup lang="ts">
import {
ref,
computed,
getCurrentInstance,
onMounted,
onBeforeUnmount,
watch,
nextTick,
markRaw,
onUnmounted
} from 'vue'
import { useConfigStore } from '@/stores/config'
type ChartDataType = { name: string; xAxis: string; yAxis: string | number; [key: string]: any }
const props = defineProps({
title: {
type: String,
default: '',
required: true
},
yAxisName: {
type: String,
default: ''
},
chartData: {
type: Array,
default: () => [
{ key: 'item1', xAxis: '2023/9/4/ 01:00', yAxis: 12 },
{ key: 'item1', xAxis: '2023/9/4/ 02:00', yAxis: 11 },
{ key: 'item1', xAxis: '2023/9/4/ 03:00', yAxis: 1 },
{ key: 'item1', xAxis: '2023/9/4/ 04:00', yAxis: 12 },
{ key: 'item1', xAxis: '2023/9/4/ 05:00', yAxis: 16 },
{ key: 'item2', xAxis: '2023/9/4/ 01:00', yAxis: 14 },
{ key: 'item2', xAxis: '2023/9/4/ 02:00', yAxis: 32 },
{ key: 'item2', xAxis: '2023/9/4/ 03:00', yAxis: 62 },
{ key: 'item2', xAxis: '2023/9/4/ 04:00', yAxis: 22 },
{ key: 'item2', xAxis: '2023/9/4/ 05:00', yAxis: 12 }
]
},
idStr: {
type: String,
required: true
},
isError: {
type: Boolean,
default: false
},
spanValue: {
type: Number,
default: 12
}
})
const container = ref()
const { proxy }: any = getCurrentInstance()
const myChart = ref<any>(null)
const resize = () => {
if (myChart.value && myChart.value.resize) {
myChart.value?.resize()
}
}
onMounted(() => {
window.addEventListener('resize', resize)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', resize)
})
onUnmounted(() => {
myChart.value && myChart.value.dispose()
myChart.value = null
})
const configStore = useConfigStore()
const leftWidth = computed(() => {
return configStore.leftWidth + 'px'
})
watch(
[() => leftWidth.value, () => props.spanValue],
() => {
nextTick(() => {
resize()
})
},
{ deep: true }
)
const initEcharts = async () => {
const _rawData: ChartDataType[] = props.chartData as ChartDataType[]
if (_rawData && Array.isArray(_rawData) && _rawData.length > 0) {
let seriesData: any = []
let dataKey: any = []
const xAxis: string[] = [...new Set(_rawData.map(i => i.xAxis))]
_rawData.forEach((v: ChartDataType) => {
if (!dataKey.includes(v.key)) {
dataKey = [...dataKey, v.key]
}
})
dataKey.sort()
dataKey.forEach((k: string) => {
seriesData = [
...seriesData,
{
name: k,
type: 'line',
smooth: true,
showSymbol: false,
data: _rawData.filter((i: ChartDataType) => i.key === k).map((d: ChartDataType) => d.yAxis)
}
]
})
const option = {
legend: {
data: dataKey,
type: 'scroll',
bottom: 20,
icon: 'circle',
itemWidth: 6
},
grid: {
right: 20,
left: 60,
bottom: 70,
top: 20
},
tooltip: {
show: true,
trigger: 'axis'
},
xAxis: {
type: 'category',
nameLocation: 'middle',
splitLine: {
show: true,
lineStyle: {
type: 'solid',
color: '#f2f2f2',
width: 1
}
},
axisLine: {
show: true,
lineStyle: {
color: '#e4e7ed'
}
},
axisTick: {
show: true,
lineStyle: {
color: '#f2f2f2'
}
},
axisLabel: {
color: '#556677',
fontSize: 12
},
data: xAxis
},
yAxis: {
// name: props.yAxisName.length > 5 ? '' : props.yAxisName,
// nameTextStyle: {
// padding: [0, 80, 0, 0],
// color: '#262626'
// },
// nameGap: -6,
// nameLocation: 'end',
type: 'value',
splitLine: {
show: true,
lineStyle: {
color: '#f5f5f5',
width: 1,
type: 'solid'
}
},
axisLine: {
show: true,
lineStyle: {
color: '#e4e7ed'
}
},
axisTick: {
show: true,
lineStyle: {
color: '#f2f2f2'
}
},
axisLabel: {
color: '#556677',
width: 50,
overflow: 'truncate'
}
},
series: seriesData
}
nextTick(() => {
if (myChart.value) {
myChart.value.dispose()
myChart.value = null
}
myChart.value = markRaw(proxy.$echarts.init(container.value))
myChart.value.setOption(option, true)
})
}
}
watch(
() => props.chartData,
() => {
initEcharts()
},
{ deep: true, immediate: true }
)
defineExpose({ initEcharts })
</script>
<style scoped lang="scss">
.echart-main {
width: 100%;
height: 270px;
min-width: 200px;
background: #fff;
border-radius: 8px;
box-shadow:
0 2px 4px 0 rgb(0 0 0 / 1%),
0 3px 6px 3px rgb(0 0 0 / 1%),
0 2px 6px 0 rgb(0 0 0 / 3%);
box-sizing: border-box;
}
.echart-nav {
display: flex;
height: 20px;
padding: 16px 16px 0;
flex-direction: row;
align-items: center;
}
.echart-title {
width: 100%;
font-size: 14px;
}
.echart-select {
float: right;
width: 40%;
min-width: 300px;
padding-right: 10px;
padding-bottom: 10px;
}
.echart {
width: 100%;
height: calc(100% - 20px);
}
.moment {
padding: 40px 20px;
}
</style>