最近有一个需求,要画一个24小时的时间轴。类似于一个简化的甘特图,可以参考苹果手机的睡眠,不过只有一种颜色。
如果直接用网络上的甘特图,有点太复杂了,所以准备使用echarts自己写一个类似的。
一、引入echarts
可以参考官方的 文档1 文档2 引入,我创建的vue项目,直接npm install echarts --save
安装,按照上面的教程进行初始化。
二、开始绘制
x轴初始化:
echarts中,x轴的具体数据可以在xAxis.data中配置。在这个时间轴中则是从0-24的一个数组。
一个一个写比较麻烦,可以直接写一个方法。这样生成的就带有分钟。
js 代码解读复制代码 getXData() {
let list = [];
for (let i = 0; i <= 24; i++) {
let str = `${i}:00`;
list.push(str);
}
return list;
},
如果希望x轴每个数据强制展示, 可以用xAxis.axisLabel. interval为0配置。 但是这样的话可能比较拥挤一些,还要画滚动条,设置文字的偏移度之类的。 我最后选择了直接写数字。
js 代码解读复制代码xAxis: {
min: 0,
max: 24,
interval:1
}
具体柱形图决定使用renderItem
绘制。我做过很多大屏可视化的图表,常见的都是什么bar,pie,line之类的,最多来个map,scatter之类的,renderItem
倒是没有用过,今天学习一下,也是拓宽视野了。
可以参考 一下 文档
感觉还是比较好理解的,只要设置series的type是custom,然后child里放一些type是react的数据应该就可以了,shape中传入x和y,宽度、高度,就可以绘制矩形的形状了。这里的值都是px。
按照教程,我随便画了几个矩形,如下图参考。这里别的难度都不大,主要难度在于计算计算矩形的x和width,别的值都是可以固定的。这里的
计算矩形,这里我们可以借鉴echarts官方教程的甘特图,里面renderGanttItem
方法。就是看着挺复杂的。
当echarts图表的宽度被我们写死时,计算x和width应该还是比较容易的,但是如果要做图表自适应,就比较麻烦了。 我们将renderItem的两个参数输出,可以发现有一个getWidth方法。这个方法可以获得echarts图表的宽度。
js 代码解读复制代码renderItem(params,api) {
console.log( 'params',params)
console.log( 'api',api)
}
或者params里的coordSys也可以获得我们要的数据,我自己本身设置的图表的宽度和高度其实分别是600px和200px,我在grid里设置了边距,coordSys的结果应该是去除空白边距的大小。我们用这个计算应该效果会更好。
这里我们自己算也可以了,我们有时间段的起始时间和结束时间,可以计算每段时间占一天的百分比,然后乘以coordSys.width,就得到了宽度。x的值可以通过比例获得,x-coordSys.x:coordSys.width = 转化为小数的时间:24。
这我就不具体写了。因为我看echarts有自己的方法,我们自己不用算。
我们把时间转化为小数,调用下面这个方法,应该就可以直接算出来的,比如6:30转化完成后是6.5。理论上宽度用series-custom.renderItem.arguments.api.size
,但是我算出来的结果不对,所以就不用这个了。调用两次coord相减。
例如下图是6:30-11:00的柱形图。这里我时间是写死的,其实可以通过api.value(0)和api.value(1)分别获得时间的开始值和结束值。
js 代码解读复制代码 renderItem(params, api) {
let x1 = api.coord([6.5, 1])[0];
let x2 = api.coord([11, 1])[0];
return {
type: "group",
children: [
{
type: "rect",
shape: { x: x1, y: 100, width: x2-x1, height: 20 },
},
],
};
},
最后整理
地图上画一个按钮,模拟接口调用重新渲染图表。按钮绑定formateData事件。用一些模拟数据测试。后端给的数据应该是x:xx这样的格式,或者x时x分,需要对数据进行格式化,重新设置echarts的option,并渲染。
methos中写入以下代码:
js 代码解读复制代码 formateData() {
let testData = ["6:30-6:45", "11:30-11:35", "11:36-11:37", "16:45-19:50"];
const data = [];
testData.forEach((e) => {
const time = e.split("-");
const time1 =
Number(time[0].split(":")[0]) + Number(time[0].split(":")[1]) / 60;
const time2 =
Number(time[1].split(":")[0]) + Number(time[1].split(":")[1]) / 60;
data.push([time1, time2]);
});
this.option.series[0].data = data;
this.myChart.setOption(this.option);
},
data中option代码如下:
js 代码解读复制代码 option: {
xAxis: {
min: 0,
max: 24,
interval: 1,
},
yAxis: {
show: false,
splitLine: false,
},
series: [
{
type: "custom",
data: [],
renderItem(params, api) {
const data1 = api.value(0);
const data2 = api.value(1);
let x1 = api.coord([data1, 1])[0];
let x2 = api.coord([data2, 1])[0];
var categoryIndex = api.value(0);
return {
type: "group",
children: [
{
type: "rect",
shape: { x: x1, y: 100, width: x2 - x1, height: 20 },
},
],
};
},
},
],
},
最终效果如下图:
这里我们画了一个横向的时间轴,我想如果画纵向的其实也是差不多的。今天也只画了一条,很多时候甘特图是有很多行的,这时候series这个数组里面再push进入一些数据,应该就没问题了。
评论记录:
回复评论: