Skip to content

Commit

Permalink
Merge pull request #792 from jopapo/master
Browse files Browse the repository at this point in the history
Added exclude weekdays to definition
  • Loading branch information
knsv authored May 28, 2019
2 parents b3dd2a4 + afeb3b5 commit 9191663
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 38 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

**Merged pull requests:**

- Adding weekend ignore do Gantt [\$314] (https://github.com/knsv/mermaid/issues/314)

- Adding init argument to the global API [\#137](https://github.com/knsv/mermaid/pull/137) ([bollwyvl](https://github.com/bollwyvl))

- Add description of manual calling of init [\#136](https://github.com/knsv/mermaid/pull/136) ([bollwyvl](https://github.com/bollwyvl))
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ sequenceDiagram
gantt
dateFormat YYYY-MM-DD
title Adding GANTT diagram to mermaid
excludes weekdays 2014-01-10
section A section
Completed task :done, des1, 2014-01-06,2014-01-08
Expand Down
1 change: 1 addition & 0 deletions dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@
dateFormat YYYY-MM-DD
axisFormat %d/%m
title Adding GANTT diagram to mermaid
excludes weekdays 2014-01-10

section A section
Completed task :done, des1, 2014-01-06,2014-01-08
Expand Down
6 changes: 6 additions & 0 deletions src/diagrams/gantt/gantt.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,16 @@ describe('when parsing a gantt diagram it', function () {

parser.parse(str)
})
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'

parser.parse(str)
})
it('should handle a section definition', function () {
const str = 'gantt\n' +
'dateFormat yyyy-mm-dd\n' +
'title Adding gantt diagram functionality to mermaid\n' +
'excludes weekdays 2019-02-01\n' +
'section Documentation'

parser.parse(str)
Expand Down
72 changes: 63 additions & 9 deletions src/diagrams/gantt/ganttDb.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { logger } from '../../logger'

let dateFormat = ''
let axisFormat = ''
let excludes = []
let title = ''
let sections = []
let tasks = []
Expand Down Expand Up @@ -31,6 +32,10 @@ export const setDateFormat = function (txt) {
dateFormat = txt
}

export const setExcludes = function (txt) {
excludes = txt.toLowerCase().split(/[\s,]+/)
}

export const setTitle = function (txt) {
title = txt
}
Expand Down Expand Up @@ -58,6 +63,42 @@ export const getTasks = function () {
return tasks
}

const isInvalidDate = function (date, dateFormat, excludes) {
if (date.isoWeekday() >= 6 && excludes.indexOf('weekends') >= 0) {
return true
}
if (excludes.indexOf(date.format('dddd').toLowerCase()) >= 0) {
return true
}
return excludes.indexOf(date.format(dateFormat.trim())) >= 0
}

const checkTaskDates = function (task, dateFormat, excludes) {
if (!excludes.length || task.manualEndTime) return
let startTime = moment(task.startTime, dateFormat, true)
startTime.add(1, 'd')
let endTime = moment(task.endTime, dateFormat, true)
let renderEndTime = fixTaskDates(startTime, endTime, dateFormat, excludes)
task.endTime = endTime.toDate()
task.renderEndTime = renderEndTime
}

const fixTaskDates = function (startTime, endTime, dateFormat, excludes) {
let invalid = false
let renderEndTime = null
while (startTime.date() <= endTime.date()) {
if (!invalid) {
renderEndTime = endTime.toDate()
}
invalid = isInvalidDate(startTime, dateFormat, excludes)
if (invalid) {
endTime.add(1, 'd')
}
startTime.add(1, 'd')
}
return renderEndTime
}

const getStartDate = function (prevTime, dateFormat, str) {
str = str.trim()

Expand All @@ -77,8 +118,9 @@ const getStartDate = function (prevTime, dateFormat, str) {
}

// Check for actual date set
if (moment(str, dateFormat.trim(), true).isValid()) {
return moment(str, dateFormat.trim(), true).toDate()
let mDate = moment(str, dateFormat.trim(), true)
if (mDate.isValid()) {
return mDate.toDate()
} else {
logger.debug('Invalid date:' + str)
logger.debug('With date format:' + dateFormat.trim())
Expand All @@ -92,8 +134,9 @@ const getEndDate = function (prevTime, dateFormat, str) {
str = str.trim()

// Check for actual date
if (moment(str, dateFormat.trim(), true).isValid()) {
return moment(str, dateFormat.trim()).toDate()
let mDate = moment(str, dateFormat.trim(), true)
if (mDate.isValid()) {
return mDate.toDate()
}

const d = moment(prevTime)
Expand All @@ -119,7 +162,6 @@ const getEndDate = function (prevTime, dateFormat, str) {
d.add(durationStatement[1], 'weeks')
break
}
return d.toDate()
}
// Default date - now
return d.toDate()
Expand Down Expand Up @@ -181,25 +223,32 @@ const compileData = function (prevTask, dataStr) {
data[i] = data[i].trim()
}

let endTimeData = ''
switch (data.length) {
case 1:
task.id = parseId()
task.startTime = prevTask.endTime
task.endTime = getEndDate(task.startTime, dateFormat, data[0])
endTimeData = data[0]
break
case 2:
task.id = parseId()
task.startTime = getStartDate(undefined, dateFormat, data[0])
task.endTime = getEndDate(task.startTime, dateFormat, data[1])
endTimeData = data[1]
break
case 3:
task.id = parseId(data[0])
task.startTime = getStartDate(undefined, dateFormat, data[1])
task.endTime = getEndDate(task.startTime, dateFormat, data[2])
endTimeData = data[2]
break
default:
}

if (endTimeData) {
task.endTime = getEndDate(task.startTime, dateFormat, endTimeData)
task.manualEndTime = endTimeData === moment(task.endTime).format(dateFormat.trim())
checkTaskDates(task, dateFormat, excludes)
}

return task
}

Expand Down Expand Up @@ -270,6 +319,8 @@ export const addTask = function (descr, data) {
section: currentSection,
type: currentSection,
processed: false,
manualEndTime: false,
renderEndTime: null,
raw: { data: data },
task: descr
}
Expand Down Expand Up @@ -333,6 +384,8 @@ const compileTasks = function () {
rawTasks[pos].endTime = getEndDate(rawTasks[pos].startTime, dateFormat, rawTasks[pos].raw.endTime.data)
if (rawTasks[pos].endTime) {
rawTasks[pos].processed = true
rawTasks[pos].manualEndTime = rawTasks[pos].raw.endTime.data === moment(rawTasks[pos].endTime).format(dateFormat.trim())
checkTaskDates(rawTasks[pos], dateFormat, excludes)
}
}

Expand All @@ -359,5 +412,6 @@ export default {
getTasks,
addTask,
findTaskById,
addTaskOrg
addTaskOrg,
setExcludes
}
56 changes: 56 additions & 0 deletions src/diagrams/gantt/ganttDb.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,60 @@ describe('when using the ganttDb', function () {
expect(tasks[2].startTime).toEqual(moment('2013-01-15', 'YYYY-MM-DD').toDate())
expect(tasks[2].endTime).toEqual(moment('2013-01-17', 'YYYY-MM-DD').toDate())
})
it('should ignore weekends', function () {
ganttDb.setDateFormat('YYYY-MM-DD')
ganttDb.setExcludes('weekends 2019-02-06,friday')
ganttDb.addSection('weekends skip test')
ganttDb.addTask('test1', 'id1,2019-02-01,1d')
ganttDb.addTask('test2', 'id2,after id1,2d')
ganttDb.addTask('test3', 'id3,after id2,7d')
ganttDb.addTask('test4', 'id4,2019-02-01,2019-02-20') // Fixed endTime
ganttDb.addTask('test5', 'id5,after id4,1d')
ganttDb.addSection('full ending taks on last day')
ganttDb.addTask('test6', 'id6,2019-02-13,2d')
ganttDb.addTask('test7', 'id7,after id6,1d')

const tasks = ganttDb.getTasks()

expect(tasks[0].startTime).toEqual(moment('2019-02-01', 'YYYY-MM-DD').toDate())
expect(tasks[0].endTime).toEqual(moment('2019-02-04', 'YYYY-MM-DD').toDate())
expect(tasks[0].renderEndTime).toEqual(moment('2019-02-02', 'YYYY-MM-DD').toDate())
expect(tasks[0].id).toEqual('id1')
expect(tasks[0].task).toEqual('test1')

expect(tasks[1].startTime).toEqual(moment('2019-02-04', 'YYYY-MM-DD').toDate())
expect(tasks[1].endTime).toEqual(moment('2019-02-07', 'YYYY-MM-DD').toDate())
expect(tasks[1].renderEndTime).toEqual(moment('2019-02-06', 'YYYY-MM-DD').toDate())
expect(tasks[1].id).toEqual('id2')
expect(tasks[1].task).toEqual('test2')

expect(tasks[2].startTime).toEqual(moment('2019-02-07', 'YYYY-MM-DD').toDate())
expect(tasks[2].endTime).toEqual(moment('2019-02-20', 'YYYY-MM-DD').toDate())
expect(tasks[2].renderEndTime).toEqual(moment('2019-02-20', 'YYYY-MM-DD').toDate())
expect(tasks[2].id).toEqual('id3')
expect(tasks[2].task).toEqual('test3')

expect(tasks[3].startTime).toEqual(moment('2019-02-01', 'YYYY-MM-DD').toDate())
expect(tasks[3].endTime).toEqual(moment('2019-02-20', 'YYYY-MM-DD').toDate())
expect(tasks[3].renderEndTime).toBeNull() // Fixed end
expect(tasks[3].id).toEqual('id4')
expect(tasks[3].task).toEqual('test4')

expect(tasks[4].startTime).toEqual(moment('2019-02-20', 'YYYY-MM-DD').toDate())
expect(tasks[4].endTime).toEqual(moment('2019-02-21', 'YYYY-MM-DD').toDate())
expect(tasks[4].renderEndTime).toEqual(moment('2019-02-21', 'YYYY-MM-DD').toDate())
expect(tasks[4].id).toEqual('id5')
expect(tasks[4].task).toEqual('test5')

expect(tasks[5].startTime).toEqual(moment('2019-02-13', 'YYYY-MM-DD').toDate())
expect(tasks[5].endTime).toEqual(moment('2019-02-18', 'YYYY-MM-DD').toDate())
expect(tasks[5].renderEndTime).toEqual(moment('2019-02-15', 'YYYY-MM-DD').toDate())
expect(tasks[5].id).toEqual('id6')
expect(tasks[5].task).toEqual('test6')

expect(tasks[6].startTime).toEqual(moment('2019-02-18', 'YYYY-MM-DD').toDate())
expect(tasks[6].endTime).toEqual(moment('2019-02-19', 'YYYY-MM-DD').toDate())
expect(tasks[6].id).toEqual('id7')
expect(tasks[6].task).toEqual('test7')
})
})
4 changes: 2 additions & 2 deletions src/diagrams/gantt/ganttRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export const draw = function (text, id) {
return i * theGap + theTopPad
})
.attr('width', function (d) {
return (timeScale(d.endTime) - timeScale(d.startTime))
return (timeScale(d.renderEndTime || d.endTime) - timeScale(d.startTime))
})
.attr('height', theBarHeight)
.attr('class', function (d) {
Expand Down Expand Up @@ -178,7 +178,7 @@ export const draw = function (text, id) {
.attr('font-size', conf.fontSize)
.attr('x', function (d) {
const startX = timeScale(d.startTime)
const endX = timeScale(d.endTime)
const endX = timeScale(d.renderEndTime || d.endTime)
const textWidth = this.getBBox().width

// Check id text width > width of rectangle
Expand Down
8 changes: 5 additions & 3 deletions src/diagrams/gantt/parser/gantt.jison
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@
"gantt" return 'gantt';
"dateFormat"\s[^#\n;]+ return 'dateFormat';
"axisFormat"\s[^#\n;]+ return 'axisFormat';
"excludes"\s[^#\n;]+ return 'excludes';
\d\d\d\d"-"\d\d"-"\d\d return 'date';
"title"\s[^#\n;]+ return 'title';
"section"\s[^#:\n;]+ return 'section';
[^#:\n;]+ return 'taskTxt';
":"[^#\n;]+ return 'taskData';
":" return ':';
<<EOF>> return 'EOF';
. return 'INVALID';
":" return ':';
<<EOF>> return 'EOF';
. return 'INVALID';

/lex

Expand Down Expand Up @@ -56,6 +57,7 @@ line
statement
: 'dateFormat' {yy.setDateFormat($1.substr(11));$$=$1.substr(11);}
| 'axisFormat' {yy.setAxisFormat($1.substr(11));$$=$1.substr(11);}
| 'excludes' {yy.setExcludes($1.substr(9));$$=$1.substr(9);}
| title {yy.setTitle($1.substr(6));$$=$1.substr(6);}
| section {yy.addSection($1.substr(8));$$=$1.substr(8);}
| taskTxt taskData {yy.addTask($1,$2);$$='task';}
Expand Down
Loading

0 comments on commit 9191663

Please sign in to comment.