123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- <script lang="ts" setup>
- import {getParametricEquation} from "@/utils/chart";
- import * as echarts from "echarts";
- import 'echarts-gl' // 3d图表库
- import {waterQualitys} from "@/utils/unit.js";
- import {nextTick, onMounted, onUnmounted, ref} from "vue";
- defineExpose({loadChart, carousel, bindListen, markLineChange})
- const chartRef = ref(null)
- let chart = null
- let timer = undefined
- let selectedIndex = ''
- let hoveredIndex = ''
- async function loadChart(option, type = null) {
- if (!chart) {
- await nextTick(); // 确保DOM已经渲染完成
- chart = echarts.init(chartRef.value);
- }
- chart.setOption(option, true);
- setTimeout(() => chart.resize(), 1000)
- if (type && type === 'bindListen') {
- bindListen();
- }
- }
- function markLineChange(index) {
- if (chart) {
- const option = chart.getOption()
- option.series[0].markLine.data = [{xAxis: index}]
- chart.setOption(option, true);
- }
- }
- function reloadChart() {
- const checkAndResize = () => {
- if (chart) {
- chart.resize();
- } else {
- setTimeout(checkAndResize, 1000);
- }
- };
- checkAndResize();
- }
- /* 轮播 */
- function carousel(timeout = 5000, yAxisChange = false) {
- const checkAndCarousel = () => {
- if (chart) {
- // 获取legend的data
- const legendData = chart.getOption().legend[0].data
- // 首次总是从0开始的
- let i = 0
- // 开始轮播
- timer = setInterval(() => {
- // 激活
- chart.dispatchAction({
- type: 'legendToggleSelect',
- name: legendData[++i % legendData.length]
- })
- }, 10000)
- if (yAxisChange) {
- chart.on('legendselectchanged', function (params) {
- let selected = undefined;
- for (let key in params.selected) {
- if (params.selected[key] === true) {
- selected = key;
- break
- }
- }
- let field = waterQualitys.find(i => i.label === selected)
- if (field) {
- chart.setOption({yAxis: {name: field.unit,}});
- }
- });
- }
- } else {
- setTimeout(checkAndCarousel, 1000);
- }
- }
- checkAndCarousel();
- }
- // 监听鼠标事件,实现饼图选中效果(单选),近似实现高亮(放大)效果。
- function bindListen() {
- // 监听点击事件,实现选中效果(单选)
- chart.on('click', (params) => {
- const option = chart.getOption()
- // 从 option.series 中读取重新渲染扇形所需的参数,将是否选中取反。
- const isSelected = !option.series[params.seriesIndex].pieStatus.selected
- const isHovered = option.series[params.seriesIndex].pieStatus.hovered
- const k = option.series[params.seriesIndex].pieStatus.k
- const startRatio = option.series[params.seriesIndex].pieData.startRatio
- const endRatio = option.series[params.seriesIndex].pieData.endRatio
- // 如果之前选中过其他扇形,将其取消选中(对 option 更新)
- if (selectedIndex !== '' && selectedIndex !== params.seriesIndex) {
- option.series[selectedIndex].parametricEquation = getParametricEquation(
- option.series[selectedIndex].pieData.startRatio,
- option.series[selectedIndex].pieData.endRatio,
- false,
- false,
- k,
- option.series[selectedIndex].pieData.value
- )
- option.series[selectedIndex].pieStatus.selected = false
- }
- // 对当前点击的扇形,执行选中/取消选中操作(对 option 更新)
- option.series[params.seriesIndex].parametricEquation = getParametricEquation(
- startRatio,
- endRatio,
- isSelected,
- isHovered,
- k,
- option.series[params.seriesIndex].pieData.value
- )
- option.series[params.seriesIndex].pieStatus.selected = isSelected
- // 如果本次是选中操作,记录上次选中的扇形对应的系列号 seriesIndex
- selectedIndex = isSelected ? params.seriesIndex : null
- // 使用更新后的 option,渲染图表
- chart.setOption(option)
- })
- // 监听 mouseover,近似实现高亮(放大)效果
- chart.on('mouseover', (params) => {
- const option = chart.getOption()
- // 准备重新渲染扇形所需的参数
- let isSelected
- let isHovered
- let startRatio
- let endRatio
- let k
- // 如果触发 mouseover 的扇形当前已高亮,则不做操作
- if (hoveredIndex === params.seriesIndex) {
- // 否则进行高亮及必要的取消高亮操作
- } else {
- // 如果当前有高亮的扇形,取消其高亮状态(对 option 更新)
- if (hoveredIndex !== '') {
- // 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 false。
- isSelected = option.series[hoveredIndex].pieStatus.selected
- isHovered = false
- startRatio = option.series[hoveredIndex].pieData.startRatio
- endRatio = option.series[hoveredIndex].pieData.endRatio
- k = option.series[hoveredIndex].pieStatus.k
- // 对当前点击的扇形,执行取消高亮操作(对 option 更新)
- option.series[
- hoveredIndex
- ].parametricEquation = getParametricEquation(
- startRatio,
- endRatio,
- isSelected,
- isHovered,
- k,
- option.series[hoveredIndex].pieData.value
- )
- option.series[hoveredIndex].pieStatus.hovered = isHovered
- // 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空
- hoveredIndex = ''
- }
- // 如果触发 mouseover 的扇形不是透明圆环,将其高亮(对 option 更新)
- if (
- params.seriesName !== 'mouseoutSeries' &&
- params.seriesName !== 'pie2d'
- ) {
- // 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 true。
- isSelected =
- option.series[params.seriesIndex].pieStatus.selected
- isHovered = true
- startRatio =
- option.series[params.seriesIndex].pieData.startRatio
- endRatio = option.series[params.seriesIndex].pieData.endRatio
- k = option.series[params.seriesIndex].pieStatus.k
- // 对当前点击的扇形,执行高亮操作(对 option 更新)
- option.series[
- params.seriesIndex
- ].parametricEquation = getParametricEquation(
- startRatio,
- endRatio,
- isSelected,
- isHovered,
- k,
- option.series[params.seriesIndex].pieData.value * 1.3
- )
- option.series[
- params.seriesIndex
- ].pieStatus.hovered = isHovered
- // 记录上次高亮的扇形对应的系列号 seriesIndex
- hoveredIndex = params.seriesIndex
- }
- // 使用更新后的 option,渲染图表
- chart.setOption(option)
- }
- })
- // 修正取消高亮失败的 bug
- chart.on('globalout', () => {
- const option = chart.getOption()
- // 准备重新渲染扇形所需的参数
- let isSelected
- let isHovered
- let startRatio
- let endRatio
- let k
- if (hoveredIndex !== '') {
- // 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 true。
- isSelected = option.series[hoveredIndex].pieStatus.selected
- isHovered = false
- k = option.series[hoveredIndex].pieStatus.k
- startRatio = option.series[hoveredIndex].pieData.startRatio
- endRatio = option.series[hoveredIndex].pieData.endRatio
- // 对当前点击的扇形,执行取消高亮操作(对 option 更新)
- option.series[
- hoveredIndex
- ].parametricEquation = getParametricEquation(
- startRatio,
- endRatio,
- isSelected,
- isHovered,
- k,
- option.series[hoveredIndex].pieData.value
- )
- option.series[hoveredIndex].pieStatus.hovered = isHovered
- // 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空
- hoveredIndex = ''
- }
- // 使用更新后的 option,渲染图表
- chart.setOption(option)
- })
- }
- onMounted(() => chartRef.value?.addEventListener("resize", reloadChart))
- onUnmounted(() => {
- if (timer) {
- clearInterval(timer)
- timer = null
- }
- chartRef.value?.removeEventListener("resize", reloadChart)
- if (chart && chart.dispose) {
- chart.dispose();
- }
- })
- </script>
- <template>
- <div ref="chartRef" class="chart-wrapper"></div>
- </template>
- <style lang="scss" scoped>
- .chart-wrapper {
- width: 100%;
- height: 100%;
- }
- </style>
|