3 小时,手把手带你完成【大屏可视化】系统(Vue3 + ECharts5)

开发 前端
在本章中,我们首先利用 vite + tailwindcss 构建了一个大屏可视化的项目。然后通过 echarts 完成了大屏可视化的功能。在项目中,每一个图表都是一个单独的组件。

Hello,大家好,我是 Sunday。

之前我在 B 站发布了一个大屏可视化的视频【2023最新:ECharts 数据可视化大屏项目】 访问地址:https://www.bilibili.com/video/BV1yu411E7cm/

图片图片

该视频到目前为止已经有了 10多万的播放,收藏也超过了 5000。

在很多同学学习该视频的过程中,有很多同学问我:“Sunday老师,我在公司没法看视频,有没有文档也可以实现这个项目呢?”

答案:肯定是有的。

所以说,咱们今天这篇文章,就让大家可以 不看视频 只通过文档,依然可以完成整个大屏可视化的项目!

1.前言

Hello,大家好,我是 Sunday。

这一小节,我们将要来实现一个地图可视化的项目,项目最终的实现效果如下:

图片图片

整个可视化项目,一共分为 8 部分。

这八部分我们会按照,难易的顺序来进行绘制,尽量帮助大家可以以 逐步深入 的方式掌握大屏可视化的内容。

  • 横向柱形图
  • 竖向柱形图
  • 雷达图
  • 环形图
  • 关系图
  • 数据云图
  • 数据展示图
  • 地图可视化

那么明确好了,本章的内容之后,下面这一章的项目开发吧~~

2.基于 vite 与 tailwindcss 创建大屏可视化项目

那么这一小节,咱们就基于 vite+tailwindcss 构建大屏可视化项目 imooc-visualization 。

  • 基于 vite 创建项目,使用:
npm create vite@latest
  • 选择脚手架配置,使用 vue3:
✔ Project name: … imooc-visualization
✔ Select a framework: › Vue
✔ Select a variant: › JavaScript

接下来 导入 tailwindcss ,按照文档给出的步骤即可。

因为咱们的大屏可视化项目仅包含一个页面,所以可以直接在 APP.vue 中进行布局。

  • 导入课程资源 imooc-visualization/src/assets,包含 fonts、imgs 和 MapData
  • 在 imooc-visualization/src/App.vue 中进行布局,整体的布局应该分为 左、中、右 三部分,并创建对应组件:
<template>
 <div
  class="bg-[url('assets/imgs/bg.jpg')] bg-cover bg-center h-screen text-white p-5 flex overflow-hidden"
 >
  <div class="flex-1 mr-5 bg-opacity-50 bg-slate-800 p-3 flex flex-col">
   <!-- 横向柱状图 -->
   <HorizontalBar class="h-1/3 box-border pb-4" />
   <!-- 雷达图 -->
   <RadarBar class="h-1/3 box-border pb-4" />
   <!-- 数据传递关系图 -->
   <Relation class="h-1/3" />
  </div>
  <div class="w-1/2 mr-5 flex flex-col">
   <!-- 数据展示图 -->
   <TotalData class="bg-opacity-50 bg-slate-800 p-3" />
   <!-- 地图可视化 -->
   <MapChart class="bg-opacity-50 bg-slate-800 p-3 mt-4 flex-1" />
  </div>
  <div class="flex-1 bg-opacity-50 bg-slate-800 p-3 flex flex-col">
   <!-- 竖向柱状图 -->
   <VerticalBar class="h-1/3 box-border pb-4" />
   <!-- 环形资源站比图 -->
   <RadiueBar class="h-1/3 box-border pb-4" />
   <!-- 文档云图 -->
   <WordCloud class="h-1/3 box-border" />
  </div>
 </div>
</template>

<script setup>
import HorizontalBar from './components/HorizontalBar.vue'
import RadarBar from './components/RadarBar.vue'
import Relation from './components/Relation.vue'
import TotalData from './components/TotalData.vue'
import MapChart from './components/MapChart.vue'
import VerticalBar from './components/VerticalBar.vue'
import RadiueBar from './components/RadiueBar.vue'
import WordCloud from './components/WordCloud.vue'
</script>

此时,展示的内容如下:

图片图片

3.导入 echarts 与 axios ,获取大屏动态数据

在大屏可视化中,数据通常是动态进行展示的,所以我们需要依赖 axios 获取服务端数据,依赖 echarts 进行展示,同时需要 定时获取数据,以保证数据的实时性。

  • 安装 echarts 与 axios:
npm i --save echarts@5.4.2 axios@1.4.0
  • 创建 imooc-visualization/src/utils/request.js 文件:
import axios from 'axios'

const service = axios.create({
 baseURL: 'https://api.imooc-web.lgdsunday.club/api',
 timeout: 5000
})

// 请求拦截器
service.interceptors.request.use(
 (config) => {
  config.headers.icode = 'input you icode'
  return config // 必须返回配置
 },
 (error) => {
  return Promise.reject(error)
 }
)

// 响应拦截器
service.interceptors.response.use((response) => {
 const { success, message, data } = response.data
 //   要根据success的成功与否决定下面的操作
 if (success) {
  return data
 } else {
  return Promise.reject(new Error(message))
 }
})

export default service
  • 创建 imooc-visualization/src/api/visualization.js 文件:
import request from '@/utils/request.js'

/**
 * 数据可视化
 */
export const getVisualization = () => {
 return request({
  url: '/visualization'
 })
}
  • 注意:**vite** 中默认并不支持 **@** 符号,所以需要在 vite.config.js 中进行配置:
