Migrating from an Excel Gantt chart to a Bryntum Gantt chart

bryntum_ab

Bryntum

Posted on September 21, 2023

Migrating from an Excel Gantt chart to a Bryntum Gantt chart

Microsoft Excel is a common tool used in project management. It's affordable and simple to use, and if you need to create a Gantt chart to schedule project tasks, Excel has many template Gantt charts to get you started.

However, you may need more advanced functionality from your Gantt chart than Microsoft Excel provides, for example:

  • Scheduling tasks using dependencies and constraints.
  • Using recurrent and fixed-time intervals.
  • Handling large datasets.
  • Customizing the rendering and styling.

If your project would benefit from these capabilities, then the Bryntum Gantt web component is a better choice.

In this tutorial, we'll show you how to get Gantt chart data from an Excel file into a Bryntum Gantt chart. We'll do the following:

  • Write a migration script to convert data from an Excel Gantt chart to a JSON file that can be read by a Bryntum Gantt chart.
  • Set up an Express.js API endpoint to return the JSON data.
  • Create a Bryntum Gantt chart that gets data from the API endpoint.

First we'll get data from a simple Excel Gantt chart. Then we'll modify the code to get data from a more complex Gantt chart. You can adjust the code to get data from different Excel Gantt charts.

Writing a migration script to convert data from an Excel Gantt chart to a JSON file

Start by cloning the Excel to Bryntum Server starter GitHub repository. This repository includes a server.js file, which contains an Express.js server API endpoint at the "/download" route for GET requests. It also has CORS set up for when we make requests to the API endpoint from our client-side Bryntum Gantt chart.

You can find the completed code for this tutorial in the completed-server branch of the starter repository.

There are two Excel files in the starter's root directory:

  • simple-gantt-chart.xlsx
  • agile-gantt-chart.xlsx

These are Excel Gantt chart templates taken from Microsoft 365 Excel templates.

Once you've cloned the repository, install the dependencies by running the following command:

npm install
Enter fullscreen mode Exit fullscreen mode

In the root folder, create a file called migration-simple-gantt.js. This is where we'll add the script to read the Excel data from simple-gantt-chart.xlsx, convert it to a JSON structure that can be read by a Bryntum Gantt chart, and save the JSON data to a file.

Converting Excel file data to a JavaScript object

To read the Excel file and convert the data to JSON format, we'll use the xlsx library. Import the library in your migration-simple-gantt.js file:

import xlsx from "xlsx";
Enter fullscreen mode Exit fullscreen mode

Add the following lines of code:

// read the Excel file
const workbook = xlsx.readFile("./simple-gantt-chart.xlsx");
const sheetName = workbook.SheetNames[0]; // select the sheet you want
const worksheet = workbook.Sheets[sheetName];

const jsonData = xlsx.utils.sheet_to_json(worksheet);
Enter fullscreen mode Exit fullscreen mode

The readFile method reads the data from the Excel file and parses it into a workbook object. The Excel file has two sheets, we only want the data from the first sheet. The workbook.SheetNames array is an ordered list of the sheets in the Excel workbook. We get the name of the first sheet from the ordered lists of sheets. We then get the worksheet data from the Sheets object.

We use the sheet_to_json utility method to convert the worksheet object into an array of JavaScript objects.

If you console.log the jsonData variable, you'll see a large array of objects returned:

