三小時,手把手帶你完成【大屏可視化】系統(Vue3 + ECharts5)
Hello,大家好,我是 Sunday。
之前我在 B 站發布了一個大屏可視化的視頻【2023最新:ECharts 數據可視化大屏項目】 訪問地址:https://www.bilibili.com/video/BV1yu411E7cm/
該視頻到目前為止已經有了 12多萬的播放,收藏也超過了 6000。
在很多同學學習該視頻的過程中,有很多同學問我:“Sunday老師,我在公司沒法看視頻,有沒有文檔也可以實現這個項目呢?”
答案:肯定是有的。
所以說,咱們今天這篇文章,就讓大家可以 不看視頻 只通過文檔,依然可以完成整個大屏可視化的項目!
一、前言
這一小節,我們將要來實現一個地圖可視化的項目,項目最終的實現效果如下:
圖片
整個可視化項目,一共分為 8 部分。
這八部分我們會按照,難易的順序來進行繪制,盡量幫助大家可以以 逐步深入 的方式掌握大屏可視化的內容。
- 橫向柱形圖
- 豎向柱形圖
- 雷達圖
- 環形圖
- 關系圖
- 數據云圖
- 數據展示圖
- 地圖可視化
那么明確好了,本章的內容之后,下面這一章的項目開發吧~~
二、基于 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>
此時,展示的內容如下:
圖片
三、導入 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)
那么此時,我們就已經拿到了大屏的動態數據。下一小節,我們就根據這個數據,繪制橫向的柱形圖。
四、繪制大區橫向柱形圖
在上一小節中,我們拿到了大屏數據,數據中的 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()
}
)
至此,橫向柱形圖渲染完成。
五、繪制服務豎向柱形圖
上一小節,我們簡單的利用 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>
六、繪制報警風險雷達圖
前面兩個小節,咱們創建了基本的柱形圖。
通過柱形圖,咱們大致應該了解了 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>
七、繪制異常處理雙環形圖
在前面的 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}(owocgsc%)'
},
// 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>
八、繪制數據傳遞關系圖
在前面,我們繪制了很多基本的 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>
九、繪制關鍵詞條文檔云圖
在前面的圖表中,我們都是基于 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>
十、繪制數據總覽圖
通常在大屏可視化項目中,除了包含基本的圖表之外,還會存在一些數據概覽的內容。這就是我們這一小節主要講解的東西。
咱們這里所實現的數據概覽,主要包含兩塊功能:
- 數值自增
- 數值漸變 + 特殊字體
首先針對于數值自增而言,主要可以通過 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;
}
- 在 src/components/TotalData.vue 中,為每個 span 添加 font-[Electronic] 類名
- 單獨為數據總量添加 text-gradient 類名
十一、地圖可視化分析與時間軸圖表繪制
那么到目前,我們就只剩下最后一塊,也是最復雜的一塊功能需要進行實現了。
這一塊圖表,可以被分為四個部分:
- 時間軸
- 橫向柱形圖
- 地圖
- 繪制地圖散點圖
所以針對這樣的功能,咱們將分成四個小節分步進行繪制。
那么這一小節,咱們就先就來實現 時間軸 繪制。
時間軸繪制,需要使用到 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>
十二、地圖可視化繪制動態柱形圖
這一小節,咱們來繪制地圖可視化中的動態柱形圖。
柱形圖的繪制,對咱們現在而言,應該是有一些熟悉的了,同時因為有時間軸的存在,所以我們可以直接添加 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)
}
十三、地圖可視化,繪制地圖
最后,我們來繪制地圖。
想要繪制地圖,那么需要首先 導入地圖的**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
}
}
}
}
十四、地圖可視化散點圖繪制
最后只需要在 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
}
十五、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 構建一個基本的柱形圖
十六、大屏數據展示組件庫 DataV
在本章的最后,我為大家介紹最后一個東西 DataV。
DataV 是一個 大屏數據展示組件庫,同時提供了 vue 版本和 react 版本。
它的使用和其他的組件庫一樣,都是安裝之后全局導入組件和局部導入組件。只不過它的組件會更加偏向于 大屏可視化的場景。
它內部提供的組件并不多,大家可以通過視頻查看對應的演示。在文檔中,咱們就不過多贅述了。
十七、總結
那么到這里,咱們本章的主要內容就已經全部完成了。
在本章中,我們首先利用 vite + tailwindcss 構建了一個大屏可視化的項目。
然后通過 echarts 完成了大屏可視化的功能。在項目中,每一個圖表都是一個單獨的組件。
在本章的最后,我們有學習了一下 antv 并且利用 G2 庫 實現了簡單的柱形圖。