前言
大家好,这是我第一次写文章,希望以简单易懂的方式分享给大家。如果有任何问题,欢迎留言或私信,我会尽快回复。如果文章中有不足之处或您有改进建议,非常感谢您的指正。
项目案例使用的是 vue2 + antd 制作,后期演示使用的是 vue3 + antd + ts 制作。
一、问题阐述
案例背景:
本案例展示的是酒店后台管理系统中的数据,通过客户的下单时间和订单价格生成一个折线图。这是一个相对简单的功能,它能直观地展示关键数据,如下图所示。
然而,随着需求的变化,我还需要在图表中添加一个提示功能。例如,如果某个时间节点上有用户下单了两间房或更多,系统需要显示相应的提示信息,如下图所示。
二、项目案例解决步骤
1.安装Echarts
// npm 安装
npm install echarts --save
// yarn 安装
yarn add echarts
2.引入Echarts
引入有好几种方法,可以参考Echarts官网在项目中引入 ECharts - 入门篇 - 使用手册 - Apache ECharts,我这里使用的是全局引入。
<script>
import * as echarts from 'echarts'
</script>
3.vue代码(简化)
<span slot="tab">
<a-icon type="line-chart" />折线图
</span>
<div>
<div v-if="detailList.length == 0">
<h1 style="text-align: center">暂无数据</h1>
</div>
<-- 这是重点代码!!! -->
<div v-else id="basicLine" style="width: 100%; height: 400px"></div>
</div>
4.涉及到的JS代码(简化)
<script>
export default{
data() {
return {
detailList: [], // 订单详情数据
}
}
methods:{
// JS统计重复元素
addSameElement(arr) {
let count = {}
for (let i = 0; i < arr.length; i++) {
if (count[arr[i]]) {
count[arr[i]]++
} else {
count[arr[i]] = 1
}
}
return count
},
// 时间戳转日期格式
timestampToDate(timestamp) {
const date = new Date(timestamp)
// 格式化日期和时间
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0') // 月份从0开始,需要加1
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
const seconds = String(date.getSeconds()).padStart(2, '0')
// 返回格式化后的字符串
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
},
// 这是我自定义的点击事件,点击打开折线图
// 我点击之传入相关的数据
openDetail(val, index_id) {
this.visibleDetail = true
// val.type_price这是后端返回的数据在type_price中
val.type_price.forEach((item, index) => {
if (index == index_id) {
let newlist = [] // 折线图数据
let newPriceArr = [] // 创建一个新数组存储 价格数据
let newReserveArr = [] // 创建一个新数组存储 时间数据
let newTypeName = '' // 创建一个名字存储 折线图名称
let e = item.new_price_detail // 我用到的数据都在该数据中
// 这里是我点击哪个数据把传进来的数据做一个遍历
// 存储为新的数组再进行遍历
let arr = Object.keys(e).map(function (t) {
return e[t]
})
arr.forEach((item) => {
const obj = {}
obj.price = item.price
obj.type = item.type
obj.reserve = item.reserve
newlist.push(obj) // 遍历数据存储新数组中
newPriceArr.push(Number(item.price)) // 存储价格数据
newReserveArr.push(item.reserve.slice(5)) // 存储时间数据
newTypeName = item.type // 赋值折线图名称
})
this.detailList = newlist // 赋值定义的订单详情数据
// 合并时间以及价格数据的数组成一个对象
const priceAndTimerArr = newReserveArr.map((timer, index) => {
return {
timer: timer,
price: newPriceArr[index],
}
})
let newLineArr = []
priceAndTimerArr.forEach((item) => {
// 这里创建完新的对象之后遍历再组成一个新数组
let date = new Date(item.timer).getTime() / 1000 + ':' + item.price * 100
// 数据转变为时间戳的格式方便计算以确保下单时间精确到时分秒
newLineArr.push(date)
})
// 因为需要计算出是否同一时间下订单所以调用查找重复元素的方法(第一个方法)
let sameElement = this.addSameElement(newLineArr)
let endSameArr = [] // 定义最终重复的数据
let newTimArr = [] // 定义最终新的时间数据
let newPrArr = [] // 定义最终新的时间数据
// 使用for...in...方法遍历该对象
for (let key in sameElement) {
// 之前通过':'做了分割,现在分割开
let splitArr = key.split(':')
// 调用转时间戳的方法并分割,不要年只留下月+时分秒
let newTime = this.timestampToDate(splitArr[0] * 1000).slice(5)
// 价格处理,之前乘100为了处理小数点
let newPrice = splitArr[1] / 100
// 随便起的名字rose ,比较喜欢 哈哈
// 这个 rose 中定义的需要看下文 echarts 中需要什么数据
let rose = { name: key, value: sameElement[key], xAxis: newTime, yAxis: splitArr[1] / 100 }
// 这里做最后判断,如果说大于1说明重复,那么把重复这个数据取出来单独存储
if (sameElement[key] > 1) {
endSameArr.push(rose)
}
// 最终新的时间数据
newTimArr.push(newTime)
// 最终新的价格数据
newPrArr.push(newPrice)
}
// 传入使用nextTick,把需要的数据传入到Echarts所用到的数据
nextTick(() => {
this.drawChart(newPrArr, newTimArr, newTypeName, endSameArr)
})
}
})
},
}
}
</script>
5.关于nextTick()
如果不使用的话会显示折线图不显示以及空白情况,我也是根据查询到的方法进行了处理,这是使用了nextTick()后还显示的控制台报错,不过不影响页面使用。
6.最终传入代码
// 折线图数据
drawChart(newPrArr, newTimArr, newTypeName, endSameArr) {
const myChart = echarts.init(document.getElementById('basicLine'))
const option = {
title: {
text: newTypeName, // 该数据是房型的名称
},
tooltip: {
trigger: 'axis', // 悬浮时显示数据
},
xAxis: {
name: '日期',
data: newTimArr, // 该数据是之前最终的时间数据
type: 'category',
},
yAxis: {
name: '价格',
type: 'value',
},
series: [
{
name: '详情',
type: 'line',
data: newPrArr, // 该数据是之前最终的价格数据
// 这里需要情调说一下markPoint(图表标注)方法
// 示例传入数据
// data: [
// { name: 这里可以随意填写, value: 这里需要传入相同的结果也就是上文中查找出重复的时间和价格数据的值有几个, xAxis: 时间数据, yAxis:价格数据 }
// ]
markPoint: {
data: endSameArr, // 详见上文中给的值
},
lineStyle: {
normal: {
color: '#1890ff',
width: 3,
},
},
label: {
show: true,
position: 'bottom',
textStyle: {
fontSize: 16,
},
},
},
],
}
myChart.setOption(option)
},
最终效果如图所示
三、后期演示案例
<template>
<div>
<h3>基础折线图</h3>
<div id="basicLine" style="width: 80%; height: 400px"></div>
</div>
</template>
<script setup lang="ts">
// 引入echarts
import * as echarts from 'echarts';
// 引入
import { onMounted, nextTick, reactive } from 'vue';
// 一进来就调用
onMounted(() => {
drawChart(newPrArr, newTimArr, endSameArr);
});
// 造原数据
const dataList = reactive([
{ timer: '2024-08-09 10:42:33', price: 514.9 },
{ timer: '2024-08-09 09:49:02', price: 495.9 }, // 写两个相同的数据
{ timer: '2024-08-09 09:49:02', price: 495.9 }, // 写两个相同的数据
{ timer: '2024-08-10 18:40:51', price: 479.0 },
{ timer: '2024-07-20 14:36:52', price: 559.0 }, // 写三个相同的数据
{ timer: '2024-07-20 14:36:52', price: 559.0 }, // 写三个相同的数据
{ timer: '2024-07-20 14:36:52', price: 559.0 }, // 写三个相同的数据
{ timer: '2024-08-08 10:56:12', price: 569.0 },
{ timer: '2024-08-10 15:10:02', price: 489.0 },
]);
// 设置空数组存放重置好的原数据
let newLineArr = reactive([]);
// 遍历原数据把定好的数据存放到 newLineArr 中
dataList.forEach((item) => {
let date = new Date(item.timer).getTime() / 1000 + ':' + item.price * 100;
newLineArr.push(date);
});
// console.log(newLineArr);
/*
打印如下:转换时间戳和价格的格式通过 : 分隔开
0: "1723171353:51490"
1: "1723168142:49590"
2: "1723168142:49590"
3: "1723286451:47900"
4: "1721457412:55900"
5: "1721457412:55900"
6: "1721457412:55900"
7: "1723085772:56900"
8: "1723273802:48900"
*/
// JS统计重复元素
function addSameElement(arr) {
let count = {};
for (let i = 0; i < arr.length; i++) {
if (count[arr[i]]) {
count[arr[i]]++;
} else {
count[arr[i]] = 1;
}
}
return count;
}
// 统计重置好的原数据中有多少个相同的数据
const sameElement = addSameElement(newLineArr);
// console.log(sameElement);
/*
打印如下所示:后面的数字代表有多少个相同的
1721457412:55900: 3
1723085772:56900: 1
1723168142:49590: 2
1723171353:51490: 1
1723273802:48900: 1
1723286451:47900: 1
*/
// 时间戳转日期格式
function timestampToDate(timestamp) {
const date = new Date(timestamp);
// 格式化日期和时间
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需要加1
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
// 返回格式化后的字符串
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
// 创造新数组存放最终相同的数据元素
const endSameArr = reactive([]);
// 创造新数组存放最终的时间数据
const newTimArr = reactive([]);
// 创造新数组存放最终的价格数据
const newPrArr = reactive([]);
// 循环遍历 sameElement,取出需要的数据并存放到 newTimArr, newPrArr, endSameArr中
for (let key in sameElement) {
// 通过 : 分隔开
let splitArr = key.split(':');
// 通过时间戳再次转换成日期格式并使用 slice() 方法去掉年
let newTime = timestampToDate(splitArr[0] * 1000).slice(5);
// 转换价格
let newPrice = splitArr[1] / 100;
// 这里是后期 echarts 中 markPoint 所用到的数据格式
let rose = { name: key, value: sameElement[key], xAxis: newTime, yAxis: splitArr[1] / 100 };
if (sameElement[key] > 1) {
// 如果 相同数据大于 1 的说明重复,需要利用起来再存到最终使用的新数组中
endSameArr.push(rose);
}
// 其它数据存到需要使用到的数组中
newTimArr.push(newTime);
newPrArr.push(newPrice);
}
// console.log(endSameArr);
/*
[
0: {
name: "1723168142:49590"
value: 2
xAxis: "08-09 09:49:02"
yAxis: 495.9
},
1:{
name: "1721457412:55900"
value: 3
xAxis: "07-20 14:36:52"
yAxis: 559
}
]
*/
// console.log(newTimArr);
/*
[
0: "08-09 10:42:33"
1: "08-09 09:49:02"
2: "08-10 18:40:51"
3: "07-20 14:36:52"
4: "08-08 10:56:12"
5: "08-10 15:10:02"
]
*/
// console.log(newPrArr);
/*
[
0: 514.9
1: 495.9
2: 479
3: 559
4: 569
5: 489
]
*/
function drawChart(newPrArr, newTimArr, endSameArr) {
var myChart = echarts.init(document.getElementById('basicLine'));
// 指定图表的配置项和数据
// 该处就是图表内容,在官网的示例里面,要复制过来到项目里面的也是这一块内容
var option = {
title: {
text: 'ECharts 入门示例',
},
tooltip: {
trigger: 'axis', // 悬浮时显示数据
},
xAxis: {
name: '日期',
data: newTimArr, // 时间数据
type: 'category',
},
yAxis: {
name: '价格',
type: 'value',
},
series: [
{
name: '详情',
type: 'line',
data: newPrArr, // 价格数据
markPoint: {
data: endSameArr, // 传入相同需要的数据
},
label: {
show: true,
position: 'bottom',
fontSize: 16,
},
},
],
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
}
</script>
<style lang="less" scoped></style>
最终效果图
总结
本文简单介绍了如何使用 Echarts 展示两个数据集。事实上,Echarts 还提供了丰富的功能和方法,可以帮助我们更快速、便捷地处理和可视化数据。如果你有任何建议或疑问,欢迎在下方留言,我们一起探讨和学习!