[
  {
    'Create a Project Schedule in this worksheet.\r\nEnter title of this project in cell B1. \r\nInformation about how to use this worksheet, 
including instructions for screen readers and the author of this workbook is in the About worksheet.\r\nContinue navigating down column A to h
ear further instructions.': 'Enter Company Name in cell B2.',
    'PROJECT TITLE': 'Company Name',

    ...
Enter fullscreen mode Exit fullscreen mode

Each object in the array is a row of Excel data, for most of the data. You'll notice that a lot of the text returned is not visible in the Excel Gantt chart. This is the text from cells with hidden values for explaining how to use the template worksheet. For example, if you click on cell A1 in the Excel file, you'll see the hidden text in the formula bar.

The tasks data that we need to extract from the array objects is in the "PROJECT TITLE", __EMPTY", "__EMPTY_1", "__EMPTY_2", "__EMPTY_3", and "__EMPTY_5" property values.

Let's create a function to extract the tasks data and convert it to the format required by Bryntum Gantt.

Converting the Excel data to a JSON file compatible with Bryntum Gantt

Later in this tutorial, we'll use the Bryntum Gantt chart Crud Manager to simplify fetching data from our API. The Crud Manager expects the data it receives from an API endpoint to have a specific structure. We need to extract the data we need from the jsonData variable and format it appropriately.

The start date and end date values of the "__EMPTY_2" and "__EMPTY_3" properties are Excel date numbers. Excel stores dates as a number format, with the number representing the offset from an epoch. We need a function to convert Excel numbers to JavaScript Date objects. Add the following function to the top of the migration-simple-gantt.js file to convert an Excel date number to a JavaScript Date object:

function excelToJSDate(excelDate) {
  const dateObj = xlsx.SSF.parse_date_code(excelDate);
  return new Date(
    dateObj.y,
    dateObj.m - 1,
    dateObj.d,
    dateObj.H,
    dateObj.M,
    dateObj.S
  );
}
Enter fullscreen mode Exit fullscreen mode

The xlsx SSF (SpreadSheet Format) object has a parse_date_code method that parses the Excel number to an SFF date object. We use this Date object to create a JavaScript Date object. To construct the JavaScript Date object, we subtract one from the SFF date object, as months are zero-indexed in JavaScript.

Now we need a function to create an array of tasks data that can be read by a Bryntum Gantt chart. Add the following function below the excelToJSDate function:

function createBryntumTasksRows(data) {
  let taskId = 0;
  let taskStore = [];
  let currentParentId;

  // name of first task is "Phase 1 Title"
  // only start adding tasks after it's found
  const firstTaskName = "Phase 1 Title";
  const exampleTaskName = "Insert new rows ABOVE this one";
  let isFirstTaskFound = false;
  for (let i = 0; i < data.length; i++) {
    if (
      data[i].hasOwnProperty("PROJECT TITLE") &&
      data[i]["PROJECT TITLE"].startsWith("Phase")
    ) {
      if (data[i]["PROJECT TITLE"] === firstTaskName) {
        isFirstTaskFound = true;
      }
      currentParentId = taskId;
      // parent tasks
      taskStore.push({
        id: taskId++,
        name: data[i]["PROJECT TITLE"],
        expanded: true,
      });
    } else if (data[i]["PROJECT TITLE"]) {
      if (!isFirstTaskFound) {
        continue;
      }
      // last task has been added
      if (data[i]["PROJECT TITLE"] === exampleTaskName) {
        break;
      }
      // child tasks
      taskStore.push({
        id: taskId++,
        name: data[i]["PROJECT TITLE"],
        parentId: currentParentId,
        resourceAssignment: data[i]["__EMPTY"],
        percentDone: data[i]["__EMPTY_1"] * 100,
        startDate: excelToJSDate(data[i]["__EMPTY_2"]),
        endDate: excelToJSDate(data[i]["__EMPTY_3"]),
        manuallyScheduled: true,
      });
    }
  }

  return taskStore;
}
Enter fullscreen mode Exit fullscreen mode

This function loops through the objects of the Excel data that we pass in as arguments. These objects mostly represent Excel rows. We construct a taskStore array to store the new task objects. We only start adding to the taskStore once the firstTaskName is found.

For this specific Gantt data, we determine which tasks are parent tasks by checking if the "PROJECT TITLE" starts with the text "Phase". We create a unique id for each task using the taskId variable, which increments on each loop.

If the "PROJECT TITLE" does not start with the text "Phase", the task is made a child of the last parent task using the parentId property. Once the exampleTaskName is reached, we break out of the loop.

Now add the following variable below the jsonData variable to create the task rows:

const tasksRows = createBryntumTasksRows(jsonData);
Enter fullscreen mode Exit fullscreen mode

If you console.log the tasksRows, you'll see the following array:

[
  { id: 0, name: 'Phase 1 Title', expanded: true },
  {
    id: 1,
    name: 'Task 1',
    parentId: 0,
    resourceAssignment: 'Name',
    percentDone: 50,
    startDate: 'Mon May 15 2023 00:00:00 GMT+0200 (South Africa Standard Time)',
    endDate: 'Thu May 18 2023 00:00:00 GMT+0200 (South Africa Standard Time)',
    manuallyScheduled: true
  },
  {
    id: 2,
    ...
Enter fullscreen mode Exit fullscreen mode

If the startDate and endDate values are behind what they should be, it may be due to the Excel TODAY() function that's used to determine the dates in the Excel file. The TODAY() function is a volatile function, which means that it recalculates every time the spreadsheet is opened. When you read the Excel file using a library like xlsx, it won't trigger these formulas to recalculate. It will read the last calculated value from when the file was last opened and saved in Excel. If the dates are behind what they should be, make a small change to the Excel file, save the change, and try again.

Now, we need to add a resources property and an assignments property for the JSON object that we'll create. The resources property will populate the ResourceStore of the Bryntum Gantt, which holds the resources that can be assigned to tasks. The simple Gantt chart only has a single resource, "Name", that's assigned to the first child task. The assignments property will show which tasks resources are assigned to.

Add the following lines of code below the tasksRows variable:

// create resources
const resourceNames = new Set();
const resourcesRows = tasksRows
  .filter(
    (item) =>
      item.resourceAssignment && !resourceNames.has(item.resourceAssignment)
  )
  .map((item, i) => {
    const name = item.resourceAssignment;
    return {
      id: i,
      name,
    };
  });
Enter fullscreen mode Exit fullscreen mode

We determine the resources of the data using the resourceAssignment property of the tasksRows data. We then create a resourcesRows array, where each object in the array is a resource.

If you console.log the resourcesRows variable, you'll see the following array:

[ { id: 0, name: 'Name' } ]
Enter fullscreen mode Exit fullscreen mode

Now let's create the rows for assignments. Add the following lines of code below the resourcesRows variable:

// create assignments
const resourcesWithAssignments = tasksRows.filter(
  (item) => item.resourceAssignment
);

const assignmentsRows = resourcesWithAssignments.map((item, i) => {
  const resource = resourcesRows.find(
    (resource) => resource.name === item.resourceAssignment
  );
  return {
    id: i,
    event: item.id,
    resource: resource.id,
  };
});
Enter fullscreen mode Exit fullscreen mode

To determine the tasks (events) that are assigned to a resource, we first find tasks that have a resource assignment. We then use the tasks to get the resource id and construct the assignmentsRows array.

If you console.log the assignmentsRows variable, you'll see the following array:

[ { id: 0, event: 1, resource: 0 } ]
Enter fullscreen mode Exit fullscreen mode

Now create an object for the data that will be sent to the Bryntum Gantt chart:

// convert JSON data to the expected load response structure
const ganttLoadResponse = {
  success: true,
  tasks: {
    rows: tasksRows,
  },
  resources: {
    rows: resourcesRows,
  },
  assignments: {
    rows: assignmentsRows,
  },
};
Enter fullscreen mode Exit fullscreen mode

Next we need to convert this object to JSON format and save it in a JSON file.

Saving the data to a JSON file

Add the following lines of code below the ganttLoadResponse variable:

const dataJson = JSON.stringify(ganttLoadResponse, null, 2); // convert the data to JSON, indented with 2 spaces

// define the path to the data folder
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const dataPath = path.join(__dirname, "data");

// ensure the data directory exists
if (!fs.existsSync(dataPath)) {
  fs.mkdirSync(dataPath);
}

// define the path to the JSON file in the data folder
const filePath = path.join(dataPath, "simple-gantt-chart.json");

// write the JSON string to a file in the data directory
fs.writeFile(filePath, dataJson, (err) => {
  if (err) throw err;
  console.log("JSON data written to file");
});
Enter fullscreen mode Exit fullscreen mode

Import the Node modules required:

import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
import { dirname } from "path";
Enter fullscreen mode Exit fullscreen mode

We convert the JavaScript object to a JSON string. We then create a JSON file called simple-gantt-chart.json in the data folder using the Node File System module and add the Excel JSON data to it.

To run this script, use the following command:

node migration-simple-gantt.js
Enter fullscreen mode Exit fullscreen mode

This will create a simple-gantt-chart.json file in the data folder.

For this tutorial, we simply save Excel Gantt data to a JSON file on the server. If you want to persist the data to a database, you can check out the saving data section of our docs

Next, we'll set up an API endpoint that will send the JSON data to the Bryntum Gantt chart.

Setting up an Express server with an API endpoint

In the server.js file, there is an API endpoint at the "/download" route for GET requests. Replace the code in the try block with the following lines of code:

const data = await fs.readFile("./data/simple-gantt-chart.json", "utf-8");
const jsonData = JSON.parse(data);
res.json(jsonData);
Enter fullscreen mode Exit fullscreen mode

Import the Node File System module with promise-based functions:

import fs from "fs/promises";
Enter fullscreen mode Exit fullscreen mode

We read the JSON data from the file system, parse it, and then return it from the API as a JSON response.

Now start the server using the following command:

npm run start
Enter fullscreen mode Exit fullscreen mode

If you make a GET request to your API endpoint at http://localhost:3000/download, you should see the following response:

{
    "success": true,
    "tasks": {
        "rows": [
            {
                "id": 0,
                "name": "Phase 1 Title",
                "expanded": true
            },
            {
                "id": 1,
                "name": "Task 1",
                "parentId": 0,
                "resourceAssignment": "Name",
                "percentDone": 50,
                "startDate": "Mon May 15 2023 00:00:00 GMT+0200 (South Africa Standard Time)",
                "endDate": "Thu May 18 2023 00:00:00 GMT+0200 (South Africa Standard Time)",
                "manuallyScheduled": true
            },
      ...
Enter fullscreen mode Exit fullscreen mode

Now we can create a Bryntum Gantt chart that will get data from this API endpoint.

Creating a client-side Bryntum Gantt chart

To get started, clone the following Excel to Bryntum Client starter GitHub repository. It has a "completed-gantt" branch that shows the code for the completed tutorial. It uses Vite, which is a development server and JavaScript bundler. Install the Vite dev dependency by running the following command:

npm install
Enter fullscreen mode Exit fullscreen mode

Next, install the Bryntum Gantt component by following our guide to installing the Gantt chart component using npm.

The main.js file contains code for a basic Bryntum Gantt chart. The project config property is used to configure the data stores the Gantt chart uses. The tasksData property contains some example inline data. To simplify the data structure, the taskStore is configured to consume a flat dataset, where the task parents are defined using the parentId property. Flat data is converted to tree data with autotree and transformFlatData so that the Bryntum Gantt can parse it.

Start the development server by running the following command:

npm run dev
Enter fullscreen mode Exit fullscreen mode

You should see a Gantt chart with one parent task and one child task.

Next, we'll use the Bryntum Gantt Crud Manager to get the Excel data from our API.

Getting the data from the API endpoint

First, remove the tasksData property from the gantt config in the main.js file.

Add the following properties to the gantt config, below the taskStore property:

  transport: {
    load: {
      url: "http://localhost:3000/download",
    },
  },
  autoLoad: true,
  validateResponse: true,
Enter fullscreen mode Exit fullscreen mode

The transport property is used to populate the Gantt chart data stores. We configured the load property to get data from our server API endpoint. We set the autoLoad and validateResponse properties to true to initiate a data load when the store is instantiated and to check the response structure of requests made by the Crud Manager, respectively.

You can also configure transport to sync data changes to a specific URL. To learn more, you can read the saving data section of the Crud Manager guide in our docs.

We need to add columns to our Gantt chart to match the headers of the Excel Gantt chart. Add the following objects to the columns property of the gantt config:

    {
      type: "resourceassignment",
      text: "Assigned Resources",
      showAvatars: false,
      width: 160,
    },
    {
      type: "percent",
      text: "PROGRESS",
      field: "renderedPercentDone",
      showValue: true,
      width: 160,
    },
    { type: "date", field: "startDate", text: "START", width: 110 },
    { type: "date", field: "endDate", text: "END", width: 110 },
Enter fullscreen mode Exit fullscreen mode

Now run the client and server development servers and you'll see the Bryntum Gantt chart with the data from the Excel file:

Bryntum Gantt chart with simple Excel Gantt data

The Bryntum Gantt chart has a lot of functionality out of the box, such as:

  • Configurable and sortable task columns. Right-click on a column header to see the options.
  • Collapsable task groups.
  • Drag-and-drop reordering of tasks.
  • Add, edit, copy, and delete tasks. Right-click on a task to see a pop-up menu with these actions and more, including editing dependencies.
  • Draggable task durations.
  • Resizeable task durations. Hover over the left or right side of a task duration until the cursor changes to a resize icon. Then click and drag left or right.
  • Create task dependencies. Hover over the left or right side of a task duration until you see a circle icon. Then click and drag to connect the task to another task.
  • Change date ranges or filter tasks by name by right-clicking on one of the date headers.

Now, let's get Excel data from a more complex Excel Gantt chart.

Getting data from a more complex Excel Gantt chart

The data source we'll use for this part of the tutorial is the agile-gantt-chart.xlsx Excel file, which will require changes to our server and client code.

Changes to the server: Writing a new migration script

Make a copy of the migration-simple-gantt.js file and rename it migration-agile-gantt.js.

The data we need from the agile-gantt-chart.xlsx Excel file is in sheet two. Change the workbook and sheetName variables in the migration-agile-gantt.js file to get data from the second workbook sheet of the agile Gantt chart:

    const workbook = xlsx.readFile("./agile-gantt-chart.xlsx");
    const sheetName = workbook.SheetNames[1];
Enter fullscreen mode Exit fullscreen mode

Remove the jsonData variable:

    const jsonData = xlsx.utils.sheet_to_json(worksheet);
Enter fullscreen mode Exit fullscreen mode

Replace it with the following lines of code:

    const csv = xlsx.utils.sheet_to_csv(worksheet);
    const jsonData = await csvToJson().fromString(csv);
Enter fullscreen mode Exit fullscreen mode

Instead of converting the Excel data directly to JSON, we first convert it to CSV values. We then use the csvtojson library to convert the CSV values to a JSON string.

Make sure that you import the csvToJson function from the csvtojson library:

import csvToJson from "csvtojson";
Enter fullscreen mode Exit fullscreen mode

We use this method to convert the Excel data to a JSON data object as the JSON object output is easier to parse than the output we used for the simple-gantt-chart.xlsx Excel file. You might like to try each method to see which works best for you.

If you console.log the jsonData object, you'll see a large array of objects:

[
    {
        field1: "",
        field2: "PROJECT: Light",
        field3: "",
        ...
        field68: "",
    },
    {
        field1: "",
        field2: "",
        ...
        field68: "",
    },
      ...
Enter fullscreen mode Exit fullscreen mode

Each object in the "data" array represents a row in the Excel file. The columns are named incrementally from "field1" to "field68".

The data we need for the Gantt chart is in columns two to seven of the Excel chart, which correspond to the properties field2 to field7 of the "data" array objects. Unlike the previous Gantt chart we imported data from, there is no end date for each task in this chart. Instead, each task has a start date and a duration in days. This Gantt chart also has a "Categories" column.

The start date values of the field6 keys are not in Excel date number format, so we don't need the excelToJSDate function. Replace it with the following function:

function convertToDate(dateStr) {
  let [month, day, year] = dateStr.split("/");
  year = year.length === 2 ? "20" + year : year;
  month = month - 1;
  return new Date(year, month, day);
}
Enter fullscreen mode Exit fullscreen mode

This function converts the date string to a JavaScript Date object.

Now, replace the existing createBryntumTasksRows with the one below:

function createBryntumTasksRows(data) {
  let taskId = 0;
  let taskStore = [];
  let currentParentId = null;

  // name of first task is "Phase 1 Title"
  // only start adding tasks after it's found
  const firstTaskName = "Project development";
  const exampleTaskName = "Task 4";
  let isFirstTaskFound = false;
  for (let i = 0; i < data.length; i++) {
    // check for first task
    if (data[i]["field2"] === firstTaskName) {
      isFirstTaskFound = true;
    }
    // check for example task
    if (data[i]["field2"] === exampleTaskName) {
      break;
    }

    if (isFirstTaskFound) {
      // parent task
      if (data[i]["field6"] === "") {
        currentParentId = taskId;
        taskStore.push({
          id: taskId++,
          name: data[i]["field2"],
          expanded: true,
        });
      } else {
        // child tasks
        taskStore.push({
          id: taskId++,
          name: data[i]["field2"],
          parentId: currentParentId,
          category: data[i]["field3"],
          resourceAssignment: data[i]["field4"] ? data[i]["field4"] : undefined,
          percentDone: data[i]["field5"].slice(0, -1) * 1,
          startDate: convertToDate(data[i]["field6"]),
          duration: data[i]["field3"] === "Milestone" ? 0 : data[i]["field7"],
          manuallyScheduled: true,
        });
      }
    }
  }

  return taskStore;
}
Enter fullscreen mode Exit fullscreen mode

This function is similar to the one we used for the simple Gantt chart. We check if a task is a parent task if the value of the "field6" property is an empty string. The child tasks have no endDate property and there's an additional category property. The duration property is set to 0 if the category is "Milestone". This will indicate to the Bryntum Gantt that the task is a milestone and the task bar will be styled like a milestone, diamond-shaped. The resources and assignments properties will be created in the same way as previously.

Change the name of the filePath that the JSON file will be written to:

const filePath = path.join(dataPath, "agile-gantt-chart.json");
Enter fullscreen mode Exit fullscreen mode

In the server.js file, change the JSON file that the fs.readFile method reads from:

    const data = await fs.readFile("./data/agile-gantt-chart.json", "utf-8");
Enter fullscreen mode Exit fullscreen mode

Run the migration script to create the agile-gantt-chart.json file:

node migration-agile-gantt.js
Enter fullscreen mode Exit fullscreen mode

We'll now change our client-side Bryntum Gantt chart to resemble the structure of the Excel Gantt chart.

Changes to the client

First, in the main.js file, we'll add extra gantt columns and adjust the width of the columns. Change the columns configuration to the following:

  columns: [
    { type: "name", width: 190, text: "Milestone description" },
    { width: 80, text: "Category", field: "category" },
    {
      type: "resourceassignment",
      text: "Assigned to",
      showAvatars: false,
      width: 100,
    },

    {
      type: "percent",
      text: "PROGRESS",
      field: "renderedPercentDone",
      showValue: true,
      width: 100,
    },
    { type: "date", field: "startDate", text: "START", width: 110 },
    { type: "date", field: "endDate", text: "END", width: 110 },
  ],
Enter fullscreen mode Exit fullscreen mode

You'll now see the following Bryntum Gantt chart when you run the development server:

Bryntum Gantt chart with Excel agile Gantt data

Notice that the "Category" values are not displayed. This is because "Category" is not one of the predefined fields of the Bryntum Gantt task store Model. We can add this custom field to the model by adding the following lines of code to the bottom of the main.js file:

gantt.taskStore.modelClass.addField({
  name: "category",
  type: "string",
});
Enter fullscreen mode Exit fullscreen mode

The "Category" values will now be displayed in your Gantt chart:

Bryntum Gantt chart with Excel agile Gantt data and categories

If you look at the agile-gantt-chart.xlsx Gantt chart, you'll see that the task bars are colored depending on the task category, and the milestones are shown as a flag. Let's color the child task bars based on the task category. Add the following method in the gantt config, below the columns property:

  // custom taskbar content
  taskRenderer({ taskRecord, renderData }) {
    const { category, parentId } = taskRecord;
    if (parentId !== null) {
      switch (category) {
        case "Goal":
          renderData.style = "background-color:" + "#d65532";
          break;
        case "Milestone":
          renderData.style = "background-color:" + "none";
          break;
        case "Low Risk":
          renderData.style = "background-color:" + "#00b0f0";
          break;
        case "Med Risk":
          renderData.style = "background-color:" + "#4868e5";
          break;
        case "High Risk":
          renderData.style = "background-color:" + "#852c98";
          break;
        case "On Track":
          renderData.style = "background-color:" + "#4ca472";
          break;
        default:
          renderData.style = "background-color:" + "#e6e6e6";
      }
    }

    return "";
  },
Enter fullscreen mode Exit fullscreen mode

The taskRenderer is called each time a task is rendered. You can use it to change what's displayed in the task bars. It returns a string that's displayed in the task bar. The string can be text or HTML. You can also return a DOM config object.

We can get information about the task being rendered from the taskRecord parameter. If the task has a parentId, it's a child task. For the child tasks, we use a switch statement to determine the category of the task. We then style the task bars based on their category using the renderData parameter. We style the task bars by changing their "background-color" CSS property.

To make the "Milestone" category task bars look like a flag, add the following lines of code directly above the return statement:

    if (category === "Milestone")
      return `<span style="position:absolute; top: -10px"><i class="b-fa b-fa-flag b-fa-2xs" style="color: orange;"></i></span>`;
Enter fullscreen mode Exit fullscreen mode

If the task is a Milestone, we'll render a Font Awesome flag icon on top of the task bar. The version of Font Awesome used by Bryntum components has a b-fa prefix instead of fa to prevent conflicts with other versions of Font Awesome on the page. If you are rendering user-provided data, you can use the xss function to sanitize the rendered string or HTML.

The Milestone task bars will have a flag icon rendered on top of them:

Bryntum Gantt - milestone with flag issue

We can use CSS to hide the underlying task bar diamond shape. Add the following lines to the style.css file:

.b-gantt-task-wrap.b-milestone-wrap
  .b-gantt-task:not(.b-gantt-task-withicon)
  .b-gantt-task-content::before {
  height: 0;
  width: 0;
}
Enter fullscreen mode Exit fullscreen mode

It's often easiest to use your browser dev tools to determine which HTML elements you want to apply the CSS styling to.

You'll now only see the flag icon for the Milestone task bars:

Bryntum Gantt - milestone with flag

Next steps

Using the code in this tutorial as a guide, try to migrate your own Excel Gantt charts to a Bryntum Gantt chart to take your project management to the next level.

You can also persist the data to a database. Check out the saving data section of our docs or take a look at one of these tutorials from our blog:

💖 💪 🙅 🚩
bryntum_ab
Bryntum

Posted on September 21, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related