最终效果
使用介绍
echarts图表的绘制,大体分为三步:
- 根据 DOM实例,通过 echarts.init方法,生成 echarts实例
- 构建 options配置对象,整个echarts的样式,皆有该对象决定
- 最后通过
实例.setOption
方法,设置配置对象配置对象是echarts中最复杂的部分,也就是核心。
<!-- 为 ECharts 准备一个定义了宽高的 DOM -->
<div id="main" style="width: 600px;height:400px;"></div>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
const myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
const option = {
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
legend: {
data: ['销量']
},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [
{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>
那么最难的 option 配置对象怎么看呢?这里我们可以跟着官方示例学习:echarts 示例,通过不断修改示例达到我们预期的效果。
还有一个难点,就是如果我们的配置写的不完全或者写的不对,是不能够看到部分效果的,也就是说,要么就是一张完整的图表,要么就是一张空白。
经过上述种种难点,我总结出一个使用 echarts 的好办法,结合 ChatGPT。
我们先向他描述图表的大致形状,然后让它先生成一个能够运行的图表,之后我们不断细化需求,进行更改。
比如:
我:我要使用 echarts 绘制一些图表,但是不知道相关代码配置怎么写,
我需要你按照我接下来的要求给出代码。
ChatGPT:xxx
我:我想绘制一张横向的柱形图,比如柱形图第一行
坐标为华北,数据为20;第二行 坐标为 西北,数据为30 ;
代码应该怎么写?
ChatGPT:xxx
我:我不想要横坐标。
ChatGPT:xxx
最终生成:
总之就是这样,逐渐细化需求,直到完成我们的要求为止。
具体示例
这里可以先试用 tailwindcss 进行初始布局搭建。
tailwindcss 结合框架使用跟着文档就就可以。
基本布局
下面均使用 mock 数据。
index
function Index(props) {
return (
<div
style={{
backgroundImage: `url(${bgImage})`,
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
width: '100%',
height: '94vh',
color: 'white',
display: 'flex',
overflow: 'hidden',
padding: '5px',
}}
>
{/*左*/}
<div className="flex-1 mr-2 bg-opacity-50 bg-slate-800 p-3 flex flex-col">
{/* 横向柱状图*/}
<HorizontalBar className="h-1/3 box-border pb-4" />
{/* 雷达图*/}
<RadarBar className="h-1/3 box-border pb-4" />
{/* 关系图*/}
<Relation className="h-1/3" />
</div>
{/*中*/}
<div className="w-1/2 mr-2 flex flex-col">
{/* 数据总览图*/}
<TotalData classNmae="bg-opacity-50 bg-slate-800 p-3 " />
{/* 地图可视化*/}
<MapChart classNmae="bg-opacity-50 bg-slate-800 p-3 mt-2 flex-1" />
</div>
{/*右*/}
<div className="flex-1 bg-opacity-50 bg-slate-800 p-3 flex flex-col">
{/* 竖向柱状图*/}
<VerticalBar className="h-1/3 box-border pb-4" />
{/* 环形图*/}
<RingBar className="h-1/3 box-border pb-4" />
{/* 文档云图*/}
<WordCloud className="h-1/3 " />
</div>
</div>
);
}
HorizontalBar
import * as echarts from 'echarts';
import { useEffect, useRef } from 'react';
function HorizontalBar(props) {
const data = {
regions: [
{ id: 1, name: '华北', value: 63 },
{ id: 2, name: '华南', value: 86 },
{ id: 3, name: '华东', value: 85 },
{ id: 4, name: '西南', value: 63 },
{ id: 5, name: '西北', value: 54 },
{ id: 6, name: '东北', value: 79 },
],
};
// 1. 初始化 echarts 实例
let myChart = null;
const target = useRef(null);
useEffect(() => {
myChart = echarts.init(target.current);
renderChart();
}, []);
// 2. 构建 options 配置对象
const renderChart = () => {
const options = {
// x 轴展示数据
xAxis: {
// 不显示 x 轴
show: false,
// x 轴类型为数据进行展示
type: 'value',
// 设置 x 轴最大值
max: function (value) {
// 将 x 轴个数据中的的最大值 * 1.2 作为 x 轴的最大值
return parseInt(value.max * 1.2);
},
},
// y 轴展示数据
yAxis: {
// y 轴为类型数据展示
type: 'category',
// data 为所需展示的数据
data: data.regions.map((item) => item.name), // 映射数据
// 反向展示数据 默认情况从下到上展示数据
inverse: true,
// 不展示轴线
axisLine: {
show: false,
},
// 不展示刻度
axisTick: {
show: false,
},
axisLabel: {
color: '#9eb1c8',
},
},
// 图表位置 上下左右
grid: {
top: 0,
right: 0,
bottom: 0,
left: 0,
// 包含标签
containLabel: true,
},
// 核心配置
series: [
{
// 柱形图
type: 'bar',
// 展示数据
data: data.regions.map((item) => ({
name: item.name,
value: item.value,
})),
showBackground: true,
backgroundStyle: {
color: 'rgba(180,180,180,0.2)',
},
// x 数据项样式
itemStyle: {
color: '#479AD3',
barBorderRadius: 5,
shadowColor: 'rgba(0,0,0,0.3)',
// 阴影模糊
shadowBlur: 5,
},
barWidth: 12,
// x 上的字体标签
label: {
show: true,
position: 'right',
textStyle: {
color: '#fff',
},
},
},
],
};
// 3. 根据数据构建 options 配置对象 myCharts.setOption(options)
myChart.setOption(options);
};
return (
<div className={props.className}>
<div>学生来源信息</div>
<div ref={target} className="w-full h-full"></div>
</div>
);
}
export default HorizontalBar;
MapChart
import mapJson from '@/assets/screen/MapData/china.json';
import * as echarts from 'echarts';
import { useEffect, useRef } from 'react';
function MapChart(props) {
const data = {
mapData: {
categoryData: {
2020: [
{ name: '北京', value: 42 },
{ name: '天津', value: 24 },
{ name: '上海', value: 53 },
{ name: '重庆', value: 64 },
{ name: '河北', value: 87 },
{ name: '河南', value: 52 },
{ name: '云南', value: 14 },
{ name: '辽宁', value: 35 },
{ name: '黑龙江', value: 85 },
{ name: '湖南', value: 95 },
{ name: '安徽', value: 41 },
{ name: '山东', value: 45 },
{ name: '新疆', value: 56 },
{ name: '江苏', value: 43 },
{ name: '浙江', value: 56 },
{ name: '江西', value: 63 },
{ name: '湖北', value: 41 },
{ name: '广西', value: 23 },
{ name: '甘肃', value: 56 },
{ name: '山西', value: 62 },
{ name: '内蒙古', value: 64 },
{ name: '陕西', value: 54 },
{ name: '吉林', value: 34 },
{ name: '福建', value: 16 },
{ name: '贵州', value: 71 },
{ name: '广东', value: 32 },
{ name: '青海', value: 56 },
{ name: '西藏', value: 52 },
{ name: '四川', value: 63 },
{ name: '宁夏', value: 74 },
{ name: '海南', value: 51 },
],
2021: [
{ name: '北京', value: 76 },
{ name: '天津', value: 54 },
{ name: '上海', value: 23 },
{ name: '重庆', value: 64 },
{ name: '河北', value: 54 },
{ name: '河南', value: 52 },
{ name: '云南', value: 34 },
{ name: '辽宁', value: 35 },
{ name: '黑龙江', value: 65 },
{ name: '湖南', value: 95 },
{ name: '安徽', value: 34 },
{ name: '山东', value: 34 },
{ name: '新疆', value: 56 },
{ name: '江苏', value: 76 },
{ name: '浙江', value: 23 },
{ name: '江西', value: 65 },
{ name: '湖北', value: 41 },
{ name: '广西', value: 34 },
{ name: '甘肃', value: 43 },
{ name: '山西', value: 65 },
{ name: '内蒙古', value: 64 },
{ name: '陕西', value: 54 },
{ name: '吉林', value: 98 },
{ name: '福建', value: 76 },
{ name: '贵州', value: 71 },
{ name: '广东', value: 65 },
{ name: '青海', value: 56 },
{ name: '西藏', value: 43 },
{ name: '四川', value: 63 },
{ name: '宁夏', value: 54 },
{ name: '海南', value: 51 },
],
2022: [
{ name: '北京', value: 23 },
{ name: '天津', value: 24 },
{ name: '上海', value: 43 },
{ name: '重庆', value: 64 },
{ name: '河北', value: 65 },
{ name: '河南', value: 52 },
{ name: '云南', value: 14 },
{ name: '辽宁', value: 35 },
{ name: '黑龙江', value: 98 },
{ name: '湖南', value: 95 },
{ name: '安徽', value: 65 },
{ name: '山东', value: 45 },
{ name: '新疆', value: 56 },
{ name: '江苏', value: 87 },
{ name: '浙江', value: 65 },
{ name: '江西', value: 63 },
{ name: '湖北', value: 54 },
{ name: '广西', value: 45 },
{ name: '甘肃', value: 56 },
{ name: '山西', value: 62 },
{ name: '内蒙古', value: 64 },
{ name: '陕西', value: 54 },
{ name: '吉林', value: 23 },
{ name: '福建', value: 16 },
{ name: '贵州', value: 54 },
{ name: '广东', value: 32 },
{ name: '青海', value: 21 },
{ name: '西藏', value: 52 },
{ name: '四川', value: 43 },
{ name: '宁夏', value: 32 },
{ name: '海南', value: 51 },
],
2023: [
{ name: '北京', value: 65 },
{ name: '天津', value: 54 },
{ name: '上海', value: 53 },
{ name: '重庆', value: 64 },
{ name: '河北', value: 23 },
{ name: '河南', value: 52 },
{ name: '云南', value: 43 },
{ name: '辽宁', value: 35 },
{ name: '黑龙江', value: 85 },
{ name: '湖南', value: 95 },
{ name: '安徽', value: 34 },
{ name: '山东', value: 45 },
{ name: '新疆', value: 56 },
{ name: '江苏', value: 42 },
{ name: '浙江', value: 56 },
{ name: '江西', value: 63 },
{ name: '湖北', value: 41 },
{ name: '广西', value: 23 },
{ name: '甘肃', value: 23 },
{ name: '山西', value: 62 },
{ name: '内蒙古', value: 64 },
{ name: '陕西', value: 54 },
{ name: '吉林', value: 34 },
{ name: '福建', value: 43 },
{ name: '贵州', value: 65 },
{ name: '广东', value: 32 },
{ name: '青海', value: 56 },
{ name: '西藏', value: 52 },
{ name: '四川', value: 76 },
{ name: '宁夏', value: 43 },
{ name: '海南', value: 51 },
],
2024: [
{ name: '北京', value: 31 },
{ name: '天津', value: 54 },
{ name: '上海', value: 53 },
{ name: '重庆', value: 64 },
{ name: '河北', value: 33 },
{ name: '河南', value: 52 },
{ name: '云南', value: 54 },
{ name: '辽宁', value: 42 },
{ name: '黑龙江', value: 85 },
{ name: '湖南', value: 95 },
{ name: '安徽', value: 41 },
{ name: '山东', value: 45 },
{ name: '新疆', value: 56 },
{ name: '江苏', value: 53 },
{ name: '浙江', value: 56 },
{ name: '江西', value: 43 },
{ name: '湖北', value: 64 },
{ name: '广西', value: 23 },
{ name: '甘肃', value: 56 },
{ name: '山西', value: 65 },
{ name: '内蒙古', value: 64 },
{ name: '陕西', value: 54 },
{ name: '吉林', value: 34 },
{ name: '福建', value: 54 },
{ name: '贵州', value: 71 },
{ name: '广东', value: 13 },
{ name: '青海', value: 56 },
{ name: '西藏', value: 52 },
{ name: '四川', value: 23 },
{ name: '宁夏', value: 74 },
{ name: '海南', value: 51 },
],
},
colors: [
'#1DE9B6',
'#F46E36',
'#04B9FF',
'#5DBd32',
'#FFC809',
'#FB05D5',
'#BDA29A',
'#6E7074',
'#546570',
'#C4CCD3',
],
topData: {
2020: [
{
name: '天津',
value: [117.4219, 39.4189, 84.1],
},
{
name: '河北',
value: [114.4995, 38.1006, 85.8],
},
{
name: '河南',
value: [113.4668, 34.6234, 83.6],
},
{
name: '北京',
value: [116.4551, 40.2539, 83.2],
},
{
name: '山东',
value: [117.1582, 36.8701, 82.5],
},
{
name: '安徽',
value: [117.29, 32.0581, 81.7],
},
{
name: '湖北',
value: [114.3896, 30.6628, 81.4],
},
{
name: '江苏',
value: [118.8062, 31.9208, 81.1],
},
{
name: '新疆',
value: [87.9236, 43.5883, 80.4],
},
{
name: '湖南',
value: [113.0823, 28.2568, 80.1],
},
],
2021: [
{
name: '天津',
value: [117.4219, 39.4189, 84.1],
},
{
name: '河北',
value: [114.4995, 38.1006, 85.8],
},
{
name: '河南',
value: [113.4668, 34.6234, 83.6],
},
{
name: '北京',
value: [116.4551, 40.2539, 83.2],
},
{
name: '山东',
value: [117.1582, 36.8701, 82.5],
},
{
name: '安徽',
value: [117.29, 32.0581, 81.7],
},
{
name: '湖北',
value: [114.3896, 30.6628, 81.4],
},
{
name: '江苏',
value: [118.8062, 31.9208, 81.1],
},
{
name: '新疆',
value: [87.9236, 43.5883, 80.4],
},
{
name: '湖南',
value: [113.0823, 28.2568, 80.1],
},
],
2022: [
{
name: '天津',
value: [117.4219, 39.4189, 84.1],
},
{
name: '河北',
value: [114.4995, 38.1006, 85.8],
},
{
name: '河南',
value: [113.4668, 34.6234, 83.6],
},
{
name: '北京',
value: [116.4551, 40.2539, 83.2],
},
{
name: '山东',
value: [117.1582, 36.8701, 82.5],
},
{
name: '安徽',
value: [117.29, 32.0581, 81.7],
},
{
name: '湖北',
value: [114.3896, 30.6628, 81.4],
},
{
name: '江苏',
value: [118.8062, 31.9208, 81.1],
},
{
name: '新疆',
value: [87.9236, 43.5883, 80.4],
},
{
name: '湖南',
value: [113.0823, 28.2568, 80.1],
},
],
2023: [
{
name: '天津',
value: [117.4219, 39.4189, 84.1],
},
{
name: '河北',
value: [114.4995, 38.1006, 85.8],
},
{
name: '河南',
value: [113.4668, 34.6234, 83.6],
},
{
name: '北京',
value: [116.4551, 40.2539, 83.2],
},
{
name: '山东',
value: [117.1582, 36.8701, 82.5],
},
{
name: '安徽',
value: [117.29, 32.0581, 81.7],
},
{
name: '湖北',
value: [114.3896, 30.6628, 81.4],
},
{
name: '江苏',
value: [118.8062, 31.9208, 81.1],
},
{
name: '新疆',
value: [87.9236, 43.5883, 80.4],
},
{
name: '湖南',
value: [113.0823, 28.2568, 80.1],
},
],
2024: [
{
name: '天津',
value: [117.4219, 39.4189, 84.1],
},
{
name: '河北',
value: [114.4995, 38.1006, 85.8],
},
{
name: '河南',
value: [113.4668, 34.6234, 83.6],
},
{
name: '北京',
value: [116.4551, 40.2539, 83.2],
},
{
name: '山东',
value: [117.1582, 36.8701, 82.5],
},
{
name: '安徽',
value: [117.29, 32.0581, 81.7],
},
{
name: '湖北',
value: [114.3896, 30.6628, 81.4],
},
{
name: '江苏',
value: [118.8062, 31.9208, 81.1],
},
{
name: '新疆',
value: [87.9236, 43.5883, 80.4],
},
{
name: '湖南',
value: [113.0823, 28.2568, 80.1],
},
],
},
voltageLevel: ['2020', '2021', '2022', '2023', '2024'],
},
};
const target = useRef(null);
let myChart = null;
useEffect(() => {
myChart = echarts.init(target.current);
renderChart();
}, []);
const renderChart = () => {
// echarts 渲染
echarts.registerMap('china', mapJson);
let options = {
// 时间线,提供了在多个 ECharts option 间进行切换
timeline: {
// 数据
data: data.mapData.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',
},
},
},
// 柱形图右侧展示
baseOption: {
grid: {
right: '2%',
top: '15%',
bottom: '10%',
width: '20%',
},
// 中国地图
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,
},
},
},
},
// 绑定时间轴的多个图表
options: [],
};
// 为每一年度的图表添加数据
data.mapData.voltageLevel.forEach((item, index) => {
options.options.push({
// 背景色
backgroundColor: '#142037',
title: [
// 主标题,对应地图
{
text: '2020-2024 年度使用人数统计',
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: data.mapData.categoryData[item].map((item) => item.name),
},
// 核心配置
series: [
// 柱形图
{
zlevel: 1.5,
// 柱形图
type: 'bar',
// 每个柱子的色值
itemStyle: {
normal: {
color: data.mapData.colors[index],
},
},
// 根据年份,获取对应数据
data: data.mapData.categoryData[item].map((item) => item.value),
},
// 散点图
{
// 散点(气泡)图
type: 'effectScatter',
// 使用地理坐标系
coordinateSystem: 'geo',
// 数据
data: data.mapData.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: data.mapData.colors[index],
// 阴影配置
shadowBlur: 5,
shadowColor: data.mapData.colors[index],
},
},
zlevel: 1,
},
],
});
});
myChart.setOption(options);
};
return <div ref={target} className={props.classNmae}></div>;
}
export default MapChart;
RadarBar
import * as echarts from 'echarts';
import { useEffect, useRef } from 'react';
function RadarBar(props) {
const data = {
regions: [
{ id: 1, name: '华北', value: 63 },
{ id: 2, name: '华南', value: 86 },
{ id: 3, name: '华东', value: 85 },
{ id: 4, name: '西南', value: 63 },
{ id: 5, name: '西北', value: 54 },
{ id: 6, name: '东北', value: 79 },
],
};
const target = useRef(null);
let myChart = null;
useEffect(() => {
myChart = echarts.init(target.current);
renderChart();
}, []);
const renderChart = () => {
const options = {
// 雷达图的坐标系位置
radar: {
name: {
textStyle: {
color: '#05D5FF',
fontSize: 14,
},
},
shape: 'polygon', // 雷达图绘制类型,支持 'polygon' 和 'circle'
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: data.regions.map((item) => {
return {
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',
symbol: 'circle', // 标记图形类型
symbolSize: 10, // 标记拐角大小
itemStyle: {
normal: {
color: '#05D5FF',
},
},
// 填充 style
areaStyle: {
normal: {
color: '#05D5FF',
opacity: 0.5,
},
},
lineStyle: {
width: 2,
color: '#05D5FF',
},
label: {
normal: {
show: true,
color: '#fff',
},
},
data: [
{
value: data.regions.map((item) => item.value),
},
],
},
};
myChart.setOption(options);
};
return (
<div className={props.className}>
<div>监控云端方位报警风险</div>
<div ref={target} className="w-full h-full"></div>
</div>
);
}
export default RadarBar;
Relation
import * as echarts from 'echarts';
import { useEffect, useRef } from 'react';
function Relation(props) {
const data = {
relations: [
{
id: 1,
name: '软件工程II',
source: '软件工程II',
speed: 66,
target: '软件工程I',
value: [0, 300],
},
{
id: 2,
name: '软件概述',
source: '软件工程I',
speed: 78,
target: '软件概述',
value: [100, 300],
},
{
id: 3,
name: '软件内容',
source: '软件工程I',
speed: 92,
target: '软件内容',
value: [100, 100],
},
{
id: 4,
name: '软件导论',
source: '软件导论',
speed: 33,
target: '软件工程I',
value: [0, 100],
},
{ id: 0, name: '软件工程I', speed: 117, value: [50, 200] },
],
};
const target = useRef(null);
let myChart = null;
useEffect(() => {
myChart = echarts.init(target.current);
renderChart();
}, []);
const renderChart = () => {
const options = {
// X 轴不需要展示
xAxis: {
show: false,
type: 'value',
},
// Y 轴不需要展示
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: data.relations.map((item) => {
// id 为 0 ,表示数据中心,数据中心单独设置
if (item.id !== 0) {
return {
name: item.name,
category: 0,
active: true,
speed: `${item.speed}kb/s`,
// 位置
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: data.relations.map((item, index) => ({
// 方向
source: item.source,
target: item.target,
// 线上的文字
speed: `${item.speed}%`,
// 线的样式
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] }],
],
},
],
};
myChart.setOption(options);
};
return (
<div className={props.className}>
<div>知识溯源概念模型</div>
<div ref={target} className="w-full h-full"></div>
</div>
);
}
export default Relation;
RingBar
import * as echarts from 'echarts';
import { useEffect, useRef } from 'react';
function RingBar(props) {
const data = {
courses: [
{ id: 1, name: '软件工程概论', value: 1363 },
{ id: 2, name: 'Java程序设计', value: 1086 },
{ id: 3, name: '计算机网络', value: 666 },
{ id: 4, name: '操作系统', value: 999 },
{ id: 5, name: '数据结构与算法', value: 765 },
],
};
const target = useRef(null);
let myChart = null;
useEffect(() => {
myChart = echarts.init(target.current);
renderChart();
}, []);
/**
* 双环形图绘制原理:
* 1. 环形图通过饼图绘制。内外边距的距离减小,即为环形。环形中心点需要不断改变,否则会重叠
* 2. 环形图绘制分为 上层和底层 两部分。上层作为绘制进度,底层作为背景图
* 3. 依据 getSeriesData 生成对应的 上层和底层 series 数据,进行渲染
*/
const getSeriesData = () => {
const series = [];
data.courses.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: data.courses.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 轴不展示(没有 x 轴)
xAxis: [
{
show: false,
},
],
// 每两个标记一条线 相当于 10 个饼图
series: getSeriesData(),
};
myChart.setOption(options);
};
return (
<div className={props.className}>
<div>课程掌握熟练度处理</div>
<div ref={target} className="w-full h-full"></div>
</div>
);
}
export default RingBar;
TotalData
// import * as echarts from 'echarts';
import '@/assets/screen/fonts/css/style.css';
import { CountUp } from 'countup.js';
import { useEffect, useRef } from 'react';
function TotalData(props) {
const data = {
totalData: {
db: '65446',
hb: '87788',
hd: '76456',
total: '6784739',
xb: '75753',
xn: '74564',
zn: '42135',
},
};
const totalCountTarget = useRef(null);
const city1 = useRef(null);
const city2 = useRef(null);
const city3 = useRef(null);
const city4 = useRef(null);
const city5 = useRef(null);
const city6 = useRef(null);
useEffect(() => {
new CountUp(totalCountTarget.current, data.totalData.total).start();
new CountUp(city1.current, data.totalData.hb).start();
new CountUp(city2.current, data.totalData.db).start();
new CountUp(city3.current, data.totalData.hd).start();
new CountUp(city4.current, data.totalData.zn).start();
new CountUp(city5.current, data.totalData.xn).start();
new CountUp(city6.current, data.totalData.xb).start();
}, []);
return (
<div className={props.className}>
<div className="p-6">
<div className="text-slate-300 text-center">
数据总量:
<span
ref={totalCountTarget}
className="text-7xl ml-2 mr-2 font-bold font-[Electronic] text-gradient"
>
679,473,929
</span>
条记录
</div>
<div className="mt-3 flex flex-wrap">
<div className="w-1/3 text-center text-slate-400 text-sm">
抬头:
<span
ref={city1}
className="text-[#5DC5EF] text-3xl font-[Electronic]"
>
8,778,988
</span>
</div>
<div className="w-1/3 text-center text-slate-400 text-sm">
睡觉:
<span
ref={city2}
className="text-[#5DC5EF] text-3xl font-[Electronic]"
>
8,778,988
</span>
</div>
<div className="w-1/3 text-center text-slate-400 text-sm">
举手:
<span
ref={city3}
className="text-[#5DC5EF] text-3xl font-[Electronic]"
>
8,778,988
</span>
</div>
<div className="w-1/3 text-center text-slate-400 text-sm">
低头:
<span
ref={city4}
className="text-[#5DC5EF] text-3xl font-[Electronic]"
>
8,778,988
</span>
</div>
<div className="w-1/3 text-center text-slate-400 text-sm">
站立:
<span
ref={city5}
className="text-[#5DC5EF] text-3xl font-[Electronic]"
>
8,778,988
</span>
</div>
<div className="w-1/3 text-center text-slate-400 text-sm">
坐直:
<span
ref={city6}
className="text-[#5DC5EF] text-3xl font-[Electronic]"
>
8,778,988
</span>
</div>
</div>
</div>
</div>
);
}
export default TotalData;
VerticalBar
import * as echarts from 'echarts';
import { useEffect, useRef } from 'react';
function VerticalBar(props) {
const data = {
servers: [
{ id: 1, name: '很好', value: 33 },
{ id: 2, name: '较好', value: 20 },
{ id: 3, name: '略好', value: 13 },
{ id: 4, name: '略差', value: 17 },
{ id: 5, name: '较差', value: 14 },
{ id: 6, name: '很差', value: 3 },
],
};
const target = useRef(null);
let myChart = null;
useEffect(() => {
myChart = echarts.init(target.current);
renderChart();
}, []);
const renderChart = () => {
const options = {
// X 轴展示选项
xAxis: {
type: 'category',
// 根据根据服务端数据筛选
data: 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: 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}%',
},
},
],
};
myChart.setOption(options);
};
return (
<div className={props.className}>
<div>听课抬头率分布占比</div>
<div ref={target} className="w-full h-full"></div>
</div>
);
}
export default VerticalBar;
WordCloud
import * as echarts from 'echarts';
import 'echarts-wordcloud';
import { useEffect, useRef } from 'react';
function WordCloud(props) {
const data = {
wordData: [
{ value: 24, name: '链表' },
{ value: 18, name: '队列' },
{ value: 16, name: '树' },
{ value: 12, name: 'Java' },
{ value: 10, name: 'JavaScript' },
{ value: 8, name: 'C++' },
{ value: 6, name: '设计模式' },
{ value: 45, name: '算法' },
{ value: 4, name: '数据结构' },
{ value: 2, name: '操作系统' },
{ value: 1, name: '计算机网络' },
{ value: 43, name: '前端' },
{ value: 3, name: '后端' },
{ value: 5, name: '数据库' },
{ value: 7, name: 'HTML' },
{ value: 9, name: 'CSS' },
{ value: 11, name: 'Vue' },
{ value: 13, name: 'React' },
{ value: 15, name: 'Webpack' },
{ value: 17, name: 'Node.js' },
],
};
const target = useRef(null);
let myChart = null;
useEffect(() => {
myChart = echarts.init(target.current);
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',
// 形状
shape: 'circle',
width: '100%',
height: '100%',
// 数据映射文本的大小范围
sizeRange: [12, 52],
// 文字旋转范围
rotationRange: [0, 0],
// 单词之间的间距
gridSize: 5,
// 渲染动画
layoutAnimation: true,
// 字体
textStyle: {
// 随机色值
color: randomRGB,
},
// 高亮字体
emphasis: {
textStyle: {
fontWeight: 'bold',
color: '#000',
},
},
// 数据
data: data.wordData,
},
],
};
myChart.setOption(options);
};
return (
<div className={props.className}>
<div>关键词条</div>
<div ref={target} className="w-full h-full"></div>
</div>
);
}
export default WordCloud;