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

view.png

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

init.png

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 

setHeader.png

//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 

setbody.png

//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 

task.png

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

cywyg-hqtna.gif

copyright notice
author[romayn],Please bring the original link to reprint, thank you.
https://en.qdmana.com/2021/08/20210827103104062s.html

Random recommended