[SOLVED] Adapt Asp.net JavaScript jsgantt-improved Gantt chart into Blazor

Issue

There is one nice looking Gantt chart available with example for Asp.net. However I am having hard times to understand how it can be done in Blazor with razor pages. Can somebody give me some hints how to proceed?

I have placed jsgantt.js and jsgantt.css into wwwroot and also added references in index.html.

But then how to handle that part? Also I guess data should better come from json?

<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Gantt.aspx.cs" Inherits="Links2.WebUI.Gannt" %>

<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">

    <link href="assets/css/jsgantt.css" rel="stylesheet" type="text/css"/>
    <script src="Scripts/jsgantt.js" type="text/javascript"></script>
    <script src="https://code.jquery.com/jquery-git.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/0.9.0rc1/jspdf.min.js"></script>

    <style>
        .box {
          display: inline-block;
          height: 20px;
          width: 20px;
          border: 2px solid;
        }
        .chartlegend 
        {
            border:1px solid none;
            text-align:right;
            margin-bottom: 30px;            
        }

        .chartlegenditem
        {
            float: right;
            margin-right: 1%;
            filter: alpha(opacity=90);
            opacity: 0.9;
            margin-top: 1px;
        }

        .body-content {
        width: 1800px !important;
    }

    </style>

   
    <%--<input type="button" id="click" value="Export to PDF"/>--%>

    <div class="chartlegend" id="ChartLegendDIV" style="width:1800;"></div>
    <div style="position:relative" class="gantt" id="GanttChartDIV"></div>
    <asp:HiddenField ID="HiddenField" runat="server" />
        <script type="text/javascript">

            var colourList = {
                L1:
                {
                    Title: 'Executing',
                    Colour: '#50C13A'
                },
                L2:
                {
                    Title: 'At Risk',
                    Colour: '#F7E438'
                },
                L3:
                {
                    Title: 'To Do',
                    Colour: '#A9A9A9'
                },
                L4:
                {
                    Title: 'On Hold',
                    Colour: '#2F4F4F'
                },
                L5:
                {
                    Title: 'Planning',
                    Colour: '#3A84C3'
                },
                L6:
                {
                    Title: 'Late',
                    Colour: '#C43A3A'
                },
                L7:
                {
                    Title: 'Initiating',
                    Colour: '#F0F8FF'
                },
                L8:
                {
                    Title: 'Complete',
                    Colour: '#000000'
                }
            };

            colorize = function (colorList)
            {
                    var container = document.getElementById('ChartLegendDIV');
  
                for (var key in colorList) {

                        var details = colorList[key];

                        var boxContainer = document.createElement("DIV");
                        boxContainer.className = 'chartlegenditem';                                               
                        var box = document.createElement("DIV");
                        var label = document.createElement("SPAN");

                        label.innerHTML = details['Title'];
                        box.className = "box";
                        box.style.backgroundColor = details['Colour'];

                        boxContainer.appendChild(box);
                        boxContainer.appendChild(label);

                        container.appendChild(boxContainer);

                   }
            }

            colorize(colourList);

            var g = new JSGantt.GanttChart(document.getElementById('GanttChartDIV'), 'month');

            var list = document.getElementById('<%= HiddenField.ClientID %>').value;

            var result = JSON.parse(list);
               
            vShowRes = document.querySelector('#vShowRes:checked') ? 1 : 0;
            vShowCost = document.querySelector('#vShowCost:checked') ? 1 : 0;
            vShowComp = document.querySelector('#vShowComp:checked') ? 1 : 0;
            vShowDur = document.querySelector('#vShowDur:checked') ? 1 : 0;
            vShowStartDate = document.querySelector('#vShowStartDate:checked') ? 1 : 0;
            vShowEndDate = document.querySelector('#vShowEndDate:checked') ? 1 : 0;
            vShowPlanStartDate = document.querySelector('#vShowPlanStartDate:checked') ? 1 : 0;
            vShowPlanEndDate = document.querySelector('#vShowPlanEndDate:checked') ? 1 : 0;
            vShowTaskInfoLink = document.querySelector('#vShowTaskInfoLink:checked') ? 1 : 0;
            vShowEndWeekDate = document.querySelector('#vShowEndWeekDate:checked') ? 1 : 0;



            g.setOptions({
                vCaptionType: 'Complete',  // Set to Show Caption : None,Caption,Resource,Duration,Complete,     
                vQuarterColWidth: 46, 
                vAdditionalHeaders: { // Add data columns to your table
                        ID:
                        {
                            title: 'ID'
                        },
                        PM:
                        {
                            title: 'PM'
                        },
                        Sponsor:
                        {
                            title: 'Sponsor'
                        }                    
                    },
               
                vDayMajorDateDisplayFormat: 'mon yyyy - Week ww',
            });

            //g.AddTaskItemObject({
            //  pID: 1,
            //  pName: "Define Chart <strong>API</strong>",
            //  pStart: "2017-02-25",
            //  pEnd: "2017-03-17",
            //  pPlanStart: "2017-04-01",
            //  pPlanEnd: "2017-04-15 12:00",
            //  pClass: "ggroupblack",
            //  pLink: "",
            //  pMile: 0,
            //  pRes: "Brian",
            //  pComp: 0,
            //  pGroup: 1,
            //  pParent: 0,
            //  pOpen: 1,
            //  pDepend: "",
            //  pCaption: "",
            //  pCost: 1000,
            //  pNotes: "Some Notes text",
            //  category: "My Category",
            //  sector: "Finance"
            //});

            // or passing parameters

            g.setShowRes(0);
            g.setShowStartDate(0);
            g.setShowEndDate(0);
            g.setShowComp(0);
            g.setShowDur(0);
            g.setScrollTo("today");
            g.setFormatArr('Month', 'Quarter');
            g.setTooltipDelay(200);

            g.AddTaskItem(new JSGantt.TaskItem(1, 'Core', '', '', 'ggroupblack', '', 0, 'Padraic', 0, 1, 0, 1, '', '', '', 'Padraic', g));
            g.AddTaskItem(new JSGantt.TaskItem(2, 'SHP', '', '', 'ggroupblack', '', 0, 'Padraic', 0, 1, 0, 1, '', '', '', 'Padraic', g));
            //g.AddTaskItem(new JSGantt.TaskItem(3, 'Undefined', '', '', 'ggroupblack', '', 0, 'Padraic', 0, 1, 0, 1, '', '', '', 'Padraic', g));
            g.AddTaskItem(new JSGantt.TaskItem(4, 'DES', '', '', 'ggroupblack', '', 0, 'Padraic', 0, 1, 1, 1, '', '', '', 'Padraic', g));
            g.AddTaskItem(new JSGantt.TaskItem(5, 'SES', '', '', 'ggroupblack', '', 0, 'Padraic', 0, 1, 1, 1, '', '', '', 'Padraic', g));
            g.AddTaskItem(new JSGantt.TaskItem(6, 'SDC', '', '', 'ggroupblack', '', 0, 'Padraic', 0, 1, 1, 1, '', '', '', 'Padraic', g));
            g.AddTaskItem(new JSGantt.TaskItem(7, 'PCT', '', '', 'ggroupblack', '', 0, 'Padraic', 0, 1, 1, 1, '', '', '', 'Padraic', g));
            g.AddTaskItem(new JSGantt.TaskItem(8, 'PTA', '', '', 'ggroupblack', '', 0, 'Padraic',   0, 1, 1, 1, '', '', '', 'Padraic', g));


            var IsFirstIteration = true;
            var IsUndefinedTypePresent = false;

            for (var i = 0; i < result.length; i++)
            {
                var statusColour = 'gtaskblack';

                var row = result[i];
                var name = row["Name"];
                var id = row["ID"];
                var start = row["Start"].split('T')[0];
                var finish = row["Finish"].split('T')[0];
                var percentageComplete = row["PercentageComplete"];
                var status = row["Status"];
                var cValue = row["CValue"];
                var pm = row["ProjectManager"];
                var sponsor = row["Sponsor"];
                var valuestream = row["ValueStream"];
                var comments = row["Comments"];

                // Set the parent as undefined by default.
                var parent = 3;

                if (row["SubParent"] != 9) {
                    parent = row["SubParent"];
                }
                else
                {
                    parent = row["Parent"];
                } 

                if (IsFirstIteration)
                {
                    parent = 3;
                    IsFirstIteration = false;
                }

                if (parent == 3 && !IsUndefinedTypePresent)
                {
                    g.AddTaskItem(new JSGantt.TaskItem(3, 'Undefined', '', '', 'ggroupblack', '', 0, 'Padraic', 0, 1, 0, 1, '', '', '', 'Padraic', g));
                    IsUndefinedTypePresent = true;
                }

                //if (percentageComplete == 0)
                //{
                //    percentageComplete = 0.001;
                //}

                switch (cValue) {
                    // Executing
                    case 333:
                        statusColour = 'gtaskgreen';
                        break;
                    // At Risk
                    case 334:
                        statusColour = 'gtaskyellow';
                        break;
                    // Late
                    case 335:
                        statusColour = 'gtaskred';
                        break;
                    // On Hold
                    case 336:
                        statusColour = 'gtaskslategray';
                        break;
                    // Planning
                    case 337:
                        statusColour = 'gtaskblue';
                        break;
                    // To Do
                    case 338:
                        statusColour = 'gtaskgray';
                        break;
                     // Initiating
                    case 350:
                        statusColour = 'gtaskaliceblue';
                        break;
                     // Complete
                    case 351:
                        statusColour = 'gtaskblack';
                        break;
                    default:
                        statusColour = 'gtaskpink';
                        break;
                }
                                
                g.AddTaskItemObject(
                    {                        
                        pID: i + 8,
                        pName: name,
                        pStart: start,
                        pEnd: finish,
                        pLink: '',
                        pClass: statusColour,
                        pMile: 0,
                        pRes: pm,
                        pComp: percentageComplete,
                        pGroup: 0,
                        pParent: parent,
                        pOpen: 1,
                        pNotes: comments,
                        ID: id,
                        PM: pm,
                        Sponsor: sponsor
                }
                );
            }
                        
            g.Draw()

            document.write("<br><br><br><br>");

            //document.getElementById("click").onclick = function ()
            //{
            //    // Default export is a4 paper, portrait, using milimeters for units
            //    var doc = new jsPDF();

            //    //doc.addHTML($('GanttChartDIV')[0], 15, 15, {
            //    //    'background': '#fff',
            //    //});

            //    doc.fromHTML($('GanttChartDIV').html(), 10, 10, {'width' : 340});
            //    doc.save("Test.pdf");

            //    //var doc = new jsPDF();
            //    //doc.addHTML($('#content')[0], 15, 15, {
            //    //    'background': '#fff',
            //    //    }, function() {
            //    //    doc.save('sample-file.pdf');
            //    //});

            //}              

        </script>
        
</asp:Content> 

Repo can be found here: https://github.com/jsGanttImproved/jsgantt-improved

Solution

Blazor can talk with javascript through Microsoft.JSInterop.IJSRuntime.
You can create a javascript function in your index.html to show Gantt, then call it from your blazor code.

Here is an example. I simply implement the example from https://github.com/jsGanttImproved/jsgantt-improved.

First, in you index.html, include jsgantt css and js, and prepare a function to be called from blazor. It is kind of an api exposed to blazor to show Gantt.
I assume you save jsgantt files under wwwroot/content folder.

<head>
    ...
    <link rel="stylesheet" href="content/jsgantt.css">
    <script src="content/jsgantt.js"></script>

    <script>
        showGantt = (chartDivID, settingOption, taskItems) => {
        var g = new JSGantt.GanttChart(document.getElementById(chartDivID), 'day');

        g.setOptions(settingOption);

        taskItems.forEach(taskItem => {
            g.AddTaskItemObject(taskItem);
        });

        g.Draw();
    }
    </script>
</head>

Then in your razor file, you add a DIV to show Gantt, prepare chart data and pass them to javascript function defined above. That is it!

...
@inject Microsoft.JSInterop.IJSRuntime _jsRuntime

<button @onclick="ShowGantt">Show Gantt</button>
<div style="position:relative" class="gantt" id="GanttChartDIV"></div>