// https://vitejs.dev/config/
export default defineConfig({
 plugins: [vue()],
 // 为 ./src 提供别名 @
 resolve: {
  alias: {
   '@': './src'
  }
 },
 // 主动开启热更新
 server: {
  hmr: true
 }
})
  • 在 imooc-visualization/src/App.vue 中发起数据请求,并通过定时器定时获取数据:
import { ref } from 'vue'
import { getVisualization } from '@/api/visualization.js'

const data = ref(null)

const loadData = async () => {
 data.value = await getVisualization()
 console.log(data.value)
}
loadData()

setInterval(() => {
 loadData()
}, 3000)

那么此时,我们就已经拿到了大屏的动态数据。下一小节,我们就根据这个数据,绘制横向的柱形图。

4.绘制大区横向柱形图

在上一小节中,我们拿到了大屏数据,数据中的 regionData 即为 大区横向柱形图 数据。

所以,我们就可以依赖该数据,进行图形绘制:

  • 在 App.vue 中,数据获取成功之后,在进行渲染:
<div
 class="bg-[url('assets/imgs/bg.jpg')] bg-cover bg-center h-screen text-white p-2 flex overflow-hidden"
 v-if="data"
>
  • 在 App.vue 中,传递指定数据到 HorizontalBar:
<!-- 横向柱状图 -->
<HorizontalBar class="h-1/3 box-border pb-4" :data="data.regionData" />
  • 在 imooc-visualization/src/components/HorizontalBar.vue 中,通过 defineProps 接收数据:
const props = defineProps({
 data: {
  type: Object,
  required: true
 }
})

此时,数据已经得到。

接下来我们根据数据绘制 echarts 图表。

echarts 图表的绘制,大体分为三步:

  • 根据 DOM 实例,通过 echarts.init 方法,生成 echarts 实例
  • 构建 options 配置对象,整个 echarts 的样式,皆有该对象决定
  • 最后通过 实例.setOption 方法,设置配置对象

配置对象是 echarts 中最复杂的部分,也就是 核心。

所有的配置项内容,都可以通过 这里 进行查阅

如果你之前 从未 使用过 echarts,那么特别建议你先看一下 快速入门 。

那么根据刚才所描述的三步,我们可以根据数据,构建出如下代码:

<template>
 <div>
  <div>【大区数据信息】</div>
  <div ref="target" class="w-full h-full"></div>
 </div>
</template>
// 获取 dom 实例
const target = ref(null)

// echarts 实例变量
let mChart = null
// 在 mounted 生命周期之后,实例化 echarts
onMounted(() => {
 mChart = echarts.init(target.value)
 // 渲染 echarts
 renderChart()
})

// 渲染图表
const renderChart = () => {
 const options = {
  // X 轴展示数据
  xAxis: {
   // 数据展示
   type: 'value',
   // 不显示轴
   show: false,
   // 最大值(防止触顶)
   max: function (value) {
    // 取整
    return parseInt(value.max * 1.2)
   }
  },
  // Y 轴展示选项
  yAxis: {
   type: 'category',
   // 根据根据服务端数据筛选
   data: props.data.regions.map((item) => item.name),
   // 反向展示
   inverse: true,
   // 不展示轴线
   axisLine: {
    show: false
   },
   // 不展示刻度
   axisTick: {
    show: false // 取消 Y 轴刻度
   },
   // 文字色值
   axisLabel: {
    color: '#9EB1C8'
   }
  },
  // echarts 网格绘制的位置,对应 上、右、下、左
  grid: {
   top: 0,
   right: 0,
   bottom: 0,
   left: 0,
   // 计算边距时,包含标签
   containLabel: true
  },
  // 柱形图核心配置
  series: [
   {
    // 图表类型
    type: 'bar',
    // 数据筛选
    data: props.data.regions.map((item) => ({
     name: item.name,
     value: item.value
    })),
    // 显示背景
    showBackground: true,
    // 背景色
    backgroundStyle: {
     color: 'rgba(180, 180, 180, 0.2)'
    },
    // 每个轴的样式
    itemStyle: {
     color: '#479AD3', // 设置柱子的颜色
     barBorderRadius: 5, // 设置柱子的圆角
     shadowColor: 'rgba(0, 0, 0, 0.3)', // 设置柱子的阴影颜色
     shadowBlur: 5 // 设置柱子的阴影模糊大小
    },
    // 轴宽度
    barWidth: 12,
    // 轴上的字体
    label: {
     show: true,
     // 设置标签位置为右侧
     position: 'right',
     textStyle: {
      // 设置标签文本颜色
      color: '#fff'
     }
    }
   }
  ]
 }

 mChart.setOption(options)
}

那么此时,一个基础的横向图表绘制完成。

同时,因为我们需要 动态更新图表,所以我们需要通过 watch 监听数据变化的行为,重新渲染视图:

// 监听数据的变化,重新渲染图表
watch(
 () => props.data,
 () => {
  renderChart()
 }
)

至此,横向柱形图渲染完成。

5.绘制服务竖向柱形图

上一小节,我们简单的利用 echarts 的特性,绘制了横向的柱形图,那么接下来我们就趁热打铁,再来绘制一个 竖向柱形图。

还是使用 visualization 接口,数据属性为 serverData。

整体的流程还是分为三步:

  • 把数据传递到 VerticalBar 组件
  • 构建 echarts 容器
  • 利用 option 绘制图表

最终代码如下:

<template>
 <div>
  <div>【服务资源占用比】</div>
  <div ref="target" class="w-full h-full"></div>
 </div>
</template>

<script setup>
import { onMounted, ref, watch } from 'vue'
import * as echarts from 'echarts'
// 不要忘记从父组件传递数据
const props = defineProps({
 data: {
  type: Object,
  required: true
 }
})

const target = ref(null)
let mChart = null
onMounted(() => {
 mChart = echarts.init(target.value)
 renderChart()
})

const renderChart = () => {
 const options = {
  // X 轴展示选项
  xAxis: {
   type: 'category',
   // 根据根据服务端数据筛选
   data: props.data.servers.map((item) => item.name),
   // 文字色值
   axisLabel: {
    color: '#9EB1C8'
   }
  },
  // Y 轴展示数据
  yAxis: {
   // 数据展示
   type: 'value',
   // 不显示轴
   show: false,
   // 最大值(防止触顶)
   max: function (value) {
    // 取整
    return parseInt(value.max * 1.2)
   }
  },
  // echarts 网格绘制的位置,对应 上、右、下、左
  grid: {
   top: 16,
   right: 0,
   bottom: 26,
   left: -26,
   // 计算边距时,包含标签
   containLabel: true
  },
  // 柱形图核心配置
  series: {
   // 柱形图
   type: 'bar',
   // 数据筛选
   data: props.data.servers.map((item) => ({
    name: item.name,
    value: item.value
   })),
   // 每个轴的样式
   itemStyle: {
    color: '#479AD3', // 设置柱子的颜色
    barBorderRadius: 5, // 设置柱子的圆角
    shadowColor: 'rgba(0, 0, 0, 0.3)', // 设置柱子的阴影颜色
    shadowBlur: 5 // 设置柱子的阴影模糊大小
   },
   // 柱子宽度
   barWidth: 12,
   // 文本
   label: {
    show: true,
    // 设置标签位置为右侧
    position: 'top',
    textStyle: {
     // 设置标签文本颜色
     color: '#fff'
    },
    formatter: '{c}%'
   }
  }
 }

 mChart.setOption(options)
}

// 监听数据的变化,重新渲染图表
watch(
 () => props.data,
 () => {
  renderChart()
 }
)
</script>

6.绘制报警风险雷达图

前面两个小节,咱们创建了基本的柱形图。

通过柱形图,咱们大致应该了解了 echarts 基本的运行方式。

所以说,接下来,咱们就来构建一个稍微复杂一些的图表 雷达图。

雷达图,使用 riskData 字段数据。

整个雷达图的绘制,包含 5 个重要的属性:

  • radar:雷达图坐标系配置
  • polar:坐标居中
  • angleAxis:坐标角度
  • radiusAxis:径向轴
  • series:图表核心配置

最终渲染的代码如下:

<template>
 <div>
  <div>【云端报警风险】</div>
  <div ref="target" class="w-full h-full"></div>
 </div>
</template>

<script setup>
import { onMounted, ref, watch } from 'vue'
import * as echarts from 'echarts'
// 不要忘记从父组件传递数据
const props = defineProps({
 data: {
  type: Object,
  required: true
 }
})

const target = ref(null)
let mChart = null
onMounted(() => {
 mChart = echarts.init(target.value)
 renderChart()
})

const renderChart = () => {
 const options = {
  // 雷达图坐标系配置
  radar: {
   // 坐标系名
   name: {
    textStyle: {
     color: '#05D5FF',
     fontSize: 14
    }
   },
   // 雷达绘制类型。polygon 多边形
   shape: 'polygon',
   // 居中
   center: ['50%', '50%'],
   // 边境
   radius: '80%',
   // 开始的角度(可以避免绘制到边框之外)
   startAngle: 120,
   // 轴线配置
   axisLine: {
    lineStyle: {
     color: 'rgba(5, 213, 255, .8)'
    }
   },
   // 网格线配置
   splitLine: {
    show: true,
    lineStyle: {
     width: 1,
     color: 'rgba(5, 213, 255, .8)' // 设置网格的颜色
    }
   },
   // 指示器文字
   indicator: props.data.risks.map((item) => ({
    name: item.name,
    max: 100
   })),
   // 不展示拆分区域
   splitArea: {
    show: false
   }
  },
  // 坐标居中
  polar: {
   center: ['50%', '50%'], // 默认全局居中
   radius: '0%'
  },
  // 坐标角度
  angleAxis: {
   // 坐标轴刻度最小值
   min: 0,
   // 坐标轴分割间隔
   interval: 5,
   // 刻度增长逆时针
   clockwise: false
  },
  // 径向轴
  radiusAxis: {
   // 最小值
   min: 0,
   // 间隔
   interval: 20,
   // 不显示分割线
   splitLine: {
    show: true
   }
  },
  // 图表核心配置
  series: [
   {
    // 雷达图
    type: 'radar',
    // 拐点的样式,还可以取值'rect','angle'等
    symbol: 'circle',
    // 拐点的大小
    symbolSize: 10,
    // 折线拐点标志的样式
    itemStyle: {
     normal: {
      color: '#05D5FF'
     }
    },
    // 区域填充样式
    areaStyle: {
     normal: {
      color: '#05D5FF',
      opacity: 0.5
     }
    },
    // 线条样式
    lineStyle: {
     width: 2,
     color: '#05D5FF'
    },
    // 图形上的文本标签
    label: {
     normal: {
      show: true,
      formatter: (params) => {
       return params.value
      },
      color: '#fff'
     }
    },
    // 数据
    data: [
     {
      value: props.data.risks.map((item) => item.value)
     }
    ]
   }
  ]
 }

 mChart.setOption(options)
}

