Gratis · Geen registratie · Werkt met .mmd-bestanden

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 verstreken
Open dit in de editor
Advertentie

Uitgewerkte 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 --> [*]
In de editor openen

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 --> [*]
In de editor openen

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 --> [*]
In de editor openen

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 --> [*]
In de editor openen

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 --> [*]
In de editor openen

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.

SyntaxisBetekenis
stateDiagram-v2Opent het diagram. `stateDiagram` werkt nog, maar gebruikt de oude indeling.
[*] --> ABegintoestand — het instappunt.
A --> [*]Eindtoestand.
A --> BEen overgang zonder naam.
A --> B: gebeurtenisOvergang gelabeld met de gebeurtenis die hem veroorzaakt.
state "Label" as idLeesbaar 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: tekstVoegt een notitie toe. `note left of` bestaat ook.
direction LRLegt de machine van links naar rechts in plaats van van boven naar beneden.
Advertentie

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.

Fout
stateDiagram-v2
    [*] --> Wacht op betaling
    Wacht op betaling --> Gesloten
Goed
stateDiagram-v2
    state "Wacht op betaling" as wachtBetaling
    [*] --> wachtBetaling
    wachtBetaling --> Gesloten

Wat 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.

Fout
stateDiagram-v2
    [*] --> in-behandeling
    in-behandeling --> Gesloten
Goed
stateDiagram-v2
    state "In behandeling" as inBehandeling
    [*] --> inBehandeling
    inBehandeling --> Gesloten

Wat 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.

Fout
stateDiagram-v2
    [*] --> Buiten
    state Buiten {
        [*] --> Binnen
Goed
stateDiagram-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 `--`.

Fout
stateDiagram-v2
    state Beide {
        [*] --> A
        ---
        [*] --> B
    }
Goed
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`.

Fout
stateDiagram-v3
    [*] --> Concept
Goed
stateDiagram-v2
    [*] --> Concept

Wat 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.

Fout
stateDiagram-v2
    [*] --> controle
    controle --> Goedgekeurd
    controle --> Afgekeurd
    state controle <<choice>>
Goed
stateDiagram-v2
    state controle <<choice>>
    [*] --> controle
    controle --> Goedgekeurd
    controle --> Afgekeurd

Aantekeningen 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:

Editor openen →