@code{
private async Task ShowGantt()
    {
        var options = new
        {

            vCaptionType = "Complete",  // Set to Show Caption : None,Caption,Resource,Duration,Complete,     
            vQuarterColWidth = 36,
            vDateTaskDisplayFormat = "day dd month yyyy", // Shown in tool tip box
            vDayMajorDateDisplayFormat = "mon yyyy - Week ww",// Set format to dates in the "Major" header of the "Day" view
            vWeekMinorDateDisplayFormat = "dd mon", // Set format to display dates in the "Minor" header of the "Week" view
            vLang = "en",
            vShowTaskInfoLink = 1, // Show link in tool tip (0/1)
            vShowEndWeekDate = 0,  // Show/Hide the date for the last day of the week in header for daily
            vAdditionalHeaders = new
            { // Add data columns to your table
                category = new
                {
                    title = "Category"
                },
                sector = new
                {
                    title = "Sector"
                }
            },
            vUseSingleCell = 10000, // Set the threshold cell per table row (Helps performance for large data.
            vFormatArr = new string[] { "Day", "Week", "Month", "Quarter" }, // Even with setUseSingleCell using Hour format on such a large chart can cause issues in some browsers,

        };

        var taskItems = new[]{
        new {
            pID = 1,
            pName = "Define Chart <strong>API</strong>",
            pStart = "2017-02-25",
            pEnd = "2017-03-17",
            pPlanStart = "2017-04-01",
            pPlanEnd = "2017-04-15 12:00",
            pClass = "ggroupblack",
            pLink = "",
            pMile = 0,
            pRes = "Brian",
            pComp = 0,
            pGroup = 0,
            pParent = 0,
            pOpen = 1,
            pDepend = "",
            pCaption = "",
            pCost = 1000,
            pNotes = "Some Notes text",
            category = "My Category",
            sector = "Finance"
        },
        new {
            pID = 2,
            pName = "Develop Chart <strong>API</strong>",
            pStart = "2017-03-01",
            pEnd = "2017-04-29",
            pPlanStart = "2017-04-01",
            pPlanEnd = "2017-04-15 12:00",
            pClass = "ggroupblack",
            pLink = "",
            pMile = 0,
            pRes = "Brian",
            pComp = 0,
            pGroup = 0,
            pParent = 0,
            pOpen = 1,
            pDepend = "",
            pCaption = "",
            pCost = 1000,
            pNotes = "Some Notes text",
            category = "My Category",
            sector = "Finance"
        }
    };

    await _jsRuntime.InvokeVoidAsync("showGantt", new object[] { "GanttChartDIV", options, taskItems });
    }
}

Answered By – ch_g

Answer Checked By – Mildred Charles (BugsFixing Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *