本文中Echarts的版本为5.5.0
首先说一下我们的项目背景,就是需要一个横坐标为时间轴的折线型数据。折线分为数值类型和枚举类型,也就是说Y坐标为数值型或者枚举型的数据;然后数据的缩放是这样的,把请求到的数据,一次性的全部显示在折线中,并且需要支持鼠标滚轮和鼠标拖拽式,缩放查看局部的数据。效果如图所示:
项目中的难点主要是三部分。1、查询的到的数据,比如查询的是今天的数据,但是今天的话,只有在10点和11点有数据,其他的时间没有数据;2、横坐标下面的显示的当前缩放完成之后的时间范围;3、需要线断开连接,具体的规则是,当数据中有flage:start的时候,就认为这是一个新的曲线了,需要和前面的数据断开显示;
1、正确显示数据
配置dataZoom
针对于第一个问题,采用的是dataZoom中配置,startValue和endValue,而不是配置start和end;
dataZoom: [ { type: "inside", // start: 50, // 不能使用百分比,因为搜索的时间和数据的时间不一定能对应上 // end: 100, startValue: zoomStartValue, endValue: zoomEndValue, filterMode: "filter", }, ],
其中zoomStartValue和zoomEndValue就是第一条数据和最后一条数据的时间;例如刚刚说的上面的例子。搜索今天的全部数据,但是只有10点和11点之间是有数据。那么zoomStartvalue="2024-04-10 10:00:00",则zoomEndValue可能就是"2024-04-10 11:30:00"。这里不需要使用时间戳,直接使用字符串类型的时间就可以;但是因为搜索的是今天,所以在用户拖动的时候,应该是能拖动到今天的0点的。结束时间应该是查询的时候的时间。所以这个时候的x轴需要单独的配置;
配置xAxis
在xAxis中,需要配置min和max两个参数,用于让x轴能滑动到今天的0点的时刻,虽然那个时间点并没有数据;
xAxis: { type: "time", // 这里需要明确为“time” min: searchBeginTime, max: searchEndTime, axisLine: { show: true, lineStyle: { color: "#C0C0C0", } }, axisTick: { show: true }, axisLabel: { color: "#676767" }, data: xdata, // 这里比较关键,需要传个数据,要不然直接靠server得到的数据,缩放有问题 },
其中的min和max对应的数据,就是搜索传给后台的数据。比如我搜索的今天的数据,那么searchBeginTime应该是"2024-04-10 00:00:00",searchEndTime应该是当前的搜索的结束时间:"2024-4-10 11:49:02";
其中还有一个问题是我在实际开发中发现的。就是xAxis中的data数据也是需要传递的。要不然直接靠server中的横坐标的数据,下面缩放以后获取到的时间就有问题了。xdata的数据,就是后台给的数据中,所有数据的时间的数组:['2024-04-10 10:00:00','2024-04-10 10:15:00',2024-04-10 10:30:00,'2024-04-10 10:45:00',……'2024-04-10 11:30:00']
2、缩放显示当前的时间区间
监听dataZoom事件
使用on("dataZoom")的方法,来监听Echats进行了缩放,而且这里面会有对应的,当前缩放的横坐标开始的百分比,和结束的百分比;
具体的方法如下:
myChart.off("dataZoom"); myChart.on("dataZoom", (params) => { var optionData = myChart.getOption(); var min = optionData.xAxis[0].min; var max = optionData.xAxis[0].max; var minT = new Date(min).getTime(); var maxT = new Date(max).getTime(); var len = maxT - minT;// 计算出时间的差额。使用的是时间戳计算~ var start = params.batch[0].start; // 横坐标左侧的百分比 var end = params.batch[0].end; // 横坐标右侧的百分比 var startIndex = Math.round((len * start) / 100); var endIndex = Math.round((len * end) / 100); var xTextContent = `${moment(minT + startIndex).format("YYYY-MM-DD HH:mm:ss")} -- ${moment(minT + endIndex).format("YYYY-MM-DD HH:mm:ss")}`; // 使用moment插件,格式化成具体的时间 xText.value = xTextContent; });
其中,start和end就是Echats缩放之后,获取的开始百分比和结束百分比;start的最小值为0,end的最大值为100。然后根据横坐标的min和max获取到整体的时间戳。然后计算出来差额,再根据百分比就能获取到当前的横坐标显示的时间了。
3、断开曲线
项目中需要把数据中,含有flags:true的,就认为是一个新的曲线。当时我们想到的断开方法是给一个数据,只传时间,然后对应的值传空,这样就能断开了。但是由于我们的数据横坐标对应都是有值的。上面的方法就不可用了。所以我们采用的了第二种方法,就是在Echats中绘制了两条曲线,这两条曲线互不干扰。
首先说一下,我们的数据:
var chartRowData = [{ timestamp: "2024-4-10 11:20:00", value: 12, status: "null", flags: true, },{ timestamp: "2024-4-10 11:21:00", value: 19, status: "ok", },{ timestamp: "2024-4-10 11:22:00", value: 20, status: "alarm", },{ timestamp: "2024-4-10 11:23:00", value: 22, status: "ok", },{ timestamp: "2024-4-10 11:24:00", value: 8, status: "ok", flags: true, },{ timestamp: "2024-4-10 11:25:00", value: 15, status: "ok", },{ timestamp: "2024-4-10 11:26:00", value: 12, status: "ok", },{ timestamp: "2024-4-10 11:27:00", value: 14, status: "ok", }]
所以我采用下面的方法整理数据
var xdata = [], seriesData = [], seriesArr=[]; // 横坐标;一段横线的小数组;全部数据的数组 var chartRowDataLength = chartRowData.length; chartRowData.forEach((item, i) => { xdata.push(item.timestamp); // 如果是flags的值为start的话,就重新添加一条线 if(item.hasOwnProperty("flags") && item.flags == "start" && seriesData.length) { seriesArr.push({ name: historyName, data: seriesData.slice(0), type: "line", smooth: true, showSymbol: false, emphasis: { // 关闭鼠标高亮 disabled: true } }) seriesData.splice(0); } seriesData.push([item.timestamp, item.value, item.status]); if (i == 0) { zoomStartValue = item.timestamp; } if (i == chartRowDataLength - 1) { zoomEndValue = item.timestamp; // 数据最后一条,也要添加到大数组中。 seriesArr.push({ name: historyName, data: seriesData.slice(0), type: "line", smooth: true, showSymbol: false, emphasis: { // 关闭鼠标高亮 disabled: true } }) } })
4、其他的小问题
设置语言
做完了发现时间显示的有问题。就是不是按照咱们写的年月日时分秒显示的。所以需要在初始化Echats的时候,指定一下语言;
var chartDom = document.getElementById("chartDom"); myChart = echarts.init(chartDom, null, { locale: "ZH" });
一天中仅有一条数据
测试提出,如果查询今天只有一条数据的话,就会发现,缩放有问题;经过查询代码发现,是因为zoomStartValue和zoomEndValue相等,导致了出现了横坐标显示的不是今天的数据。所以有了以下的一个判断:
// 如果之有一个数据的话,zoomStartValue和zoomEndValue的值是一样的。这样Echarts的zoom就有问题了~ // 所以需要单独处理一下 if(chartRowData.length == 1) { zoomStartValue = searchBeginTime; zoomEndValue = searchEndTime; }
如有需要,可以查看资源。里面的代码可以直接运行,因为没有请求,所以里面很多内容都是直接写死的。