added parallel task with real / planned work

updated timeliney to use latest CeTZ
This commit is contained in:
Louis Heredero 2024-08-10 18:13:15 +02:00
parent dff52e79ea
commit 2a31df7d50
Signed by: HEL
GPG Key ID: 8D83DE470F8544E7
4 changed files with 61 additions and 46 deletions

Binary file not shown.

View File

@ -59,6 +59,7 @@
[Report / Presentation], [Report / Presentation],
(date.start, date.finish, true), (date.start, date.finish, true),
(datetime(year: 2024, month: 06, day: 24), 1), (datetime(year: 2024, month: 06, day: 24), 1),
(datetime(year: 2024, month: 06, day: 20), 1.2, false, true),
(datetime(year: 2024, month: 08, day: 26), 1), (datetime(year: 2024, month: 08, day: 26), 1),
) )

View File

@ -145,6 +145,7 @@
complemented_task.push(( complemented_task.push((
from: weeks, from: weeks,
to: end, to: end,
real: true,
style: ( style: (
stroke: ( stroke: (
//dash: "dotted", //dash: "dotted",

View File

@ -1,4 +1,4 @@
#import "@preview/cetz:0.1.2": canvas, draw #import "@preview/cetz:0.2.2": canvas, draw, coordinate, util
#let timeline( #let timeline(
body, body,
@ -51,22 +51,22 @@
content( content(
(rel: (0, 0)), (rel: (0, 0)),
task.name, task.name,
anchor: "top", anchor: "north",
name: "task" + str(i), name: "task" + str(i),
padding: spacing, padding: if task.parallel {(x: spacing, y: 2 * spacing)} else {spacing},
) )
anchor( anchor(
"task" + str(i) + "-bottom", "task" + str(i) + "-bottom",
(rel: (0, 0), to: "task" + str(i) + ".bottom", update: true), (rel: (0, 0), to: "task" + str(i) + ".south", update: true),
) )
anchor( anchor(
"task" + str(i) + "-top", "task" + str(i) + "-top",
(rel: (0, 0), to: "task" + str(i) + ".top-left", update: false), (rel: (0, 0), to: "task" + str(i) + ".north-west", update: false),
) )
anchor( anchor(
"task" + str(i), "task" + str(i),
(rel: (0, 0), to: "task" + str(i) + ".right", update: false), (rel: (0, 0), to: "task" + str(i) + ".east", update: false),
) )
flat_tasks.push(task) flat_tasks.push(task)
@ -77,22 +77,22 @@
content( content(
(rel: (0, 0)), (rel: (0, 0)),
t.name, t.name,
anchor: "top", anchor: "north",
name: "task" + str(i), name: "task" + str(i),
padding: spacing, padding: spacing,
) )
anchor( anchor(
"task" + str(i) + "-bottom", "task" + str(i) + "-bottom",
(rel: (0, 0), to: "task" + str(i) + ".bottom", update: true), (rel: (0, 0), to: "task" + str(i) + ".south", update: true),
) )
anchor( anchor(
"task" + str(i) + "-top", "task" + str(i) + "-top",
(rel: (0, 0), to: "task" + str(i) + ".top-left", update: false), (rel: (0, 0), to: "task" + str(i) + ".north-west", update: false),
) )
anchor( anchor(
"task" + str(i), "task" + str(i),
(rel: (0, 0), to: "task" + str(i) + ".right", update: false), (rel: (0, 0), to: "task" + str(i) + ".east", update: false),
) )
flat_tasks.push(t) flat_tasks.push(t)
@ -107,22 +107,22 @@
content( content(
(rel: (0, 0)), (rel: (0, 0)),
milestone.body, milestone.body,
anchor: "top", anchor: "north",
name: "milestone" + str(i), name: "milestone" + str(i),
padding: spacing, padding: spacing,
) )
anchor( anchor(
"milestone" + str(i) + "-bottom", "milestone" + str(i) + "-bottom",
(rel: (0, 0), to: "milestone" + str(i) + ".bottom", update: true), (rel: (0, 0), to: "milestone" + str(i) + ".south", update: true),
) )
anchor( anchor(
"milestone" + str(i) + "-right", "milestone" + str(i) + "-right",
(rel: (0, 0), to: "milestone" + str(i) + ".right", update: false), (rel: (0, 0), to: "milestone" + str(i) + ".east", update: false),
) )
anchor( anchor(
"milestone" + str(i) + "-top", "milestone" + str(i) + "-top",
(rel: (0, 0), to: "milestone" + str(i) + ".top", update: false), (rel: (0, 0), to: "milestone" + str(i) + ".north", update: false),
) )
} }
} }
@ -136,7 +136,7 @@
on-layer( on-layer(
1, 1,
{ {
let (start_x, _, _) = coordinate.resolve(ctx, "titles.top-left") let (_, (start_x,_ , _)) = coordinate.resolve(ctx, "titles.north-west")
let end_x = 1 + start_x let end_x = 1 + start_x
let i = 0 let i = 0
@ -152,11 +152,11 @@
for task in group.tasks { for task in group.tasks {
if group_start == none { if group_start == none {
let (_, start_y, _) = coordinate.resolve(ctx, "titles.task" + str(i) + "-top") let (_, (_, start_y, _)) = coordinate.resolve(ctx, "titles.task" + str(i) + "-top")
group_start = (start_x, start_y) group_start = (start_x, start_y)
} }
let (_, end_y, _) = coordinate.resolve(ctx, "titles.task" + str(i) + "-bottom") let (_, (_, end_y, _)) = coordinate.resolve(ctx, "titles.task" + str(i) + "-bottom")
group_end = (end_x, end_y) group_end = (end_x, end_y)
i += 1 i += 1
@ -166,7 +166,7 @@
} }
if tasks-vline { if tasks-vline {
line("titles.top-right", "titles.bottom-right") line("titles.north-east", "titles.south-east")
} }
if box-milestones and milestone-layout == "aligned" { if box-milestones and milestone-layout == "aligned" {
@ -175,10 +175,10 @@
for (i, milestone) in milestones.enumerate() { for (i, milestone) in milestones.enumerate() {
if start == none { if start == none {
let (_, start_y, _) = coordinate.resolve(ctx, "titles.milestone" + str(i) + "-top") let (_, (_, start_y, _)) = coordinate.resolve(ctx, "titles.milestone" + str(i) + "-top")
start = (start_x, start_y) start = (start_x, start_y)
} }
let (_, end_y, _) = coordinate.resolve(ctx, "titles.milestone" + str(i) + "-bottom") let (_, (_, end_y, _)) = coordinate.resolve(ctx, "titles.milestone" + str(i) + "-bottom")
end = (end_x, end_y) end = (end_x, end_y)
} }
@ -192,9 +192,9 @@
get-ctx( get-ctx(
ctx => { ctx => {
let (start_x, start_y, _) = coordinate.resolve(ctx, "titles.top-right") let (_, (start_x, start_y, _)) = coordinate.resolve(ctx, "titles.north-east")
let end_x = 1 + coordinate.resolve(ctx, "titles.top-left").at(0) let end_x = 1 + coordinate.resolve(ctx, "titles.north-west").at(1).at(0)
let end_y = coordinate.resolve(ctx, "titles.bottom").at(1) let end_y = coordinate.resolve(ctx, "titles.south").at(1).at(1)
group( group(
{ {
@ -208,7 +208,7 @@
let start = ( let start = (
a: (start_x, start_y + 16 * (i + 1) * pt), a: (start_x, start_y + 16 * (i + 1) * pt),
b: (end_x, start_y + 16 * (i + 1) * pt), b: (end_x, start_y + 16 * (i + 1) * pt),
number: passed / n_cols, number: passed / n_cols * 100%,
) )
if group_start == none { group_start = start } if group_start == none { group_start = start }
@ -216,12 +216,12 @@
let end = ( let end = (
a: (start_x, start_y + 16 * i * pt), a: (start_x, start_y + 16 * i * pt),
b: (end_x, start_y + 16 * i * pt), b: (end_x, start_y + 16 * i * pt),
number: (passed + len) / n_cols, number: (passed + len) / n_cols * 100%,
) )
group_end = end group_end = end
content(start, end, anchor: "top-left", align(center + horizon, name)) content(start, end, anchor: "north-west", align(center + horizon, name))
passed += len passed += len
} }
@ -240,21 +240,30 @@
// Draw the lines // Draw the lines
for (i, task) in flat_tasks.enumerate() { for (i, task) in flat_tasks.enumerate() {
let start = "titles.task" + str(i) let start = "titles.task" + str(i)
let (_, task_start_y, _) = coordinate.resolve(ctx, "titles.task" + str(i)) let (_, (_, task_start_y, _)) = coordinate.resolve(ctx, "titles.task" + str(i))
let (task_top_x, task_top_y, _) = coordinate.resolve(ctx, "titles.task" + str(i) + "-top") let (_, (task_top_x, task_top_y, _)) = coordinate.resolve(ctx, "titles.task" + str(i) + "-top")
let (_, task_bottom_y, _) = coordinate.resolve(ctx, "titles.task" + str(i) + "-bottom") let (_, (_, task_bottom_y, _)) = coordinate.resolve(ctx, "titles.task" + str(i) + "-bottom")
let h = task_top_y - task_bottom_y
for gantt_line in task.lines { for gantt_line in task.lines {
let y = task_start_y
if task.parallel {
if gantt_line.at("real", default: false) {
y -= h / 6
} else {
y += h / 6
}
}
let start = ( let start = (
a: (start_x, task_start_y), a: (start_x, y),
b: (end_x, task_start_y), b: (end_x, y),
number: (gantt_line.from + offset) / n_cols, number: (gantt_line.from + offset) / n_cols * 100%,
) )
let end = ( let end = (
a: (start_x, task_start_y), a: (start_x, y),
b: (end_x, task_start_y), b: (end_x, y),
number: (gantt_line.to + offset) / n_cols, number: (gantt_line.to + offset) / n_cols * 100%,
) )
let style = line-style let style = line-style
@ -283,20 +292,20 @@
if show-grid == true or show-grid == "y" { if show-grid == true or show-grid == "y" {
for (i, task) in flat_tasks.enumerate() { for (i, task) in flat_tasks.enumerate() {
let (_, task_bottom_y, _) = coordinate.resolve(ctx, "titles.task" + str(i) + "-bottom") let (_, (_, task_bottom_y, _)) = coordinate.resolve(ctx, "titles.task" + str(i) + "-bottom")
line((start_x, task_bottom_y), (end_x, task_bottom_y), ..grid-style) line((start_x, task_bottom_y), (end_x, task_bottom_y), ..grid-style)
} }
if milestone-layout == "aligned" { if milestone-layout == "aligned" {
for (i, milestone) in milestones.enumerate() { for (i, milestone) in milestones.enumerate() {
let (_, bottom_y, _) = coordinate.resolve(ctx, "titles.milestone" + str(i) + "-bottom") let (_, (_, bottom_y, _)) = coordinate.resolve(ctx, "titles.milestone" + str(i) + "-bottom")
line((start_x, bottom_y), (end_x, bottom_y), ..grid-style) line((start_x, bottom_y), (end_x, bottom_y), ..grid-style)
} }
} }
} }
// Border all around the timeline // Border all around the timeline
rect("titles.top-left", (end_x, end_y), stroke: black + 1pt) rect("titles.north-west", (end_x, end_y), stroke: black + 1pt)
}, },
) )
} }
@ -310,7 +319,7 @@
style: milestone-line-style, style: milestone-line-style,
overhang: milestone-overhang, overhang: milestone-overhang,
spacing: spacing, spacing: spacing,
anchor: "top", anchor: "north",
type: "milestone", type: "milestone",
) = { ) = {
if milestone-layout == "in-place" { if milestone-layout == "in-place" {
@ -321,14 +330,14 @@
let pos = (x: x, y: end_y - (spacing + overhang).pt() * pt) let pos = (x: x, y: end_y - (spacing + overhang).pt() * pt)
let box_x = x let box_x = x
let (w, h) = measure(body, ctx) let (w, h) = util.measure(ctx, body)
if x + w / 2 > end_x { if x + w / 2 > end_x {
box_x = end_x - w / 2 box_x = end_x - w / 2
} }
if i != 0 { if i != 0 {
let (prev_end_x, prev_start_y, _) = coordinate.resolve-anchor(ctx, "milestone" + str(i - 1) + ".top-right") let (prev_end_x, prev_start_y, _) = coordinate.resolve-anchor(ctx, "milestone" + str(i - 1) + ".north-east")
let prev_end_y = coordinate.resolve-anchor(ctx, "milestone" + str(i - 1) + ".bottom").at(1) let prev_end_y = coordinate.resolve-anchor(ctx, "milestone" + str(i - 1) + ".south").at(1)
if box_x - w / 2 < prev_end_x and pos.y <= prev_start_y and pos.y + h >= prev_end_y { if box_x - w / 2 < prev_end_x and pos.y <= prev_start_y and pos.y + h >= prev_end_y {
pos = (x: x, y: prev_end_y - spacing.pt() * pt * 2) pos = (x: x, y: prev_end_y - spacing.pt() * pt * 2)
@ -346,7 +355,7 @@
) )
} else if milestone-layout == "aligned" { } else if milestone-layout == "aligned" {
let x = (end_x - start_x) * (at / n_cols) + start_x let x = (end_x - start_x) * (at / n_cols) + start_x
let end_y = coordinate.resolve(ctx, "titles.milestone" + str(i) + "-right").at(1) let end_y = coordinate.resolve(ctx, "titles.milestone" + str(i) + "-right").at(1).at(1)
line((x, start_y), (x, end_y), (start_x, end_y), ..style) line((x, start_y), (x, end_y), (start_x, end_y), ..style)
} }
} }
@ -354,7 +363,7 @@
on-layer(-0.5, { on-layer(-0.5, {
if milestone-layout == "aligned" { if milestone-layout == "aligned" {
set-ctx(ctx => { set-ctx(ctx => {
ctx.prev.pt = coordinate.resolve(ctx, "titles.bottom") ctx.prev.pt = coordinate.resolve(ctx, "titles.south").at(1)
return ctx return ctx
}) })
} }
@ -417,9 +426,13 @@
#let task(name, style: none, ..lines) = { #let task(name, style: none, ..lines) = {
let processed_lines = () let processed_lines = ()
let parallel = false
for line in lines.pos() { for line in lines.pos() {
if type(line) == dictionary { if type(line) == dictionary {
if line.at("real", default: false) {
parallel = true
}
processed_lines.push(line) processed_lines.push(line)
} else { } else {
let (from, to) = line let (from, to) = line
@ -431,7 +444,7 @@
} }
} }
((type: "task", name: name, lines: processed_lines),) ((type: "task", name: name, parallel: parallel, lines: processed_lines),)
} }
#let taskgroup(title: none, tasks) = { #let taskgroup(title: none, tasks) = {