坐标轴固定0-24h
以时间甘特图的形式显示某天24小时状态切片图,空白时间轴使用其他背景颜色填充
效果如下:
完整代码如下
var data = [
{
"ROW": "4",
"GROUPID": "0",
"NAME": "Traffic_14",
"STATUSDESC": "运行",
"RUNTIME": "2023-11-27 01:00:00.000",
"END_TIME": "2023-11-27 11:15:00.000",
"DIFF_MILLISEC": "0"
}, {
"ROW": "5",
"GROUPID": "0",
"NAME": "Traffic_14",
"STATUSDESC": "故障",
"RUNTIME": "2023-11-27 12:15:00.000",
"END_TIME": "2023-11-27 15:35:00.000",
"DIFF_MILLISEC": "0"
}, {
"ROW": "6",
"GROUPID": "0",
"NAME": "Traffic_14",
"STATUSDESC": "运行",
"RUNTIME": "2023-11-27 15:35:00.000",
"END_TIME": "2023-11-27 22:35:00.000",
"DIFF_MILLISEC": "0"
},{
"ROW": "4",
"GROUPID": "1",
"NAME": "Traffic_15",
"STATUSDESC": "运行",
"RUNTIME": "2023-11-27 03:00:00.000",
"END_TIME": "2023-11-27 10:15:00.000",
"DIFF_MILLISEC": "0"
}, {
"ROW": "5",
"GROUPID": "1",
"NAME": "Traffic_15",
"STATUSDESC": "故障",
"RUNTIME": "2023-11-27 10:15:00.000",
"END_TIME": "2023-11-27 13:35:00.000",
"DIFF_MILLISEC": "0"
}, {
"ROW": "6",
"GROUPID": "1",
"NAME": "Traffic_15",
"STATUSDESC": "运行",
"RUNTIME": "2023-11-27 14:35:00.000",
"END_TIME": "2023-11-27 21:35:00.000",
"DIFF_MILLISEC": "0"
}];
var types = [
{ name: '运行', color: '#1bb57d' },
{ name: '故障', color: '#ff3374' },
{ name: '空闲', color: '#edb217' }
];
var startTime;
var startDate;
startTime = new Date(data[0].RUNTIME).getTime();
startDate = new Date(data[0].RUNTIME);
var datatemp = data.map(d => ({
name: d.STATUSDESC,
value: [
parseInt(d.GROUPID),
new Date(d.RUNTIME).getTime(),
new Date(d.END_TIME).getTime()
],
itemStyle: {
normal: {
color: types.filter(a => a.name == d.STATUSDESC)[0].color
}
}
}));
var groupedData = datatemp.reduce((acc, curr) => {
if (!acc[curr.value[0]]) {
acc[curr.value[0]] = [];
}
acc[curr.value[0]].push(curr);
return acc;
}, {});
var gaps = [];
var startTime_ = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate()).getTime();
var endTime_ = startTime_ + 24 * 60 * 60 * 1000; // 24小时后的时间
Object.keys(groupedData).forEach(groupID => {
var groupData = groupedData[groupID];
// 按开始时间排序
groupData.sort((a, b) => a.value[1] - b.value[1]);
var lastEndTime = startTime_;
for (var i = 0; i < groupData.length; i++) {
var currentStartTime = groupData[i].value[1];
var currentEndTime = groupData[i].value[2];
if (currentStartTime > lastEndTime) {
gaps.push([
parseInt(groupID),
lastEndTime,
currentStartTime
]);
}
lastEndTime = Math.max(lastEndTime, currentEndTime);
}
// 检查最后一个时间段结束时间与24小时结束时间之间的空隙
if (lastEndTime < endTime_) {
gaps.push([
parseInt(groupID),
lastEndTime,
endTime_
]);
}
});
console.log(gaps)
for (var i = 0; i < gaps.length; i++) {
var date = new Date(gaps[i][1])
var year = date.getFullYear();
var month = (date.getMonth() + 1).toString().padStart(2, '0'); // Months are zero-indexed
var day = date.getDate().toString().padStart(2, '0');
var hours = date.getHours().toString().padStart(2, '0');
var minutes = date.getMinutes().toString().padStart(2, '0');
var seconds = date.getSeconds().toString().padStart(2, '0');
var sdformattedDate = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
date = new Date(gaps[i][2])
year = date.getFullYear();
month = (date.getMonth() + 1).toString().padStart(2, '0'); // Months are zero-indexed
day = date.getDate().toString().padStart(2, '0');
hours = date.getHours().toString().padStart(2, '0');
minutes = date.getMinutes().toString().padStart(2, '0');
seconds = date.getSeconds().toString().padStart(2, '0');
var edformattedDate = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
console.log("groupID: " + gaps[i][0] + " st: " + sdformattedDate + " et: " + edformattedDate)
}
var categories = Array.from(new Set(data.map(item => item.NAME)));
function renderItem(params, api) {
var categoryIndex = api.value(0);
var start = api.coord([api.value(1), categoryIndex]);
var end = api.coord([api.value(2), categoryIndex]);
var height = api.size([0, 1])[1] * 0.6;
var rectShape = echarts.graphic.clipRectByRect(
{
x: start[0],
y: start[1] - height / 2,
width: end[0] - start[0],
height: height
},
{
x: params.coordSys.x,
y: params.coordSys.y,
width: params.coordSys.width,
height: params.coordSys.height
}
);
var shapes;
shapes = rectShape && {
type: 'rect',
transition: ['shape'],
shape: rectShape,
style: api.style()
};
return shapes;
}
var now = new Date(); // 获取当前时间
var todayStart = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate()); // 获取今天的起始时间
var todayEnd = new Date(todayStart.getTime() + 24 * 60 * 60 * 1000+1); // 获取今天的结束时间
var todayEnd_ = new Date(todayStart.getTime() + 24 * 60 * 60 * 1000); // 获取今天的结束时间
const series = [
{
type: 'custom',
renderItem: renderItem,
encode: {
x: [1, 2],
y: 0
},
data: datatemp
},
{
type: 'custom',
renderItem: renderItem,
z: -1, // 放在最底层
data: gaps,
}
];
// 手动添加最后一个数据点,放在当天的最后一秒
option = {
grid: {
left: '6%',
right: '4%',
bottom: '3%',
containLabel: true,
},
tooltip: {
show: true,
textStyle: {
fontSize: 10
},
position: function (point, params, dom, rect, size) {
var mouseX = point[0];
var mouseY = point[1];
// 获取容器的宽度和 tooltip 的宽度
var containerWidth = size.viewSize[0];
var tooltipWidth = size.contentSize[0];
// 调整 tooltip 的位置
var offsetX = 10; // x 方向偏移量
var offsetY = 10; // y 方向偏移量
// 如果 tooltip 超出容器的右侧,将其显示在鼠标的左侧
if (mouseX + tooltipWidth + offsetX > containerWidth) {
// 新的位置坐标
var newX = mouseX - tooltipWidth - offsetX;
var newY = mouseY + offsetY;
// 返回新的位置坐标
return [newX, newY];
} else {
// tooltip 显示在鼠标的下方
var newX = mouseX + offsetX;
var newY = mouseY + offsetY;
// 返回新的位置坐标
return [newX, newY];
}
},
formatter: function (params) {
let duration = params.value[2] - params.value[1];
// 将毫秒数转换为小时和分钟
let hours = Math.floor(duration / (1000 * 60 * 60));
let s_d = new Date(params.value[1])
let s_hours = s_d.getHours()
let s_hours_ = s_hours < 10 ? '0' + s_hours : s_hours;
let s_mins = s_d.getMinutes()
let s_mins_ = s_mins < 10 ? '0' + s_mins : s_mins;
let e_d = new Date(params.value[2])
let e_hours = e_d.getHours()
let e_hours_ = e_hours < 10 ? '0' + e_hours : e_hours;
//console.log("s_d: " + s_d + " e_d : " + e_d)
//console.log("params.value[1]" + params.value[1] + " params.value[2] : " + params.value[2])
let e_mins = e_d.getMinutes()
let e_mins_ = e_mins < 10 ? '0' + e_mins : e_mins;
let minutes = Math.floor((duration % (1000 * 60 * 60)) / (1000 * 60));
let minutes_ = minutes < 10 ? '0' + minutes : minutes
if (params.seriesIndex === 1) {
return params.marker + params.name + '空白时长:'+ hours + '小时' + minutes + '分钟' + '<br/>'
+ params.marker + '时间区间:' + s_hours_ + ':' + s_mins_ + ' - ' + e_hours_ + ':' + e_mins_;
}
return params.marker + params.name + '时长:'+ hours + '小时' + minutes + '分钟' + '<br/>'
+ params.marker + '时间区间:' + s_hours_ + ':' + s_mins_ + ' - ' + e_hours_ + ':' + e_mins_;
}
},
dataZoom: [
{
type: 'inside',
filterMode: 'none',
showDataShadow: false,
show: true,
}
],
xAxis: {
type: 'time',
min: todayStart, // 设置最小值为今天的起始时间
max: todayEnd,
//min: new Date(startTime).setHours(0, 0, 0, 0),
//max: new Date(startTime + 24 * 60 * 60 * 1000+1),
axisLabel: {
formatter: function (value) {
var date = new Date(value);
var hours = date.getHours();
var minutes = date.getMinutes();
//console.log(date)
if(date.getTime() == todayEnd_.getTime())
{
return '24h'
}
return `${hours}h`;
}, // 标签与轴线紧挨在一起
padding: [0, 0, 0, 0], // 标签的内边距(可根据实际情况调整)
},
splitNumber: 6,
splitLine: {
show: false
},
axisLine: {
show: true // 隐藏坐标轴线
},
axisTick: {
show: true // 隐藏刻度线
},
},
yAxis: [
{
yAxisIndex: 0,
type: 'category',
data: categories,
axisLine: {
show: true
},
axisTick: {
show: true
},
axisLabel: {
show: true,
}
},
],
series: series
};