// 监听数据的变化,重新渲染图表
watch(
 () => props.data,
 () => {
  renderChart()
 }
)
</script>

7.绘制异常处理双环形图

在前面的 echarts 图表绘制中,整体的绘制还是比较简单的。那么接下来咱们就来绘制一个稍微复杂一些的图形 双环形图。

图片图片

首选我们现在分析一下双环形图的构图原理:

  • 在 echarts 中,是没有提供环形图图表的。所以这里的环形图本质上是通过 饼图 来进行绘制的(只需要把饼图的内边距调大,外边距调小,就可以实现环形)。
  • 每个环都是都是有两个饼图组成。其中一个饼图表示上层展示,一个饼图作为底层的背景。只需要让它们位置一致就可以得到对应的图形
  • 动态变化每一对环形的位置,从而得到一个逐层向内的环形展示

那么,咱们分析完成双环形的原理之后,接下来咱们就根据数据 abnormalData 来实现这个双环形:

<template>
 <div>
  <div>【大区异常处理】</div>
  <div ref="target" class="w-full h-full"></div>
 </div>
</template>

<script setup>
import { onMounted, ref, watch } from 'vue'
import * as echarts from 'echarts'

const props = defineProps({
 data: {
  type: Object,
  required: true
 }
})

const target = ref(null)
let mChart = null
onMounted(() => {
 mChart = echarts.init(target.value)
 renderChart()
})

/**
 * 双环形图绘制原理:
 * 1. 环形图通过饼图绘制。内外边距的距离减小,即为环形。环形中心点需要不断改变,否则会重叠
 * 2. 环形图绘制分为 上层和底层 两部分。上层作为绘制进度,底层作为背景图
 * 3. 依据 getSeriesData 生成对应的 上层和底层 series 数据,进行渲染
 */
const getSeriesData = () => {
 const series = []

 props.data.abnormals.forEach((item, index) => {
  // 上层环形绘制
  series.push({
   name: item.name,
   // 使用饼图绘制,减少饼图宽度即为环形图
   type: 'pie',
   // 逆时针排布
   clockWise: false,
   // 不展示鼠标移入动画
   hoverAnimation: false,
   // 半径位置,需要依次递减,否则会重复在一处进行展示
   radius: [73 - index * 15 + '%', 68 - index * 15 + '%'],
   // 中心点
   center: ['55%', '55%'],
   // 不展示 label
   label: { show: false },
   // 数据配置
   data: [
    // 设置数据与名称
    { value: item.value, name: item.name },
    // 最大数据,展示比例
    {
     value: 1000,
     name: '',
     itemStyle: { color: 'rgba(0,0,0,0)', borderWidth: 0 },
     tooltip: { show: false },
     hoverAnimation: false
    }
   ]
  })

  // 底层图
  series.push({
   name: item.name,
   type: 'pie',
   // 图形不响应事件
   silent: true,
   // z-index: 置于底层
   z: 1,
   // 逆时针排布
   clockWise: false,
   // 不展示鼠标移入动画
   hoverAnimation: false,
   // 半径位置,需要依次递减,否则会重复在一处进行展示
   radius: [73 - index * 15 + '%', 68 - index * 15 + '%'],
   // 中心点
   center: ['55%', '55%'],
   // 不展示 label
   label: { show: false },
   // 数据
   data: [
    // 绘制底线 75%
    {
     value: 7.5,
     itemStyle: { color: 'rgb(3, 31, 62)', borderWidth: 0 },
     tooltip: { show: false },
     hoverAnimation: false
    },
    // 绘制底线 25% 透明区域
    {
     value: 2.5,
     name: '',
     itemStyle: { color: 'rgba(0,0,0,0)', borderWidth: 0 },
     tooltip: { show: false },
     hoverAnimation: false
    }
   ]
  })
 })

 return series
}

const renderChart = () => {
 const options = {
  // 图例配置
  legend: {
   show: true,
   // 图例色块
   icon: 'circle',
   // 位置
   top: '14%',
   left: '60%',
   // 展示数据
   data: props.data.abnormals.map((item) => item.name),
   // 总宽度(一列)
   width: -5,
   // 每个色块的宽
   itemWidth: 10,
   // 每个色块的高度
   itemHeight: 10,
   // item 间距
   itemGap: 6,
   // 展示内容
   formatter: function (name) {
    return '{title|' + name + '}'
   },
   // 字体配置
   textStyle: {
    rich: {
     title: {
      fontSize: 12,
      lineHeight: 5,
      color: 'rgba(255,255,255,0.8)'
     }
    }
   }
  },
  // 提示层
  tooltip: {
   show: true,
   trigger: 'item',
   formatter: '{a}<br>{b}:{c}({d}%)'
  },
  // Y 轴展示选项
  yAxis: [
   {
    type: 'category',
    // 反向展示
    inverse: true,
    // 不展示轴线
    axisLine: {
     show: false
    },
    // 不展示刻度
    axisTick: {
     show: false
    }
   }
  ],
  // X 轴不展示
  xAxis: [
   {
    show: false
   }
  ],
  // 每两个标记一条线
  series: getSeriesData()
 }

 mChart.setOption(options)
}

// 监听数据的变化,重新渲染图表
watch(
 () => props.data,
 () => {
  renderChart()
 }
)
</script>

8.绘制数据传递关系图

在前面,我们绘制了很多基本的 echarts 图表。

但是在实际的企业开发中,可能会存在一些比较特殊的图表类型,比如 信息传递图 :

想要完成这样的图表,咱们需要借助两个 series 中的图表类型:

  • graph:它表示 关系图,主要用于展现节点以及节点之间的关系数据。
  • lines:它表示 路径图,主要用来绘制两个节点 从起点到终点 的路径。

两者之间进行结合,就可以得到咱们上面的数据关系图了。

具体代码如下:

<template>
 <div>
  <div>【数据传递信息】</div>
  <div ref="target" class="w-full h-full"></div>
 </div>
</template>

<script setup>
import { onMounted, ref, watch } from 'vue'
import * as echarts from 'echarts'

const props = defineProps({
 data: {
  type: Object,
  required: true
 }
})

// 获取 dom 实例
const target = ref(null)

// echarts 实例变量
let mChart = null
// 在 mounted 生命周期之后,实例化 echarts
onMounted(() => {
 mChart = echarts.init(target.value)
 // 渲染 echarts
 renderChart()
})

// 渲染图表
const renderChart = () => {
 const options = {
  // X 轴不需要展示
  xAxis: {
   show: false,
   type: 'value'
  },
  // X 轴不需要展示
  yAxis: {
   show: false,
   type: 'value'
  },
  // 核心数据配置
  series: [
   {
    // 用于展现节点以及节点之间的关系数据
    type: 'graph',
    // 不采用任何布局
    layout: 'none',
    // 使用二维的直角坐标系
    coordinateSystem: 'cartesian2d',
    // 节点标记的大小
    symbolSize: 26,
    // z-index
    z: 3,
    // 边界标签(线条文字)
    edgeLabel: {
     normal: {
      show: true,
      color: '#fff',
      textStyle: {
       fontSize: 14
      },
      formatter: function (params) {
       let txt = ''
       if (params.data.speed !== undefined) {
        txt = params.data.speed
       }
       return txt
      }
     }
    },
    // 圆饼下文字
    label: {
     normal: {
      show: true,
      position: 'bottom',
      color: '#5e5e5e'
     }
    },
    // 边两端的标记类型
    edgeSymbol: ['none', 'arrow'],
    // 边两端的标记大小
    edgeSymbolSize: 8,
    // 圆数据
    data: props.data.relations.map((item) => {
     // id 为 0 ,表示数据中心,数据中心单独设置
     if (item.id !== 0) {
      return {
       name: item.name,
       category: 0,
       active: true,
       // 位置
       value: item.value
      }
     } else {
      return {
       name: item.name,
       // 位置
       value: item.value,
       // 数据中心圆的大小
       symbolSize: 100,
       // 圆的样式
       itemStyle: {
        normal: {
         // 渐变色
         color: {
          colorStops: [
           { offset: 0, color: '#157eff' },
           { offset: 1, color: '#35c2ff' }
          ]
         }
        }
       },
       // 字体
       label: { normal: { fontSize: '14' } }
      }
     }
    }),
    // 线
    links: props.data.relations.map((item, index) => ({
     // 方向
     source: item.source,
     target: item.target,
     // 线上的文字
     speed: `${item.speed}kb/s`,
     // 线的样式
     lineStyle: { normal: { color: '#12b5d0', curveness: 0.2 } },
     // 文字位置
     label: {
      show: true,
      position: 'middle',
      offset: [10, 0]
     }
    }))
   },
   {
    // 用于带有起点和终点信息的线数据的绘制
    type: 'lines',
    // 使用二维的直角坐标系
    coordinateSystem: 'cartesian2d',
    // z-index
    z: 1,
    // 线特效的配置
    effect: {
     show: true,
     smooth: false,
     trailLength: 0,
     symbol: 'arrow',
     color: 'rgba(55,155,255,0.5)',
     symbolSize: 12
    },
    // 线的样式
    lineStyle: {
     normal: {
      curveness: 0.2
     }
    },
    // 线的数据级,前后线需要重合。数据固定
    data: [
     [{ coord: [0, 300] }, { coord: [50, 200] }],
     [{ coord: [0, 100] }, { coord: [50, 200] }],
     [{ coord: [50, 200] }, { coord: [100, 100] }],
     [{ coord: [50, 200] }, { coord: [100, 300] }]
    ]
   }
  ]
 }

 mChart.setOption(options)
}

// 监听数据的变化,重新渲染图表
watch(
 () => props.data,
 () => {
  renderChart()
 }
)
</script>

9.绘制关键词条文档云图

在前面的图表中,我们都是基于 echarts 的原生图表支持进行的绘制。但是有些情况下,某些图表我们需要依赖插件才可以完成对应的绘制,比如:文档云图

想要绘制这样的文档云图,那么我们首先必须先安装 echarts-wordcloud,执行:

cnpm i --save echarts-wordcloud@2.1.0

安装完成之后,需要在使用 wordcloud 的组件上,导入 import 'echarts-wordcloud'。

那么这样,我们就可以基于 wordCloudData 数据渲染文档云图了:

<template>
 <div>
  <div>【关键词条】</div>
  <div ref="target" class="w-full h-full"></div>
 </div>
</template>

<script setup>
import { onMounted, ref, watch } from 'vue'
import * as echarts from 'echarts'
import 'echarts-wordcloud'

const props = defineProps({
 data: {
  type: Object,
  required: true
 }
})

// 获取 dom 实例
const target = ref(null)

