效果演示:
主要属性:
chart: {
scrollablePlotArea: {
minHeight: 741, // 设置这个属性能在页面滚动时,头部固定
},
},
示例图中的功能除了设置头部固定外,自定义了复选框。因为highcharts中使用
formatter
自定义html
内容,不能渲染html
表单相关标签,屏蔽了表单元素,而又有复选框的需求,故自定义了复选框,并找到对应复选框元素绑定点击事件。
示例图完整的代码解析:
<template>
<div id="container" style="width: 100vw; height: 500px"></div>
</template>
<script>
import moment from "moment";
import Highcharts from "@/utils/highcharts-gantt.js"; // https://code.hcharts.cn/gantt/highcharts-gantt.js
export default {
data() {
return {
ganttData: [
{
name: "任务1",
x: new Date("2022-12-01 09:00:00").getTime(),
x2: new Date("2022-12-11 09:00:00").getTime(),
y: 0,
},
{
name: "任务2",
x: new Date("2022-12-08 09:00:00").getTime(),
x2: new Date("2022-12-10 19:20:40").getTime(),
y: 1,
},
{
name: "任务3",
x: new Date("2022-12-06 09:00:00").getTime(),
x2: new Date("2022-12-20 19:20:40").getTime(),
y: 2,
},
{
name: "任务4",
x: new Date("2022-12-18 09:00:00").getTime(),
x2: new Date("2022-12-22 19:20:40").getTime(),
y: 10,
},
{
name: "任务5",
x: new Date("2022-12-05 09:00:00").getTime(),
x2: new Date("2022-12-15 19:20:40").getTime(),
y: 12,
},
],
scatterData: [
{
name: "计划1",
x: new Date("2022-12-06 09:00:00").getTime(),
y: 0,
},
{
name: "计划2",
x: new Date("2022-12-05 09:00:00").getTime(),
y: 1,
},
{
name: "计划3",
x: new Date("2022-12-06 09:00:00").getTime(),
y: 2,
},
{
name: "计划4",
x: new Date("2022-12-12 09:00:00").getTime(),
y: 12,
},
{
name: "计划5",
x: new Date("2022-12-05 09:00:00").getTime(),
y: 10,
},
],
scatterData2: [
{
name: "12",
x: new Date("2022-12-01 09:00:00").getTime(),
y: 0,
},
{
name: "33",
x: new Date("2022-12-02 09:00:00").getTime(),
y: 1,
},
{
name: "1065",
x: new Date("2022-12-03 09:00:00").getTime(),
y: 2,
},
{
name: "123",
x: new Date("2022-12-14 09:00:00").getTime(),
y: 2,
},
{
name: "4",
x: new Date("2022-12-05 09:00:00").getTime(),
y: 11,
},
{
name: "4",
x: new Date("2022-12-06 09:00:00").getTime(),
y: 2,
},
{
name: "4",
x: new Date("2022-12-07 09:00:00").getTime(),
y: 12,
},
],
categories: [
{
id: 1,
value: "分类1",
},
{
id: 2,
value: "分类2",
},
{
id: 3,
value: "分类3",
},
{
id: 4,
value: "分类4",
},
{
id: 5,
value: "分类5",
},
{
id: 6,
value: "分类6",
},
{
id: 7,
value: "分类7",
},
{
id: 8,
value: "分类8",
},
{
id: 9,
value: "分类9",
},
{
id: 10,
value: "分类10",
},
{
id: 11,
value: "分类11",
},
{
id: 12,
value: "分类12",
},
{
id: 13,
value: "分类13",
},
],
};
},
mounted() {
this.categories = this.categories.map((i) => ({
...i,
checked: false,
}));
let month = "2022-12";
const WEEKS = {
0: "日",
1: "一",
2: "二",
3: "三",
4: "四",
5: "五",
6: "六",
};
Highcharts.setOptions({
global: {
useUTC: false, // 不使用utc时间
},
lang: {
noData: "暂无数据",
},
});
Highcharts.ganttChart("container", {
series: [
{
type: "gantt",
name: "设备",
data: this.ganttData,
dataLabels: {
enabled: true,
format: "{point.name}",
},
tooltip: {
pointFormatter: function () {
// console.log(this);
return `<div>
<span style="color:{point.color}">\u25CF</span> ${this.name}
<br />
开始时间:${moment(this.x).format("YYYY-MM-DD HH:mm:ss")}
<br />
结束时间:${moment(this.x2).format("YYYY-MM-DD HH:mm:ss")}
</div>`;
},
},
},
{
type: "scatter",
name: "计划",
data: this.scatterData,
stickyTracking: false, // 粘性跟踪默认是 true,可以去掉注释查看效果
marker: {
enabled: true,
symbol: "circle",
radius: 6,
},
tooltip: {
pointFormat:
'<span style="color:{point.color}">\u25CF</span> <b>{point.name}</b><br/>',
},
findNearestPointBy: "xy",
},
{
type: "scatter",
name: "任务",
data: this.scatterData2,
stickyTracking: false,
enableMouseTracking: false, // 隐藏他的tooltip
marker: {
enabled: false, // 不显示散点图的图案
states: {
hover: {
enabled: false,
},
},
},
tooltip: {
pointFormat:
'<span style="color:{point.color}">\u25CF</span> <b>{point.name}</b><br/>',
},
dataLabels: {
enabled: true,
align: "center",
verticalAlign: "middle",
crop: false,
overflow: "none",
style: {
fontWeight: 300,
fontSize: "14px",
color: "#333",
textOutline: "1px contrast",
},
formatter: function () {
return this.point.name;
},
},
},
],
xAxis: [
{
// maxPadding: 0,
// minPadding: 0,
// startOnTick: true,
// endOnTick: true,
min: moment(month).valueOf(),
max: moment(month).endOf("month").valueOf(),
gridLineEidth: 1,
minTickInterval: 1000 * 60 * 60 * 24,
currentDateIndicator: true,
tickPixelInterval: 70,
grid: {
borderWidth: 1, // 右侧表头边框宽度
cellHeight: 35, // 右侧日期表头高度
},
labels: {
align: "center",
formatter: function () {
return `周${WEEKS[moment(this.value).day()]}`;
},
},
},
{
// maxPadding: 0,
// minPadding: 0,
// startOnTick: true,
// endOnTick: true,
gridLineWidth: 1,
minTickInterval: 1000 * 60 * 60 * 24,
tickPixelInterval: 100,
grid: {
borderWidth: 1, // 右侧表头边框宽度
cellHeight: 30, // 右侧日期表头高度
},
labels: {
align: "center",
formatter: function () {
return `${moment(this.value).format("D")} `;
},
},
},
],
yAxis: {
// max: 500,
// scrollbar: {
// enabled: true,
// },
type: "category",
categories: this.categories,
reversed: true,
title: {
text: "任务分类",
},
labels: {
useHTML: true,
formatter: function () {
var label = `
<div style="display:flex;align-items:center">
<div class="checkbox" style="width:16px;height:16px;border:1px solid #444;margin-right:5px;cursor:pointer" id='${this.value.id}'>
<span
class="has-check"
style="opacity: 0;font-size:12px;padding-left:3px;">✔</span>
</div>
${this.value.value}
</div>`;
return label;
},
},
},
chart: {
scrollablePlotArea: {
minHeight: 741, // 52 * this.categories.length + 65(52是每个y轴label的高度,65是2个xAxis的高度),设置这个属性能在页面滚动时,头部固定
},
},
});
const labelElements = document.querySelectorAll(
"#container .highcharts-yaxis-labels .checkbox"
);
// 自定义复选框,给复选框添加点击事件
labelElements.forEach((label) => {
label.addEventListener(
"click",
(el) => {
let element = el.target; // element是.checkbox元素
const addClickElement = this.getParentElement(element, "checkbox");
let id = "";
if (element.classList.toString().indexOf("checkbox") !== -1) {
id = element.getAttribute("id");
}
if (addClickElement) {
id = addClickElement.getAttribute("id");
element = addClickElement;
}
this.categories[id - 1].checked = !this.categories[id - 1].checked;
element.style.background = this.categories[id - 1].checked
? "#0061ff"
: "none";
element.style.borderColor = this.categories[id - 1].checked
? "#0061ff"
: "#444";
element.querySelector(".has-check").style.opacity = 1;
element.querySelector(".has-check").style.color = "#fff";
},
true
);
});
},
methods: {
// 根据当前target元素找到指定className的父元素
getParentElement(target, className) {
let parent = target.parentElement;
while (parent) {
if (parent.classList.toString().indexOf(className) !== -1) {
return parent;
}
parent = parent.parentElement;
}
return null;
},
},
};
</script>
<style scoped></style>