ECharts:一个基于 JavaScript 的开源可视化图表库。

目录

效果

一、介绍

1、官方文档:Apache ECharts

2、官方示例

二、准备工作

1、安装依赖包

2、示例版本 

三、使用步骤

1、在单页面引入 ' echarts '

2、指定容器并设置容器宽高

3、数据处理(关键点)

        1)自定义tooltip样式

        2)图例横向滚动,超出出现滚动条

        3)series平滑曲线+面积渐变

四、完整示例

/@/components/ECharts/index.vue

chart.vue

欢迎关注:【前端小知识营地】


效果

一、介绍

1、官方文档:Apache ECharts

Apache EChartsApache ECharts,一款基于JavaScript的数据可视化图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表。https://echarts.apache.org/zh/index.html

2、官方示例

​​

二、准备工作

1、安装依赖包

npm install echarts --save

2、示例版本 

"echarts": "^5.6.0",

三、使用步骤

1、在单页面引入 ' echarts '

import * as echarts from 'echarts'

注:上面的代码会引入 ECharts 中所有的图表和组件,如果你不想引入所有组件,也可以使用 ECharts 提供的按需引入的接口来打包必需的组件。详见官方文档:在项目中引入 ECharts - 入门篇 - Handbook - Apache ECharts

2、指定容器并设置容器宽高

<template>
  <!-- 页面根容器 -->
  <div class="w-full h-[200px] overflow-hidden flex flex-col p-5 bg-[#131E2C]">
    <!-- 趋势折线图容器 -->
    <Echarts
      ref="chartInstanceRef"
      :options="chartOptions"
      :id="`generalTrendChart_${chartId}`"
      width="100%"
      height="100%"
    />
  </div>
</template>

3、数据处理(关键点)

        1)自定义tooltip样式
// 悬浮提示框配置
tooltip: {
  trigger: 'axis',
  confine: true,
  backgroundColor: 'rgba(17,25,40,0.95)',
  borderColor: 'rgba(72,168,246,0.4)',
  textStyle: {
    color: '#fff'
  }
},
        2)图例横向滚动,超出出现滚动条
// 图例配置
legend: {
  show: true,
  top: 0,
  left: 100,
  right: 10,
  itemWidth: 12,
  itemHeight: 12,
  icon: 'rect',
  itemGap: 20,
  textStyle: { color: '#fff', fontSize: 14 },
  data: legendData,
  // 图例横向滚动,超出出现滚动条
  type: 'scroll',
  orient: 'horizontal'
},
        3)series平滑曲线+面积渐变
{
  name: seriesName,
  type: 'line',
  smooth: true, // 平滑曲线
  symbol: 'circle', // 标记点样式
  symbolSize: 4, // 标记点大小
  // 线条样式
  lineStyle: {
    width: 2,
    color: colorConfig.color
  },
  // 标记点样式
  itemStyle: {
    color: colorConfig.color
  },
  // 面积渐变填充
  areaStyle: {
    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
      { offset: 0, color: hexToRgba(colorConfig.color, 0.6) },
      { offset: 1, color: hexToRgba(colorConfig.color, 0) }
    ])
  },
  data: item.data || []
}

四、完整示例

/@/components/ECharts/index.vue

<template>
  <!-- ECharts 渲染容器DOM -->
  <div :id="id" :class="className" ref="chartContainerRef" class="domEle" />
</template>

<script setup lang="ts">
import * as echarts from 'echarts'
import {
  ref,
  defineProps,
  watch,
  onMounted,
  onUnmounted,
  defineEmits,
  markRaw,
  nextTick
} from 'vue'
import { useRouter } from 'vue-router'
import type { ECharts, EChartsOption, EventParams } from 'echarts'
// 项目用到3D图表可保留,无需可删除
import 'echarts-gl'

// 抛出图表点击事件
const emit = defineEmits(['click'])
const router = useRouter()

// 响应式变量
const chartInstance = ref()
const autoTooltipTimer = ref()
const resizeObserver = ref()
const resizeTimer = ref()
const chartContainerRef = ref()

// 组件入参
const props = defineProps({
  options: {
    type: Object,
    default: () => ({}),
    required: true
  },
  id: {
    type: String,
    default: 'chart',
    required: true
  },
  className: {
    type: String,
    default: 'chart'
  },
  width: {
    type: String,
    default: '100%'
  },
  height: {
    type: String,
    default: '100%'
  },
  // 点击跳转路由相关
  clickRouterName: String,
  clickRouterQuery: String,
  // 自动轮播tooltip
  trendsTooltip: {
    type: Boolean,
    default: false
  }
})

