diff --git a/cypress/integration/rendering/gantt.spec.js b/cypress/integration/rendering/gantt.spec.js index a0c2dbcb9e..d439829ffb 100644 --- a/cypress/integration/rendering/gantt.spec.js +++ b/cypress/integration/rendering/gantt.spec.js @@ -548,6 +548,247 @@ describe('Gantt diagram', () => { ); }); + it('should render when there is a date-only dateRange with both start and end dates', () => { + imgSnapshotTest( + ` + gantt + title GANTT with date-only startDate and endDate dateRange + dateFormat YYYY-MM-DD + dateRange 2022-01-01,2022-03-31 + axisFormat %m-%d + tickInterval 1week + section DB Clean + Clean: 2022-01-01, 2d + Clean: 2022-01-05, 3d + Clean: 2022-01-30, 6d + Clean: 2022-02-02, 3d + Clean: 2022-02-15, 6d + Clean: 2022-03-10, 1d + Clean: 2022-03-29, 1d + section Sessions + A: 2022-01-01, 3d + B: 2022-01-07, 4d + C: 2022-01-31, 5d + D: 2022-02-03, 6d + E: 2022-02-22, 1d + F: 2022-02-25, 2d + G: 2022-03-01, 12d + H: 2022-03-19, 8d + I: 2022-03-23, 7d + `, + {} + ); + }); + + it('should render when there is a date-only dateRange with a startDate only', () => { + imgSnapshotTest( + ` + gantt + title GANTT with date-only startDate dateRange + dateFormat YYYY-MM-DD + dateRange 2022-01-01 + axisFormat %m-%d + tickInterval 1week + section DB Clean + Clean: 2022-01-01, 2d + Clean: 2022-01-05, 3d + Clean: 2022-01-30, 6d + Clean: 2022-02-02, 3d + Clean: 2022-02-15, 6d + Clean: 2022-03-10, 1d + Clean: 2022-03-29, 1d + section Sessions + A: 2022-01-01, 3d + B: 2022-01-07, 4d + C: 2022-01-31, 5d + D: 2022-02-03, 6d + E: 2022-02-22, 1d + F: 2022-02-25, 2d + G: 2022-03-01, 12d + H: 2022-03-19, 8d + I: 2022-03-23, 7d + `, + {} + ); + }); + + it('should render when there is a date-only dateRange with an endDate only', () => { + imgSnapshotTest( + ` + gantt + title GANTT with date-only endDate dateRange + dateFormat YYYY-MM-DD + dateRange ,2022-03-31 + axisFormat %m-%d + tickInterval 1week + section DB Clean + Clean: 2022-01-01, 2d + Clean: 2022-01-05, 3d + Clean: 2022-01-30, 6d + Clean: 2022-02-02, 3d + Clean: 2022-02-15, 6d + Clean: 2022-03-10, 1d + Clean: 2022-03-29, 1d + section Sessions + A: 2022-01-01, 3d + B: 2022-01-07, 4d + C: 2022-01-31, 5d + D: 2022-02-03, 6d + E: 2022-02-22, 1d + F: 2022-02-25, 2d + G: 2022-03-01, 12d + H: 2022-03-19, 8d + I: 2022-03-23, 7d + `, + {} + ); + }); + + it('should render when there is a date-only dateRange with startDate and endDate, with tasks before and after the dateRange', () => { + imgSnapshotTest( + `gantt + title Gantt diagram with date-only date range and tasks before and after the date range + dateFormat YYYY-MM-DD + dateRange 2022-01-01,2022-03-31 + axisFormat %m-%d + tickInterval 1week + section Section + A task before : 2021-12-01, 20d + A task starting before and completing within: 2021-12-25, 10d + A task within : 2022-01-15, 40d + A task starting within and ending after: 2022-03-25, 10d + A task after : 2022-04-01, 20d + section Another + A task before : 2021-11-01, 40d + A task within : 2022-02-15, 30d + A task after : 2023-04-01, 20d + `, + {} + ); + }); + + it('should render when there is a time-only dateRange with both start and end dates', () => { + imgSnapshotTest( + ` + gantt + title GANTT with time-only startDate and endDate dateRange + dateFormat HH:mm:ss + dateRange 12:30:00,13:30:00 + axisFormat %Hh%M + section DB Clean + Clean: 12:30:00, 12m + Clean: 13:00:00, 8m + Clean: 13:20:00, 9m + section Sessions + B: 12:30:00, 12m + C: 13:05:00, 12m + D: 13:06:00, 33m + E: 13:15:00, 55m + F: 13:20:00, 10m + `, + {} + ); + }); + + it('should render when there is a time-only dateRange with a startDate only', () => { + imgSnapshotTest( + ` + gantt + title GANTT with time-Only startDate dateRange + dateFormat HH:mm:ss + dateRange 12:30:00 + axisFormat %Hh%M + section DB Clean + Clean: 12:30:00, 12m + Clean: 13:00:00, 8m + Clean: 13:30:00, 9m + Clean: 14:00:00, 13m + Clean: 14:30:00, 10m + Clean: 15:00:00, 11m + section Sessions + A: 12:30:00, 12m + B: 13:05:00, 12m + C: 13:06:00, 33m + D: 13:15:00, 55m + E: 13:20:00, 12m + F: 13:32:00, 18m + G: 13:50:00, 20m + H: 14:10:00, 10m + `, + {} + ); + }); + + it('should render when there is a time-only dateRange with an endDate only', () => { + imgSnapshotTest( + ` + gantt + title GANTT with time-Only endDate dateRange + dateFormat HH:mm:ss + dateRange ,13:30:00 + axisFormat %Hh%M + section DB Clean + Clean: 12:00:00, 10m + Clean: 12:30:00, 12m + Clean: 13:00:00, 8m + section Sessions + A: 12:00:00, 63m + B: 12:30:00, 12m + C: 13:05:00, 12m + D: 13:06:00, 33m + E: 13:15:00, 55m + F: 13:20:00, 10m + `, + {} + ); + }); + + it('should render when there is a time-only dateRange with startDate and endDate, with tasks before and after the dateRange', () => { + imgSnapshotTest( + `gantt + title Gantt diagram with time-only date range and tasks before and after the date range + dateFormat HH:mm:ss + dateRange 12:00:00, 18:00:00 + axisFormat %Hh%M + tickInterval 1week + section Section + A task before : 11:30:00, 25m + A task starting before and completing within: 11:00:00, 2h + A task within : 12:05:00, 60m + A task starting within and ending after: 17:30:00, 75m + A task after : 18:30:00, 30m + section Another + A task before : 10:00:00, 119m + A task within : 12:00:00, 6h + A task after : 20:00:00, 4h + `, + {} + ); + }); + + it('should render when there is a date and time dateRange, with both start and end dates, and tasks before and after the dateRange', () => { + imgSnapshotTest( + `gantt + title Gantt diagram with time-only date range and tasks before and after the date range + dateFormat DD-MM-YYYY HH:mm:ss + dateRange 01-01-2021 12:00:00, 08-01-2021 18:00:00 + axisFormat %m-%d + tickInterval 1week + section Section + A task before : 01-01-2021 11:30:00, 25m + A task starting before and completing within: 01-01-2021 10:00:00, 2d + A task within : 02-01-2021 12:05:00, 4d + A task starting within and ending after: 05-01-2021 12:30:00, 4d + A task after : 08-01-2021 18:30:00, 30m + section Another + A task before : 31-12-2020 10:00:00, 1d + A task within : 01-01-2021 12:00:00, 7d + A task after : 15-01-2021 12:00:00, 1d + `, + {} + ); + }); + // TODO: fix it // // This test is skipped deliberately diff --git a/cypress/integration/rendering/theme.spec.js b/cypress/integration/rendering/theme.spec.js index 1965f8c99b..176be4825e 100644 --- a/cypress/integration/rendering/theme.spec.js +++ b/cypress/integration/rendering/theme.spec.js @@ -286,8 +286,8 @@ erDiagram accTitle: This is a title accDescr: This is a description - dateFormat :YYYY-MM-DD - title :Adding GANTT diagram functionality to mermaid + dateFormat YYYY-MM-DD + title Adding GANTT diagram functionality to mermaid excludes :excludes the named dates/days from being included in a charted task.. section A section Completed task :done, des1, 2014-01-06,2014-01-08 diff --git a/docs/community/contributing.md b/docs/community/contributing.md index c78a3cb40f..849778e49f 100644 --- a/docs/community/contributing.md +++ b/docs/community/contributing.md @@ -357,6 +357,12 @@ it('should render forks and joins', () => { }); ``` +**Verifying Snapshots** + +```sh +pnpm e2e open cypress/snapshots +``` + diff --git a/docs/syntax/gantt.md b/docs/syntax/gantt.md index 31bac5e29a..74ab479587 100644 --- a/docs/syntax/gantt.md +++ b/docs/syntax/gantt.md @@ -338,6 +338,36 @@ gantt > **Warning** > `millisecond` and `second` support was added in v10.3.0 +### Date Ranges (v\+) + +The default behavior is to set the x range to include all of the data in the chart. You can override +the range by specifying `dateRange`. Any tasks falling outside the specified range will be removed +from the plot, and tasks overlapping with the boundaries will be truncated. The `dateRange` command +should follow the `dateFormat` and use the same format. + +```mermaid-example +gantt + dateFormat HH:mm + dateRange 13:00, 14:00 + axisFormat %H:%M + Task A : 13:24, 13:39 + Task B : 13:50, 14:35 + Dropped : 14:01, 14:20 +``` + +```mermaid +gantt + dateFormat HH:mm + dateRange 13:00, 14:00 + axisFormat %H:%M + Task A : 13:24, 13:39 + Task B : 13:50, 14:35 + Dropped : 14:01, 14:20 +``` + +It is also possible to specify only a lower bound using `dateRange ` or only an upper bound +using `dateRange ,`. + ## Output in compact mode The compact mode allows you to display multiple tasks in the same row. Compact mode can be enabled for a gantt chart by setting the display mode of the graph via preceding YAML settings. diff --git a/packages/mermaid/src/diagrams/gantt/ganttDb.js b/packages/mermaid/src/diagrams/gantt/ganttDb.js index 15c7fab979..269161385b 100644 --- a/packages/mermaid/src/diagrams/gantt/ganttDb.js +++ b/packages/mermaid/src/diagrams/gantt/ganttDb.js @@ -22,7 +22,10 @@ dayjs.extend(dayjsCustomParseFormat); dayjs.extend(dayjsAdvancedFormat); const WEEKEND_START_DAY = { friday: 5, saturday: 6 }; -let dateFormat = ''; +let dateFormat = 'YYYY-MM-DD'; +let dateRange = ''; +let startDateRange = ''; +let endDateRange = ''; let axisFormat = ''; let tickInterval = undefined; let todayMarker = ''; @@ -53,6 +56,9 @@ export const clear = function () { lastTaskID = undefined; rawTasks = []; dateFormat = ''; + dateRange = ''; + startDateRange = ''; + endDateRange = ''; axisFormat = ''; displayMode = ''; tickInterval = undefined; @@ -104,6 +110,22 @@ export const endDatesAreInclusive = function () { return inclusiveEndDates; }; +export const setDateRange = function (txt) { + dateRange = txt; + + if (!dateRange) { + return; + } + const [startStr, endStr] = dateRange.split(','); + + if (startStr) { + startDateRange = getStartDate(undefined, dateFormat, startStr); + } + if (endStr) { + endDateRange = getEndDate(undefined, dateFormat, endStr); + } +}; + export const enableTopAxis = function () { topAxis = true; }; @@ -124,6 +146,34 @@ export const getDateFormat = function () { return dateFormat; }; +export const getDateRange = function () { + return dateRange; +}; + +export const getStartRange = function () { + if (startDateRange) { + return startDateRange; + } + if (getTasks().length > 0) { + return getTasks().reduce((min, task) => { + return task.startTime < min ? task.startTime : min; + }, Infinity); + } + return ''; +}; + +export const getEndRange = function () { + if (endDateRange) { + return endDateRange; + } + if (getTasks().length > 0) { + return getTasks().reduce((max, task) => { + return task.endTime > max ? task.endTime : max; + }, -Infinity); + } + return ''; +}; + export const setIncludes = function (txt) { includes = txt.toLowerCase().split(/[\s,]+/); }; @@ -161,7 +211,25 @@ export const getTasks = function () { iterationCount++; } - tasks = rawTasks; + if (dateRange === '') { + return rawTasks; + } + + const filteredTasks = rawTasks.filter(function (task) { + if ( + (startDateRange && task.endTime <= startDateRange) || + (endDateRange && task.startTime >= endDateRange) + ) { + return false; + } + return true; + }); + + tasks = filteredTasks.map((task) => ({ + ...task, + startTime: startDateRange && task.startTime < startDateRange ? startDateRange : task.startTime, + endTime: endDateRange && task.endTime > endDateRange ? endDateRange : task.endTime, + })); return tasks; }; @@ -288,6 +356,12 @@ const getStartDate = function (prevTime, dateFormat, str) { return today; } + if (str === '') { + // If only an end-only dateRange is provided, we determine the start date + // by comparing the start times of the tasks. + return getStartRange(); + } + // Check for actual date set let mDate = dayjs(str, dateFormat.trim(), true); if (mDate.isValid()) { @@ -295,21 +369,7 @@ const getStartDate = function (prevTime, dateFormat, str) { } else { log.debug('Invalid date:' + str); log.debug('With date format:' + dateFormat.trim()); - const d = new Date(str); - if ( - d === undefined || - isNaN(d.getTime()) || - // WebKit browsers can mis-parse invalid dates to be ridiculously - // huge numbers, e.g. new Date('202304') gets parsed as January 1, 202304. - // This can cause virtually infinite loops while rendering, so for the - // purposes of Gantt charts we'll just treat any date beyond 10,000 AD/BC as - // invalid. - d.getFullYear() < -10000 || - d.getFullYear() > 10000 - ) { - throw new Error('Invalid date:' + str); - } - return d; + throw new Error(`Invalid date: '${str}' with date format: '${dateFormat}'`); } }; @@ -757,6 +817,10 @@ export default { setDateFormat, getDateFormat, enableInclusiveEndDates, + setDateRange, + getDateRange, + getStartRange, + getEndRange, endDatesAreInclusive, enableTopAxis, topAxisEnabled, diff --git a/packages/mermaid/src/diagrams/gantt/ganttDb.spec.ts b/packages/mermaid/src/diagrams/gantt/ganttDb.spec.ts index 6f2c8c1afe..393028e931 100644 --- a/packages/mermaid/src/diagrams/gantt/ganttDb.spec.ts +++ b/packages/mermaid/src/diagrams/gantt/ganttDb.spec.ts @@ -34,6 +34,7 @@ describe('when using the ganttDb', function () { beforeEach(function () { ganttDb.setDateFormat('YYYY-MM-DD'); ganttDb.enableInclusiveEndDates(); + ganttDb.setDateRange('2019-02-01, 2019-03-01'); ganttDb.setDisplayMode('compact'); ganttDb.setTodayMarker('off'); ganttDb.setExcludes('weekends 2019-02-06,friday'); @@ -50,6 +51,9 @@ describe('when using the ganttDb', function () { ${'getAccDescription'} | ${''} ${'getDateFormat'} | ${''} ${'getAxisFormat'} | ${''} + ${'getDateRange'} | ${''} + ${'getStartRange'} | ${''} + ${'getEndRange'} | ${''} ${'getTodayMarker'} | ${''} ${'getExcludes'} | ${[]} ${'getSections'} | ${[]} @@ -158,6 +162,42 @@ describe('when using the ganttDb', function () { expect(tasks[2].startTime).toEqual(new Date(2013, 0, 15)); expect(tasks[2].endTime).toEqual(new Date(2013, 0, 17)); }); + it('should handle fixed date ranges', function () { + const DATE_FORMAT = 'YYYY-MM-DD'; + ganttDb.setDateFormat(DATE_FORMAT); + ganttDb.setDateRange('2023-07-01, 2023-07-30'); + ganttDb.addSection('testa1'); + ganttDb.addTask('test1', 'id1,2013-07-01,2w'); + ganttDb.addTask('test2', 'id2,2023-07-02,2w'); + ganttDb.addSection('testa2'); + ganttDb.addTask('test3', 'id3,after id2,2d'); + ganttDb.addSection('testa3'); + ganttDb.addTask('test4', 'id4,2023-06-25,2w'); + ganttDb.addTask('test5', 'id5,2023-07-25,2w'); + + const tasks = ganttDb.getTasks(); + + expect(tasks.length).toEqual(4); + expect(tasks[0].id).toEqual('id2'); + expect(tasks[0].task).toEqual('test2'); + expect(tasks[0].startTime).toEqual(dayjs('2023-07-02', DATE_FORMAT, true).toDate()); + expect(tasks[0].endTime).toEqual(dayjs('2023-07-16', DATE_FORMAT, true).toDate()); + + expect(tasks[1].id).toEqual('id3'); + expect(tasks[1].task).toEqual('test3'); + expect(tasks[1].startTime).toEqual(dayjs('2023-07-16', DATE_FORMAT, true).toDate()); + expect(tasks[1].endTime).toEqual(dayjs('2023-07-18', DATE_FORMAT, true).toDate()); + + expect(tasks[2].id).toEqual('id4'); + expect(tasks[2].task).toEqual('test4'); + expect(tasks[2].startTime).toEqual(dayjs('2023-07-01', DATE_FORMAT, true).toDate()); + expect(tasks[2].endTime).toEqual(dayjs('2023-07-09', DATE_FORMAT, true).toDate()); + + expect(tasks[3].id).toEqual('id5'); + expect(tasks[3].task).toEqual('test5'); + expect(tasks[3].startTime).toEqual(dayjs('2023-07-25', DATE_FORMAT, true).toDate()); + expect(tasks[3].endTime).toEqual(dayjs('2023-07-30', DATE_FORMAT, true).toDate()); + }); it('should handle relative end date based on id regardless of sections', function () { ganttDb.setDateFormat('YYYY-MM-DD'); @@ -503,6 +543,30 @@ describe('when using the ganttDb', function () { it('should reject dates with ridiculous years', function () { ganttDb.setDateFormat('YYYYMMDD'); ganttDb.addTask('test1', 'id1,202304,1d'); - expect(() => ganttDb.getTasks()).toThrowError('Invalid date:202304'); + expect(() => ganttDb.getTasks()).toThrowError( + "Invalid date: '202304' with date format: 'YYYYMMDD'" + ); + }); + + it.each(convert` + testName | dateRange | expStartRange | expEndRange | expTasksLength + ${'No dateRange'} | ${''} | ${'2023-06-01'} | ${'2023-07-07'} | ${2} + ${'Wide dateRange'} | ${'2023-01-01, 2023-12-31'} | ${'2023-01-01'} | ${'2023-12-31'} | ${2} + ${'Narrow dateRange'} | ${'2023-06-29, 2023-06-30'} | ${'2023-06-29'} | ${'2023-06-30'} | ${0} + ${'Overlapping dateRange'} | ${'2023-06-06, 2023-07-03'} | ${'2023-06-06'} | ${'2023-07-03'} | ${2} + ${'Starting dateRange'} | ${'2023-06-06'} | ${'2023-06-06'} | ${'2023-07-07'} | ${2} + ${'Ending dateRange'} | ${',2023-06-06'} | ${'2023-06-01'} | ${'2023-06-06'} | ${1} + `)('$testName', ({ dateFormat, dateRange, expStartRange, expEndRange, expTasksLength }) => { + ganttDb.setDateFormat('YYYY-MM-DD'); + expect('').toEqual(ganttDb.getDateRange()); + ganttDb.setDateRange(dateRange); + ganttDb.addTask('task1', 't1, 2023-06-01, 2023-06-07'); + ganttDb.addTask('task2', 't2, 2023-07-02, 2023-07-07'); + const tasks = ganttDb.getTasks(); + const startRange = ganttDb.getStartRange(); + const endRange = ganttDb.getEndRange(); + expect(expTasksLength).toEqual(tasks.length); + expect(dayjs(expStartRange, 'YYYY-MM-DD').toDate()).toEqual(startRange); + expect(dayjs(expEndRange, 'YYYY-MM-DD').toDate()).toEqual(endRange); }); }); diff --git a/packages/mermaid/src/diagrams/gantt/ganttRenderer.js b/packages/mermaid/src/diagrams/gantt/ganttRenderer.js index a10eb100f4..91dec73a17 100644 --- a/packages/mermaid/src/diagrams/gantt/ganttRenderer.js +++ b/packages/mermaid/src/diagrams/gantt/ganttRenderer.js @@ -3,8 +3,6 @@ import { log } from '../../logger.js'; import { select, scaleTime, - min, - max, scaleLinear, interpolateHcl, axisBottom, @@ -148,14 +146,7 @@ export const draw = function (text, id, version, diagObj) { // Set timescale const timeScale = scaleTime() - .domain([ - min(taskArray, function (d) { - return d.startTime; - }), - max(taskArray, function (d) { - return d.endTime; - }), - ]) + .domain([diagObj.db.getStartRange(), diagObj.db.getEndRange()]) .rangeRound([0, w - conf.leftPadding - conf.rightPadding]); /** diff --git a/packages/mermaid/src/diagrams/gantt/parser/gantt.jison b/packages/mermaid/src/diagrams/gantt/parser/gantt.jison index f2333ff84e..0e591e947e 100644 --- a/packages/mermaid/src/diagrams/gantt/parser/gantt.jison +++ b/packages/mermaid/src/diagrams/gantt/parser/gantt.jison @@ -71,6 +71,7 @@ that id. "gantt" return 'gantt'; "dateFormat"\s[^#\n;]+ return 'dateFormat'; "inclusiveEndDates" return 'inclusiveEndDates'; +"dateRange"\s[^#\n;]+ return 'dateRange'; "topAxis" return 'topAxis'; "axisFormat"\s[^#\n;]+ return 'axisFormat'; "tickInterval"\s[^#\n;]+ return 'tickInterval'; @@ -138,6 +139,7 @@ weekend statement : dateFormat {yy.setDateFormat($1.substr(11));$$=$1.substr(11);} | inclusiveEndDates {yy.enableInclusiveEndDates();$$=$1.substr(18);} + | dateRange {yy.setDateRange($1.substr(10));$$=$1.substr(10);} | topAxis {yy.TopAxis();$$=$1.substr(8);} | axisFormat {yy.setAxisFormat($1.substr(11));$$=$1.substr(11);} | tickInterval {yy.setTickInterval($1.substr(13));$$=$1.substr(13);} diff --git a/packages/mermaid/src/diagrams/gantt/parser/gantt.spec.js b/packages/mermaid/src/diagrams/gantt/parser/gantt.spec.js index 281e9b6bd3..b00a8dbde5 100644 --- a/packages/mermaid/src/diagrams/gantt/parser/gantt.spec.js +++ b/packages/mermaid/src/diagrams/gantt/parser/gantt.spec.js @@ -26,6 +26,18 @@ describe('when parsing a gantt diagram it', function () { expect(parserFnConstructor(str)).not.toThrow(); }); + it.each([ + ['2023-06-01', '2023-07-01', 'YYYY-MM-DD'], + ['13:00', '14:00', 'HH:mm'], + ['2023-06-01 13:00', '2023-07-01 14:00', 'YYYY-MM-DD HH:mm'], + ])( + 'should handle a dateRange definition (startDate: %s, endDate: %s)', + function (startDate, endDate, dateFormat) { + const str = `gantt\ndateFormat ${dateFormat}\ndateRange ${startDate}, ${endDate}`; + + expect(parserFnConstructor(str)).not.toThrow(); + } + ); it('should handle a title definition', function () { const str = 'gantt\ndateFormat yyyy-mm-dd\ntitle Adding gantt diagram functionality to mermaid'; const semi = 'gantt\ndateFormat yyyy-mm-dd\ntitle ;Gantt diagram titles support semicolons'; @@ -35,6 +47,23 @@ describe('when parsing a gantt diagram it', function () { expect(parserFnConstructor(semi)).not.toThrow(); expect(parserFnConstructor(hash)).not.toThrow(); }); + it.each([ + ['dateRange: 2023-06-01, 2023-07-01', 'YYYY-MM-DD'], + ['dateRange: 13:00, 14:00', 'HH:mm'], + ])('should ignore improper dateRange syntax (%s)', function (dateRange, dateFormat) { + const str = `gantt\ndateFormat ${dateFormat}\n${dateRange}`; + + expect(parserFnConstructor(str)).not.toThrow(); + expect(ganttDb.getDateRange()).toEqual(''); + }); + it.each([ + ['dateRange : 2023-06-01, 2023-07-01', 'YYYY-MM-DD'], + ['dateRange : 13:00, 14:00', 'HH:mm'], + ])(`should reject invalid dateRange definition (%s)`, function (dateRange, dateFormat) { + const str = `gantt\ndateFormat ${dateFormat}\n${dateRange}`; + + expect(parserFnConstructor(str)).toThrow(); + }); it('should handle an excludes definition', function () { const str = 'gantt\ndateFormat yyyy-mm-dd\ntitle Adding gantt diagram functionality to mermaid\nexcludes weekdays 2019-02-01'; diff --git a/packages/mermaid/src/docs/community/contributing.md b/packages/mermaid/src/docs/community/contributing.md index 71048d0952..a1bce212d8 100644 --- a/packages/mermaid/src/docs/community/contributing.md +++ b/packages/mermaid/src/docs/community/contributing.md @@ -358,6 +358,12 @@ it('should render forks and joins', () => { }); ``` +**Verifying Snapshots** + +```sh +pnpm e2e open cypress/snapshots +``` + diff --git a/packages/mermaid/src/docs/syntax/gantt.md b/packages/mermaid/src/docs/syntax/gantt.md index 8497b96a13..2cb7423d22 100644 --- a/packages/mermaid/src/docs/syntax/gantt.md +++ b/packages/mermaid/src/docs/syntax/gantt.md @@ -255,6 +255,26 @@ gantt `millisecond` and `second` support was added in v10.3.0 ``` +### Date Ranges (v+) + +The default behavior is to set the x range to include all of the data in the chart. You can override +the range by specifying `dateRange`. Any tasks falling outside the specified range will be removed +from the plot, and tasks overlapping with the boundaries will be truncated. The `dateRange` command +should follow the `dateFormat` and use the same format. + +```mermaid-example +gantt + dateFormat HH:mm + dateRange 13:00, 14:00 + axisFormat %H:%M + Task A : 13:24, 13:39 + Task B : 13:50, 14:35 + Dropped : 14:01, 14:20 +``` + +It is also possible to specify only a lower bound using `dateRange ` or only an upper bound +using `dateRange ,`. + ## Output in compact mode The compact mode allows you to display multiple tasks in the same row. Compact mode can be enabled for a gantt chart by setting the display mode of the graph via preceding YAML settings.