2024-07-13: Code updated to version 2.1 – fix starting position of the bars.
This is the updated version of the Project Gantt Chart view for SharePoint Online.
Over 2 years ago I published a Gantt Chart view for Tasks in SharePoint Online both here and on github. After publishing I have received numerous questions and suggestions and even an alternative version was created by Federico Sapia.
An updated version
The ideas from Federico’s version and suggestions made by several people got me triggered to create an updated version. But, yeah, time flies.
Apparently summer holidays are good for something because I finally made some time to get back to the initial version.
First of all, it is cleaner. The bar is no longer changing colours depending on the state of the task. It is just blue or lightblue, using the same shades of blue as Project for the web. And for the rest, this new version now supports/includes:
- Milestones
- Progressbar
- Clicks to update the progress
- Task description
- Task assignment
- Labels that mover from right to left based on the amount of space.
To accomedate these changes I needed three more columns.
Columnname | Columntype | |
---|---|---|
Title | Text | |
ProjectStart | Date and time | |
ProjectDue | Date and time | |
TaskStart | Date and time | |
TaskDue | Date and time | |
Progress | Number (min: 0, max:100, percentage) | |
TaskType | Choice (2 options: Task, Milestone) | New |
AssignedToUser | People (Single select) | New |
TaskDescription | Multilines of text (no format) | New |
Please note that whenever you create a column an internal name is assigned to this column. If you change the name of a column, you do not change the internal name. So make sure you use the correct name straight away.
The code
If you don’t know how to create a view and apply the code below, please do check the post of the orginal SharePoint Project Gantt Chart, just make sure that all of the above columns are used in your view.
2024-07-13: Code updated to version 2.1 – fix starting position of the bars and progesslabels.
As was pointed out by George, the bars didn’t start at correct location. Since this position is relatively based on the total duration of the project, the problem only becomes really visible when the whole project has a rather short duration. The code below is the updated version.
{ "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/row-formatting.schema.json", "hideSelection": true, "hideColumnHeader": true, "rowFormatter": { "elmType": "div", "style": { "height": "=if(@rowIndex == 0, '88px', '52px')", "display": "block", "width": "100%", "position": "sticky" }, "attributes": { "class": "ms-bgColor-neutralLighter--hover" }, "children": [ { "elmType": "div", "_comment": "Header area", "attributes": { "class": "ms-bgColor-themePrimary" }, "style": { "width": "100%", "display": "=if(@rowIndex == 0, 'flex', 'none')", "height": "36px", "padding": "0", "font-weight": "bold", "border-radius": "6px 6px 0 0" }, "children": [ { "elmType": "div", "txtContent": "Task", "style": { "width": "220px", "text-align": "left", "padding-left": "0.4em", "box-sizing": "border-box" }, "attributes": { "class": "ms-fontSize-16 ms-fontColor-white" } }, { "elmType": "div", "style": { "flex-grow": "1", "height": "100%", "position": "relative" }, "children": [ { "elmType": "div", "_comment": "ProjectStart label", "txtContent": "=toLocaleDateString([$ProjectStart])", "style": { "position": "absolute", "padding": "14px 4px 0 4px", "height": "22px", "border-radius": "6px 6px 0 0" }, "attributes": { "title": "='Project Start: ' + toLocaleDateString([$ProjectStart])", "class": "ms-bgColor-themeDarker ms-fontSize-14 ms-fontColor-white" } }, { "elmType": "div", "_comment": "ProjectDue label", "txtContent": "=toLocaleDateString([$ProjectDue])", "style": { "position": "absolute", "right": "0", "padding": "14px 4px 0 4px", "height": "22px", "border-radius": "6px 6px 0 0" }, "attributes": { "title": "='Project Finish: ' + toLocaleDateString([$ProjectDue])", "class": "ms-bgColor-themeDarker ms-fontSize-14 ms-fontColor-white" } }, { "elmType": "span", "_comment": "CurrentDate label", "txtContent": "=toLocaleDateString( @now)", "style": { "position": "relative", "width": "90px", "z-index": "100", "display": "=if([$ProjectDue] < @now , 'none', 'block')", "left": "=floor( (Number(Date(@now)-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])) * 100 ) + '%'", "background-color": "#e1dfdd", "text-align": "center", "padding": "0 3px", "margin": "0 0 0 3px" } }, { "elmType": "span", "_comment": "Vertical line for today", "attributes": { "class": "ms-fontColor-gray40" }, "style": { "position": "relative", "display": "=if( [$ProjectDue] < @now , 'none', 'block')", "top": "-1.3em", "z-index": "1", "border-left": "5px solid", "height": "800px", "width": "0.1em", "left": "= (Number(@now)-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])) * 100 + '%' " } } ] } ] }, { "elmType": "div", "_comment": "Rows", "style": { "width": "100%", "display": "flex" }, "children": [ { "elmType": "div", "_comment": "Row (task) header", "style": { "width": "220px", "display": "flex", "flex-wrap": "wrap" }, "attributes": { "class": "" }, "children": [ { "elmType": "span", "_comment": "Progress circle icon ", "style": { "width": "24px", "padding": "6px 0", "text-align": "center", "cursor": "pointer" }, "attributes": { "iconName": "=if([$Progress] >= 1, 'CompletedSolid', if([$Progress] > 0 , 'CortanaLogoReadyOuter', 'CircleRing'))", "title": "='Progress: ' + Number([$Progress] * 100) + '%'", "class": "= 'ms-fontSize-14 ms-fontColor-' + if([$Progress] >= 1, 'green', 'neutralSecondaryAlt')" }, "customRowAction": { "action": "setValue", "actionInput": { "Progress": "=if([$Progress] == 0, if([$TaskType] == 'Task' || [$TaskType] == '', 25 , 100) , if([$Progress] == 0.25 , 50, if([$Progress] == 0.50, 75, if([$Progress] == 0.75, 100, 0))))" } } }, { "elmType": "button", "_comment": "tasktitle", "txtContent": "[$Title]", "customRowAction": { "action": "editProps" }, "style": { "width": "196px", "height": "1.6em", "padding": "0.3em 0 0 0", "border": "none", "background-color": "transparent", "cursor": "pointer", "text-decoration": "none", "text-align": "left", "outline": "none", "display": "inline-block", "overflow": "hidden", "text-overflow": "ellipsis", "white-space": "nowrap" }, "attributes": { "title": "[$Title]", "class": "ms-fontSize-14 ms-fontWeight-semibold ms-fontColor-gray140 ms-fontColor-black--hover" } }, { "elmType": "span", "_comment": "Task status warning", "style": { "width": "24px", "padding": "1px 0 0 0", "text-align": "center" }, "attributes": { "iconName": "=if([$TaskDue]< @now && [$Progress] < 1, 'EventDateMissed12', '')", "title": "This task is running late!", "class": "='ms-fontSize-14 ms-fontColor-' + if([$TaskDue]< @now && [$Progress] < 1, 'sharedRed20', 'themePrimary')" } }, { "elmType": "div", "txtContent": "=toLocaleDateString([$TaskStart])", "style": { "width": "96px", "padding": "0.1em 0", "text-align": " center", "heigth": "1.4em", "border-radius": "12px", "margin": "0 2px 0 0 " }, "attributes": { "class": "ms-fontSize-12 ms-bgColor-neutralLight" } }, { "elmType": "div", "txtContent": "=toLocaleDateString([$TaskDue])", "style": { "width": "96px", "padding": "0.1em 0", "text-align": " center", "border-radius": "12px", "margin": "0 2px 0 0 " }, "attributes": { "class": "ms-fontSize-12 ms-bgColor-neutralLight" } } ] }, { "elmType": "div", "_comment": "Ganttchart area", "style": { "flex-grow": "1", "position": "relative", "height": "3.3em", "padding": "0.3em 0 0 0" }, "attributes": { "class": "" }, "children": [ { "elmType": "div", "_comment": "NormalTask Bar", "txtContent": "", "style": { "position": "absolute", "box-sizing": "border-box", "display": "=if([$TaskType] == 'Task' || [$TaskType] == '' , 'flex', 'none')", "border-radius": "6px", "z-index": "10", "top": "0.6em", "height": "2.4em", "overflow": "hidden", "text-overflow": "ellipsis", "border": "1px solid", "border-color": "#0078db", "background-color": "#cfe6f7", "left": "= (Number([$TaskStart])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 + '%'", "width": "= if( [$TaskDue] > [$ProjectDue], (Number([$ProjectDue])-Number([$TaskStart])+ 86400000) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 , (Number([$TaskDue])-Number([$TaskStart])+ 86400000) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 ) + '%'" }, "attributes": { "class": "", "title": "" } }, { "elmType": "div", "_comment": "NormalTask Progress Bar", "style": { "position": "absolute", "box-sizing": "border-box", "display": "=if(( [$TaskType] == 'Task' || [$TaskType] == '' ) && [$Progress] > 0, 'flex', 'none')", "border-radius": "=if( [$Progress] < 1, '6px 0 0 6px', '6px')", "z-index": "20", "top": "0.6em", "height": "2.4em", "overflow": "hidden", "text-overflow": "ellipsis", "border": "1px solid", "border-color": "#0078db", "background-color": "#0078db", "left": "= (Number([$TaskStart])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 + '%'", "width": "= if( [$TaskDue] > [$ProjectDue], ((Number([$ProjectDue])-Number([$TaskStart])+ 86400000) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100) * [$Progress] + '%' , ((Number([$TaskDue])-Number([$TaskStart])+ 86400000) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 * [$Progress]) + '%'" }, "attributes": { "class": "sp-field-bold", "title": "=[$Title] + ' - ' + toLocaleDateString([$TaskStart]) + ' - ' + toLocaleDateString([$TaskDue])" } }, { "elmType": "div", "_comment": "Bar Placeholder for customcard", "txtContent": "", "style": { "position": "absolute", "box-sizing": "border-box", "border-radius": "6px", "z-index": "50", "top": "0.6em", "height": "2.4em", "overflow": "hidden", "text-overflow": "ellipsis", "border": "=if([$TaskDue]< @now && [$Progress] < 1, '2px solid #f8b7bd', 'none')", "background-color": "", "left": "= (Number([$TaskStart])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 + '%'", "width": "=if([$TaskType] == 'Milestone', '28px' , if( [$TaskDue] > [$ProjectDue], (Number([$ProjectDue])-Number([$TaskStart])+ 86400000) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 , (Number([$TaskDue])-Number([$TaskStart])+ 86400000) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 ) + '%'", "margin-left": "=if([$TaskType] == 'Milestone', '-14px' , 0" }, "attributes": { "class": "", "title": "" }, "customCardProps": { "openOnEvent": "hover", "directionalHint": "bottomCenter", "isBeakVisible": true, "beakStyle": { "backgroundColor": "white" }, "formatter": { "elmType": "div", "style": { "max-height": "256px", "width": "282px", "display": "flex", "flex-wrap": "wrap", "align-items": "flex-start" }, "attributes": { "class": "ms-ContextualMenu-list is-open list-436" }, "children": [ { "elmType": "div", "txtContent": "[$Title]", "style": { "width": "250px", "height": "40px", "padding": "4px 4px 0 4px", "overflow": "hidden", "text-overflow": "ellipsis" }, "attributes": { "class": "ms-fontSize-14 ms-bgColor-themeLight ms-fontWeight-semibold ms-fontColor-gray160" } }, { "elmType": "div", "style": { "width": "12", "flex-grow": "1", "height": "34px", "padding": "10px 0 0 0 ", "text-align": "center", "cursor": "pointer" }, "attributes": { "iconName": "Edit", "class": "ms-fontSize-14 ms-bgColor-themeLight ms-fontColor-gray160" }, "customRowAction": { "action": "editProps" } }, { "elmType": "div", "_comment": "Progress actionbar", "style": { "width": "100%", "display": "flex", "flex-wrap": "wrap", "align-items": "flex-start", "margin": "2px 0" }, "children": [ { "elmType": "div", "style": { "width": "24px", "padding": "6px 0", "text-align": " center", "heigth": "1.4em" }, "attributes": { "iconName": "Timeline" } }, { "elmType": "div", "txtContent": "0%", "style": { "padding": "2px 6px", "text-align": " center", "border-radius": "14px", "margin": "2px 2px 0 0 ", "cursor": "pointer" }, "attributes": { "class": "='ms-fontSize-14 ms-bgColor-themeLight--hover ms-fontColor-themeDarker--hover ms-bgColor-' + if([$Progress] == 0, 'themeTertiary', 'neutralLight')" }, "customRowAction": { "action": "setValue", "actionInput": { "Progress": "0" } } }, { "elmType": "div", "txtContent": "25%", "style": { "padding": "2px 6px", "text-align": " center", "border-radius": "14px", "margin": "2px 2px 0 0 ", "cursor": "pointer" }, "attributes": { "class": "='ms-fontSize-14 ms-bgColor-themeLight--hover ms-fontColor-themeDarker--hover ms-bgColor-' + if([$Progress] == 0.25, 'themeTertiary', 'neutralLight')" }, "customRowAction": { "action": "setValue", "actionInput": { "Progress": "25" } } }, { "elmType": "div", "txtContent": "50%", "style": { "padding": "2px 6px", "text-align": " center", "border-radius": "14px", "margin": "2px 2px 0 0 ", "cursor": "pointer" }, "attributes": { "class": "='ms-fontSize-14 ms-bgColor-themeLight--hover ms-fontColor-themeDarker--hover ms-bgColor-' + if([$Progress] == 0.5, 'themeTertiary', 'neutralLight')" }, "customRowAction": { "action": "setValue", "actionInput": { "Progress": "50" } } }, { "elmType": "div", "txtContent": "75%", "style": { "padding": "2px 6px", "text-align": " center", "border-radius": "14px", "margin": "2px 2px 0 0 ", "cursor": "pointer" }, "attributes": { "class": "='ms-fontSize-14 ms-bgColor-themeLight--hover ms-fontColor-themeDarker--hover ms-bgColor-' + if([$Progress] == 0.75, 'themeTertiary', 'neutralLight')" }, "customRowAction": { "action": "setValue", "actionInput": { "Progress": "75" } } }, { "elmType": "div", "txtContent": "100%", "style": { "padding": "2px 6px", "text-align": " center", "border-radius": "14px", "margin": "2px 2px 0 0 ", "cursor": "pointer" }, "attributes": { "class": "='ms-fontSize-14 ms-bgColor-themeLight--hover ms-fontColor-themeDarker--hover ms-bgColor-' + if([$Progress] == 1, 'themeTertiary', 'neutralLight')" }, "customRowAction": { "action": "setValue", "actionInput": { "Progress": "100" } } } ] }, { "elmType": "div", "_comment": "Warning ICON for Late tasks", "style": { "width": "24px", "display": "=if([$TaskDue]< @now && [$Progress] < 1, 'block', 'none')", "padding": "6px 0 7px 0", "text-align": " center", "heigth": "18px", "margin": "2px 0" }, "attributes": { "iconName": "EventDateMissed12", "class": "sp-field-severity--blocked30 ms-fontSize-14 ms-fontColor-sharedRed20" } }, { "elmType": "div", "_comment": "Warning TEXT for Late tasks", "txtContent": "This task is running late!", "style": { "width": "254px", "display": "=if([$TaskDue]< @now && [$Progress] < 1, 'block', 'none')", "padding": "4px 0 4px 4px", "text-align": " Left", "heigth": "18px", "margin": "2px 0" }, "attributes": { "class": "sp-field-severity--blocked30 ms-fontSize-14 ms-fontColor-sharedRed20" } }, { "elmType": "div", "style": { "width": "24px", "padding": "6px 0", "text-align": " center", "heigth": "1.4em" }, "attributes": { "iconName": "Calendar" } }, { "elmType": "div", "_comment": "Task StartdDate in customCard", "txtContent": "=toLocaleDateString([$TaskStart])", "style": { "width": "127px", "padding": "2px 0", "text-align": " center", "border-radius": "14px", "margin": "2px 2px 0 0 " }, "attributes": { "class": "ms-fontSize-14 ms-bgColor-neutralLight" } }, { "elmType": "div", "_comment": "Task DueDate in customCard", "txtContent": "=toLocaleDateString([$TaskDue])", "style": { "width": "127px", "padding": "2px 0", "text-align": " center", "border-radius": "14px", "margin": "2px 2px 0 0 " }, "attributes": { "class": "ms-fontSize-14 ms-bgColor-neutralLight" } }, { "elmType": "div", "style": { "width": "24px", "padding": "6px 0", "text-align": " center", "heigth": "1.4em" }, "attributes": { "iconName": "Contact", "title": "='Assigned to : ' + [$AssignedToUser.title]" } }, { "elmType": "div", "txtContent": "[$AssignedToUser.title]", "style": { "width": "254px", "padding": "4px 0 4px 4px" }, "defaultHoverField": "[$AssignedToUser]" }, { "elmType": "div", "txtContent": "[$TaskDescription]", "style": { "font-style": "italic", "width": "254px", "padding": "4px 0 4px 4px" } } ] } } }, { "elmType": "div", "_comment": "flag for milestone", "txtContent": "", "style": { "position": "relative", "box-sizing": "border-box", "display": "=if([$TaskType] == 'Milestone', 'flex', 'none')", "z-index": "10", "top": "0.3em", "height": "3em", "left": "= (Number([$TaskStart])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])+43200000) * 100 + '%'", "margin-left": "-14px", "width": "28px" }, "attributes": { "iconName": "TriangleSolidDown12", "title": "=[$Title] + ' - ' + toLocaleDateString([$TaskStart]) ", "class": "ms-fontColor-themePrimary ms-fontSize-24" } }, { "elmType": "div", "_comment": "Milestone Date label", "txtContent": "=getDate([$TaskStart]) + '-' + if(getMonth([$TaskStart])==0,'Jan',if(getMonth([$TaskStart])==1,'Feb',if(getMonth([$TaskStart])==2,'Mar',if(getMonth([$TaskStart])==3,'Apr',if(getMonth([$TaskStart])==4,'May',if(getMonth([$TaskStart])==5,'Jun',if(getMonth([$TaskStart])==6,'Jul',if(getMonth([$TaskStart])==7,'Aug',if(getMonth([$TaskStart])==8,'Sep',if(getMonth([$TaskStart])==9,'Oct',if(getMonth([$TaskStart])==10,'Nov',if(getMonth([$TaskStart])==11,'Dec',''))))))))))))", "style": { "position": "absolute", "box-sizing": "border-box", "display": "=if([$TaskType] == 'Milestone' , 'flex', 'none')", "z-index": "3", "top": "10px", "height": "24px", "margin-left": "-60px", "left": "= (Number([$TaskStart])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])+43200000) * 100 + '%'", "width": "60px", "text-align": "right" }, "attributes": { "class": "sp-field-bold ms-fontSize-14" } }, { "elmType": "div", "_comment": "Progress percentagelabel", "txtContent": "=(Number[$Progress]) * 100 + '%'", "style": { "position": "absolute", "box-sizing": "border-box", "display": "=if([$TaskType] == 'Task' || [$TaskType] == '' , 'flex', 'none')", "z-index": "3", "top": "10px", "height": "24px", "margin-left": "=if((Number([$TaskDue])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])) <= 0.9 , '10px' , '-40px')", "left": "=if((Number([$TaskDue])-Number([$ProjectStart])+ 86400000) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) <= 0.9 , (Number([$TaskDue])-Number([$ProjectStart])+ 86400000) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 + '%' , (Number([$TaskStart])-Number([$ProjectStart])- 86400000) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 + '%' ) ", "width": "40px" }, "attributes": { "class": "sp-field-bold ms-fontSize-14" } } ] } ] } ] } }
[…] A new version of the Gantt Chart for SharePoint Online is available. […]
Hello! Thank you so much for this. I am working on incorporating this into our document review schedule for a yearly basis. Is there a way to segment the chart by quarters where there will be a “task” heading for each quarter? For example:
1Q2023
Document A
Document B
2Q2023
Document C
Document D
Or would it be best to just create a separate view for each quarter? Also the line specifying the current date seems to cut off halfway down the page. Thank you again!
Hi Shawn,
Sorry for my late reply.
I would create multiple views and filter per quarter, it is rather hard to use this together with a grouping option.
The CurrentDate is displayed at 800 px, just look for :
“height”: “800px”,
and increase the value.
Geert
HI
That is what I have been wanting for some time to put all the projects I run for a client in visual form.
One issue can I on one line have an appointment date, then the bar for construction in two different colours, and as per MS Project have a diamond for the appointment date?
Hi Andrew,
Having 2 options on the same line is not possible in this example.
It would be feasable to design it, by creating an extra AppointmentDate Column, because all information needs to be stored in the same item.
Geert
Hi Geert,
The Gantt Chart isn’t showing corret in neither Teams or SharePoint.
It look like some columns are compressed and others are too wide.
I can send you a screen shot.
/Martin
Hi Geert,
I deleted the entries I had made in the chart and did it over again and now everything looks fine.
Would it be possible to have a function that created a ‘compound bar’ where the overall duration was defined by columns for (say) overall_start and overall_end, with columns for activity_1_start, activity_1_end, activity_2_start, activity_2_end, activity_3_start, activity_3_end, a bit like this?
https://www.dropbox.com/scl/fi/c1x6o96s7id0z100ryezl/Screenshot-2023-10-19-at-15.48.44.png?rlkey=cb3fam325rpybi0h2x9x5u0kq&dl=0
Hi @Jim Allen,
Well this can certainly be done … but not in this sample.
To format this all activities need to be savedin the same row. That means you basically have to hardcode the number of columns, so like in your example you have to decide that there will always be three activities, which is most likely not the desired situation.
The other option is drop all activities in a single multiline text field (plain text, so no format), allowing you to loop through all the activities using a forEach, whilst storing the ProjectStart and ProjectEnd in two separate columns.
[Activity1Title];[Activity1Start;Activity1End]
I will keep the idea in mind and when I have more time try to write a sample. I will keep you informed.
grt Geert
Hi Geert,
That’s really helpful – thanks!
Actually, for me there will only ever be 3 activities which I think works pretty well in terms for many people in terms of (say) feasibility, design and implementation.
What I have is 8 date columns:
_Start_ (initial notification date)
StartA( e.g. feasibility start)
End A (e.g. feasibiity end)
StartB( e.g. design start)
End B (e.g. design end)
StartC( e.g. implementation start)
EndC (e.g. implementation end)
_End_ (estimated end date)
_End_99 (calculated field based on max value of _end_ and EndC
Activity C will always follow Activity B which will always follow Activity A.
If there is no data for the sub-activities, data in _Start_ and _End_99 becomes a ‘base progress bar’.
If there is any data in any of the sub-activities, it can then be ‘overlaid’ on the base progress bar when then acts as a rollup bar.
I think it’s far better to do this than to embed data for multiple activities in a single field – that would break other kinds of formatting and reporting.
It allows views to be created containing just dates for specific activities.
If it’s possible to do this, it should be possible to code as many fixed sub-activities as required I guess.
I think it would be such a useful feature for so many people.
Hi Geert,
Many thanks for this great development, which can be very useful. I have the same need than Jim Allen “how to display several sequential bars within the same row”.
Which part of the code would need to be duplicated to have this visual with fixed columns ?
Thanks.
Hi @michael,
At this moment I don’t have the time to develop an additional code.
Basically you are gonna need all the code that generates the bars, so in the code
starting from
“_comment”: “Ganttchart area”,
it creates the different chart elements
So if you copy the block starting from
“_comment”: “NormalTask Bar”,
and then adapt the references to $TaskStart and $TaskDue towards your own columns it should render correctly.
Sorry for not being able to create the code at this point, simply a matter of not having anough spare time.
Geert
@Geert
Thanks for the info. I will make a try.
Don’t worry, what you do and sharing it with others is already great.
Thanks @Michael, it is my pleasure.
Hi Geert,
I tried and managed to duplicate the first version of your code (not this new version) and it works : there are the sequential activities.
I still have one issue: the display of the bars are not on the same row, but below each other. I don’t know if this is because the start date of the following activity is the same as the end date of the previous one or if there is another reason ?
Do you eventually have an idea of what is going wrong and how to have the bars on the same row ?
Many thanks
Hi Michael,
The bars are in div’s and therefore the positioning woudld force it to move to the next row. so that would be normal.
Withou seeing you code… try to set the positioning to absolute and the top to 0 or something close to zero
position": "absolute",
"top": "0.6em"
Hi Geert,
I modified according to your suggestion “relative” => “absolute” with “top: 0.2” and it works. Many thanks for your help.
Have a nice day.
Hi, this is fabulous, thank you.
I have a problem though. I don’t get all the information visible as you can see in this screenshot.
https://www.dropbox.com/scl/fi/hrykqd3id6zozlxdwj8zd/Screenshot-2023-10-27-131320.png?rlkey=uhfivyfx4tnfxphabvk3b36i8&dl=0
What am I doing wrong?
Hi Jason,
Most Lively, you didn’t use the correct names when you created the columns.
This kind of formatting is always referring to the internal names of the columns. You can see these names when you go to the library settings and click on a column, you will see the internal name in the address bar.
Internal names can not be changed.
So you have to make them correct from. The beginning.
In the original article this is explained.
Does this help?
Geert
HI Geert,
I created a new project using those fields as you can see in the screenshot?
https://www.dropbox.com/scl/fi/2ny08cl3n8s93nwabas2r/Screenshot-2023-10-27-144126.png?rlkey=d22p7fawqxajc3w996z78n95z&dl=0
Can the list only contain the required fields or can additional fields be included but not impact the gantt view?
I experienced the same thing. Please kindly help
Hi Aldi,
It is almost always the same issue, you did not use the proper column names, and renaming columns doesn’t help.
When you create a column in SharePoint an internal name is assigned, this name is not always the same thing as what you typed, plus this name will never change. So if you made a mistake with a specific column… delete it en create it again.
Column names are also case sensitive.
Geert
Hi Jason,
You can have as many columns as you like withou impacting the Gantt Chart?
The only thing you have to take into account is that the gantt chart columns are active in the view.
grt Geert
Hi, so I tried using a blank list and it seems to work. I was trying to upload a spreadsheet using columns named as required but looks like there is some residual that makes the code not work when applying to a list created from a spreadsheet
Hi Jason,
Importing directly from Excel, seems to me as a bad idea because you have no control ove the column names.
grt Geert
Hello Geert,
Can the code recognize project start time and end time in hh:mm format?
Thank you,
Alvin
Hi Alvin,
No not by default.
But if you are willing to use the SharePoint dd/mm/yyyy hh:mm or mm/dd/yyyy hh:mm the code can be adopted to your needs.
You probably want to change the toLocaleDateString() instances to toLocaleString() or toLocaleTimeString().
In the code you see a few times the number 8640000 this is the number of milliseconds in a day. If you want to work with minutes you probably need to change it to 6000 (the number milliseconds per minute)
I hope this helps
Grt Geert
Hello, I appreciate your valuable collaboration since applying the format does not work for me. I have changed the column names to the internal name but it doesn’t work either. I do not know what I’m doing wrong.
https://1drv.ms/i/s!Altf2rSsMhb6x2QGXKtRA6Jua-Oc?e=sDIiYF
Thank you,
Jose Manuel
Hi Jose Manuel,
You can’t actually change the internal names. The internal names are assigned tje moment you create the column.
So can you create a new sample and start using the proper columnnames from the start.
You can actually see the internal columnnames when you go to the list settings and click on the column. The addressbar shows the internalcolumnname at the end of url.
Let me know if this helpt.
Geert
Hi Geert, thank you very much, I followed your instructions and it works OK.
Thanks,
Jose Manuel
Perfect.
Glad I could help.
Geert
Amazing work… This is exactly what I need to get a jump start on my custom list!
I made some fairly hefty changes. Mine allows for groups and it is also a static view. The items on the screen will move to the left as time goes by. It’s currently set to -30 days and +60 days from current date. This range is currently set in the JSON, but I plan to make this a bit more user friendly in the future.
I just started this last week and still plan to add some additional functionality to have items filter out once they are completed and the due date is beyond the past 30 days. I would gladly share if anyone is interested in my version.
I created a a couple additional columns. One to group tasks to have multiple projects. The other is a calculated field to determine if the progress of the task is on target or not.
Here is a link to a screenshots I shared on Imgur.
https://imgur.com/a/yAPHHaF
Hi Jorge,
That is a very nice result.
I am always interested in other code samples and the extra columns you have used. And to see how you tackled some of the challenges.
It would be really awesome if you would share it on github.
Either as a new example, or as a second code in the existing example that I started there: https://github.com/pnp/List-Formatting/tree/master/view-samples/project-gantt-chart
If you don’t know how to start I can help you out, or bring you into contact with some of the moderators there.
Geert
Happy to! I added it as a comment. I tried to create a branch, but wasn’t able to do so. I’ll also add as a second code.
Here is the link to the comment.
https://github.com/pnp/List-Formatting/issues/759#issuecomment-1943883815
To be honest, I’m not very experienced with GitHub, besides just finding some samples.
Not sure if it’s user error or permissions, but I’m unable to create a new fork. For now, I created a new issue specific to my changes rather than posting under an older issue.
If you can offer any help, I would really appreciate it. If not, guess I can create a separate project if needed.
Link to new Issue with my updates.
https://github.com/pnp/List-Formatting/issues/772
Updated JSON script to calculate the Expected Progress vs. a Calculated Column. Expected calculated column is no longer required.
Changes are reflected in the same issue link.
https://github.com/pnp/List-Formatting/issues/772
Hi Jorge, your build on Geert’s awesome work sounds really useful to me.
I want to be able to use this view to visualise our portfolio of work, instead of individual tasks within a project. So, having the option to group line items together would be a big help.
I would love to get a copy of your code, if you’re happy to share, either directly or via github.
Of course! I added a comment in the GitHub with the settings and sample JSON.
Here is the link to the comment.
https://github.com/pnp/List-Formatting/issues/759#issuecomment-1943883815
Feel free to reply here or on the GitHub comment if you have any questions.
If you decided to use the updated version I created, please use the JSON from this link instead.
https://github.com/pnp/List-Formatting/issues/772
I removed the calculated column due to issues with using Today() in the calculations. That function has been moved into the JSON script to ensure the expected percentage remains current and accurate.
Dear Geert, this solution is what I am looking for. However, despite giving the correct internal names, as you described, from the moment of creation of columns I cannot have a correct view. See the view I end up with here:
https://drive.google.com/file/d/1YLQNDz8mQXyWMD1PWt-mHPJJBnKfxAKJ/view?usp=drive_link
I first formatted the view as you explain and then started to add each element and still does not work, also I did the other way around (first the element list and then format the view).
I am not sure if working in a mac environment has something to do with it.
Help will be appreciated!
Hi Diana,
The order in which you add the view or the elements doesn’t matter.
I have requested access to your drive link.
I can not imagine that working on a mac breaks the view.
Geert
Hi Diana,
Thanks for sharing the picture.
I am trying to create the issue, and one way I am capable of doing so is by not enetering the ProjectStart and the ProjectEnd for every task.
This is really necessary, because individual rows in a list, “don’t see” the contents of other rows.
Second, it looks like your ProjectStart is not recognized properly, since the currentday should be moved towards the middle.
Third, I noticed that the progress is displayed as 50% % which is a little strange as well. Is it really a numerical column with a percentage display?
Just wondering, heva you tested on different browsers and machines? Or you using google translate on top of all your pages?
Hope this helps a little.
Geert
Hi Gert, I am also having the same problem as Diana, on a PC, that is the bar is small and not representative of the value
Hi Geert, many thanks for taking the time to check this. I have tried another browser and it does change the look compare to what I sent you, however still not totally correct. I am not sure what else to try, as I have not translator on the webpage and created the columns as specified in your table.
Hi Diana,
Have you tried to create a complete new list?
I will sent you also a direct mail.
Geert
I was having a similar challenge but decided to change my approach. This is not MS Project so we need to stop asking for it to operate in that way.
I changed my project start and due dates for all items to run between 1st Jan 2024 and 31st Dec 2024. I then amended the task/milestone dates to those within the year. Now my Gantt looks good. Sure, it runs for a year only, but now I have the shape, I can extend out if needed.
Assuming a person uses the list for a single project, your project start and due dates will be the same for each task anyway.
Hi Mark,
Yes indeed, it is impossible to make it work like a Project tool.
I had to and wanted to work within the boundaries of MS Lists.
The problem of Alan and Diana is, I think, somewhat different because they are not able to make it work.
Which is very unfortunate, but since I am not capable of reproducing the problem, I don’t see how to solve their issue.
Kind regards,
Geert
Good-day Geert,
Thank you so much for sharing this wonderful formatting tool! I am having a slight issue where the progress bars do not line-up from end-to-end. There always seems to be an overlap, or space between task progress bars. Please see the links below for examples. Would you have any idea why this would be the case?
https://drive.google.com/file/d/1Zyxib7e_nXl3XZ6dO9s7j-x0_mRBYmUE/view?usp=drive_link
https://drive.google.com/file/d/16Z0uAPQpE8_HrUbT8mnY1yaicOONWeVo/view?usp=drive_link
Thank you
George
Hi George,
It seems to me that the projectStart and the ProjectEnd date fot both tasks are not the same.
Could you double check on those two columns.
Basically the individual taskstart and Taskend dates are compared towards the projectStart and ProjectEnd.
So to make sure those are aligned the ProjectStart and the ProjectEnd need to be the same for each row you have.
I am not sure this is the reason, but it should explain why the second task End after the shown projectend date.
Geert
Geert,
Thank you for looking at this! I’m pretty sure ProjectStart and ProjectEnd dates were in line. Please see the screen shot:
https://drive.google.com/file/d/1KGsFJvdam3KH_DJiHIX3A9c0F4NvNSZZ/view?usp=sharing
Is there something else that might be causing the formatting issue?
Thank you
George
Hello Geert,
I tried creating a new list and re-copying your JSON to see if something may have been interfering with the proper operation. I obtained the same results. I know that some time ago, this was working properly, and I can’t figure out what may have gone wrong. I did notice the Microsoft had made some visual changes to the SharePoint UI however, I do not know what else may have gone on in the background. Please see the screen shots of the new list/tasks, and timeline results below:
https://drive.google.com/file/d/1TaNrU14Nn2TVaN7V3bW0_1XnnE53g5il/view?usp=drive_link
https://drive.google.com/file/d/1OWIWLJ_uNbGufQI_DUPKheOnbxgy-vuc/view?usp=drive_link
Thank you
George
Hi George,
Okay, I see now.
I think there is an issue with the calculation and how it treats days.
I think that the issue was there already since the beginning, but since your total duration of the project is very short, the issue is more noticeable.
I will try to get you an update tomorrow.
Geert
Hello Geert,
Thank you for figuring this out – much appreciated! I look forward to your update!
Best regards,
George Minich
Hi George,
I have fixed and documented the issue.
The position of the bar chart was based on
“left”: “= (Number([$TaskStart])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])) * 100 + ‘%'”
But since the ProjectDue (and the Taskdue ) are actually refering to the end of the day I should have added one day to the denominator.
meaning
“left”: “= (Number([$TaskStart])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 + ‘%'”,
This has been updated on various locations in the code
“left”: “= (Number([$TaskStart])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 + ‘%'”,
“left”: “= (Number([$TaskStart])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 + ‘%'”,
“left”: “= (Number([$TaskStart])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 + ‘%'”,
“left”: “= (Number([$TaskStart])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])+43200000) * 100 + ‘%'”,
“left”: “= (Number([$TaskStart])-Number([$ProjectStart])) / (Number([$ProjectDue])-Number([$ProjectStart])+43200000) * 100 + ‘%'”,
“left”: “=if((Number([$TaskDue])-Number([$ProjectStart])+ 86400000) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) <= 0.9 , (Number([$TaskDue])-Number([$ProjectStart])+ 86400000) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 + '%' , (Number([$TaskStart])-Number([$ProjectStart])- 86400000) / (Number([$ProjectDue])-Number([$ProjectStart])+ 86400000) * 100 + '%' ) ",
Hello Geert,
Thank you for making this fix. It looks much better now!!
https://drive.google.com/file/d/1UPRImeSXD5lyJk8YwMkd1G0KLq1ggot9/view?usp=drive_link
Best regards,
George Minich
Thanks for this great work
One question
The milestone icon is shown as a “calendar icon (21)”
Can i change this to an icon “milestone”
Thx
Hello Hans,
Actually the milstone is shown as a triangle, no?
“iconName”: “TriangleSolidDown12”,
Anyway, you can change that icon into anything you like, as long as it is in the list with the Microsoft Fabric icons, you can find that list here:
https://www.flicon.io/
Unfortunately, a diamond shape, (rotated square) which is generally used for milestones, is not available.
And CSS rotation is not supported, as far as I know and tested.
Kind regardsn
Geert
Hi Geert,
Could you please tell me on the code where I can add the AssigntoUser in the left bar of the Gantt chart.
Good job by the way!
Regards,
Charles
Hi Charles,
Just look for the line
“_comment”: “tasktitle”,
There is not really a lot of space to add the AssignedToUser
If you create new div element underneath that element.
But the row height is hardcoded, so that needs to change too.
The current row height is 52 and is shown on row nuumber 8, you just have too adjust it to whatever fits.
I hope this helps.
Regards,
Geert