current position:Home>A different Gantt graph based on native JS
A different Gantt graph based on native JS
2021-08-27 10:31:08 【romayn】
brief introduction
This paper is based on customer needs and reference to the old owner plusgantt Achieve different perspectives gantt chart , Extra introduction of moment.js Quick processing of dates
1. In order to achieve this effect, the customer must first confirm the data source , Project as a task , Work as a crossing . Meet the needs of multi plan management
{
"id": "2103211629501365",
"name": " Test project ",
"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": " Shen Songtao "
}]
},
{
"id": "2103211636069805",
"start_date": "2021/3/21",
"end_date": "2021/3/23",
"name": "TF-458-002-002",
}
]
},
Copy code
To achieve this effect gantt chart , First design gantt The basic configuration of . The following basic properties are summarized
this.config = {
width: "100%",
height: "100%",
columnDefaultWidth: "100px", // The default width of the table column
scaleDefautWidth: 28, //gantt Default column width
scaleDefaultHeight: 48, //gantt The default single row height is
ganttTopDateMode: "YYYY year MM month ", // Calendar format
type: "project", // Project dimension , project: project resources: personnel
initScrollTop: 0, // Record initialization scroll bar top
initScrollLeft: 0, // Record initialization scroll bar left
scrollTicking: false // Scroll timer
}
Copy code
Code entry and usage
<div id="ganttChart" class="row row-grid ganttview" style="margin: 5px;height: 100%;"></div>
var powerGantt = new powerGantt(document.getElementById("ganttChart"));
Copy code
var powerGantt = function (element, config) {
this.config = {
width: "100%",
height: "100%",
columnDefaultWidth: "100px", // The default width of the table column
scaleDefautWidth: 28, //gantt Default column width
scaleDefaultHeight: 48, //gantt The default single row height is
ganttTopDateMode: "YYYY year MM month ", // Calendar format
type: "project", // Project dimension , project: project user: personnel
initScrollTop: 0, // Record initialization scroll bar top
initScrollLeft: 0, // Record initialization scroll bar left
scrollTicking: false // Scroll timer
}
this.data = [];
this.columns = [];
this.el = element;
this.config = {
...this.config,
...config
};
this.init();
}
powerGantt.prototype.init = function () {
let self = this;
// initialization gantt Structure and configuration
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";
// establish grid Area
this.ganttGrid = document.createElement("div");
this.ganttGrid.innerHTML = "";
this.ganttGrid.className = "power-ganttgrid"
// establish gantt Area
this.ganttView = document.createElement("div");
this.ganttView.innerHTML = "";
this.ganttView.className = "power-ganttview "
this.el.appendChild(this.ganttGrid);
this.el.appendChild(this.ganttView);
// Began to draw
this.render();
}
Copy code
Preview the generated effect 、 Can't see anything , If you can't see it , Because it hasn't started yet
Began to draw gantt, Including preprocessed validation data 、 Calculation gantt The beginning and end of the view area 、 According to the task startDate、endDate On data level Handle
powerGantt.prototype.render = function () {
// data level Handle
this.startDate = moment().add(-7, 'day').format('L');
this.endDate = moment().add(7, 'day').format('L');
if (this.data.length) {
// find gantt Start and end date of
for (var i = 0; i < this.data.length; i++) {
let projectTask = this.data[i].tasks;
var project = this.data[i];
// The tasks of each project are level grouping
this.toLevelData(project);
// Update during the cycle startDate、endDate
this.startDate=....
this.endDate=....
}
}
// draw grid, Table drawing , No additional description
this.renderGrid();
// draw ganttview Area
this.renderGantt();
}
Copy code
draw ganttview( draw grid No additional introduction )
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) {
// Scroll up and down , Synchronize tables and gantt The rolling height of
}
self.renderGanttHeader();
self.renderGanttBody();
}
Copy code
//ganttview Time scale
powerGantt.prototype.renderGanttHeader = function () {
//month-day
this.scalcColumnLength = 0;
let scaleWidth = this.config.scaleDefautWidth;
let topMode = this.config.ganttTopDateMode;
let topTimeScale = `<div class="power-ganttview-toptimescale">`;
let bottomTimeScale = `<div class="power-ganttview-bottomtimescale">`;
let viewData = this.startDate;
let left = 0;
// Head area edit no event , String splicing is available
...
topTimeScale += `</div>`
bottomTimeScale += `</div>`
let gutter = `<div class='gutter' style='left:${left}px;width:17px'></div>`
this.ganttView.children[0].innerHTML = topTimeScale + bottomTimeScale + gutter;
}
Copy code
//ganttview Content area
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 Table drawing
powerGantt.prototype.renderGanttGrid = function () {
let ganttGrid = document.createElement("div");
ganttGrid.className = "power-ganttview-grid";
// Calculation line 、 Number of columns
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;
}
Copy code
//gantt Task drawing
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;
// Task drag , The business code is omitted below
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;
}
}
// Drag to modify the task end date
reszieRight.onmousedown = function (event) {
event.stopPropagation();
document.onmousemove = function (event) {
event.stopPropagation();
}
document.onmouseup = function (event) {
event.stopPropagation();
document.onmousemove = null;
document.onmouseup = null;
}
}
// Drag to modify the start date
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;
}
// Add latest timeline
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;
}
Copy code
Finish drawing . Methods use 、 Binding events and event usage methods
Usage mode
<div id="ganttChart" class="row row-grid ganttview" style="margin: 5px;height: 100%;"></div>
var powerGantt = new powerGantt(document.getElementById("ganttChart"));
powerGantt.setData([]);
powerGantt.on("onTaskDblClick", function (event, task) {
console.log("onTaskDblClick",task)
})
Copy code
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
}
Copy code
Preview effect and source code
copyright notice
author[romayn],Please bring the original link to reprint, thank you.
https://en.qdmana.com/2021/08/20210827103104062s.html
The sidebar is recommended
- Crazy blessing! Tencent boss's "million JVM learning notes", real topic of Huawei Java interview 2020-2021
- JS JavaScript how to get the subscript of a value in the array
- How to implement injection in vuex source code?
- JQuery operation select (value, setting, selected)
- One line of code teaches you how to advertise on Tanabata Valentine's Day - Animation 3D photo album (music + text) HTML + CSS + JavaScript
- An article disassembles the pyramid architecture behind the gamefi outbreak
- BEM - a front-end CSS naming methodology
- [vue3] encapsulate custom global plug-ins
- Error using swiper plug-in in Vue
- Another ruthless character fell by 40000, which was "more beautiful" than Passat and maiteng, and didn't lose BMW
guess what you like
-
Huang Lei basks in Zhang Yixing's album, and the relationship between teachers and apprentices is no less than that in the past. Netizens envy Huang Lei
-
He was cheated by Wang Xiaofei and Li Chengxuan successively. Is an Yixuan a blessed daughter and not a blessed home?
-
Zhou Shen sang the theme song of the film "summer friends and sunny days" in mainland China. Netizen: endless aftertaste
-
Pink is Wangyuan online! Back to the peak! The new hairstyle is creamy and sassy
-
Front end interview daily 3 + 1 - day 858
-
Spring Webflux tutorial: how to build reactive web applications
-
[golang] walk into go language lesson 24 TCP high-level operation
-
August 23, 2021 Daily: less than three years after its establishment, Google dissolved the health department
-
The female doctor of Southeast University is no less beautiful than the female star. She has been married four times, and her personal experience has been controversial
-
There are many potential safety hazards in Chinese restaurant. The top of the program recording shed collapses, and the artist will fall down if he is careless
Random recommended
- Anti Mafia storm: He Yun's helpless son, Sun Xing, is destined to be caught by his dry son
- Introduction to flex flexible layout in CSS -- learning notes
- CSS learning notes - Flex layout (Ruan Yifeng tutorial summary)
- Today, let's talk about the arrow function of ES6
- Some thoughts on small program development
- Talk about mobile terminal adaptation
- Unwilling to cooperate with Wang Yibo again, Zhao Liying's fans went on a collective strike and made a public apology in less than a day
- JS function scope, closure, let, const
- Zheng Shuang's 30th birthday is deserted. Chen Jia has been sending blessings for ten years. Is it really just forgetting to make friends?
- Unveil the mystery of ascension
- Asynchronous solution async await
- Analysis and expansion of Vue infinite scroll source code
- Compression webpack plugin first screen loading optimization
- Specific usage of vue3 video play plug-in
- "The story of huiyeji" -- people are always greedy, and fairies should be spotless!
- Installing Vue devtool for chrome and Firefox
- Basic usage of JS object
- 1. JavaScript variable promotion mechanism
- Two easy-to-use animation JS that make the page move
- Front end Engineering - scaffold
- Java SQL Server intelligent fixed asset management, back end + front end + mobile end
- Mediator pattern of JavaScript Design Pattern
- Array de duplication problem solution - Nan recognition problem
- New choice for app development: building mobile applications using Vue native
- New gs8 Chengdu auto show announces interior Toyota technology blessing
- Vieira officially terminated his contract and left the team. The national security club sent blessings to him
- Less than 200000 to buy a Ford RV? 2.0T gasoline / diesel power, horizontal bed / longitudinal bed layout can be selected
- How does "heart 4" come to an end? Pinhole was boycotted by the brand, Ma Dong deleted the bad comments, and no one blessed him
- We are fearless in epidemic prevention and control -- pay tribute to the front-line workers of epidemic prevention!
- Front end, netty framework tutorial
- Xiaomi 11 | miui12.5 | android11 solves the problem that the httpcanary certificate cannot be installed
- The wireless charging of SAIC Roewe rx5 plus is so easy to use!
- Upload and preview pictures with JavaScript, and summarize the most complete mybatis core configuration file
- [25] typescript
- CSS transform Complete Guide (Second Edition) flight.archives 007
- Ajax foundation - HTTP foundation of interview essential knowledge
- Cloud lesson | explain in detail how Huawei cloud exclusive load balancing charges
- Decorator pattern of JavaScript Design Pattern
- [JS] 10. Closure application (loop processing)
- Left hand IRR, right hand NPV, master the password of getting rich