/**
 * 自适应重绘
 * 无参调用,自动读取容器真实尺寸
 */
const resize = () => {
  clearTimeout(resizeTimer.value)
  resizeTimer.value = setTimeout(() => {
    if (chartInstance.value) chartInstance.value.resize()
  }, 200)
}

/**
 * 初始化图表实例
 */
const initChart = () => {
  chartInstance.value = markRaw(echarts.init(chartContainerRef.value))
  // 初始化自适应适配
  chartInstance.value.resize()
  chartInstance.value.setOption(props.options, true)

  // 支持图表点击路由跳转
  if (props.clickRouterName) {
    chartInstance.value.on('click', params => {
      const routeParams = {
        name: props.clickRouterName,
        query: {}
      }
      if (props.clickRouterQuery) {
        routeParams.query[props.clickRouterQuery] = params.name
      }
      router.push(routeParams)
    })
  }

  // 向外抛出点击事件
  chartInstance.value.on('click', (params: EventParams) => {
    emit('click', params)
  })
}

onMounted(() => {
  nextTick(() => {
    initChart()
    // 监听容器DOM尺寸变化
    resizeObserver.value = new ResizeObserver(() => resize())
    resizeObserver.value.observe(chartContainerRef.value)
    // 监听窗口缩放
    window.addEventListener('resize', resize)
  })
})

// 销毁清理,防止内存泄漏
onUnmounted(() => {
  resizeObserver.value?.disconnect()
  window.removeEventListener('resize', resize)
  chartInstance.value?.dispose()
  chartInstance.value = null
  resizeTimer.value && clearTimeout(resizeTimer.value)
  autoTooltipTimer.value && clearTimeout(autoTooltipTimer.value)
})

// 监听配置项变化自动重绘
watch(
  () => props.options,
  () => nextTick(() => initChart()),
  { deep: true }
)
</script>

<style scoped>
.domEle {
  width: 100%;
  height: 100%;
}
</style>

注:自适应重绘resize()优化

chart.vue

<template>
  <!-- 页面根容器 -->
  <div class="w-full h-[200px] overflow-hidden flex flex-col p-5 bg-[#131E2C]">
    <!-- 趋势折线图容器 -->
    <Echarts
      ref="chartInstanceRef"
      :options="chartOptions"
      :id="`generalTrendChart_${chartId}`"
      width="100%"
      height="100%"
    />
  </div>
</template>

<script setup lang="ts">
// 导入Vue核心API
import { ref, computed, onMounted, watch, defineAsyncComponent, defineProps } from 'vue'
// 导入ECharts核心库
import * as echarts from 'echarts'

// 异步导入自定义ECharts组件
const Echarts = defineAsyncComponent(() => import('/@/components/Echarts/index.vue'))

// ==================== 全局常量配置 ====================
// 数据系列配色配置
const COMMON_COLOR_CONFIG = {
  type1: { color: '#66F1E6' },
  type2: { color: '#F6B97A' },
  type3: { color: '#FF6B6B' }
} as const

// ==================== 响应式变量 ====================
// 图表唯一ID(防止重复)
const chartId = ref('generalTrendChart_' + Date.now())
// 图表实例引用
const chartInstanceRef = ref<any>(null)
// ECharts 配置项
const chartOptions = ref<echarts.EChartsOption>({})
// X轴坐标数据
const xAxisData = ref<string[]>([])

// ==================== TS类型定义 + Props ====================
// 数据系列项类型
interface TrendSeriesItem {
  sourceType: string // 数据来源类型
  name: string // 系列名称
  data: number[] // 系列数值
}
// 趋势图数据类型
interface TrendStatisticData {
  categories?: string[] // X轴分类数据
  series?: TrendSeriesItem[] // 数据系列
}

// 组件Props定义
const props = defineProps({
  statisticData: {
    type: Object as () => TrendStatisticData,
    // 模拟数据
    default: () => ({
      categories: ['1月', '2月', '3月', '4月', '5月', '6月'],
      series: [
        { sourceType: 'type1', name: '数据模块A', data: [10, 15, 12, 18, 22, 20] },
        { sourceType: 'type2', name: '数据模块B', data: [8, 12, 16, 14, 19, 25] },
        { sourceType: 'type3', name: '数据模块C', data: [5, 8, 10, 15, 12, 18] }
      ]
    })
  }
})

// ==================== 工具函数 ====================
/**
 * @description 十六进制颜色转RGBA
 * @param hex 十六进制颜色码
 * @param opacity 透明度
 * @returns rgba颜色字符串
 */
