Vue3 EMS 项目实战:ECharts 按需封装与 ZoomChart 图表放大-06
Vue3 EMS 项目实战:ECharts 按需封装与 ZoomChart 图表放大
系列:组件与工具专题
本篇主题:echarts.ts按需引入 +Echart组件 +ZoomChart+ 大屏适配
源码:src/utils/echarts.ts、src/components/Echart/、src/components/ZoomChart/index.vue
一、EMS 项目的图表需求
储能 EMS 页面图表密度高:
- 电量曲线、SOC 曲线、收益柱状图
- 液位图(liquidfill)、3D 关系图(echarts-gl)
- 侧边栏折叠/展开时图表需自动 resize
- 小图点击「放大」查看细节
本项目封装了 Echart 基础组件和 ZoomChart 放大组件,并统一主题与尺寸缩放。
二、ECharts 按需引入,控制包体积
// utils/echarts.ts
import * as echarts from 'echarts/core'
import 'echarts-liquidfill'
import { LineChart, BarChart, PieChart, GraphChart, ScatterChart, LinesChart, TreeChart } from 'echarts/charts'
import { TitleComponent, TooltipComponent, GridComponent, LegendComponent, DataZoomComponent, ... } from 'echarts/components'
import { CanvasRenderer } from 'echarts/renderers'
echarts.use([
LineChart, BarChart, PieChart, ScatterChart, TreeChart, GraphChart, LinesChart,
TitleComponent, TooltipComponent, GridComponent, LegendComponent, DataZoomComponent,
CanvasRenderer,
])
export default echarts
好处:只打包用到的 chart / component,避免 import echarts from 'echarts' 全量引入。
新增图表类型时,在 echarts.use([...]) 中注册即可。
三、Echart 组件:生命周期与 resize
<template>
<div :id="id" ref="chartDom" class="__echart__hnt" :style="{ height, width }"></div>
</template>
3.1 初始化与 markRaw
onMounted(async () => {
await nextTick()
myChart.value = markRaw(echarts.init(chartDom.value, 'normal'))
myChart.value.setOption(props.options, true)
emit('mountEchat', myChart.value)
})
markRaw 避免 ECharts 实例被 Vue 代理,防止性能问题和奇怪 bug。
3.2 三重 resize 保障
| 触发源 | 处理方式 |
|---|---|
| 窗口 resize | window.addEventListener('resize', initChart) |
| 全屏切换 | document.addEventListener('fullscreenchange', resizeHandler) |
| 容器尺寸变化 | ResizeObserver 监听 chartDom(侧边栏折叠场景) |
resizeObserver = new ResizeObserver(() => {
resizeHandler()
})
resizeObserver.observe(chartDom.value)
3.3 统一主题 normal
./normal.ts 定义 EMS 品牌色、坐标轴、tooltip 等默认样式,refreshNormal() 在 init 前刷新主题变量,保证多图表视觉一致。
3.4 数据点 clickFn
option 的 data 项可挂 clickFn,组件内统一监听:
myChart.value.on('click', (params) => {
params.data?.clickFn?.(params.data, params)
})
鼠标 hover 时自动切换 cursor 为 pointer。
四、sizeFn:1920 基准的大屏缩放
EMS 大屏按 1920 设计,小屏需等比缩放字号和间距:
export const sizeFn = (val?: number) => {
let clientWidth = window.innerWidth || document.documentElement.clientWidth
let scale = clientWidth / 1920
if (val === undefined) return scale
return val * scale
}
Echart 组件配合 useSizeStore,在 resize 时重新计算 option 中的 fontSize、grid 等。
五、ZoomChart:一键放大图表
小模块嵌入的图表空间有限,用户需要放大查看。ZoomChart 封装「放大镜按钮 + 弹窗大图」:
<ZoomChart
:title="$t('100xxxx')"
:options="chartOptions"
width="70%"
chart-height="550px"
/>
5.1 Teleport 浮动按钮
按钮通过 Teleport 挂到图表容器右下角,不破坏原有布局:
const findAnchorContainer = () => {
// 向上查找 .chart / .chartBox 容器
for (const selector of anchorSelectorList.value) {
const found = triggerMount.value?.closest(selector)
if (found) return found
}
return triggerMount.value?.parentElement
}
5.2 弹窗内复用 Echart
点击放大后打开 h-dialog,内部渲染同一份 cloneDeep(options) 的 Echart,宽高可配置。
const showFn = () => {
chartOptions.value = cloneDeep(props.options)
showModal.value = true
}
Props 亮点:
| Prop | 作用 |
|---|---|
noButton |
隐藏按钮,外部控制打开 |
autoAnchor |
自动定位到父 chart 容器 |
fullscreen |
全屏弹窗模式 |
anchorSelectors |
自定义锚点选择器 |
六、compareFun:实时数据涨跌标记
BMS 实时监控需对比新旧值,ECharts rich text 中展示涨跌箭头:
export function compareFun(oldVal: string | number, newVal: string | number) {
oldVal = Number(oldVal)
newVal = Number(newVal)
if (isNaN(oldVal) || isNaN(newVal)) return ''
if (oldVal > newVal) return '{down|}'
if (oldVal < newVal) return '{rise|}'
return ''
}
配合 HDataItem 组件在数值旁展示趋势(见专题第 8 篇)。
七、典型页面用法
<template>
<div class="chartBox">
<Echart :options="lineOptions" height="280px" @mountEchat="onChartReady" />
<ZoomChart title="电量曲线" :options="lineOptions" />
</div>
</template>
<script setup>
const lineOptions = computed(() => ({
xAxis: { type: 'category', data: times.value },
yAxis: { type: 'value' },
series: [{ type: 'line', data: values.value }],
}))
</script>
八、本篇小结
| 模块 | 职责 |
|---|---|
echarts.ts |
按需注册 chart/component |
Echart |
init、resize、主题、事件 |
ZoomChart |
放大镜 + Dialog 大图 |
sizeFn |
1920 基准缩放 |
compareFun |
涨跌 rich text |
踩坑:
- ECharts 实例必须
markRaw,否则 tooltip 异常 - 侧边栏动画结束后图表可能尺寸不对,靠 ResizeObserver 而非仅 window resize
- ZoomChart 打开时用
cloneDeep,避免弹窗内外 option 互相污染
源码索引:src/utils/echarts.ts、src/components/Echart/index.vue、src/components/ZoomChart/index.vue、src/utils/common.ts
更多推荐


所有评论(0)