Compare commits
12 Commits
3b25d68f1e
...
v0.1.0
Author | SHA1 | Date | |
---|---|---|---|
6f563750fb
|
|||
5822d705f2
|
|||
226efa46b7
|
|||
3d9e045b56
|
|||
eb05c41810
|
|||
b9bbe6f93d
|
|||
b5c34c154f
|
|||
030fd3edba
|
|||
cbba14ed04
|
|||
77a65a3199
|
|||
ff6a7e52bc
|
|||
ebd4d8f1ca
|
149
README.md
149
README.md
@ -1,3 +1,150 @@
|
|||||||
# chronos
|
# chronos
|
||||||
|
|
||||||
A Typst package to draw sequence diagrams with CeTZ
|
A Typst package to draw sequence diagrams with CeTZ
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
This package lets you render sequence diagrams directly in Typst. The following boilerplate code creates an empty sequence diagram with two participants:
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Typst</strong></td>
|
||||||
|
<td><strong>Result</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
```typst
|
||||||
|
#import "@preview/chronos:0.1.0"
|
||||||
|
#chronos.diagram({
|
||||||
|
import chronos: *
|
||||||
|
_par("Alice")
|
||||||
|
_par("Bob")
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td><img src="./gallery/readme/boilerplate.png"></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
> *Disclaimer*\
|
||||||
|
> The package cannot parse PlantUML syntax for the moment, and thus requires the use of element functions, as shown in the examples.
|
||||||
|
> A PlantUML parser is in the TODO list, just not the top priority
|
||||||
|
|
||||||
|
## Basic sequences
|
||||||
|
|
||||||
|
You can make basic sequences using the `_seq` function:
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Typst</strong></td>
|
||||||
|
<td><strong>Result</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
```typst
|
||||||
|
#chronos.diagram({
|
||||||
|
import chronos: *
|
||||||
|
_par("Alice")
|
||||||
|
_par("Bob")
|
||||||
|
|
||||||
|
_seq("Alice", "Bob", comment: "Hello")
|
||||||
|
_seq("Bob", "Bob", comment: "Think")
|
||||||
|
_seq("Bob", "Alice", comment: "Hi")
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td><img src="./gallery/readme/simple_sequence.png"></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
You can make lifelines using the following parameters of the `_seq` function:
|
||||||
|
- `enable-dst`: enables the destination lifeline
|
||||||
|
- `create-dst`: creates the destination lifeline and participant
|
||||||
|
- `disable-dst`: disables the destination lifeline
|
||||||
|
- `destroy-dst`: destroys the destination lifeline and participant
|
||||||
|
- `disable-src`: disables the source lifeline
|
||||||
|
- `destroy-src`: destroy the source lifeline and participant
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Typst</strong></td>
|
||||||
|
<td><strong>Result</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
```typst
|
||||||
|
#chronos.diagram({
|
||||||
|
import chronos: *
|
||||||
|
_par("A", display-name: "Alice")
|
||||||
|
_par("B", display-name: "Bob")
|
||||||
|
_par("C", display-name: "Charlie")
|
||||||
|
_par("D", display-name: "Derek")
|
||||||
|
|
||||||
|
_seq("A", "B", comment: "hello", enable-dst: true)
|
||||||
|
_seq("B", "B", comment: "self call", enable-dst: true)
|
||||||
|
_seq("C", "B", comment: "hello from thread 2", enable-dst: true, lifeline-style: (fill: rgb("#005500")))
|
||||||
|
_seq("B", "D", comment: "create", create-dst: true)
|
||||||
|
_seq("B", "C", comment: "done in thread 2", disable-src: true, dashed: true)
|
||||||
|
_seq("B", "B", comment: "rc", disable-src: true, dashed: true)
|
||||||
|
_seq("B", "D", comment: "delete", destroy-dst: true)
|
||||||
|
_seq("B", "A", comment: "success", disable-src: true, dashed: true)
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td><img src="./gallery/readme/lifelines.png"></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
## Showcase
|
||||||
|
|
||||||
|
Several features have already been implemented in Chronos. Don't hesitate to checkout the examples in the [gallery](./gallery) folder to see what you can do.
|
||||||
|
|
||||||
|
#### Quick example reference:
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Example</strong></td>
|
||||||
|
<td><strong>Features</strong></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
`example1` <br>([PDF](./gallery/example1.pdf)|[Typst](./gallery/example1.typ))
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>Simple cases, color sequences, groups, separators, gaps, self-sequences</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
`example2` <br>([PDF](./gallery/example2.pdf)|[Typst](./gallery/example2.typ))
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>Lifelines, found/lost messages, synchronized sequences, slanted sequences</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
`example3` <br>([PDF](./gallery/example3.pdf)|[Typst](./gallery/example3.typ))
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>Participant shapes, sequence tips, hidden partipicant ends</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
`notes` <br>([PDF](./gallery/notes.pdf)|[Typst](./gallery/notes.typ))
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>Notes (duh), deferred participant creation</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
>
|
||||||
|
> Many examples were taken/adapted from the PlantUML [documentation](https://plantuml.com/sequence-diagram) on sequence diagrams
|
8
TODO.md
8
TODO.md
@ -10,9 +10,11 @@
|
|||||||
- [x] Lifelines
|
- [x] Lifelines
|
||||||
- [x] Different types of participants
|
- [x] Different types of participants
|
||||||
- [x] Notes
|
- [x] Notes
|
||||||
- [ ] Synchronized arrows
|
- [x] Synchronized arrows
|
||||||
- [ ] Slanted arrows
|
- [x] Slanted arrows
|
||||||
- [ ] Different types of arrow tips (WIP)
|
- [x] Different types of arrow tips
|
||||||
|
- [x] Sequence comment alignment
|
||||||
|
- [x] Fix group size with syncs
|
||||||
- [ ] Fix column spacing with notes over multiple columns
|
- [ ] Fix column spacing with notes over multiple columns
|
||||||
- [ ] Fix notes with arrows from start / to end / small arrows
|
- [ ] Fix notes with arrows from start / to end / small arrows
|
||||||
- [ ] Fix group size with self arrows + notes
|
- [ ] Fix group size with self arrows + notes
|
||||||
|
11
gallery.bash
11
gallery.bash
@ -14,3 +14,14 @@ do
|
|||||||
typst c --root ./ "$f" "$f2"
|
typst c --root ./ "$f" "$f2"
|
||||||
i=$((i+1))
|
i=$((i+1))
|
||||||
done
|
done
|
||||||
|
|
||||||
|
set -- ./gallery/readme/*.typ
|
||||||
|
cnt="$#"
|
||||||
|
i=1
|
||||||
|
for f
|
||||||
|
do
|
||||||
|
f2="${f/typ/png}"
|
||||||
|
echo "($i/$cnt) $f -> $f2"
|
||||||
|
typst c --root ./ "$f" "$f2"
|
||||||
|
i=$((i+1))
|
||||||
|
done
|
||||||
|
Binary file not shown.
Binary file not shown.
@ -48,4 +48,122 @@
|
|||||||
_seq("Alice", "]", comment: [->\]\ from actor1 *to end*])
|
_seq("Alice", "]", comment: [->\]\ from actor1 *to end*])
|
||||||
_seq("Alice", "?", comment: [->?\ *short* from actor1])
|
_seq("Alice", "?", comment: [->?\ *short* from actor1])
|
||||||
_seq("Alice", "Bob", comment: [->\ from actor1 to actor2])
|
_seq("Alice", "Bob", comment: [->\ from actor1 to actor2])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
#chronos.diagram({
|
||||||
|
import chronos: *
|
||||||
|
_par("alice", display-name: "Alice")
|
||||||
|
_par("bob", display-name: "Bob")
|
||||||
|
_par("craig", display-name: "Craig")
|
||||||
|
|
||||||
|
_seq("bob", "alice")
|
||||||
|
_seq("bob", "craig")
|
||||||
|
_gap()
|
||||||
|
|
||||||
|
_sync({
|
||||||
|
_seq("bob", "alice", comment: "Synched", comment-align: "start")
|
||||||
|
_seq("bob", "craig", comment: "Synched", comment-align: "start")
|
||||||
|
})
|
||||||
|
_gap()
|
||||||
|
|
||||||
|
_seq("alice", "bob")
|
||||||
|
_seq("craig", "bob")
|
||||||
|
_gap()
|
||||||
|
|
||||||
|
_sync({
|
||||||
|
_seq("alice", "bob")
|
||||||
|
_seq("craig", "bob")
|
||||||
|
})
|
||||||
|
_gap()
|
||||||
|
|
||||||
|
_sync({
|
||||||
|
_seq("alice", "bob", enable-dst: true)
|
||||||
|
_seq("craig", "bob")
|
||||||
|
})
|
||||||
|
_gap()
|
||||||
|
|
||||||
|
_evt("bob", "disable")
|
||||||
|
})
|
||||||
|
|
||||||
|
#chronos.diagram({
|
||||||
|
import chronos: *
|
||||||
|
_par("alice", display-name: "Alice")
|
||||||
|
_par("bob", display-name: "Bob")
|
||||||
|
_par("craig", display-name: "Craig")
|
||||||
|
|
||||||
|
_seq("alice", "bob")
|
||||||
|
_seq("bob", "craig", slant: auto)
|
||||||
|
_seq("alice", "craig", slant: 20)
|
||||||
|
|
||||||
|
_sync({
|
||||||
|
_seq("alice", "bob", slant: 10)
|
||||||
|
_seq("craig", "bob", slant: 20)
|
||||||
|
})
|
||||||
|
|
||||||
|
_sync({
|
||||||
|
_seq("alice", "bob", slant: auto)
|
||||||
|
_seq("bob", "alice", slant: auto)
|
||||||
|
})
|
||||||
|
|
||||||
|
_gap()
|
||||||
|
_evt("bob", "disable")
|
||||||
|
})
|
||||||
|
|
||||||
|
#grid(columns: 2, column-gutter: 2em,
|
||||||
|
chronos.diagram({
|
||||||
|
import chronos: *
|
||||||
|
|
||||||
|
_par("alice", display-name: "Alice")
|
||||||
|
_par("bob", display-name: "Bob")
|
||||||
|
_seq("alice", "bob", comment: "This is a very long comment")
|
||||||
|
|
||||||
|
// Left to right
|
||||||
|
_seq("alice", "bob", comment: "Start aligned", comment-align: "start")
|
||||||
|
_seq("alice", "bob", comment: "End aligned", comment-align: "end")
|
||||||
|
_seq("alice", "bob", comment: "Left aligned", comment-align: "left")
|
||||||
|
_seq("alice", "bob", comment: "Right aligned", comment-align: "right")
|
||||||
|
_seq("alice", "bob", comment: "Centered", comment-align: "center")
|
||||||
|
_gap()
|
||||||
|
|
||||||
|
// Right to left
|
||||||
|
_seq("bob", "alice", comment: "Start aligned", comment-align: "start")
|
||||||
|
_seq("bob", "alice", comment: "End aligned", comment-align: "end")
|
||||||
|
_seq("bob", "alice", comment: "Left aligned", comment-align: "left")
|
||||||
|
_seq("bob", "alice", comment: "Right aligned", comment-align: "right")
|
||||||
|
_seq("bob", "alice", comment: "Centered", comment-align: "center")
|
||||||
|
_gap()
|
||||||
|
|
||||||
|
// Slant left to right
|
||||||
|
_seq("alice", "bob", comment: "Start aligned", comment-align: "start", slant: 10)
|
||||||
|
_seq("alice", "bob", comment: "End aligned", comment-align: "end", slant: 10)
|
||||||
|
_seq("alice", "bob", comment: "Left aligned", comment-align: "left", slant: 10)
|
||||||
|
_seq("alice", "bob", comment: "Right aligned", comment-align: "right", slant: 10)
|
||||||
|
_seq("alice", "bob", comment: "Centered", comment-align: "center", slant: 10)
|
||||||
|
_gap()
|
||||||
|
|
||||||
|
// Slant right to left
|
||||||
|
_seq("bob", "alice", comment: "Start aligned", comment-align: "start", slant: 10)
|
||||||
|
_seq("bob", "alice", comment: "End aligned", comment-align: "end", slant: 10)
|
||||||
|
_seq("bob", "alice", comment: "Left aligned", comment-align: "left", slant: 10)
|
||||||
|
_seq("bob", "alice", comment: "Right aligned", comment-align: "right", slant: 10)
|
||||||
|
_seq("bob", "alice", comment: "Centered", comment-align: "center", slant: 10)
|
||||||
|
}),
|
||||||
|
|
||||||
|
chronos.diagram({
|
||||||
|
import chronos: *
|
||||||
|
|
||||||
|
_par("alice", display-name: "Alice")
|
||||||
|
|
||||||
|
_seq("alice", "alice", comment: "Start aligned", comment-align: "start")
|
||||||
|
_seq("alice", "alice", comment: "End aligned", comment-align: "end")
|
||||||
|
_seq("alice", "alice", comment: "Left aligned", comment-align: "left")
|
||||||
|
_seq("alice", "alice", comment: "Right aligned", comment-align: "right")
|
||||||
|
_seq("alice", "alice", comment: "Centered", comment-align: "center")
|
||||||
|
|
||||||
|
_seq("alice", "alice", comment: "Start aligned", comment-align: "start", flip: true)
|
||||||
|
_seq("alice", "alice", comment: "End aligned", comment-align: "end", flip: true)
|
||||||
|
_seq("alice", "alice", comment: "Left aligned", comment-align: "left", flip: true)
|
||||||
|
_seq("alice", "alice", comment: "Right aligned", comment-align: "right", flip: true)
|
||||||
|
_seq("alice", "alice", comment: "Centered", comment-align: "center", flip: true)
|
||||||
|
})
|
||||||
|
)
|
Binary file not shown.
@ -65,11 +65,11 @@ chronos.diagram({
|
|||||||
_seq("a", "b", end-tip: "x", comment: `->x`)
|
_seq("a", "b", end-tip: "x", comment: `->x`)
|
||||||
_seq("a", "b", start-tip: "x", comment: `x->`)
|
_seq("a", "b", start-tip: "x", comment: `x->`)
|
||||||
_seq("a", "b", start-tip: "o", comment: `o->`)
|
_seq("a", "b", start-tip: "o", comment: `o->`)
|
||||||
_seq("a", "b", end-tip: "o", comment: `->o`)
|
_seq("a", "b", end-tip: ("o", ">"), comment: `->o`)
|
||||||
_seq("a", "b", start-tip: "o", end-tip: "o", comment: `o->o`)
|
_seq("a", "b", start-tip: "o", end-tip: ("o", ">"), comment: `o->o`)
|
||||||
_seq("a", "b", start-tip: ">", end-tip: ">", comment: `<->`)
|
_seq("a", "b", start-tip: ">", end-tip: ">", comment: `<->`)
|
||||||
_seq("a", "b", start-tip: ("o", ">"), end-tip: ("o", ">"), comment: `o<->o`)
|
_seq("a", "b", start-tip: ("o", ">"), end-tip: ("o", ">"), comment: `o<->o`)
|
||||||
_seq("a", "b", start-tip: ("x", ">"), end-tip: ("x", ">"), comment: `x<->x`)
|
_seq("a", "b", start-tip: "x", end-tip: "x", comment: `x<->x`)
|
||||||
_seq("a", "b", end-tip: ("o", ">>"), comment: `->>o`)
|
_seq("a", "b", end-tip: ("o", ">>"), comment: `->>o`)
|
||||||
_seq("a", "b", end-tip: ("o", "\\"), comment: `-\o`)
|
_seq("a", "b", end-tip: ("o", "\\"), comment: `-\o`)
|
||||||
_seq("a", "b", end-tip: ("o", "\\\\"), comment: `-\\o`)
|
_seq("a", "b", end-tip: ("o", "\\\\"), comment: `-\\o`)
|
||||||
@ -78,6 +78,34 @@ chronos.diagram({
|
|||||||
_seq("a", "b", start-tip: "x", end-tip: ("o", ">"), comment: `x->o`)
|
_seq("a", "b", start-tip: "x", end-tip: ("o", ">"), comment: `x->o`)
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
chronos.diagram({
|
||||||
|
import chronos: *
|
||||||
|
|
||||||
|
_par("a", display-name: "Alice")
|
||||||
|
_par("b", display-name: "Bob")
|
||||||
|
|
||||||
|
_seq("b", "a", end-tip: ">", comment: `->`)
|
||||||
|
_seq("b", "a", end-tip: ">>", comment: `->>`)
|
||||||
|
_seq("b", "a", end-tip: "\\", comment: `-\`)
|
||||||
|
_seq("b", "a", end-tip: "\\\\", comment: `-\\`)
|
||||||
|
_seq("b", "a", end-tip: "/", comment: `-/`)
|
||||||
|
_seq("b", "a", end-tip: "//", comment: `-//`)
|
||||||
|
_seq("b", "a", end-tip: "x", comment: `->x`)
|
||||||
|
_seq("b", "a", start-tip: "x", comment: `x->`)
|
||||||
|
_seq("b", "a", start-tip: "o", comment: `o->`)
|
||||||
|
_seq("b", "a", end-tip: ("o", ">"), comment: `->o`)
|
||||||
|
_seq("b", "a", start-tip: "o", end-tip: ("o", ">"), comment: `o->o`)
|
||||||
|
_seq("b", "a", start-tip: ">", end-tip: ">", comment: `<->`)
|
||||||
|
_seq("b", "a", start-tip: ("o", ">"), end-tip: ("o", ">"), comment: `o<->o`)
|
||||||
|
_seq("b", "a", start-tip: "x", end-tip: "x", comment: `x<->x`)
|
||||||
|
_seq("b", "a", end-tip: ("o", ">>"), comment: `->>o`)
|
||||||
|
_seq("b", "a", end-tip: ("o", "\\"), comment: `-\o`)
|
||||||
|
_seq("b", "a", end-tip: ("o", "\\\\"), comment: `-\\o`)
|
||||||
|
_seq("b", "a", end-tip: ("o", "/"), comment: `-/o`)
|
||||||
|
_seq("b", "a", end-tip: ("o", "//"), comment: `-//o`)
|
||||||
|
_seq("b", "a", start-tip: "x", end-tip: ("o", ">"), comment: `x->o`)
|
||||||
|
}),
|
||||||
|
|
||||||
chronos.diagram({
|
chronos.diagram({
|
||||||
import chronos: *
|
import chronos: *
|
||||||
|
|
||||||
@ -93,11 +121,11 @@ chronos.diagram({
|
|||||||
_seq("a", "a", end-tip: "x", comment: `->x`)
|
_seq("a", "a", end-tip: "x", comment: `->x`)
|
||||||
_seq("a", "a", start-tip: "x", comment: `x->`)
|
_seq("a", "a", start-tip: "x", comment: `x->`)
|
||||||
_seq("a", "a", start-tip: "o", comment: `o->`)
|
_seq("a", "a", start-tip: "o", comment: `o->`)
|
||||||
_seq("a", "a", end-tip: "o", comment: `->o`)
|
_seq("a", "a", end-tip: ("o", ">"), comment: `->o`)
|
||||||
_seq("a", "a", start-tip: "o", end-tip: "o", comment: `o->o`)
|
_seq("a", "a", start-tip: "o", end-tip: ("o", ">"), comment: `o->o`)
|
||||||
_seq("a", "a", start-tip: ">", end-tip: ">", comment: `<->`)
|
_seq("a", "a", start-tip: ">", end-tip: ">", comment: `<->`)
|
||||||
_seq("a", "a", start-tip: ("o", ">"), end-tip: ("o", ">"), comment: `o<->o`)
|
_seq("a", "a", start-tip: ("o", ">"), end-tip: ("o", ">"), comment: `o<->o`)
|
||||||
_seq("a", "a", start-tip: ("x", ">"), end-tip: ("x", ">"), comment: `x<->x`)
|
_seq("a", "a", start-tip: "x", end-tip: "x", comment: `x<->x`)
|
||||||
_seq("a", "a", end-tip: ("o", ">>"), comment: `->>o`)
|
_seq("a", "a", end-tip: ("o", ">>"), comment: `->>o`)
|
||||||
_seq("a", "a", end-tip: ("o", "\\"), comment: `-\o`)
|
_seq("a", "a", end-tip: ("o", "\\"), comment: `-\o`)
|
||||||
_seq("a", "a", end-tip: ("o", "\\\\"), comment: `-\\o`)
|
_seq("a", "a", end-tip: ("o", "\\\\"), comment: `-\\o`)
|
||||||
@ -105,4 +133,15 @@ chronos.diagram({
|
|||||||
_seq("a", "a", end-tip: ("o", "//"), comment: `-//o`)
|
_seq("a", "a", end-tip: ("o", "//"), comment: `-//o`)
|
||||||
_seq("a", "a", start-tip: "x", end-tip: ("o", ">"), comment: `x->o`)
|
_seq("a", "a", start-tip: "x", end-tip: ("o", ">"), comment: `x->o`)
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#chronos.diagram({
|
||||||
|
import chronos: *
|
||||||
|
|
||||||
|
_par("a", display-name: "Alice")
|
||||||
|
_par("b", display-name: "Bob", show-bottom: false)
|
||||||
|
_par("c", display-name: "Caleb", show-top: false)
|
||||||
|
_par("d", display-name: "Danny", show-bottom: false, show-top: false)
|
||||||
|
|
||||||
|
_gap()
|
||||||
|
})
|
Binary file not shown.
BIN
gallery/readme/boilerplate.pdf
Normal file
BIN
gallery/readme/boilerplate.pdf
Normal file
Binary file not shown.
BIN
gallery/readme/boilerplate.png
Normal file
BIN
gallery/readme/boilerplate.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
13
gallery/readme/boilerplate.typ
Normal file
13
gallery/readme/boilerplate.typ
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#import "/src/lib.typ" as chronos
|
||||||
|
|
||||||
|
#set page(
|
||||||
|
width: auto,
|
||||||
|
height: auto,
|
||||||
|
margin: 0.5cm
|
||||||
|
)
|
||||||
|
|
||||||
|
#chronos.diagram({
|
||||||
|
import chronos: *
|
||||||
|
_par("Alice")
|
||||||
|
_par("Bob")
|
||||||
|
})
|
BIN
gallery/readme/lifelines.pdf
Normal file
BIN
gallery/readme/lifelines.pdf
Normal file
Binary file not shown.
BIN
gallery/readme/lifelines.png
Normal file
BIN
gallery/readme/lifelines.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 96 KiB |
24
gallery/readme/lifelines.typ
Normal file
24
gallery/readme/lifelines.typ
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#import "/src/lib.typ" as chronos
|
||||||
|
|
||||||
|
#set page(
|
||||||
|
width: auto,
|
||||||
|
height: auto,
|
||||||
|
margin: 0.5cm
|
||||||
|
)
|
||||||
|
|
||||||
|
#chronos.diagram({
|
||||||
|
import chronos: *
|
||||||
|
_par("A", display-name: "Alice")
|
||||||
|
_par("B", display-name: "Bob")
|
||||||
|
_par("C", display-name: "Charlie")
|
||||||
|
_par("D", display-name: "Derek")
|
||||||
|
|
||||||
|
_seq("A", "B", comment: "hello", enable-dst: true)
|
||||||
|
_seq("B", "B", comment: "self call", enable-dst: true)
|
||||||
|
_seq("C", "B", comment: "hello from thread 2", enable-dst: true, lifeline-style: (fill: rgb("#005500")))
|
||||||
|
_seq("B", "D", comment: "create", create-dst: true)
|
||||||
|
_seq("B", "C", comment: "done in thread 2", disable-src: true, dashed: true)
|
||||||
|
_seq("B", "B", comment: "rc", disable-src: true, dashed: true)
|
||||||
|
_seq("B", "D", comment: "delete", destroy-dst: true)
|
||||||
|
_seq("B", "A", comment: "success", disable-src: true, dashed: true)
|
||||||
|
})
|
BIN
gallery/readme/simple_sequence.pdf
Normal file
BIN
gallery/readme/simple_sequence.pdf
Normal file
Binary file not shown.
BIN
gallery/readme/simple_sequence.png
Normal file
BIN
gallery/readme/simple_sequence.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
17
gallery/readme/simple_sequence.typ
Normal file
17
gallery/readme/simple_sequence.typ
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#import "/src/lib.typ" as chronos
|
||||||
|
|
||||||
|
#set page(
|
||||||
|
width: auto,
|
||||||
|
height: auto,
|
||||||
|
margin: 0.5cm
|
||||||
|
)
|
||||||
|
|
||||||
|
#chronos.diagram({
|
||||||
|
import chronos: *
|
||||||
|
_par("Alice")
|
||||||
|
_par("Bob")
|
||||||
|
|
||||||
|
_seq("Alice", "Bob", comment: "Hello")
|
||||||
|
_seq("Bob", "Bob", comment: "Think")
|
||||||
|
_seq("Bob", "Alice", comment: "Hi")
|
||||||
|
})
|
@ -3,6 +3,9 @@
|
|||||||
#let COMMENT-PAD = 8
|
#let COMMENT-PAD = 8
|
||||||
#let LIFELINE-W = 10
|
#let LIFELINE-W = 10
|
||||||
#let CREATE-OFFSET = 15
|
#let CREATE-OFFSET = 15
|
||||||
|
#let DEFAULT-SLANT = 10
|
||||||
|
#let CROSS-TIP-SIZE = 4
|
||||||
|
#let CIRCLE-TIP-RADIUS = 3
|
||||||
|
|
||||||
#let SYM-GAP = 5
|
#let SYM-GAP = 5
|
||||||
#let PAR-PAD = (5pt, 3pt)
|
#let PAR-PAD = (5pt, 3pt)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#import "utils.typ": get-group-span
|
#import "utils.typ": get-group-span, fit-canvas
|
||||||
#import "renderer.typ": render
|
#import "renderer.typ": render
|
||||||
#import "participant.typ" as participant: _par, PAR-SPECIALS
|
#import "participant.typ" as participant: _par, PAR-SPECIALS
|
||||||
|
|
||||||
@ -18,7 +18,7 @@
|
|||||||
),)
|
),)
|
||||||
}
|
}
|
||||||
|
|
||||||
#let diagram(elements) = {
|
#let diagram(elements, width: auto) = {
|
||||||
if elements == none {
|
if elements == none {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -188,7 +188,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
set text(font: "Source Sans 3")
|
set text(font: "Source Sans 3")
|
||||||
render(participants, elmts)
|
let canvas = render(participants, elmts)
|
||||||
|
fit-canvas(canvas, width: width)
|
||||||
}
|
}
|
||||||
|
|
||||||
#let from-plantuml(code) = {
|
#let from-plantuml(code) = {
|
||||||
|
@ -4,4 +4,5 @@
|
|||||||
#import "group.typ": _grp
|
#import "group.typ": _grp
|
||||||
#import "participant.typ": _par
|
#import "participant.typ": _par
|
||||||
#import "separator.typ": _sep
|
#import "separator.typ": _sep
|
||||||
#import "note.typ": _note
|
#import "note.typ": _note
|
||||||
|
#import "sync.typ": _sync
|
@ -109,7 +109,7 @@
|
|||||||
}
|
}
|
||||||
} else if note.side == "right" {
|
} else if note.side == "right" {
|
||||||
x0 += NOTE-GAP
|
x0 += NOTE-GAP
|
||||||
x0 -= lifelines.at(i).level * LIFELINE-W / 2
|
x0 += lifelines.at(i).level * LIFELINE-W / 2
|
||||||
} else if note.side == "over" or note.side == "across" {
|
} else if note.side == "over" or note.side == "across" {
|
||||||
x0 -= total-w / 2
|
x0 -= total-w / 2
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,9 @@
|
|||||||
invisible: false,
|
invisible: false,
|
||||||
shape: "participant",
|
shape: "participant",
|
||||||
color: rgb("#E2E2F0"),
|
color: rgb("#E2E2F0"),
|
||||||
custom-image: none
|
custom-image: none,
|
||||||
|
show-bottom: true,
|
||||||
|
show-top: true,
|
||||||
) = {
|
) = {
|
||||||
return ((
|
return ((
|
||||||
type: "par",
|
type: "par",
|
||||||
@ -31,7 +33,9 @@
|
|||||||
invisible: invisible,
|
invisible: invisible,
|
||||||
shape: shape,
|
shape: shape,
|
||||||
color: color,
|
color: color,
|
||||||
custom-image: custom-image
|
custom-image: custom-image,
|
||||||
|
show-bottom: show-bottom,
|
||||||
|
show-top: show-top
|
||||||
),)
|
),)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#import participant: PAR-SPECIALS
|
#import participant: PAR-SPECIALS
|
||||||
#import "sequence.typ"
|
#import "sequence.typ"
|
||||||
#import "separator.typ"
|
#import "separator.typ"
|
||||||
|
#import "sync.typ"
|
||||||
#import "consts.typ": *
|
#import "consts.typ": *
|
||||||
#import "note.typ" as note: get-note-box
|
#import "note.typ" as note: get-note-box
|
||||||
|
|
||||||
@ -19,6 +20,16 @@
|
|||||||
let pars-i = get-participants-i(participants)
|
let pars-i = get-participants-i(participants)
|
||||||
let cells = ()
|
let cells = ()
|
||||||
|
|
||||||
|
// Unwrap syncs
|
||||||
|
let i = 0
|
||||||
|
while i < elements.len() {
|
||||||
|
let elmt = elements.at(i)
|
||||||
|
if elmt.type == "sync" {
|
||||||
|
elements = elements.slice(0, i + 1) + elmt.elmts + elements.slice(i + 1)
|
||||||
|
}
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
|
||||||
// Compute max lifeline levels
|
// Compute max lifeline levels
|
||||||
for elmt in elements {
|
for elmt in elements {
|
||||||
if elmt.type == "seq" {
|
if elmt.type == "seq" {
|
||||||
@ -203,10 +214,11 @@
|
|||||||
let draw-sep = separator.render.with(x-pos)
|
let draw-sep = separator.render.with(x-pos)
|
||||||
let draw-par = participant.render.with(x-pos)
|
let draw-par = participant.render.with(x-pos)
|
||||||
let draw-note = note.render.with(pars-i, x-pos)
|
let draw-note = note.render.with(pars-i, x-pos)
|
||||||
|
let draw-sync = sync.render.with(pars-i, x-pos, participants)
|
||||||
|
|
||||||
// Draw participants (start)
|
// Draw participants (start)
|
||||||
for p in participants {
|
for p in participants {
|
||||||
if p.from-start and not p.invisible {
|
if p.from-start and not p.invisible and p.show-top {
|
||||||
shapes += draw-par(p)
|
shapes += draw-par(p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -295,6 +307,12 @@
|
|||||||
(y, shps) = draw-note(elmt, y, lifelines)
|
(y, shps) = draw-note(elmt, y, lifelines)
|
||||||
shapes += shps
|
shapes += shps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Synched sequences
|
||||||
|
} else if elmt.type == "sync" {
|
||||||
|
let shps
|
||||||
|
(y, lifelines, shps) = draw-sync(elmt, y, lifelines)
|
||||||
|
shapes += shps
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,7 +417,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw participants (end)
|
// Draw participants (end)
|
||||||
draw-par(p, y: y, bottom: true)
|
if p.show-bottom {
|
||||||
|
draw-par(p, y: y, bottom: true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
221
src/sequence.typ
221
src/sequence.typ
@ -1,4 +1,4 @@
|
|||||||
#import "@preview/cetz:0.2.2": draw
|
#import "@preview/cetz:0.2.2": draw, vector
|
||||||
#import "consts.typ": *
|
#import "consts.typ": *
|
||||||
#import "participant.typ"
|
#import "participant.typ"
|
||||||
#import "note.typ"
|
#import "note.typ"
|
||||||
@ -16,14 +16,39 @@
|
|||||||
"/": (symbol: ">", fill: color, harpoon: true),
|
"/": (symbol: ">", fill: color, harpoon: true),
|
||||||
"//": (symbol: "straight", harpoon: true),
|
"//": (symbol: "straight", harpoon: true),
|
||||||
"x": none,
|
"x": none,
|
||||||
"o": (symbol: "o"),
|
"o": none,
|
||||||
).at(sym)
|
).at(sym)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#let reverse-arrow-mark(mark) = {
|
||||||
|
if type(mark) == array {
|
||||||
|
return mark.map(m => reverse-arrow-mark(m))
|
||||||
|
}
|
||||||
|
let mark2 = mark
|
||||||
|
if type(mark) == dictionary and mark.at("harpoon", default: false) {
|
||||||
|
let flipped = mark.at("flip", default: false)
|
||||||
|
mark2.insert("flip", not flipped)
|
||||||
|
}
|
||||||
|
return mark2
|
||||||
|
}
|
||||||
|
|
||||||
|
#let is-tip-of-type(type_, tip) = {
|
||||||
|
if type(tip) == str and tip == type_ {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if type(tip) == array and tip.contains(type_) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
#let is-circle-tip = is-tip-of-type.with("o")
|
||||||
|
#let is-cross-tip = is-tip-of-type.with("x")
|
||||||
|
|
||||||
#let _seq(
|
#let _seq(
|
||||||
p1,
|
p1,
|
||||||
p2,
|
p2,
|
||||||
comment: none,
|
comment: none,
|
||||||
|
comment-align: "left",
|
||||||
dashed: false,
|
dashed: false,
|
||||||
start-tip: "",
|
start-tip: "",
|
||||||
end-tip: ">",
|
end-tip: ">",
|
||||||
@ -35,13 +60,15 @@
|
|||||||
destroy-dst: false,
|
destroy-dst: false,
|
||||||
disable-src: false,
|
disable-src: false,
|
||||||
destroy-src: false,
|
destroy-src: false,
|
||||||
lifeline-style: auto
|
lifeline-style: auto,
|
||||||
|
slant: none
|
||||||
) = {
|
) = {
|
||||||
return ((
|
return ((
|
||||||
type: "seq",
|
type: "seq",
|
||||||
p1: p1,
|
p1: p1,
|
||||||
p2: p2,
|
p2: p2,
|
||||||
comment: comment,
|
comment: comment,
|
||||||
|
comment-align: comment-align,
|
||||||
dashed: dashed,
|
dashed: dashed,
|
||||||
start-tip: start-tip,
|
start-tip: start-tip,
|
||||||
end-tip: end-tip,
|
end-tip: end-tip,
|
||||||
@ -54,6 +81,7 @@
|
|||||||
disable-src: disable-src,
|
disable-src: disable-src,
|
||||||
destroy-src: destroy-src,
|
destroy-src: destroy-src,
|
||||||
lifeline-style: lifeline-style,
|
lifeline-style: lifeline-style,
|
||||||
|
slant: slant
|
||||||
),)
|
),)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,27 +115,38 @@
|
|||||||
y: y,
|
y: y,
|
||||||
ll-lvl: lifelines.at(i2).level * LIFELINE-W / 2
|
ll-lvl: lifelines.at(i2).level * LIFELINE-W / 2
|
||||||
)
|
)
|
||||||
|
let slant = if elmt.slant == auto {
|
||||||
|
DEFAULT-SLANT
|
||||||
|
} else if elmt.slant != none {
|
||||||
|
elmt.slant
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
end-info.y -= slant
|
||||||
|
if elmt.p1 == elmt.p2 {
|
||||||
|
end-info.y -= 10
|
||||||
|
}
|
||||||
|
|
||||||
if elmt.disable-src {
|
if elmt.disable-src {
|
||||||
let src-line = lifelines.at(i1)
|
let src-line = lifelines.at(i1)
|
||||||
src-line.level -= 1
|
src-line.level -= 1
|
||||||
src-line.lines.push(("disable", y))
|
src-line.lines.push(("disable", start-info.y))
|
||||||
lifelines.at(i1) = src-line
|
lifelines.at(i1) = src-line
|
||||||
}
|
}
|
||||||
if elmt.destroy-src {
|
if elmt.destroy-src {
|
||||||
let src-line = lifelines.at(i1)
|
let src-line = lifelines.at(i1)
|
||||||
src-line.lines.push(("destroy", y))
|
src-line.lines.push(("destroy", start-info.y))
|
||||||
lifelines.at(i1) = src-line
|
lifelines.at(i1) = src-line
|
||||||
}
|
}
|
||||||
if elmt.disable-dst {
|
if elmt.disable-dst {
|
||||||
let dst-line = lifelines.at(i2)
|
let dst-line = lifelines.at(i2)
|
||||||
dst-line.level -= 1
|
dst-line.level -= 1
|
||||||
dst-line.lines.push(("disable", y))
|
dst-line.lines.push(("disable", end-info.y))
|
||||||
lifelines.at(i2) = dst-line
|
lifelines.at(i2) = dst-line
|
||||||
}
|
}
|
||||||
if elmt.destroy-dst {
|
if elmt.destroy-dst {
|
||||||
let dst-line = lifelines.at(i2)
|
let dst-line = lifelines.at(i2)
|
||||||
dst-line.lines.push(("destroy", y))
|
dst-line.lines.push(("destroy", end-info.y))
|
||||||
lifelines.at(i2) = dst-line
|
lifelines.at(i2) = dst-line
|
||||||
}
|
}
|
||||||
if elmt.enable-dst {
|
if elmt.enable-dst {
|
||||||
@ -120,7 +159,7 @@
|
|||||||
let m = measure(box(par.display-name))
|
let m = measure(box(par.display-name))
|
||||||
let f = if i1 > i2 {-1} else {1}
|
let f = if i1 > i2 {-1} else {1}
|
||||||
end-info.x -= (m.width + PAR-PAD.last() * 2) / 2pt * f
|
end-info.x -= (m.width + PAR-PAD.last() * 2) / 2pt * f
|
||||||
shapes += participant.render(x-pos, par, y: y - CREATE-OFFSET)
|
shapes += participant.render(x-pos, par, y: end-info.y - CREATE-OFFSET)
|
||||||
}
|
}
|
||||||
|
|
||||||
end-info.ll-lvl = lifelines.at(i2).level * LIFELINE-W / 2
|
end-info.ll-lvl = lifelines.at(i2).level * LIFELINE-W / 2
|
||||||
@ -156,12 +195,25 @@
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
let y0 = y
|
let y0 = start-info.y
|
||||||
if "linked-note" in elmt {
|
if "linked-note" in elmt {
|
||||||
let shps = note.render(pars-i, x-pos, elmt.linked-note, y, lifelines).last()
|
let shps = note.render(pars-i, x-pos, elmt.linked-note, start-info.y, lifelines).last()
|
||||||
shapes += shps
|
shapes += shps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let flip-mark = end-info.i <= start-info.i
|
||||||
|
if elmt.flip {
|
||||||
|
flip-mark = not flip-mark
|
||||||
|
}
|
||||||
|
if flip-mark {
|
||||||
|
style.mark.end = reverse-arrow-mark(style.mark.end)
|
||||||
|
}
|
||||||
|
|
||||||
|
let pts
|
||||||
|
let comment-pt
|
||||||
|
let comment-anchor
|
||||||
|
let comment-angle = 0deg
|
||||||
|
|
||||||
if elmt.p1 == elmt.p2 {
|
if elmt.p1 == elmt.p2 {
|
||||||
if elmt.flip {
|
if elmt.flip {
|
||||||
x1 = start-info.lx
|
x1 = start-info.lx
|
||||||
@ -175,61 +227,144 @@
|
|||||||
calc.max(x1, x2) + 20
|
calc.max(x1, x2) + 20
|
||||||
}
|
}
|
||||||
|
|
||||||
if elmt.comment != none {
|
pts = (
|
||||||
shapes += draw.content(
|
(x1, start-info.y),
|
||||||
(x1, y),
|
(x-mid, start-info.y),
|
||||||
elmt.comment,
|
(x-mid, end-info.y),
|
||||||
anchor: if elmt.flip {"south-east"} else {"south-west"},
|
(x2, end-info.y)
|
||||||
padding: 3pt
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
shapes += draw.line(
|
|
||||||
(x1, y),
|
|
||||||
(x-mid, y),
|
|
||||||
(x-mid, y - 10),
|
|
||||||
(x2, y - 10),
|
|
||||||
..style
|
|
||||||
)
|
)
|
||||||
y -= 10
|
|
||||||
|
if elmt.comment != none {
|
||||||
|
comment-anchor = (
|
||||||
|
start: if x-mid < x1 {"south-east"} else {"south-west"},
|
||||||
|
end: if x-mid < x1 {"south-west"} else {"south-east"},
|
||||||
|
left: "south-west",
|
||||||
|
right: "south-east",
|
||||||
|
center: "south",
|
||||||
|
).at(elmt.comment-align)
|
||||||
|
|
||||||
|
comment-pt = (
|
||||||
|
start: pts.first(),
|
||||||
|
end: pts.at(1),
|
||||||
|
left: if x-mid < x1 {pts.at(1)} else {pts.first()},
|
||||||
|
right: if x-mid < x1 {pts.first()} else {pts.at(1)},
|
||||||
|
center: (pts.first(), 50%, pts.at(1))
|
||||||
|
).at(elmt.comment-align)
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
pts = (
|
||||||
|
(x1, start-info.y),
|
||||||
|
(x2, end-info.y)
|
||||||
|
)
|
||||||
|
|
||||||
if elmt.comment != none {
|
if elmt.comment != none {
|
||||||
let x = calc.min(x1, x2)
|
let start-pt = pts.first()
|
||||||
if x2 < x1 {
|
let end-pt = pts.last()
|
||||||
x += COMMENT-PAD
|
if elmt.start-tip != "" {
|
||||||
|
start-pt = (pts.first(), COMMENT-PAD, pts.last())
|
||||||
}
|
}
|
||||||
shapes += draw.content(
|
if elmt.end-tip != "" {
|
||||||
(x, y),
|
end-pt = (pts.last(), COMMENT-PAD, pts.first())
|
||||||
elmt.comment,
|
}
|
||||||
anchor: "south-west",
|
|
||||||
padding: 3pt
|
comment-pt = (
|
||||||
)
|
start: start-pt,
|
||||||
|
end: end-pt,
|
||||||
|
left: if x2 < x1 {end-pt} else {start-pt},
|
||||||
|
right: if x2 < x1 {start-pt} else {end-pt},
|
||||||
|
center: (start-pt, 50%, end-pt)
|
||||||
|
).at(elmt.comment-align)
|
||||||
|
|
||||||
|
comment-anchor = (
|
||||||
|
start: if x2 < x1 {"south-east"} else {"south-west"},
|
||||||
|
end: if x2 < x1 {"south-west"} else {"south-east"},
|
||||||
|
left: "south-west",
|
||||||
|
right: "south-east",
|
||||||
|
center: "south",
|
||||||
|
).at(elmt.comment-align)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (p1, p2) = pts
|
||||||
|
if x2 < x1 {
|
||||||
|
(p1, p2) = (p2, p1)
|
||||||
|
}
|
||||||
|
comment-angle = vector.angle2(p1, p2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start circle tip
|
||||||
|
if is-circle-tip(elmt.start-tip) {
|
||||||
|
shapes += draw.circle(pts.first(), radius: CIRCLE-TIP-RADIUS, stroke: elmt.color, fill: none, name: "_circle-start-tip")
|
||||||
|
pts.at(0) = "_circle-start-tip"
|
||||||
|
|
||||||
|
// Start cross tip
|
||||||
|
} else if is-cross-tip(elmt.start-tip) {
|
||||||
|
let size = CROSS-TIP-SIZE
|
||||||
|
let cross-pt = (pts.first(), size * 2, pts.at(1))
|
||||||
shapes += draw.line(
|
shapes += draw.line(
|
||||||
(x1, y),
|
(rel: (-size, -size), to: cross-pt),
|
||||||
(x2, y),
|
(rel: (size, size), to: cross-pt),
|
||||||
..style
|
stroke: elmt.color + 1.5pt
|
||||||
|
)
|
||||||
|
shapes += draw.line(
|
||||||
|
(rel: (-size, size), to: cross-pt),
|
||||||
|
(rel: (size, -size), to: cross-pt),
|
||||||
|
stroke: elmt.color + 1.5pt
|
||||||
|
)
|
||||||
|
pts.at(0) = cross-pt
|
||||||
|
}
|
||||||
|
|
||||||
|
// End circle tip
|
||||||
|
if is-circle-tip(elmt.end-tip) {
|
||||||
|
shapes += draw.circle(pts.last(), radius: 3, stroke: elmt.color, fill: none, name: "_circle-end-tip")
|
||||||
|
pts.at(pts.len() - 1) = "_circle-end-tip"
|
||||||
|
|
||||||
|
// End cross tip
|
||||||
|
} else if is-cross-tip(elmt.end-tip) {
|
||||||
|
let size = CROSS-TIP-SIZE
|
||||||
|
let cross-pt = (pts.last(), size * 2, pts.at(pts.len() - 2))
|
||||||
|
shapes += draw.line(
|
||||||
|
(rel: (-size, -size), to: cross-pt),
|
||||||
|
(rel: (size, size), to: cross-pt),
|
||||||
|
stroke: elmt.color + 1.5pt
|
||||||
|
)
|
||||||
|
shapes += draw.line(
|
||||||
|
(rel: (-size, size), to: cross-pt),
|
||||||
|
(rel: (size, -size), to: cross-pt),
|
||||||
|
stroke: elmt.color + 1.5pt
|
||||||
|
)
|
||||||
|
pts.at(pts.len() - 1) = cross-pt
|
||||||
|
}
|
||||||
|
|
||||||
|
shapes += draw.line(..pts, ..style)
|
||||||
|
|
||||||
|
if elmt.comment != none {
|
||||||
|
shapes += draw.content(
|
||||||
|
comment-pt,
|
||||||
|
elmt.comment,
|
||||||
|
anchor: comment-anchor,
|
||||||
|
angle: comment-angle,
|
||||||
|
padding: 3pt
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if elmt.enable-dst {
|
if elmt.enable-dst {
|
||||||
let dst-line = lifelines.at(i2)
|
let dst-line = lifelines.at(i2)
|
||||||
dst-line.lines.push(("enable", y, elmt.lifeline-style))
|
dst-line.lines.push(("enable", end-info.y, elmt.lifeline-style))
|
||||||
lifelines.at(i2) = dst-line
|
lifelines.at(i2) = dst-line
|
||||||
}
|
}
|
||||||
if elmt.create-dst {
|
if elmt.create-dst {
|
||||||
y -= CREATE-OFFSET
|
end-info.y -= CREATE-OFFSET
|
||||||
let dst-line = lifelines.at(i2)
|
let dst-line = lifelines.at(i2)
|
||||||
dst-line.lines.push(("create", y))
|
dst-line.lines.push(("create", end-info.y))
|
||||||
lifelines.at(i2) = dst-line
|
lifelines.at(i2) = dst-line
|
||||||
}
|
}
|
||||||
|
|
||||||
if "linked-note" in elmt {
|
if "linked-note" in elmt {
|
||||||
let m = note.get-size(elmt.linked-note)
|
let m = note.get-size(elmt.linked-note)
|
||||||
y = calc.min(y, y0 - m.height / 2)
|
end-info.y = calc.min(end-info.y, y0 - m.height / 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
let r = (y, lifelines, shapes)
|
let r = (end-info.y, lifelines, shapes)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
27
src/sync.typ
Normal file
27
src/sync.typ
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#import "sequence.typ"
|
||||||
|
|
||||||
|
#let _sync(elmts) = {
|
||||||
|
return ((
|
||||||
|
type: "sync",
|
||||||
|
elmts: elmts
|
||||||
|
),)
|
||||||
|
}
|
||||||
|
|
||||||
|
#let render(pars-i, x-pos, participants, elmt, y, lifelines) = {
|
||||||
|
let draw-seq = sequence.render.with(pars-i, x-pos, participants)
|
||||||
|
|
||||||
|
let shapes = ()
|
||||||
|
|
||||||
|
let end-y = y
|
||||||
|
|
||||||
|
for e in elmt.elmts {
|
||||||
|
let yi
|
||||||
|
let shps
|
||||||
|
(yi, lifelines, shps) = draw-seq(e, y, lifelines)
|
||||||
|
shapes += shps
|
||||||
|
end-y = calc.min(end-y, yi)
|
||||||
|
}
|
||||||
|
|
||||||
|
let r = (end-y, lifelines, shapes)
|
||||||
|
return r
|
||||||
|
}
|
@ -21,6 +21,10 @@
|
|||||||
let (i0, i1) = get-group-span(participants, elmt)
|
let (i0, i1) = get-group-span(participants, elmt)
|
||||||
min-i = calc.min(min-i, i0)
|
min-i = calc.min(min-i, i0)
|
||||||
max-i = calc.max(max-i, i1)
|
max-i = calc.max(max-i, i1)
|
||||||
|
} else if elmt.type == "sync" {
|
||||||
|
let (i0, i1) = get-group-span(participants, elmt)
|
||||||
|
min-i = calc.min(min-i, i0)
|
||||||
|
max-i = calc.max(max-i, i1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (min-i, max-i)
|
return (min-i, max-i)
|
||||||
@ -40,4 +44,27 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
panic("Invalid type for parameter mods, expected auto or dictionary, got " + str(type(mods)))
|
panic("Invalid type for parameter mods, expected auto or dictionary, got " + str(type(mods)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#let fit-canvas(canvas, width: auto) = layout(size => {
|
||||||
|
let m = measure(canvas)
|
||||||
|
let w = m.width
|
||||||
|
let h = m.height
|
||||||
|
let r = if w == 0pt {0} else {
|
||||||
|
if width == auto {1}
|
||||||
|
else if type(width) == length {
|
||||||
|
width / w
|
||||||
|
} else {
|
||||||
|
size.width * width / w
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let new-w = w * r
|
||||||
|
let new-h = h * r
|
||||||
|
r *= 100%
|
||||||
|
|
||||||
|
box(
|
||||||
|
width: new-w,
|
||||||
|
height: new-h,
|
||||||
|
scale(x: r, y: r, reflow: true, canvas)
|
||||||
|
)
|
||||||
|
})
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "chronos"
|
name = "chronos"
|
||||||
version = "0.0.1"
|
version = "0.1.0"
|
||||||
compiler = "0.11.0"
|
compiler = "0.11.0"
|
||||||
repository = "https://git.kb28.ch/HEL/chronos"
|
repository = "https://git.kb28.ch/HEL/chronos"
|
||||||
entrypoint = "src/lib.typ"
|
entrypoint = "src/lib.typ"
|
||||||
@ -11,4 +11,4 @@ categories = ["visualization"]
|
|||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
description = "A package to draw sequence diagrams with CeTZ"
|
description = "A package to draw sequence diagrams with CeTZ"
|
||||||
keywords = ["sequence", "diagram", "plantuml"]
|
keywords = ["sequence", "diagram", "plantuml"]
|
||||||
exclude = [ "/gallery/*" ]
|
exclude = [ "gallery", "gallery.bash" ]
|
||||||
|
Reference in New Issue
Block a user