数据可视化Echarts
前言:ECharts,一个使用JavaScript实现的开源可视化库。
一、什么是数据可视化?
什么是数据可视化呢?
1.为了清晰有效地传递信息,数据可视化使用统计图形、图表、信息图表和其他工具;
2. 可以使用点、线或条,对数字数据进行编码;
3.数据可视化让我们可以更加清晰的去认识、理解、表达数据;
前端可视化的工具
1.常见的框架: ECharts 、g2、d3、vis、hightChart等等;
2.g2框架封装:bizcharts(react) viser(vue);
3.地理可视化: g2、L7、高德的 Loca、 菜鸟的 鸟图;
4.3D可视化:three.js;
认识ECharts
什么是ECharts呢?官方的解释是:一个基于 JavaScript 的开源可视化图表库;
ECharts的历史:
- ECharts由百度团队开源;
- 2018年初,捐赠给Apache基金会,成为ASF(Apache Software Foundation,简称为ASF,Apache软件基金会)孵化级项目;
- 2021年1月26日晚,Apache基金会官方宣布 ECharts项目正式毕业,成为Apache顶级项目;
- 2021年1月28日,ECharts 5线上发布会举行;
ECharts的特点:
- 丰富的图表类型:提供开箱即用的 20 多种图表和十几种组件,并且支持各种图表以及组件的任意组合;
- 强劲的渲染引擎:Canvas、SVG 双引擎一键切换,增量渲染、流加载等技术实现千万级数据的流畅交互;
- 专业的数据分析:通过数据集管理数据,支持数据过滤、聚类、回归,帮助实现同一份数据的多维度分析;
- 优雅的可视化设计:默认设计遵从可视化原则,支持响应式设计,并且提供了灵活的配置项方便开发者定制;
- 健康的开源社区:活跃的社区用户保证了项目的健康发展,也贡献了丰富的第三方插件满足不同场景的需求;
- 友好的无障碍访问:智能生成的图表描述和贴花图案,帮助视力障碍人士了解图表内容,读懂图表背后的故事;
二、使用Echarts的步骤
第一步:我们可以通过以下方式获取ECharts:
- 从 Apache ECharts 官网下载界面 获取官方源码包后构建;
- 在 ECharts 的 GitHub 获取;
- 通过 npm 获取 echarts,npm install echarts --save;
- 通过 jsDelivr 等 CDN 引入;
第二步:引入Echarts
可以通过不同的方式引入
第三步:初始化Echarts对象,并且设置配置进行绘制
1.通过echarts.init(dom, theme, options)初始化;
2.通过setOption方法设置绘制的数据;
三、ECharts配置信息
option = {
xAxis: {
type: 'category',
boundaryGap: false,
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [
{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line',
areaStyle: {}
}
]
};
四、Echarts的渲染模式
1.通常在渲染图表是我们会选择 SVG或者canvas进行渲染:
- 通常情况下,这两种渲染模式是比较相近的,并且是可以相互替换的;
- 但是在一些场景中,它们的表现和能力有一定的差异;
- 对于它们之间的取舍,一直是没有一个明确、标准的答案的,也是一个经常被拿到讨论的话题;
2.ECharts最初采用的是canvas绘制图表,从ECharts4.x开始,发布了SVG渲染器,提供了另外的一种选择。
3.那么它们之间到底如何选择呢?
- 一般来说,Canvas 更适合绘制图形元素数量非常大(这一般是由数据量大导致)的图表(如热力图、地理坐标 系或平行坐标系上的大规模线图或散点图等),也利于实现某些视觉特效;
- 但是,在不少场景中,SVG 具有重要的优势:它的内存占用更低(这对移动端尤其重要)、渲染性能略高、并
且用户使用浏览器内置的缩放功能时不会模糊;
4.ECharts在不同的设备上,进行了性能的测试:
- 从图片来看,在这些场景中,SVG 渲染器相比 Canvas 渲染器在移动端的总体表现更好;
- 当然,这个实验并非是全面的评测,在另一些数据量较大或者有图表交互动画的场景中,目前的 SVG 渲染器的性能还比不过 Canvas 渲染器;
5.那么到底选择哪一个渲染器呢? - 在软硬件环境较好,数据量不大的场景下(例如 PC 端做商务报表),两种渲染器都可以适用,并不需要太多纠结;
- 在环境较差,出现性能问题需要优化的场景下,可以通过试验来确定使用哪种渲染器;
- 比如在须要创建很多 ECharts 实例且浏览器易崩溃的情况下(可能是因为 Canvas 数量多导致内存占用超出手
机承受能力),可以使用 SVG 渲染器来进行改善; - 大略的说,如果图表运行在低端安卓机,或者我们在使用一些特定图表如 水球图等,SVG 渲染器可能效果更好; p数据量很大、较多交互时,可以选用 Canvas 渲染器;
建议:因为Echarts里面的配置太多了,建议使用的时候先去查看案例,然后删删改改,回头查看配置文档。
五、Vue使用Echarts
实现组件化,工程化项目 => 使用分层结构,我辈义不容辞。
这里代码展示从顶层封装 => 页面展示
1.useEchart.ts
import * as Echarts from 'echarts'
// 获取中国地图数据
import chinaMapData from '../data/china.json'
Echarts.registerMap('china', chinaMapData)
// 封装Echarts的顶级hooks,新添加相关的逻辑很方便
export default function (el: HTMLElement) {
// 1.创建Echarts实例
const echartInstance = Echarts.init(el)
// 2.把option创建好
const setOption = (option: Echarts.EChartsOption) => {
echartInstance.setOption(option)
}
// 3.调用Echarts实例来适配echarts大小
window.addEventListener('resize', () => {
echartInstance.resize()
})
// 4.把函数放出去,比如折叠菜单时,调用,echarts就会适配
const updataSize = () => {
echartInstance.resize()
}
return { setOption, updataSize }
}
2.base-echart.vue
<template>
<div class="base-echart">
<div ref="echartDivRef" :style="{ width: width, height: height }"></div>
</div>
</template>
<script lang="ts" setup>
// 使用setup最新版
import { ref, onMounted, withDefaults, defineProps, watchEffect } from 'vue'
import { EChartsOption } from 'echarts'
import useEchart from '../hooks/useEchart'
// 定义prpos
const props = withDefaults(
defineProps<{
option: EChartsOption
width?: string
height?: string
}>(),
{
width: '100%',
height: '360px'
}
)
const echartDivRef = ref<HTMLElement>()
onMounted(() => {
const { setOption } = useEchart(echartDivRef.value!)
watchEffect(() => {
setOption(props.option)
})
// const echartInstance = echarts.init(echartDivRef.value!)
// echartInstance.setOption(props.option)
})
</script>
<style lang="less" scoped></style>
3.bar-echart.vue(这里就写一个柱状图封装哈)
<template>
<div class="bar-echart">
<base-echart :option="option"></base-echart>
</div>
</template>
<script setup lang="ts">
import { computed, defineProps, withDefaults } from 'vue'
import * as echarts from 'echarts'
import baseEchart from '@/base-ui/echart/index'
const props = withDefaults(
defineProps<{
title?: string
xLabels: string[]
values: any[]
}>(),
{
title: '这是一个柱状图'
}
)
const option = computed(() => {
return {
title: {
text: '特性示例:渐变色 阴影 点击缩放',
subtext: 'Feature Sample: Gradient Color, Shadow, Click Zoom'
},
xAxis: {
data: props.xLabels,
axisLabel: {
inside: true,
color: '#fff'
},
axisTick: {
show: false
},
axisLine: {
show: false
},
z: 10
},
yAxis: {
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
color: '#999'
}
},
dataZoom: [
{
type: 'inside'
}
],
series: [
{
type: 'bar',
showBackground: true,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#83bff6' },
{ offset: 0.5, color: '#188df0' },
{ offset: 1, color: '#188df0' }
])
},
emphasis: {
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#2378f7' },
{ offset: 0.7, color: '#2378f7' },
{ offset: 1, color: '#83bff6' }
])
}
},
data: props.values
}
]
}
})
</script>
<style lang="less" scoped></style>
4.dashboard.vue(页面使用)
<template>
<div class="dashboard">
<el-row :gutter="10">
<el-col :span="7">
<hy-card title="分类商品数量(饼图)">
<pie-echart :pieData="categoryGoodsCount"></pie-echart>
</hy-card>
</el-col>
<el-col :span="10">
<hy-card title="不同城市商品销量">
<map-echart :mapData="addressGoodsSale"></map-echart>
</hy-card>
</el-col>
<el-col :span="7">
<hy-card title="分类商品数量(玫瑰图)">
<rose-echart :roseData="categoryGoodsCount"></rose-echart>
</hy-card>
</el-col>
</el-row>
<el-row :gutter="10" class="content-row">
<el-col :span="12">
<hy-card title="分类商品的销量">
<line-echart v-bind="categoryGoodsSale"></line-echart>
</hy-card>
</el-col>
<el-col :span="12">
<hy-card title="分类商品的收藏">
<bar-echart v-bind="categoryGoodsFavor"></bar-echart>
</hy-card>
</el-col>
</el-row>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted, computed } from 'vue'
import { useStore } from '@/store'
import {
PieEchart,
roseEchart,
lineEchart,
barEchart,
mapEchart
} from '@/components/page-echarts'
import HyCard from '@/base-ui/card/index'
export default defineComponent({
name: 'dashboard',
components: {
HyCard,
PieEchart,
roseEchart,
lineEchart,
barEchart,
mapEchart
},
setup() {
const store = useStore()
// 请求数据
store.dispatch('dashboard/getDashboardDataAction')
// 获取数据
// 饼图
const categoryGoodsCount = computed(() => {
return store.state.dashboard.categoryGoodsCount.map((item: any) => {
return { name: item.name, value: item.goodsCount }
})
})
// 折线图
const categoryGoodsSale = computed(() => {
const xLabels: string[] = []
const values: any[] = []
const categoryGoodsSale = store.state.dashboard.categoryGoodsSale
for (const item of categoryGoodsSale) {
xLabels.push(item.name)
values.push(item.goodsCount)
}
return { xLabels, values }
})
// 柱形图数据
const categoryGoodsFavor = computed(() => {
const xLabels: string[] = []
const values: any[] = []
const categoryGoodsFavor = store.state.dashboard.categoryGoodsFavor
for (const item of categoryGoodsFavor) {
xLabels.push(item.name)
values.push(item.goodsFavor)
}
return { xLabels, values }
})
return { categoryGoodsCount, categoryGoodsSale, categoryGoodsFavor }
}
})
</script>
<style scoped>
.content-row {
margin-top: 20px;
}
</style>
六、效果图
水平有限,还不能写到尽善尽美,希望大家多多交流,跟春野一同进步!!!