added flow rendering
This commit is contained in:
parent
5231f4b324
commit
047b679656
176
src/diagram.typ
176
src/diagram.typ
@ -51,20 +51,37 @@
|
||||
return (total-depth, nodes)
|
||||
}
|
||||
|
||||
#let FLOW-COLOR = (
|
||||
"source",
|
||||
"target",
|
||||
"gradient"
|
||||
)
|
||||
|
||||
#let diagram(
|
||||
elmts,
|
||||
height,
|
||||
min-spacing: 1cm
|
||||
width: auto,
|
||||
h-space: 2cm,
|
||||
min-spacing: 1cm,
|
||||
node-width: 0.5cm,
|
||||
flow-color: "source",
|
||||
roundiness: 50%,
|
||||
align-sources: false,
|
||||
align-sinks: false
|
||||
) = {
|
||||
let columns = ()
|
||||
let nodes = (:)
|
||||
let flows = ()
|
||||
|
||||
let order = ()
|
||||
for elmt in elmts {
|
||||
if elmt.type == "node" {
|
||||
order.push(elmt.name)
|
||||
nodes.insert(elmt.name, elmt)
|
||||
} else if elmt.type == "flow" {
|
||||
flows.push(elmt)
|
||||
order.push(elmt.from)
|
||||
order.push(elmt.to)
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,22 +117,22 @@
|
||||
|
||||
columns = ((),) * (total-depth + 1)
|
||||
let column-totals = (0,) * columns.len()
|
||||
for (key, node) in nodes.pairs() {
|
||||
columns.at(node.max-depth).push(key)
|
||||
column-totals.at(node.max-depth) += node.total.max
|
||||
let pairs = nodes.pairs()
|
||||
// Order nodes by reference order
|
||||
pairs = pairs.sorted(key: p => {
|
||||
order.position(n => n == p.first())
|
||||
})
|
||||
for (key, node) in pairs {
|
||||
let col = node.max-depth
|
||||
if not node.is-dst and align-sources {
|
||||
col = 0
|
||||
}
|
||||
if not node.is-src and align-sinks {
|
||||
col = columns.len() - 1
|
||||
}
|
||||
columns.at(col).push(key)
|
||||
column-totals.at(col) += node.total.max
|
||||
}
|
||||
|
||||
//total-depth
|
||||
[
|
||||
*nodes*: #nodes
|
||||
|
||||
*total-depth*: #total-depth
|
||||
|
||||
*columns*: #columns
|
||||
|
||||
*column-totals*: #column-totals
|
||||
]
|
||||
//flows
|
||||
|
||||
let h-factor = calc.min(
|
||||
..columns.zip(column-totals).map(((col, total)) => {
|
||||
@ -124,12 +141,21 @@
|
||||
})
|
||||
)
|
||||
|
||||
let get-color(nid) = {
|
||||
let r = nodes.keys().position(n => n == nid) / nodes.len()
|
||||
return color.hsv(r * 270deg, 60%, 90%)
|
||||
}
|
||||
let colors = (red, orange, yellow, green, blue, purple).map(c => c.lighten(50%))
|
||||
|
||||
let h-space = h-space
|
||||
if width != auto and columns.len() > 1 {
|
||||
let remaining-w = width - columns.len() * node-width
|
||||
h-space = remaining-w / (columns.len() - 1)
|
||||
}
|
||||
|
||||
canvas({
|
||||
let c = 0
|
||||
let x = 0pt
|
||||
for (i, column) in columns.enumerate() {
|
||||
let x = i * 3
|
||||
let total = column.map(n => nodes.at(n).total.max).sum()
|
||||
let total-h = total * h-factor
|
||||
let remaining-h = height - total-h
|
||||
@ -142,39 +168,111 @@
|
||||
let h = h-factor * node.total.max
|
||||
draw.rect(
|
||||
(x, y),
|
||||
(x + 1, y - h),
|
||||
(x + node-width, y - h),
|
||||
name: nid,
|
||||
fill: colors.at(c)
|
||||
fill: get-color(nid),
|
||||
stroke: none
|
||||
)
|
||||
c += 1
|
||||
|
||||
let pos = nid
|
||||
let algn = center
|
||||
let txt = [
|
||||
#node.display-name\
|
||||
#node.total.max
|
||||
]
|
||||
let args = (
|
||||
anchor: "center"
|
||||
)
|
||||
if node.is-src and not node.is-dst {
|
||||
draw.content(
|
||||
nid + ".west",
|
||||
anchor: "east",
|
||||
node.display-name,
|
||||
padding: 5pt
|
||||
)
|
||||
pos = nid + ".west"
|
||||
args.anchor = "east"
|
||||
algn = right
|
||||
} else if node.is-src and node.is-dst {
|
||||
draw.content(
|
||||
nid + ".center",
|
||||
anchor: "center",
|
||||
node.display-name,
|
||||
padding: 5pt,
|
||||
frame: "rect",
|
||||
fill: white.transparentize(20%)
|
||||
)
|
||||
pos = nid + ".center"
|
||||
args.anchor = "center"
|
||||
algn = center
|
||||
args.insert("frame", "rect")
|
||||
args.insert("fill", white.transparentize(50%))
|
||||
args.insert("stroke", none)
|
||||
} else if not node.is-src and node.is-dst {
|
||||
pos = nid + ".east"
|
||||
args.anchor = "west"
|
||||
algn = left
|
||||
}
|
||||
draw.content(
|
||||
nid + ".east",
|
||||
anchor: "west",
|
||||
node.display-name,
|
||||
pos,
|
||||
..args,
|
||||
align(algn, txt),
|
||||
padding: 5pt
|
||||
)
|
||||
}
|
||||
|
||||
y -= spacing + h
|
||||
}
|
||||
|
||||
x += node-width + h-space
|
||||
}
|
||||
|
||||
let offsets = (:)
|
||||
for nid in nodes.keys() {
|
||||
offsets.insert(nid, (
|
||||
"in": 0pt,
|
||||
"out": 0pt
|
||||
))
|
||||
}
|
||||
|
||||
draw.on-layer(-1, {
|
||||
|
||||
for flow in flows {
|
||||
let tl = flow.from + ".north-east"
|
||||
let tr = flow.to + ".north-west"
|
||||
let off-out = offsets.at(flow.from).out
|
||||
let off-in = offsets.at(flow.to).in
|
||||
let h = flow.amount * h-factor
|
||||
|
||||
offsets.at(flow.from).out += h
|
||||
offsets.at(flow.to).in += h
|
||||
|
||||
tl = (rel: (0, -off-out), to: tl)
|
||||
tr = (rel: (0, -off-in), to: tr)
|
||||
let br = (rel: (0, -h), to: tr)
|
||||
let bl = (rel: (0, -h), to: tl)
|
||||
|
||||
let fill = gray.lighten(50%).transparentize(50%)
|
||||
|
||||
let col1 = get-color(flow.from).desaturate(50%).lighten(50%).transparentize(50%)
|
||||
let col2 = get-color(flow.to).desaturate(50%).lighten(50%).transparentize(50%)
|
||||
|
||||
if flow-color == "source" {
|
||||
fill = col1
|
||||
} else if flow-color == "target" {
|
||||
fill = col2
|
||||
} else if flow-color == "gradient" {
|
||||
fill = gradient.linear(col1, col2)
|
||||
} else {
|
||||
fill = flow-color
|
||||
}
|
||||
|
||||
let dx = roundiness * h-space
|
||||
draw.merge-path(
|
||||
fill: fill,
|
||||
stroke: none,
|
||||
{
|
||||
draw.bezier(
|
||||
tl,
|
||||
tr,
|
||||
(rel: (dx, 0), to: tl),
|
||||
(rel: (-dx, 0), to: tr),
|
||||
)
|
||||
draw.bezier(
|
||||
br,
|
||||
bl,
|
||||
(rel: (-dx, 0), to: br),
|
||||
(rel: (dx, 0), to: bl),
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user