// echarts 实例变量
let mChart = null
// 在 mounted 生命周期之后,实例化 echarts
onMounted(() => {
 mChart = echarts.init(target.value)
 // 渲染 echarts
 renderChart()
})

/**
 * 生成随机色值
 */
const randomRGB = () => {
 const r = Math.floor(Math.random() * 255)
 const g = Math.floor(Math.random() * 255)
 const b = Math.floor(Math.random() * 255)
 return `rgb(${r}, ${g}, ${b})`
}

// 渲染图表
const renderChart = () => {
 const options = {
  series: [
   {
    // 类型
    type: 'wordCloud',
    // 数据映射文本的大小范围
    sizeRange: [8, 46],
    // 文字旋转范围
    rotationRange: [0, 0],
    // 单词之间的间距
    gridSize: 0,
    // 渲染动画
    layoutAnimation: true,
    // 字体
    textStyle: {
     // 随机色值
     color: randomRGB
    },
    // 高亮字体
    emphasis: {
     textStyle: {
      fontWeight: 'bold',
      color: '#000'
     }
    },
    // 数据
    data: props.data.datas
   }
  ]
 }

 mChart.setOption(options)
}

// 监听数据的变化,重新渲染图表
watch(
 () => props.data,
 () => {
  renderChart()
 }
)
</script>

10.绘制数据总览图

通常在大屏可视化项目中,除了包含基本的图表之外,还会存在一些数据概览的内容。这就是我们这一小节主要讲解的东西。

咱们这里所实现的数据概览,主要包含两块功能:

  • 数值自增
  • 数值渐变 + 特殊字体

首先针对于数值自增而言,主要可以通过 countup.js 进行实现:

  • 安装 countup.js:
cnpm i --save countup.js@2.6.2
  • 实现如下布局代码:
<template>
 <div class="p-6">
  <div class="text-slate-300 text-center">
   数据总量:
   <span
    ref="totalCountTarget"
    class="text-7xl ml-2 mr-2 font-bold"
   >
    679,473,929
   </span>
   条记录
  </div>
  <div class="mt-3 flex flex-wrap">
   <div class="w-1/3 text-center text-slate-400 text-sm">
    华北:
    <span ref="city1" class="text-[#5DC5EF] text-3xl"> 8,778,988 </span>
   </div>
   <div class="w-1/3 text-center text-slate-400 text-sm">
    东北:<span ref="city2" class="text-[#5DC5EF] text-3xl">8,778,988</span>
   </div>
   <div class="w-1/3 text-center text-slate-400 text-sm">
    华东:<span ref="city3" class="text-[#5DC5EF] text-3xl">8,778,988</span>
   </div>
   <div class="w-1/3 text-center text-slate-400 text-sm">
    中南:<span ref="city4" class="text-[#5DC5EF] text-3xl">8,778,988</span>
   </div>
   <div class="w-1/3 text-center text-slate-400 text-sm">
    西南:<span ref="city5" class="text-[#5DC5EF] text-3xl">8,778,988</span>
   </div>
   <div class="w-1/3 text-center text-slate-400 text-sm">
    西北:<span ref="city6" class="text-[#5DC5EF] text-3xl">8,778,988</span>
   </div>
  </div>
 </div>
</template>

<script setup>
import { onMounted, ref } from 'vue'
import { CountUp } from 'countup.js'

const props = defineProps({
 data: {
  type: Object,
  required: true
 }
})

const totalCountTarget = ref(null)
const city1 = ref(null)
const city2 = ref(null)
const city3 = ref(null)
const city4 = ref(null)
const city5 = ref(null)
const city6 = ref(null)

onMounted(() => {
 new CountUp(totalCountTarget.value, props.data.total).start()
 new CountUp(city1.value, props.data.hb).start()
 new CountUp(city2.value, props.data.db).start()
 new CountUp(city3.value, props.data.hd).start()
 new CountUp(city4.value, props.data.zn).start()
 new CountUp(city5.value, props.data.xn).start()
 new CountUp(city6.value, props.data.xb).start()
})
</script>

那么此时,我们就实现了数据自增的功能。

接下来第二块是实现数值渐变 + 特殊字体。

数值渐变可以直接通过 css 进行实现,本质上是通过 背景渐变 + 字体镂空 进行实现。

而特殊字体需要导入资料中 07:图表与大屏可视化 -> assets -> fonts 中的字体

  • 导入电子表字体到 src/assets/fonts/FX-LED.ttf 中
  • 在 src/style.css 中写入如下 css:
@font-face {
  font-family: 'Electronic';
  src: url('./assets/fonts/FX-LED.ttf') format('truetype');
}

