基于原生js手撸一个不一样的gantt图

您所在的位置:网站首页 甘特图js插件 基于原生js手撸一个不一样的gantt图

基于原生js手撸一个不一样的gantt图

2023-08-22 04:06| 来源: 网络整理| 查看: 265

简介

本文基于客户需求及参考老东家plusgantt实现不同角度的gantt图,额外引入了moment.js对日期快速处理

view.png

1.为了达到客户这种效果首先要确认数据源,项目作为一条任务,作业作为横道。达到多计划管理的需求 { "id": "2103211629501365", "name": "测试项目", "projCode": "458", "taskNum": "2", "latest_date": "2021/3/21", "tasks": [ { "id": "2103211630124214", "start_date": "2021/3/21", "end_date": "2021/3/23", "name": "TF-L233-002-001", "state": "add", "resources": [{ "id": "a2fa0534-ba64-4b16-8fb8-0638868a09d1", "name": "沈松涛" }] }, { "id": "2103211636069805", "start_date": "2021/3/21", "end_date": "2021/3/23", "name": "TF-458-002-002", } ] }, 2.为了实现此效果gantt图,要先设计gantt的基础配置。总结了以下几个基础属性 this.config = { width: "100%", height: "100%", columnDefaultWidth: "100px", //表格列默认宽度 scaleDefautWidth: 28, //gantt列默认宽度 scaleDefaultHeight: 48, //gantt 默认单行行高 ganttTopDateMode: "YYYY年MM月", //日历格式 type: "project", //项目维度, project:项目 resources:人员 initScrollTop: 0, //记录初始化滚动条top initScrollLeft: 0, //记录初始化滚动条left scrollTicking: false //滚动定时器 }

代码入口及使用方法

var powerGantt = new powerGantt(document.getElementById("ganttChart")); powerGantt.setColumn([]); powerGantt.setData([]) var powerGantt = function (element, config) { this.config = { width: "100%", height: "100%", columnDefaultWidth: "100px", //表格列默认宽度 scaleDefautWidth: 28, //gantt列默认宽度 scaleDefaultHeight: 48, //gantt 默认单行行高 ganttTopDateMode: "YYYY年MM月", //日历格式 type: "project", //项目维度, project:项目 user:人员 initScrollTop: 0, //记录初始化滚动条top initScrollLeft: 0, //记录初始化滚动条left scrollTicking: false //滚动定时器 } this.data = []; this.columns = []; this.el = element; this.config = { ...this.config, ...config }; this.init(); } powerGantt.prototype.init = function () { let self = this; //初始化gantt结构和配置 this.el.classList.add("power-gantt"); // this.el.style.width = this.config.width; // this.el.style.height = this.config.height; this.el.style.position = "relative"; //创建grid区域 this.ganttGrid = document.createElement("div"); this.ganttGrid.innerHTML = ""; this.ganttGrid.className = "power-ganttgrid" //创建gantt区域 this.ganttView = document.createElement("div"); this.ganttView.innerHTML = ""; this.ganttView.className = "power-ganttview " this.el.appendChild(this.ganttGrid); this.el.appendChild(this.ganttView); //开始绘制 this.render(); }

预览生成效果、是不是啥也看不到,看不到就对了,因为还没开始

init.png

3.开始绘制gantt,含预处理验证数据、计算gantt视图区域的开始结束、根据任务的startDate、endDate对数据进行level处理 powerGantt.prototype.render = function () { //数据level处理 this.startDate = moment().add(-7, 'day').format('L'); this.endDate = moment().add(7, 'day').format('L'); if (this.data.length) { //找出gantt的开始结束日期 for (var i = 0; i < this.data.length; i++) { let projectTask = this.data[i].tasks; var project = this.data[i]; //对每个项目的任务进行level分组 this.toLevelData(project); //循环过程中更新startDate、endDate this.startDate=.... this.endDate=.... } } //绘制grid,表格绘制,不在额外描述 this.renderGrid(); //绘制ganttview区域 this.renderGantt(); } 4.绘制ganttview(绘制grid不在额外介绍) powerGantt.prototype.renderGantt = function () { let self = this; self.ganttView.innerHTML = ''; self.ganttViewHeader = document.createElement("div"); self.ganttViewHeader.className = "power-ganttview-header" self.ganttViewBody = document.createElement("div"); self.ganttViewBody.className = "power-ganttview-body"; self.ganttView.appendChild(self.ganttViewHeader); self.ganttView.appendChild(self.ganttViewBody); self.ganttViewBody.onscroll = function (event) { //上下滚动,同步表格和gantt的滚动高度 } self.renderGanttHeader(); self.renderGanttBody(); } //ganttview时间刻度 powerGantt.prototype.renderGanttHeader = function () { //month-day this.scalcColumnLength = 0; let scaleWidth = this.config.scaleDefautWidth; let topMode = this.config.ganttTopDateMode; let topTimeScale = ``; let bottomTimeScale = ``; let viewData = this.startDate; let left = 0; //头部区域编辑无事件,可用字符串拼接 ... topTimeScale += `` bottomTimeScale += `` let gutter = `` this.ganttView.children[0].innerHTML = topTimeScale + bottomTimeScale + gutter; }

setHeader.png

//ganttview内容区域 powerGantt.prototype.renderGanttBody = function () { let ganttGrid = this.renderGanttGrid(); this.ganttView.children[1].appendChild(ganttGrid) let ganttTask = this.renderGanttTask(); this.ganttView.children[1].appendChild(ganttTask) } //gantt表格绘制 powerGantt.prototype.renderGanttGrid = function () { let ganttGrid = document.createElement("div"); ganttGrid.className = "power-ganttview-grid"; //计算行、列数量 let scaleWidth = this.config.scaleDefautWidth; let scaleHeight = this.config.scaleDefaultHeight; let rowLength = this.data.length; let columnLength = this.scalcColumnLength; let rowHeight = 0; for (let i = 0; i < rowLength; i++) { let level = this.data[i].level; let gridRow = document.createElement("div"); gridRow.className = "power-ganttview-row"; gridRow.style.top = rowHeight + "px"; gridRow.style.width = columnLength * scaleWidth + "px"; gridRow.style.height = scaleHeight * level + "px"; rowHeight += scaleHeight * level; ganttGrid.appendChild(gridRow) } for (let l = 0; l < columnLength; l++) { let weekdd = moment(this.startDate).add(l, 'day').days();; let gridColumn = document.createElement("div"); gridColumn.className = "power-ganttview-column" if (weekdd == "6" || weekdd == "0") { gridColumn.classList.add("weeked"); } gridColumn.style.left = l * scaleWidth + "px"; gridColumn.style.width = scaleWidth + "px"; gridColumn.style.height = rowHeight + "px"; ganttGrid.appendChild(gridColumn) } return ganttGrid; }

setbody.png

//gantt任务绘制 powerGantt.prototype.renderGanttTask = function () { let self = this; let scaleHeight = this.config.scaleDefaultHeight; let scaleWidth = this.config.scaleDefautWidth; let taskDomContainer = document.createElement("div"); taskDomContainer.className = "power-ganttview-taskview" let taskTop = 0; let levelTop = 0; for (var i = 0; i < this.data.length; i++) { var row = this.data[i]; let rowLevelList = row.levelList; let projectRow = document.createElement("div"); projectRow.className = "power-ganttview-project-row" for (let key in rowLevelList) { for (let j = 0; j < rowLevelList[key].length; j++) { let task = rowLevelList[key][j] let days = moment(task.end_date).diff(moment(task.start_date), 'days') + 1; let width = scaleWidth * days; let left = moment(task.start_date).diff(moment(this.startDate), 'days') * scaleWidth; let taskDom = document.createElement("div"); taskDom.className = "power-ganttview-task"; taskDom.setAttribute("title", task.name); taskDom.style.left = left + "px"; taskDom.style.top = levelTop + "px"; taskDom.style.width = width + "px"; taskDom.style.position = "absolute"; taskDom.ondblclick = this.onTaskDblClick.bind(this, taskDom, task); projectRow.appendChild(taskDom); let userContent = document.createElement("div"); userContent.className = "ganttview-block-user"; userContent.id = task.id; userContent.setAttribute("project-id", row.id); taskDom.appendChild(userContent); let reszieLeft = document.createElement("div"); reszieLeft.className = "ui-resizable-handle ui-resizable-w"; reszieLeft.style.zIndex = 90; let reszieRight = document.createElement("div"); reszieRight.className = "ui-resizable-handle ui-resizable-e"; reszieRight.style.zIndex = 90; taskDom.appendChild(reszieLeft); taskDom.appendChild(reszieRight); let taksName = document.createElement("div"); taksName.className = "ganttview-block-text"; taksName.innerText = task.name; taskDom.appendChild(taksName); let startX = 0; //任务拖动,以下省略业务代码 taskDom.onmousedown = function (event) { event.stopPropagation(); document.onmousemove = function (event) { event.stopPropagation(); console.log("onmousemove") } document.onmouseup = function (event) { console.log("onmouseup") event.stopPropagation(); document.onmousemove = null; document.onmouseup = null; } } //拖动修改任务结束日期 reszieRight.onmousedown = function (event) { event.stopPropagation(); document.onmousemove = function (event) { event.stopPropagation(); } document.onmouseup = function (event) { event.stopPropagation(); document.onmousemove = null; document.onmouseup = null; } } //拖动修改开始日期 reszieLeft.onmousedown = function (event) { event.stopPropagation(); document.onmousemove = function (event) { event.stopPropagation(); } document.onmouseup = function (event) { event.stopPropagation(); document.onmousemove = null; document.onmouseup = null; } } } levelTop += scaleHeight; } //添加最晚时间线 if (row.latest_date) { let left = (moment(row.latest_date).diff(moment(this.startDate), 'days') + 1) * scaleWidth; let lastLine = document.createElement("div"); lastLine.className = "power-ganttview-laseLine"; lastLine.style.background = "red"; lastLine.style.left = left + "px"; lastLine.style.top = taskTop + "px"; lastLine.style.width = "2px"; lastLine.style.marginLeft = "-1.5px"; lastLine.style.position = "absolute"; lastLine.style.height = (row.level * scaleHeight) + "px"; projectRow.appendChild(lastLine); } taskTop += row.level * scaleHeight; levelTop = taskTop; taskDomContainer.appendChild(projectRow) } return taskDomContainer; }

task.png

5.绘制完成。方法使用、绑定事件及事件使用方法

使用方式

var powerGantt = new powerGantt(document.getElementById("ganttChart")); powerGantt.setData([]); powerGantt.on("onTaskDblClick", function (event, task) { console.log("onTaskDblClick",task) }) powerGantt.prototype.setColumn = function (columns) { this.columns = columns; this.renderGrid(); } powerGantt.prototype.on = function (event, callback) { let eventName = "on" + event.replace(event[0], event[0].toUpperCase()); this[eventName] = callback.bind(this); } powerGantt.prototype.onTaskDblClick = function (event, task) { console.log(task) return false } 6.预览效果及源代码

源码地址

cywyg-hqtna.gif



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3