const hexToRgba = (hex: string, opacity: number) => {
  hex = hex.replace('#', '')
  const r = parseInt(hex.substring(0, 2), 16)
  const g = parseInt(hex.substring(2, 4), 16)
  const b = parseInt(hex.substring(4, 6), 16)
  return `rgba(${r}, ${g}, ${b}, ${opacity})`
}

// ==================== 核心初始化方法 ====================
/**
 * @description 初始化通用趋势折线图
 * @param data 图表统计数据
 */
const initChart = (data: TrendStatisticData) => {
  // 无数据时清空图表配置
  if (!data?.categories || !data?.series?.length) {
    xAxisData.value = []
    chartOptions.value = {}
    return
  }

  // 赋值X轴数据
  xAxisData.value = data.categories
  // 图例数据
  const legendData = data.series.map(item => item.name || '未知类型')
  // 图表系列配置
  const chartSeries: any[] = []

  // 遍历生成系列配置
  data.series.forEach(item => {
    // 获取对应配色,无匹配则使用白色
    const colorConfig = COMMON_COLOR_CONFIG[
      item.sourceType as keyof typeof COMMON_COLOR_CONFIG
    ] || {
      color: '#ffffff'
    }
    const seriesName = item.name || '未知类型'

    // 组装折线图系列配置(平滑曲线+面积渐变)
    chartSeries.push({
      name: seriesName,
      type: 'line',
      smooth: true, // 平滑曲线
      symbol: 'circle', // 标记点样式
      symbolSize: 4, // 标记点大小
      // 线条样式
      lineStyle: {
        width: 2,
        color: colorConfig.color
      },
      // 标记点样式
      itemStyle: {
        color: colorConfig.color
      },
      // 面积渐变填充
      areaStyle: {
        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
          { offset: 0, color: hexToRgba(colorConfig.color, 0.6) },
          { offset: 1, color: hexToRgba(colorConfig.color, 0) }
        ])
      },
      data: item.data || []
    })
  })

  // 最终ECharts配置项
  chartOptions.value = {
    backgroundColor: 'transparent', // 画布透明,继承父深色背景
    // 悬浮提示框配置
    tooltip: {
      trigger: 'axis',
      confine: true,
      backgroundColor: 'rgba(17,25,40,0.95)',
      borderColor: 'rgba(72,168,246,0.4)',
      textStyle: {
        color: '#fff'
      }
    },
    // 图例配置
    legend: {
      show: true,
      top: 0,
      left: 100,
      right: 10,
      itemWidth: 12,
      itemHeight: 12,
      icon: 'rect',
      itemGap: 20,
      textStyle: {
        color: '#fff',
        fontSize: 14
      },
      data: legendData,
      // 图例横向滚动,超出出现滚动条
      type: 'scroll',
      orient: 'horizontal'
    },
    // 网格边距
    grid: {
      left: 10,
      right: 0,
      bottom: 0,
      top: 40,
      containLabel: true
    },
    // X轴配置
    xAxis: {
      type: 'category',
      data: xAxisData.value,
      axisLine: {
        lineStyle: {
          color: 'rgba(255,255,255,0.2)'
        }
      },
      axisLabel: {
        color: 'rgba(255,255,255,0.7)',
        fontSize: 12
      },
      axisTick: {
        show: false
      },
      boundaryGap: true
    },
    // Y轴配置
    yAxis: {
      type: 'value',
      min: 0,
      name: '统计数量',
      nameGap: 20,
      nameTextStyle: {
        color: '#FFFFFF',
        fontSize: 14
      },
      splitLine: {
        lineStyle: {
          color: 'rgba(255,255,255,0.1)',
          type: 'solid'
        }
      },
      axisLabel: {
        color: 'rgba(255,255,255,0.7)'
      },
      axisLine: {
        show: false
      },
      axisTick: {
        show: false
      }
    },
    series: chartSeries
  }
}

// ==================== 生命周期 & 数据监听 ====================
// 页面挂载后初始化图表
onMounted(() => {
  initChart(props.statisticData)
})

// 深度监听数据变化,自动更新图表
watch(
  () => props.statisticData,
  val => {
    if (val) initChart(val)
  },
  { deep: true, immediate: true }
)
</script>

<style lang="scss" scoped></style>

 注:文本使用了CSS框架 - Tailwind CSS,可参考这里哦CSS框架 - Tailwind CSS - 附示例-CSDN博客

欢迎关注:【前端小知识营地】

更多推荐