Introduction to the

In this paper, based on customer needs and the reference of the old company plusgantt to achieve different angles of gantt diagram, the additional introduction of moment.js for fast date processing

1. In order to achieve this effect for customers, the data source should be confirmed first, with the project as a task and the job as a horizontal path. Meet the requirements of multi-plan management
  {
        "id": "2103211629501365"."name": "Test items"."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 the code
2. In order to achieve the effect of gANTT diagram, first design the basic configuration of GANTT. The following basic attributes are summarized
  this.config = {
        width: "100%".height: "100%".columnDefaultWidth: "100px".// Table column default width
        scaleDefautWidth: 28.//gantt column default width
        scaleDefaultHeight: 48.// Gantt defaults to single line height
        ganttTopDateMode: "YYYY year MM month".// Calendar format
        type: "project".// Project dimensions: project resources: personnel
        initScrollTop: 0.// Record the initialization scroll bar top
        initScrollLeft: 0.// Record the initialization scroll left
        scrollTicking: false             // Scroll timer
    }
Copy the code

Code entry and usage method

<div id="ganttChart" class="row row-grid ganttview" style="margin: 5px; height: 100%;"></div>

 var powerGantt = new powerGantt(document.getElementById("ganttChart"));
 powerGantt.setColumn([]);
 powerGantt.setData([])
Copy the code
var powerGantt = function (element, config) {
    this.config = {
        width: "100%".height: "100%".columnDefaultWidth: "100px".// Table column default width
        scaleDefautWidth: 28.//gantt column default width
        scaleDefaultHeight: 48.// Gantt defaults to single line height
        ganttTopDateMode: "YYYY year MM month".// Calendar format
        type: "project".// Project dimension, project: project user: personnel
        initScrollTop: 0.// Record the initialization scroll bar top
        initScrollLeft: 0.// Record the initialization scroll 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;
    // Initialize the 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";
    
    // Create a grid region
    this.ganttGrid = document.createElement("div");
    this.ganttGrid.innerHTML = "";
    this.ganttGrid.className = "power-ganttgrid"

    // Create a 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);
    
    // Start drawing
    this.render();
   
}
Copy the code

Preview the generated effect, is not what also can not see, can not see on the right, because it has not started

3. Start drawing GANTT, including preprocessing validation data, calculating the start and end of GANTT view area, and level processing of data according to startDate and endDate of the task
powerGantt.prototype.render = function () {
    // Data level processing
    this.startDate = moment().add(-7.'day').format('L');
    this.endDate = moment().add(7.'day').format('L');
    if (this.data.length) {
        // Find the start and end dates of gantt
        for (var i = 0; i < this.data.length; i++) {
            let projectTask = this.data[i].tasks;
            var project = this.data[i];
            // Level groups the tasks for each project
            this.toLevelData(project);
            
            // Update startDate and endDate during the loop
             this.startDate=....
             this.endDate=.... }}// Draw grid, table draw, no additional description
    this.renderGrid();

    // Draw the GanttView area
    this.renderGantt();
}
Copy the code
4. Rendering ganttView (rendering grid is not covered in extra detail)
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 to synchronize table and gantt scroll height
    }
    self.renderGanttHeader();
    self.renderGanttBody();
}
Copy the 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;
    // There is no event for editing the header area. String concatenation 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 the 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 rendering
powerGantt.prototype.renderGanttGrid = function () {
    let ganttGrid = document.createElement("div");
    ganttGrid.className = "power-ganttview-grid";
    // Count rows and 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 the code

// Gantt task rendering
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, omit business code 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 end date of the task
                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 change 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 the 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 the code

5. The drawing is complete. Method usage, binding events, and event usage methods

use

<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 the 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 the code
6. Preview the effect and source code

The source address