mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-11-01 03:14:10 +01:00
Merge pull request #6479 from Shahir-47/feature/3250/add_vertline_to_gantt_plot
feat: Add vertical line to gantt plot at specified time
This commit is contained in:
5
.changeset/add-vert-tag-bar-chart.md
Normal file
5
.changeset/add-vert-tag-bar-chart.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': minor
|
||||
---
|
||||
|
||||
feat: Add Vertical Line To Gantt Plot At Specified Time
|
||||
@@ -358,6 +358,23 @@ describe('Gantt diagram', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should render a gantt diagram with a vert tag', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
gantt
|
||||
title A Gantt Diagram
|
||||
dateFormat ss
|
||||
axisFormat %Ss
|
||||
|
||||
section Section
|
||||
A task : a1, 00, 6s
|
||||
Milestone : vert, 01,
|
||||
section Another
|
||||
Task in sec : 06, 3s
|
||||
another task : 3s
|
||||
`
|
||||
);
|
||||
});
|
||||
it('should render a gantt diagram with tick is 2 milliseconds', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
|
||||
@@ -229,6 +229,30 @@ gantt
|
||||
Final milestone : milestone, m2, 18:08, 4m
|
||||
```
|
||||
|
||||
### Vertical Markers
|
||||
|
||||
The `vert` keyword lets you add vertical lines to your Gantt chart, making it easy to highlight important dates like deadlines, events, or checkpoints. These markers extend across the entire chart and are positioned based on the date you provide. Unlike milestones, vertical markers don’t take up a row. They’re purely visual reference points that help break up the timeline and make important moments easier to spot.
|
||||
|
||||
```mermaid-example
|
||||
gantt
|
||||
dateFormat HH:mm
|
||||
axisFormat %H:%M
|
||||
Initial vert : vert, v1, 17:30, 2m
|
||||
Task A : 3m
|
||||
Task B : 8m
|
||||
Final vert : vert, v2, 17:58, 4m
|
||||
```
|
||||
|
||||
```mermaid
|
||||
gantt
|
||||
dateFormat HH:mm
|
||||
axisFormat %H:%M
|
||||
Initial vert : vert, v1, 17:30, 2m
|
||||
Task A : 3m
|
||||
Task B : 8m
|
||||
Final vert : vert, v2, 17:58, 4m
|
||||
```
|
||||
|
||||
## Setting dates
|
||||
|
||||
`dateFormat` defines the format of the date **input** of your gantt elements. How these dates are represented in the rendered chart **output** are defined by `axisFormat`.
|
||||
|
||||
@@ -33,7 +33,7 @@ let sections = [];
|
||||
let tasks = [];
|
||||
let currentSection = '';
|
||||
let displayMode = '';
|
||||
const tags = ['active', 'done', 'crit', 'milestone'];
|
||||
const tags = ['active', 'done', 'crit', 'milestone', 'vert'];
|
||||
let funs = [];
|
||||
let inclusiveEndDates = false;
|
||||
let topAxis = false;
|
||||
@@ -422,7 +422,7 @@ const compileData = function (prevTask, dataStr) {
|
||||
|
||||
const task = {};
|
||||
|
||||
// Get tags like active, done, crit and milestone
|
||||
// Get tags like active, done, crit, milestone, and vert
|
||||
getTaskTags(data, task, tags);
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
@@ -470,7 +470,7 @@ const parseData = function (prevTaskId, dataStr) {
|
||||
|
||||
const task = {};
|
||||
|
||||
// Get tags like active, done, crit and milestone
|
||||
// Get tags like active, done, crit, milestone, and vert
|
||||
getTaskTags(data, task, tags);
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
@@ -538,6 +538,7 @@ export const addTask = function (descr, data) {
|
||||
rawTask.done = taskInfo.done;
|
||||
rawTask.crit = taskInfo.crit;
|
||||
rawTask.milestone = taskInfo.milestone;
|
||||
rawTask.vert = taskInfo.vert;
|
||||
rawTask.order = lastOrder;
|
||||
|
||||
lastOrder++;
|
||||
@@ -570,6 +571,7 @@ export const addTaskOrg = function (descr, data) {
|
||||
newTask.done = taskInfo.done;
|
||||
newTask.crit = taskInfo.crit;
|
||||
newTask.milestone = taskInfo.milestone;
|
||||
newTask.vert = taskInfo.vert;
|
||||
lastTask = newTask;
|
||||
tasks.push(newTask);
|
||||
};
|
||||
|
||||
@@ -231,10 +231,11 @@ export const draw = function (text, id, version, diagObj) {
|
||||
* @param w
|
||||
*/
|
||||
function drawRects(theArray, theGap, theTopPad, theSidePad, theBarHeight, theColorScale, w) {
|
||||
// Sort theArray so that tasks with `vert` come last
|
||||
theArray.sort((a, b) => (a.vert === b.vert ? 0 : a.vert ? 1 : -1));
|
||||
// Get unique task orders. Required to draw the background rects when display mode is compact.
|
||||
const uniqueTaskOrderIds = [...new Set(theArray.map((item) => item.order))];
|
||||
const uniqueTasks = uniqueTaskOrderIds.map((id) => theArray.find((item) => item.order === id));
|
||||
|
||||
// Draw background rects covering the entire width of the graph, these form the section rows.
|
||||
svg
|
||||
.append('g')
|
||||
@@ -259,7 +260,8 @@ export const draw = function (text, id, version, diagObj) {
|
||||
}
|
||||
}
|
||||
return 'section section0';
|
||||
});
|
||||
})
|
||||
.enter();
|
||||
|
||||
// Draw the rects representing the tasks
|
||||
const rectangles = svg.append('g').selectAll('rect').data(theArray).enter();
|
||||
@@ -289,15 +291,26 @@ export const draw = function (text, id, version, diagObj) {
|
||||
.attr('y', function (d, i) {
|
||||
// Ignore the incoming i value and use our order instead
|
||||
i = d.order;
|
||||
if (d.vert) {
|
||||
return conf.gridLineStartPadding;
|
||||
}
|
||||
return i * theGap + theTopPad;
|
||||
})
|
||||
.attr('width', function (d) {
|
||||
if (d.milestone) {
|
||||
return theBarHeight;
|
||||
}
|
||||
if (d.vert) {
|
||||
return 0.08 * theBarHeight;
|
||||
}
|
||||
return timeScale(d.renderEndTime || d.endTime) - timeScale(d.startTime);
|
||||
})
|
||||
.attr('height', theBarHeight)
|
||||
.attr('height', function (d) {
|
||||
if (d.vert) {
|
||||
return taskArray.length * (conf.barHeight + conf.barGap) + conf.barHeight * 2;
|
||||
}
|
||||
return theBarHeight;
|
||||
})
|
||||
.attr('transform-origin', function (d, i) {
|
||||
// Ignore the incoming i value and use our order instead
|
||||
i = d.order;
|
||||
@@ -354,6 +367,9 @@ export const draw = function (text, id, version, diagObj) {
|
||||
if (d.milestone) {
|
||||
taskClass = ' milestone ' + taskClass;
|
||||
}
|
||||
if (d.vert) {
|
||||
taskClass = ' vert ' + taskClass;
|
||||
}
|
||||
|
||||
taskClass += secNum;
|
||||
|
||||
@@ -377,10 +393,13 @@ export const draw = function (text, id, version, diagObj) {
|
||||
let endX = timeScale(d.renderEndTime || d.endTime);
|
||||
if (d.milestone) {
|
||||
startX += 0.5 * (timeScale(d.endTime) - timeScale(d.startTime)) - 0.5 * theBarHeight;
|
||||
}
|
||||
if (d.milestone) {
|
||||
endX = startX + theBarHeight;
|
||||
}
|
||||
|
||||
if (d.vert) {
|
||||
return timeScale(d.startTime) + theSidePad;
|
||||
}
|
||||
|
||||
const textWidth = this.getBBox().width;
|
||||
|
||||
// Check id text width > width of rectangle
|
||||
@@ -396,6 +415,9 @@ export const draw = function (text, id, version, diagObj) {
|
||||
})
|
||||
.attr('y', function (d, i) {
|
||||
// Ignore the incoming i value and use our order instead
|
||||
if (d.vert) {
|
||||
return conf.gridLineStartPadding + taskArray.length * (conf.barHeight + conf.barGap) + 60;
|
||||
}
|
||||
i = d.order;
|
||||
return i * theGap + conf.barHeight / 2 + (conf.fontSize / 2 - 2) + theTopPad;
|
||||
})
|
||||
@@ -406,6 +428,7 @@ export const draw = function (text, id, version, diagObj) {
|
||||
if (d.milestone) {
|
||||
endX = startX + theBarHeight;
|
||||
}
|
||||
|
||||
const textWidth = this.getBBox().width;
|
||||
|
||||
let classStr = '';
|
||||
@@ -445,6 +468,10 @@ export const draw = function (text, id, version, diagObj) {
|
||||
taskType += ' milestoneText';
|
||||
}
|
||||
|
||||
if (d.vert) {
|
||||
taskType += ' vertText';
|
||||
}
|
||||
|
||||
// Check id text width > width of rectangle
|
||||
if (textWidth > endX - startX) {
|
||||
if (endX + textWidth + 1.5 * conf.leftPadding > w) {
|
||||
|
||||
@@ -237,6 +237,16 @@ const getStyles = (options) =>
|
||||
fill: ${options.taskTextDarkColor} !important;
|
||||
}
|
||||
|
||||
.vert {
|
||||
stroke: ${options.vertLineColor};
|
||||
}
|
||||
|
||||
.vertText {
|
||||
font-size: 15px;
|
||||
text-anchor: middle;
|
||||
fill: ${options.vertLineColor} !important;
|
||||
}
|
||||
|
||||
.activeCritText0,
|
||||
.activeCritText1,
|
||||
.activeCritText2,
|
||||
|
||||
@@ -150,6 +150,20 @@ gantt
|
||||
Final milestone : milestone, m2, 18:08, 4m
|
||||
```
|
||||
|
||||
### Vertical Markers
|
||||
|
||||
The `vert` keyword lets you add vertical lines to your Gantt chart, making it easy to highlight important dates like deadlines, events, or checkpoints. These markers extend across the entire chart and are positioned based on the date you provide. Unlike milestones, vertical markers don’t take up a row. They’re purely visual reference points that help break up the timeline and make important moments easier to spot.
|
||||
|
||||
```mermaid-example
|
||||
gantt
|
||||
dateFormat HH:mm
|
||||
axisFormat %H:%M
|
||||
Initial vert : vert, v1, 17:30, 2m
|
||||
Task A : 3m
|
||||
Task B : 8m
|
||||
Final vert : vert, v2, 17:58, 4m
|
||||
```
|
||||
|
||||
## Setting dates
|
||||
|
||||
`dateFormat` defines the format of the date **input** of your gantt elements. How these dates are represented in the rendered chart **output** are defined by `axisFormat`.
|
||||
|
||||
@@ -98,6 +98,7 @@ class Theme {
|
||||
this.critBorderColor = this.critBorderColor || '#ff8888';
|
||||
this.critBkgColor = this.critBkgColor || 'red';
|
||||
this.todayLineColor = this.todayLineColor || 'red';
|
||||
this.vertLineColor = this.vertLineColor || 'navy';
|
||||
this.taskTextColor = this.taskTextColor || this.textColor;
|
||||
this.taskTextOutsideColor = this.taskTextOutsideColor || this.textColor;
|
||||
this.taskTextLightColor = this.taskTextLightColor || this.textColor;
|
||||
|
||||
@@ -79,6 +79,7 @@ class Theme {
|
||||
this.critBkgColor = '#E83737';
|
||||
this.taskTextDarkColor = 'calculated';
|
||||
this.todayLineColor = '#DB5757';
|
||||
this.vertLineColor = '#00BFFF';
|
||||
|
||||
/* C4 Context Diagram variables */
|
||||
this.personBorder = this.primaryBorderColor;
|
||||
|
||||
@@ -88,6 +88,7 @@ class Theme {
|
||||
this.critBorderColor = 'calculated';
|
||||
this.critBkgColor = 'calculated';
|
||||
this.todayLineColor = 'calculated';
|
||||
this.vertLineColor = 'calculated';
|
||||
|
||||
this.sectionBkgColor = rgba(102, 102, 255, 0.49);
|
||||
this.altSectionBkgColor = 'white';
|
||||
@@ -107,6 +108,7 @@ class Theme {
|
||||
this.critBorderColor = '#ff8888';
|
||||
this.critBkgColor = 'red';
|
||||
this.todayLineColor = 'red';
|
||||
this.vertLineColor = 'navy';
|
||||
|
||||
/* C4 Context Diagram variables */
|
||||
this.personBorder = this.primaryBorderColor;
|
||||
|
||||
@@ -81,6 +81,7 @@ class Theme {
|
||||
this.critBorderColor = '#ff8888';
|
||||
this.critBkgColor = 'red';
|
||||
this.todayLineColor = 'red';
|
||||
this.vertLineColor = '#00BFFF';
|
||||
|
||||
/* C4 Context Diagram variables */
|
||||
this.personBorder = this.primaryBorderColor;
|
||||
|
||||
@@ -93,6 +93,7 @@ class Theme {
|
||||
this.critBkgColor = 'calculated';
|
||||
this.critBorderColor = 'calculated';
|
||||
this.todayLineColor = 'calculated';
|
||||
this.vertLineColor = 'calculated';
|
||||
|
||||
/* C4 Context Diagram variables */
|
||||
this.personBorder = this.primaryBorderColor;
|
||||
@@ -209,6 +210,7 @@ class Theme {
|
||||
this.critBorderColor = darken(this.critBkgColor, 10);
|
||||
|
||||
this.todayLineColor = this.critBkgColor;
|
||||
this.vertLineColor = this.critBkgColor;
|
||||
|
||||
/* Architecture Diagram variables */
|
||||
this.archEdgeColor = this.lineColor;
|
||||
|
||||
Reference in New Issue
Block a user