elegantt/src/gantt.typ

242 lines
5.6 KiB
Typst

#import "timeliney.typ"
#import "datetime_calc.typ" as dtc
#let _header-months(start-time, end-time) = {
let months-name = ()
let months-duration = ()
let nbr-months = dtc.count-months(start-time, end-time)
let i = 0
let date = start-time
while (i < nbr-months) {
let rmg_week = dtc.remaining_week_on_month-workingday(date)
if date.month() == end-time.month() {
rmg_week = dtc.diff-weeks-workingday(date, dtc.offset(end-time, 2))
}
months-name.push(date.display("[month repr:long]"))
months-duration.push(rmg_week)
if date.month() == 12 {
date = datetime(
year: date.year()+1,
month: 1,
day: 1
)
} else {
date = datetime(
year: date.year(),
month: date.month()+1,
day: 1
)
}
i = i + 1
}
timeliney.headerline(
..range(nbr-months).map(
n => timeliney.group((
strong(months-name.at(n)),
months-duration.at(n)
))
),
)
}
#let _header-week-number(start-time, end-time) = {
timeliney.headerline(
timeliney.group(
..range(dtc.count-weeks(start-time, end-time)).map(
n => strong("W" + str(n + int(start-time.display("[week_number]"))))
)
),
)
}
#let _header-week-date(start-time, end-time) = {
timeliney.headerline(
timeliney.group(
..range(dtc.count-weeks(start-time, end-time)).map(
n => strong(
dtc.offset(start-time, n*7).display("[day]/[month]")
)
)
),
)
}
#let _today(project-start-date) = {
let weeks = 0
let foo = project-start-date
while (foo <= datetime.today()) {
weeks += 1
foo = dtc.add(foo, 7)
}
weeks = weeks - 1 + dtc.workingday_ratio(datetime.today())
timeliney.milestone(
at: weeks,
style: (stroke: red),
[]
)
}
#let create(
date-beginning: none,
date-finish: none,
header-months: true,
header-week-number: true,
header-week-date: false,
today-line: true,
doc
) = {
let gTask(description, ..args) = {
let complemented_task = ()
for arg in args.pos() {
if type(line) == dictionary {
complemented_task.push(arg)
} else {
let (date, eod, ..) = arg
let dashed = arg.at(2, default: false)
let real = arg.at(3, default: false)
let weeks = 0
let foo = date-beginning
let task-week-duration = if type(eod) == datetime {
dtc.diff-weeks-workingday(date, eod)
} else {
eod
}
while (foo <= date) {
weeks += 1
foo = dtc.add(foo, 7)
}
weeks = weeks - 1 + dtc.workingday_ratio(date)
let end = weeks + task-week-duration
// let p = pattern(size: (4pt, 4pt))[
// #line(start: (0pt, 3pt), end: (4pt, 0pt), stroke: black.lighten(20%) + .3pt)
// ]
let p = pattern(size: (4.5pt, 4.01pt))[
#circle(radius: 1.5pt, fill: gray.lighten(20%))
//#line(start: (0pt, 3pt), end: (4pt, 0pt), stroke: black.lighten(20%) + .3pt)
]
if dashed {
complemented_task.push((
from: weeks,
to: end,
style: (
stroke: (
dash: "loosely-dotted",
thickness: 2.5pt,
paint: gray.lighten(10%),
cap: "round",
)
// stroke: (paint: p, thickness: 4pt)
)
))
} else if real{
complemented_task.push((
from: weeks,
to: end,
style: (
stroke: (
//dash: "dotted",
thickness: 1pt,
paint: rgb("#ff0000")
)
)
))
} else {
complemented_task.push((weeks, end))
}
}
}
timeliney.task(
align(center, description),
..complemented_task,
style: (stroke: 5pt + gray.lighten(40%))
)
}
let gMilestone(description, date) = {
let weeks = 0
let foo = date-beginning
while (foo <= date) {
weeks += 1
foo = dtc.add(foo, 7)
}
weeks = weeks - 1 + dtc.workingday_ratio(date)
timeliney.milestone(
at: weeks,
style: (stroke: (dash: "dashed")),
align(center, strong(description) + "\n" + date.display("[day]/[month]/[year]"))
)
}
let doc2 = ()
for elmt in doc {
if "type" in elmt and elmt.type == "gTask" {
doc2 += gTask(elmt.description, ..elmt.args)
} else if "type" in elmt and elmt.type == "gMilestone" {
doc2 += gMilestone(elmt.description, elmt.milestone-date)
} else {
doc2.push(elmt)
}
}
timeliney.timeline(
show-grid: true,
{
import timeliney: *
let duration-weeks = int(dtc.diff-weeks(date-beginning, dtc.offset(date-finish, 2)))
let year = date-beginning.display("[year]")
headerline(group(([*#year*], duration-weeks)))
if header-months {
_header-months(date-beginning, date-finish)
}
if header-week-number {
_header-week-number(date-beginning, date-finish)
}
if header-week-date {
_header-week-date(date-beginning, date-finish)
}
if today-line {
_today(date-beginning)
}
//timeliney.task(align(center, [foo]),(0,1),style: (stroke: 2pt + gray))
doc2
}
)
}
#let task(description, ..args) = ((
type: "gTask",
description: description,
args: args.pos(),
),)
#let milestone(description, milestone-date) = ((
type: "gMilestone",
milestone-date: milestone-date,
description: description,
),)