目录
Vue3 + hook + Apexcharts实现可视化图表渲染的封装 - 第一节 - 基础封装
Vue3 + hook + Apexcharts实现可视化图表渲染的封装 - 第二节 - 图表的全屏功能 (当前所在)
摘要
上一节中,我们用Vue3 + hook + Apexcharts封装了图表渲染的基础代码。这节我们将在那个基础上进行图表的全屏查看功能。上一级代码中的
renderCharts
函数中有通过getScatterData
和interceptFn
对图表数据进行截取,当图表数据有几万条时,像条形图、散点图这些如果一次性渲染出来就会导致页面卡顿,从而影响页面的其他功能。这时我们就可以在初始的时候渲染部分的数据,全屏的时候再渲染全部的数据。
正文
- 怎么自定义全屏图表?
- 当同一个页面中有多个图表时,在全屏某个图表时怎么获取正确的渲染?
实现思路
自定义全屏图表按钮
效果
右上角中有个全屏图表按钮,Apexcharts中提供了自定义工具栏的功能
代码实现
// 导入全屏按钮的图标
import fullScreenImg from '@/assets/images/fullScreen.webp'
// 在图表中配置
chart: {
toolbar: {
tools: {
download: true,
selection: false,
zoom: false,
zoomin: false,
zoomout: false,
pan: false,
reset: false,
customIcons: [{
icon: `<img src="${fullScreenImg}" width="16" height="16">`,
index: -1,
title: '全屏',
class: 'custom-icon',
click: (chart, options) => {}
}]
},
}
// 设置全局的css
.vue-apexcharts .custom-icon {
margin-right: 6px;
transform: translateY(2px);
}
渲染正确的图表
实现过程
- 在全局的store中记录当前页面的全部图表的
chartInfo
,包括chartObj
初始化的某些图表配置项、option
渲染图表后需要根据数据设置的配置项, 以及data
当前渲染图表所需的数据。 - 为了区分对应的图表数据,全局的
chartInfo
为一个Map
对象,通过ID
可获取对应当前全屏对应的图表的数据。需要在ApexChart
的父级中设置一个唯一的ID
。
<div id="ChartID">
<ApexChart>
</div>
何时设置数据?
,在图表渲染时,也就是调用renderChart
时,图表的数据更新会触发updated
事件,在这个时候可以设置当前图表的信息。
<div id="ChartID">
<ApexChart @updated="onChartUpdated">
</div>
- 创建全局的全屏图表弹窗,通过全局的store去控制。当我点击某个图表的全屏按钮时会在上面自定义全屏按钮里的
click
中将对应的当前的图表父元素的ID
和chartType
记录下来。
customIcons: [{
click: (chart, options) => {
store.dispatch('chart/setChartType', options.config.chart.type)
store.dispatch('chart/setChartId', chart.el.parentElement.id)
store.dispatch('chart/visibleDialog', true)
}
}]
代码实现
store/chart.js
const state = {
visible: false,
chartType: 'line',
chartId: '',
chartInfo: {},
}
const mutations = {
VISIBLE_DIALOG: (state, view) => {
state.visible = view
},
SET_CHART_TYPE: (state, view) => {
state.chartType = view
},
SET_CHART_ID: (state, view) => {
state.chartId = view
},
SET_CHART_INFO: (state, view) => {
if (!view) {
state.chartInfo = {}
return
}
const { id, chartObj, option, data } = view
state.chartInfo[id] = { chartObj, option, data }
},
}
const actions = {
visibleDialog({ commit }, view) {
commit('VISIBLE_DIALOG', view)
},
setChartType({ commit }, view) {
commit('SET_CHART_TYPE', view)
},
setChartId({ commit }, view) {
commit('SET_CHART_ID', view)
},
setChartInfo({ commit }, view) {
commit('SET_CHART_INFO', view)
},
}
export default {
namespaced: true,
state,
mutations,
actions,
}
utils/chart.js
import _ from 'lodash'
import store from '@/store'
export const setChartDialogInfo = (id, chartObj, data, ...rest) => {
const obj = _.cloneDeep(chartObj)
obj.options.responsive = []
obj.options.chart.toolbar.tools.customIcons = []
const option = obj.updateOptions(data, ...rest)
store.dispatch('chart/setChartInfo', {id, chartObj: obj, option, data})
}
hook/useRenderChart.js
其他代码请访问第一节:Vue3 + hook + Apexcharts实现可视化图表渲染的封装 - 第一节 - 基础封装
const useRenderChart = (chartList) => {
.....其他代码
const count = ref(0)
// 监听图表更新,设置ChartDialog弹框的信息
const configChartDialog = () => {
if (!chartList[count.value]) return
const { chartObj, data, key } = chartList[count.value]
setChartDialogInfo(key, chartObj, data)
count.value++
if (count.value === chartList.length) {
count.value = 0
}
}
return {
configChartDialog
}
}
ApexChart组件中使用
<ApexChart
:ref="el => setRefMap(el, index)"
:type="item.type"
:options="item.chartObj.options"
:series="item.chartObj.series"
@updated="configChartDialog"
/>
全屏弹框组件components/ChartDialog
<template>
<el-dialog
class="chart-dialog"
:title="$t('common.chart')"
v-model="visible"
:fullscreen="true"
center
@close="handleClose"
>
<ApexChart
v-loading="loading"
:key="chartId"
ref="chartRef"
:height="height"
:type="chartType"
:options="chartObj.options || {}"
:series="chartObj.series || []"
@updated="onChartUpdated"
/>
</el-dialog>
</template>
<script setup>
import ApexChart from 'vue3-apexcharts'
const store = useStore()
const visible = computed(() => store.state.chart.visible)
const chartType = computed(() => store.state.chart.chartType)
const chartId = computed(() => store.state.chart.chartId)
const chartInfo = computed(() => store.state.chart.chartInfo)
const chartObj = computed(() => chartInfo.value[chartId.value]?.chartObj || {})
const chartRef = ref()
const height = computed(() => window.innerHeight - 140)
const loading = ref(true)
watch(visible, (val) => {
if (val) {
nextTick(() => {
setTimeout(() => {
chartRef.value.updateOptions(chartInfo.value[chartId.value].option)
loading.value = false
}, 500)
})
}
})
const handleClose = () => {
store.dispatch('chart/visibleDialog', false)
store.dispatch('chart/setChartId', '')
loading.value = false
}
</script>
总结
因为网上Apexcharts的文章极少,这是自己使用过程中的一下记录。这次记录的是图表的全屏的弹窗功能。下一节开始将记录一些Apexcharts无法满足的需要,但是业务中却需要的图表绘制功能。