Mermaid toestandsdiagram-editor
Een toestandsdiagram laat zien in welke toestanden iets kan verkeren en wat het van de ene naar de andere brengt. Het past wanneer het onderwerp een levensloop heeft — een bestelling, een factuur, een abonnement — en de interessante vraag is welke overgangen zijn toegestaan. Beschrijf je uit te voeren stappen in plaats van toestanden om in te verkeren, dan heb je een stroomdiagram nodig.
De levensloop van een webshopbestelling
Dit is het geval waarin een toestandsmachine zijn plaats verdient: na verzending zijn er drie elkaar uitsluitende afloopen, en twee ervan gaan terug. Let erop dat elke overgang een label heeft. Een toestandsdiagram zonder labels zegt welke toestanden er zijn maar niet wat ze doet wisselen, en dat is de helft van de informatie.
stateDiagram-v2
direction LR
state "Concept" as concept
state "Wacht op betaling" as wachtBetaling
state "Gereed voor verzending" as gereed
state "Onderweg" as onderweg
state "Bezorgd" as bezorgd
state "Retour aangemeld" as retour
[*] --> concept
concept --> wachtBetaling: besteld
wachtBetaling --> gereed: betaling ontvangen
wachtBetaling --> [*]: verlopen na 24 uur
gereed --> onderweg: opgehaald door de vervoerder
onderweg --> bezorgd: afgetekend
bezorgd --> retour: binnen de bedenktijd
retour --> wachtBetaling: terugbetaling verwerkt
bezorgd --> [*]: bedenktijd verstrekenUitgewerkte voorbeelden
1. De kleinste toestandsmachine
`[*]` is zowel het instappunt als het eindpunt: welke van de twee hangt af van aan welke kant van de pijl het staat. Dit is de minimale opzet die het tekenen waard is.
stateDiagram-v2
[*] --> Actief
Actief --> Gesloten
Gesloten --> [*]2. Overgangen met een naam
De tekst na de dubbele punt benoemt de gebeurtenis die de overgang veroorzaakt. Dat is het deel dat het diagram nuttig maakt: zonder heb je een lijst toestanden en geen enkele regel.
stateDiagram-v2
[*] --> Openstaand
Openstaand --> Betaald: incasso geslaagd
Openstaand --> Vervallen: termijn verstreken
Betaald --> Verzonden: uit het magazijn
Verzonden --> Bezorgd: afgetekend
Bezorgd --> [*]
Vervallen --> [*]3. Leesbare labels met veilige id's
In het Nederlands past bijna geen enkele toestandsnaam in één woord, en een spatie in de id sloopt het stilletjes. `state "Label" as id` lost dat in één keer op: het label is leesbaar, de id is veilig.
stateDiagram-v2
state "Wacht op betaling" as wachtBetaling
state "Gereed voor verzending" as gereed
state "Onderweg naar de klant" as onderweg
[*] --> wachtBetaling
wachtBetaling --> gereed: betaling bevestigd
gereed --> onderweg: opgehaald door de vervoerder
onderweg --> [*]4. Samengestelde toestanden en keuzepunten
Een samengestelde toestand bevat een eigen machine: gebruik hem wanneer een fase een intern verloop heeft dat ertoe doet. `<<choice>>` is een voorwaardelijke vertakking, en die moet gedeclareerd worden vóór de overgangen die hem gebruiken.
stateDiagram-v2
state controle <<choice>>
[*] --> InBehandeling
state InBehandeling {
[*] --> Verzamelen
Verzamelen --> Inpakken: artikelen verzameld
Inpakken --> [*]
}
InBehandeling --> controle
controle --> Goedgekeurd: kwaliteitscontrole gehaald
controle --> Afgekeurd: gebrek gevonden
Goedgekeurd --> [*]
Afgekeurd --> [*]5. Gelijktijdige regio's
Twee streepjes op een eigen regel splitsen een samengestelde toestand in regio's die tegelijk actief zijn. Dit is het enige wat een toestandsdiagram doet en een stroomdiagram werkelijk niet kan.
stateDiagram-v2
[*] --> Registratie
state Registratie {
[*] --> EmailOnbevestigd
EmailOnbevestigd --> EmailBevestigd: link aangeklikt
--
[*] --> ProfielLeeg
ProfielLeeg --> ProfielCompleet: formulier verstuurd
}
Registratie --> Actief: allebei afgerond
Actief --> [*]Overzicht van de toestandsdiagram-syntaxis
Gebruik `stateDiagram-v2` en niet `stateDiagram`. Allebei tekenen ze, maar v2 is de indelingsmotor die nog doorontwikkeld wordt en gaat merkbaar beter om met samengestelde en gelijktijdige toestanden.
| Syntaxis | Betekenis |
|---|---|
| stateDiagram-v2 | Opent het diagram. `stateDiagram` werkt nog, maar gebruikt de oude indeling. |
| [*] --> A | Begintoestand — het instappunt. |
| A --> [*] | Eindtoestand. |
| A --> B | Een overgang zonder naam. |
| A --> B: gebeurtenis | Overgang gelabeld met de gebeurtenis die hem veroorzaakt. |
| state "Label" as id | Leesbaar label met een id zonder spaties. |
| state A { ... } | Samengestelde toestand, met een eigen machine erin. |
| -- | Binnen een samengestelde toestand splitst dit hem in gelijktijdige regio's. |
| state x <<choice>> | Voorwaardelijk vertakkingspunt. |
| state f <<fork>> / <<join>> | Splitsen naar gelijktijdige overgangen en weer samenvoegen. |
| note right of A: tekst | Voegt een notitie toe. `note left of` bestaat ook. |
| direction LR | Legt de machine van links naar rechts in plaats van van boven naar beneden. |
De zes fouten die een toestandsdiagram slopen
Nagemaakt op Mermaid 11.12.2. De eerste vier stoppen het tekenen. De laatste twee zijn erger: ze tekenen zonder met de ogen te knipperen en geven een diagram terug dat niet betekent wat je hebt opgeschreven.
Wat je ziet
Het tekent, maar in plaats van één toestand staan er meerdere
Waarom
Een spatie in de toestands-id. In het Nederlands is dit de makkelijkst te maken fout, want bijna geen enkele van onze toestandsnamen past in één woord. Mermaid weigert het niet en behandelt de rest ook niet als beschrijving: het maakt voor elk woord een apart vakje. Gemeten door de uitgegeven id's te lezen — `[*] --> Wacht op betaling` levert drie toestanden op, `Wacht`, `op` en `betaling`, waarvan alleen de eerste aan de pijl hangt; de rest blijft er los bij staan. Het diagram wordt zo stilletjes breder. De beschrijving bestaat wel degelijk, maar die vraagt een dubbele punt: `wachtBetaling: wacht op de incasso`.
Oplossing
Declareer de toestand met `state "Label" as id` en verwijs er altijd via de id naar.
stateDiagram-v2
[*] --> Wacht op betaling
Wacht op betaling --> GeslotenstateDiagram-v2
state "Wacht op betaling" as wachtBetaling
[*] --> wachtBetaling
wachtBetaling --> GeslotenWat je ziet
Parse error die eindigt op: got 'INVALID'
Waarom
Een koppelteken in de toestands-id. Namen met een koppelteken komen vanzelf op — `in-behandeling`, `voor-goedgekeurd` — maar het koppelteken wordt gelezen als het begin van een overgangspijl.
Oplossing
Gebruik één woord of een liggend streepje voor de id, en zet de leesbare tekst in een label tussen aanhalingstekens.
stateDiagram-v2
[*] --> in-behandeling
in-behandeling --> GeslotenstateDiagram-v2
state "In behandeling" as inBehandeling
[*] --> inBehandeling
inBehandeling --> GeslotenWat je ziet
Parse error binnen een samengestelde toestand
Waarom
Een samengestelde toestand die met `{` geopend is en nooit gesloten. De sluitende accolade moet op een eigen regel staan.
Oplossing
Sluit het blok.
stateDiagram-v2
[*] --> Buiten
state Buiten {
[*] --> BinnenstateDiagram-v2
[*] --> Buiten
state Buiten {
[*] --> Binnen
}Wat je ziet
Lexical error on line N. Unrecognized text.
Waarom
De scheiding tussen gelijktijdige regio's is met het verkeerde aantal streepjes geschreven. Binnen een samengestelde toestand, op een eigen regel, zijn het er precies twee. Drie streepjes zijn een compleet ander token.
Oplossing
Gebruik precies `--`.
stateDiagram-v2
state Beide {
[*] --> A
---
[*] --> B
}stateDiagram-v2
state Beide {
[*] --> A
--
[*] --> B
}Wat je ziet
Parse error on line 1 die eindigt op: got 'ID'
Waarom
Een versieachtervoegsel dat niet bestaat. Er zijn `stateDiagram` en `stateDiagram-v2`, en verder niets: `-v3` sneuvelt op de eerste regel.
Oplossing
Gebruik `stateDiagram-v2`.
stateDiagram-v3
[*] --> ConceptstateDiagram-v2
[*] --> ConceptWat je ziet
Het tekent, maar het keuzepunt wordt als een gewone toestand getekend
Waarom
De `<<choice>>`-declaratie staat na de overgangen die hem gebruiken. Mermaid maakt de toestand aan op het moment dat hij hem voor het eerst tegenkomt, en een later toegevoegd stereotype verandert niets aan wat er al is.
Oplossing
Declareer pseudotoestanden vóór de overgangen die ernaar verwijzen.
stateDiagram-v2
[*] --> controle
controle --> Goedgekeurd
controle --> Afgekeurd
state controle <<choice>>stateDiagram-v2
state controle <<choice>>
[*] --> controle
controle --> Goedgekeurd
controle --> AfgekeurdAantekeningen over het tekenen
Gemeten op Mermaid 11.12.2, de versie die deze site gebruikt.
Hier faalt de spatie in een id stilletjes
De vergelijking tussen de typen is het weten waard, want dezelfde onoplettendheid wordt heel verschillend afgestraft. In een stroomdiagram levert een spatie in een knoop-id een Parse error op en weet je het meteen. In een toestandsdiagram levert het niets op: het diagram tekent en er komt een vakje per woord. Gemeten: `Wacht op betaling --> Gesloten` komt uit op 263 pixels breed met vier losse vakjes — `Wacht`, `op`, `betaling` en `Gesloten` — waar je er twee bedoelde. Dat is het verschil tussen een fout die je waarschuwt en een die zwijgt. Omdat in het Nederlands bijna geen toestandsnaam in één woord past, is de enige echte verdediging om uit gewoonte `state "…" as id` te schrijven.
De hoogte groeit met ongeveer 114 pixels per toestand
Gemeten: drie toestanden geven een viewBox van ongeveer 91×348, veertig geven er 100×4566 — ruwweg 114 pixels per toestand. Net als bij stroomdiagrammen beweegt de breedte nauwelijks: toestandsmachines groeien naar beneden. Is de levensloop lang en weinig vertakt, dan is `direction LR` in het diagram zetten de gebruikelijke oplossing.
Zowel stateDiagram als stateDiagram-v2 tekent — en dat is de val
Je leest vaak dat er «zonder `stateDiagram-v2` niets getekend wordt». In 11.12.2 klopt dat niet: beide sleutelwoorden tekenen zonder fout. Wat verschilt is de kwaliteit van de indeling, vooral bij samengestelde en gelijktijdige toestanden, en bij het gebruik van de oude verschijnt er geen enkele waarschuwing. Ziet een samengestelde toestand er geperst uit of lopen de pijlen vreemde routes, kijk dan met welk sleutelwoord je het diagram geopend hebt voordat je het gaat herschrijven.
Labels zijn HTML, dus de PNG-export tekent opnieuw
Net als bij stroom-, klassen- en ER-diagrammen worden ook toestandslabels binnen een `<foreignObject>` in de SVG getekend. Omdat browsers weigeren dat op een canvas te rasteren, tekent de PNG-export van deze site het diagram eerst opnieuw met gewone SVG-tekstlabels. De PNG komt correct en op volle grootte uit; de zetwijze wijkt heel licht af van het scherm.
Het thema verandert de kleuren, nooit de geometrie
Het lichte en het donkere thema leveren voor dezelfde bron dezelfde viewBox op, dus een toestandsmachine wordt niet opnieuw ingedeeld als het thema wisselt.
Wanneer een ander diagram beter past
Zijn je labels handelingen — valideer, verstuur, probeer opnieuw — dan beschrijf je een proces en geen levensloop, en is het stroomdiagram de eerlijke keuze. Het duidelijkste signaal is dat je de vraag «wat is het ding dat zich in deze toestand bevindt?» niet kunt beantwoorden.
Hebben meerdere onderdelen elk hun eigen levensloop en is juist hun samenspel het interessante, dan wint een toestandsdiagram per onderdeel plus een sequentiediagram voor het samenspel het van één reusachtige machine.
Is elke toestand met elke andere toestand verbonden, dan wordt het diagram een kluwen hoe je het ook tekent. Meestal betekent dat de dingen die je als toestanden hebt opgesomd in werkelijkheid vlaggen zijn die vrij combineren; dan zegt een tabel van geldige combinaties veel meer dan een plaatje.
Andere diagramtypen
Geschreven door Dominik Malsch · Laatst bijgewerkt: