效果图:

需求:

  • 自动滚动展示数据:当数据量较大时,自动滚动显示不同的数据区间
  • 循环播放:当滚动到末尾时,重新从头开始播放
  • 鼠标交互控制:鼠标悬停时暂停动画,移开后继续播放
<template>
  <div @mouseover="mouseover" @mouseout="mouseout">
    <v-chart
      ref="vChartRef"
      :option="option"
      style="width: 100%; height: 800px"
    />
  </div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, onBeforeUnmount, watch } from "vue";
import VChart from "vue-echarts";
import { use } from "echarts/core";
import { CanvasRenderer } from "echarts/renderers";
import { BarChart } from "echarts/charts";
import {
  DatasetComponent,
  GridComponent,
  TooltipComponent,
  LegendComponent,
  TitleComponent,
} from "echarts/components";

use([
  DatasetComponent,
  CanvasRenderer,
  BarChart,
  GridComponent,
  TooltipComponent,
  LegendComponent,
  TitleComponent,
]);

// 定义数据类型
interface ChartDataItem {
  x: string;
  y: number;
  s: string;
}

// 模拟接口数据数组
const chartData = ref<ChartDataItem[]>([
  { x: "Mon", y: 120, s: "测试1" },
  { x: "Tue", y: 200, s: "测试1" },
  { x: "Wed", y: 150, s: "测试1" },
  { x: "Thu", y: 80, s: "测试1" },
  { x: "Fri", y: 70, s: "测试1" },
  { x: "Sat", y: 110, s: "测试1" },
  { x: "Sun", y: 130, s: "测试1" },
  { x: "Mon", y: 130, s: "测试2" },
  { x: "Tue", y: 130, s: "测试2" },
  { x: "Wed", y: 312, s: "测试2" },
  { x: "Thu", y: 268, s: "测试2" },
  { x: "Fri", y: 155, s: "测试2" },
  { x: "Sat", y: 117, s: "测试2" },
  { x: "Sun", y: 160, s: "测试2" },
]);

// 获取图表实例
const vChartRef = ref();

// 获取series
const seriesItem = ref({
  type: "bar",
  barWidth: 15,
  name: "",
  label: {
    show: true,
    position: "top",
    color: "#000",
    fontSize: 12,
  },
  itemStyle: {
    borderRadius: 2,
    color: null,
  },
  data: [],
});

const getSeries = () => {
  const seriesNames = [...new Set(chartData.value.map((item) => item.s))];
  const xValues = [...new Set(chartData.value.map((item) => item.x))];

  const series = seriesNames.map((name) => {
    const seriesItemCopy = JSON.parse(JSON.stringify(seriesItem.value));
    seriesItemCopy.name = name;

    const seriesData = new Array(xValues.length).fill(null);

    chartData.value.forEach((item) => {
      if (item.s === name) {
        const index = xValues.indexOf(item.x);
        if (index !== -1) {
          seriesData[index] = item.y;
        }
      }
    });

    seriesItemCopy.data = seriesData;
    return seriesItemCopy;
  });

  return { series, xValues };
};

const option = reactive({
  tooltip: {
    trigger: "axis",
    backgroundColor: "#000",
    borderWidth: 0,
    padding: 10,
    axisPointer: {
      type: "shadow",
    },
    textStyle: {//浮框文本样式
      color: "#fff",
      fontFamily: "Arial",
      fontSize: 14,
    },
  },
  title: {
    show: true,
    text: "数据统计图表",
    subtext: "",
    left: "center",
    top: "0",
    right: "0",
    bottom: "0",
    textStyle: {
      color: "#000",
      fontSize: 16,
    },
    subtextStyle: {
      color: "#eee",
      fontSize: 14,
    },
  },
  legend: {
    show: true,
    textStyle: {
      color: "#000",
    },
  },
  xAxis: [
    {
      type: "category",
      data: <any>[],
    },
  ],
  yAxis: [
    {
      type: "value",
    },
  ],
  series: <any>[],
});

onMounted(() => {
  const { series, xValues } = getSeries();
  option.series = series;
  option.xAxis[0].data = xValues;

  setAnimate();
});

watch(
  () => option.series,
  () => {
    setShowTips();
  }
);

const isShowTips = ref(true);
const timer: any = ref(null);
let seriesDataNum = 0;
const setShowTips = () => {
  if (!isShowTips.value && isShowTips.value !== undefined) {
    clearInterval(timer.value);
    return;
  }
  clearInterval(timer.value);
  timer.value = setInterval(() => {
    let series = option.series;
    let length = series[0].data.length;
    vChartRef.value?.dispatchAction({
      type: "showTip",
      seriesIndex: 0,
      dataIndex: seriesDataNum,
    });
    seriesDataNum = seriesDataNum >= length - 1 ? 0 : seriesDataNum + 1;
  }, 2000);
};

const mouseover = () => {
  if (timer.value) clearInterval(timer.value);
  if (timechartes.value) clearInterval(timechartes.value);
};

const mouseout = () => {
  setShowTips();
  setAnimate();
};

onBeforeUnmount(() => {
  if (timer.value) clearInterval(timer.value);
  if (timechartes.value) clearInterval(timechartes.value);
});
const timechartes: any = ref(null);
let dataZoom = ref([
  {
    xAxisIndex: 0, //这里是从X轴的0刻度开始
    show: false, //是否显示滑动条,不影响使用
    type: "inside", // 这个 dataZoom 组件是 slider 型 dataZoom 组件
    startValue: 0, // 从头开始。
    endValue: 8, // 一次性展示几个。
  },
]);
const setAnimate = () => {
  if (timechartes.value) clearInterval(timechartes.value);
  timechartes.value = setInterval(() => {
    const xValuesLength = [...new Set(chartData.value.map((item) => item.x))]
      .length;
    // 每次向后滚动一个,最后一个从头开始。
    if (dataZoom.value[0].endValue === xValuesLength) {
      dataZoom.value[0].endValue = 8;
      dataZoom.value[0].startValue = 0;
    } else {
      dataZoom.value[0].endValue += 1;
      dataZoom.value[0].startValue += 1;
    }
  }, 2000);
};
</script>

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