.text-gradient {
  /* 背景渐变 */
  background-image: linear-gradient(to bottom, #e5e4ea, #5EA8F2);
  /* 元素背景延伸到文本 */
  -webkit-background-clip: text;
  /* 文本字符填充颜色透明 */
  -webkit-text-fill-color: transparent;
}
  1. 在 src/components/TotalData.vue 中,为每个 span 添加 font-[Electronic] 类名
  2. 单独为数据总量添加 text-gradient 类名

11.地图可视化分析与时间轴图表绘制

那么到目前,我们就只剩下最后一块,也是最复杂的一块功能需要进行实现了。

这一块图表,可以被分为四个部分:

  • 时间轴
  • 横向柱形图
  • 地图
  • 绘制地图散点图

所以针对这样的功能,咱们将分成四个小节分步进行绘制。

那么这一小节,咱们就先就来实现 时间轴 绘制。

时间轴绘制,需要使用到 echarts 中的 timeline 属性,具体代码如下:

<template>
 <div>
  <div ref="target" class="w-full h-full"></div>
 </div>
</template>

<script setup>
import { onMounted, ref } from 'vue'
import * as echarts from 'echarts'

const props = defineProps({
 data: {
  type: Object,
  required: true
 }
})

const target = ref(null)
let mChart = null
onMounted(() => {
 mChart = echarts.init(target.value)
 renderChart()
})

const renderChart = () => {
 let options = {
  // 时间线,提供了在多个 ECharts option 间进行切换
  timeline: {
   // 数据
   data: props.data.voltageLevel,
   // 类目轴
   axisType: 'category',
   // 自动切换
   autoPlay: true,
   // 间隔时间
   playInterval: 3000,
   // 位置
   left: '10%',
   right: '10%',
   bottom: '0%',
   width: '80%',
   // 轴的文本标签
   label: {
    // 默认状态
    normal: {
     textStyle: {
      color: '#ddd'
     }
    },
    // 高亮状态
    emphasis: {
     textStyle: {
      color: '#fff'
     }
    }
   },
   // 文字大小
   symbolSize: 10,
   // 线的样式
   lineStyle: {
    color: '#555'
   },
   // 选中点的样式
   checkpointStyle: {
    borderColor: '#888',
    borderWidth: 2
   },
   // 控件样式
   controlStyle: {
    // 上一步按钮
    showNextBtn: true,
    // 下一步按钮
    showPrevBtn: true,
    // 默认样式
    normal: {
     color: '#666',
     borderColor: '#666'
    },
    // 高亮样式
    emphasis: {
     color: '#aaa',
     borderColor: '#aaa'
    }
   }
  }
 }
 mChart.setOption(options)
}
</script>

12.地图可视化绘制动态柱形图

这一小节,咱们来绘制地图可视化中的动态柱形图。

柱形图的绘制,对咱们现在而言,应该是有一些熟悉的了,同时因为有时间轴的存在,所以我们可以直接添加 options 属性,来为时间轴动态绑定多个图表。

对应的绘制代码如下:

const renderChart = () => {
 let options = {
  // 时间线,提供了在多个 ECharts option 间进行切换
  timeline: {...},
  // 柱形图右侧展示
  baseOption: {
   grid: {
    right: '2%',
    top: '15%',
    bottom: '10%',
    width: '20%'
   }
  },
  // 绑定时间轴的多个图表
  options: []
 }

 // 为每一年度的图表添加数据
 props.data.voltageLevel.forEach((item, index) => {
  options.options.push({
   // 背景色
   backgroundColor: '#142037',
   title: [
    // 主标题,对应地图
    {
     text: '2019-2023 年度数据统计',
     left: '0%',
     top: '0',
     textStyle: {
      color: '#ccc',
      fontSize: 30
     }
    },
    // 副标题,对应柱形图
    {
     id: 'statistic',
     text: item + '年数据统计情况',
     right: '0%',
     top: '4%',
     textStyle: {
      color: '#ccc',
      fontSize: 20
     }
    }
   ],
   // X 轴配置
   xAxis: {
    // 数据轴
    type: 'value',
    // 脱离 0 值比例
    scale: true,
    // 位置
    position: 'top',
    // 不显示分割线
    splitLine: {
     show: false
    },
    // 不显示轴线
    axisLine: {
     show: false
    },
    // 不显示刻度尺
    axisTick: {
     show: false
    },
    // 类别文字
    axisLabel: {
     margin: 2,
     textStyle: {
      color: '#aaa'
     }
    }
   },
   // Y 轴
   yAxis: {
    // 选项轴
    type: 'category',
    // 轴线
    axisLine: {
     show: true,
     lineStyle: {
      color: '#ddd'
     }
    },
    // 轴刻度
    axisTick: {
     show: false,
     lineStyle: {
      color: '#ddd'
     }
    },
    // 轴标签
    axisLabel: {
     interval: 0,
     textStyle: {
      color: '#ddd'
     }
    },
    // 根据年份,获取对应数据
    data: props.data.categoryData[item].map((item) => item.name)
   },
   // 核心配置
   series: [
    {
     zlevel: 1.5,
     // 柱形图
     type: 'bar',
     // 每个柱子的色值
     itemStyle: {
      normal: {
       color: props.data.colors[index]
      }
     },
     // 根据年份,获取对应数据
     data: props.data.categoryData[item].map((item) => item.value)
    }
   ]
  })
 })

 mChart.setOption(options)
}

13.地图可视化,绘制地图

最后,我们来绘制地图。

想要绘制地图,那么需要首先 导入地图的 **json** 文件:

import mapJson from '@/assets/MapData/china.json'

echarts.registerMap('china', mapJson)

然后在 baseOption 中,添加 geo 作为地图配置:

baseOption: {
 ...

 // 中国地图
 geo: {
  // 展示
  show: true,
  // 中国地图
  map: 'china',
  // 开启缩放
  roam: true,
  // 初始缩放
  zoom: 0.8,
  // 中心点
  center: [113.83531246, 34.0267395887],
  // 默认状态的省份样式
  itemStyle: {
   normal: {
    // 边框色值
    borderColor: 'rgba(147, 235, 248, 1)',
    // 边框宽度
    borderWidth: 1,
    // 区域颜色
    areaColor: {
     // 经向色值
     type: 'radial',
     x: 0.5,
     y: 0.5,
     r: 0.5,
     colorStops: [
      // 0% 处的颜色
      {
       offset: 0,
       color: 'rgba(147, 235, 248, 0)'
      },
      // 100% 处的颜色
      {
       offset: 1,
       color: 'rgba(147, 235, 248, .2)'
      }
     ],
     // 缺省为 false
     globalCoord: false
    }
   },
   // 鼠标移入的色值
   emphasis: {
    areaColor: '#389BB7',
    borderWidth: 0
   }
  }
 }
}

14.地图可视化散点图绘制

最后只需要在 series 中绘制散点图即可:

// 散点图
{
 // 散点(气泡)图
 type: 'effectScatter',
 // 使用地理坐标系
 coordinateSystem: 'geo',
 // 数据
 data: props.data.topData[item],
 // 标记大小
 symbolSize: function (val) {
  return val[2] / 4
 },
 // 绘制完成后显示特效
 showEffectOn: 'render',
 // 展示涟漪特效
 rippleEffect: {
  brushType: 'stroke'
 },
 // 文字
 label: {
  normal: {
   formatter: '{b}',
   position: 'right',
   show: true
  }
 },
 // 每一项的配置
 itemStyle: {
  normal: {
   color: props.data.colors[index],
   // 阴影配置
   shadowBlur: 5,
   shadowColor: props.data.colors[index]
  }
 },
 zlevel: 1
}

15.AntV  概述与 G2 开发柱形图

那么到现在为止,咱们就已经利用利用 echarts 完成了一个大屏可视化项目的开发。

但是大家需要知道的是,除了 ehcarts 之外,还有一些其他的框架,也可以实现可视化图表开发,比如 antv。

AntV:由蚂蚁集团数据可视化团队发布,内部进行了库的细分:

  • G2:类似于 Echarts ,提供了各种常见的图表。课程中的 大屏可视化项目 ,也可以基于此实现
  • S2:表格数据图形化
  • G6:数据关系可视化。比如脑图实现
  • X6:图形编辑引擎。比如流程图、ER 图构建
  • L7:地理空间数据可视化。与地图相关
  • F2:移动端数据可视化。可以理解为 G2 的移动端版本
  • AVA:可视化生成框架。可以理解为可视化的低代码框架

Antv 从使用中和 echarts 会有一些不同,我们可以通过这个 案例 来查看 G2 的基本使用:

  • 通过 vite 创建新的项目 antv-g2:
npm create vite@latest
  • 在 App.vue 中写入如下代码:
<template>
 <div>
  <div id="container"></div>
 </div>
</template>

<script setup>
import { Chart } from '@antv/g2'
import { onMounted } from 'vue'

// 准备数据
const data = [
 { genre: 'Sports', sold: 275 },
 { genre: 'Strategy', sold: 115 },
 { genre: 'Action', sold: 120 },
 { genre: 'Shooter', sold: 350 },
 { genre: 'Other', sold: 150 }
]

onMounted(() => {
 // 初始化图表实例
 const chart = new Chart({
  container: 'container',
  theme: 'classic'
 })

 // 声明可视化
 chart
  .interval() // 创建一个 Interval 标记
  .data(data) // 绑定数据
  .encode('x', 'genre') // 编码 x 通道
  .encode('y', 'sold') // 编码 y 通道

 // 渲染可视化
 chart.render()
})
</script>

这样,咱们可以利用 G2 构建一个基本的柱形图

16.大屏数据展示组件库 DataV

在本章的最后,我为大家介绍最后一个东西 DataV。

DataV 是一个 大屏数据展示组件库,同时提供了 vue 版本和 react 版本。

它的使用和其他的组件库一样,都是安装之后全局导入组件和局部导入组件。只不过它的组件会更加偏向于 大屏可视化的场景。

它内部提供的组件并不多,大家可以通过视频查看对应的演示。在文档中,咱们就不过多赘述了。

17.总结

那么到这里,咱们本章的主要内容就已经全部完成了。

在本章中,我们首先利用  vite + tailwindcss 构建了一个大屏可视化的项目。

然后通过 echarts 完成了大屏可视化的功能。在项目中,每一个图表都是一个单独的组件。

在本章的最后,我们有学习了一下 antv 并且利用 G2 库 实现了简单的柱形图。

责任编辑:武晓燕 来源: 程序员Sunday
相关推荐

2023-05-29 09:37:17

Vue3Vite

2023-07-30 15:11:03

Vue3第三方组件库

2022-07-26 01:06:18

Vue3自定义指令

2022-08-01 11:41:00

Vue插件

2020-12-17 09:40:01

Matplotlib数据可视化命令

2022-03-24 15:28:43

Vue开发框架

2017-10-18 16:08:15

可视化交叉验证代码

2022-09-08 11:19:53

Vue可视化插件

2023-03-29 10:02:36

2023-01-30 09:27:57

开发自动化配置

2021-08-26 09:00:48

PyechartsPython可视化

2022-07-24 21:43:48

数据可视化大数据

2023-12-27 10:47:45

Flask数据可视化开发

2022-08-11 07:32:51

Starter自动装配

2014-08-08 13:22:54

测试手机站点移动设备

2021-07-14 09:00:36

Python数据Python基础

2021-12-01 08:11:44

Vue3 插件Vue应用

2021-12-28 08:38:26

Linux 中断唤醒系统Linux 系统

2022-01-08 20:04:20

拦截系统调用

2021-01-21 09:10:29

ECharts柱状图大数据
点赞
收藏

51CTO技术栈公众号