Редактор диаграмм состояний Mermaid
Диаграмма состояний показывает, в каких состояниях может находиться один объект и какие события переводят его между ними. Она уместна, когда предмет — жизненный цикл: заказ, подписка, документ на согласовании. Верный признак: ваши подписи — это причастия и прилагательные, а не глаголы: ожидает, отгружен, отменён.
Жизненный цикл заказа с тупиковой отменой
Состояния — это то, чем заказ является; подписи на стрелках — то, что с ним произошло. Обратите внимание: в «Отменён» попадают из трёх состояний, но из него не ведёт ничего. Именно такую асимметрию диаграмма состояний делает очевидной, а блок-схема скрывает.
stateDiagram-v2
[*] --> Новый: заказ оформлен
Новый --> Оплачен: платёж прошёл
Новый --> Отменён: клиент отказался
Оплачен --> Собран: склад собрал
Оплачен --> Возвращён: платёж отменён
Собран --> Отгружен: передан перевозчику
Собран --> Отменён: товара нет в наличии
Отгружен --> Доставлен: доставка подтверждена
Отгружен --> Потерян: нет сканов 14 дней
Доставлен --> [*]
Возвращён --> [*]
Отменён --> [*]
Потерян --> Возвращён: претензия удовлетворенаРазобранные примеры
1. Минимальный конечный автомат
`[*]` — это и начальное, и конечное псевдосостояние: что именно оно означает, зависит от того, с какой стороны стрелки стоит.
stateDiagram-v2
[*] --> Черновик
Черновик --> Опубликован: опубликовать
Опубликован --> [*]2. Как называть состояния с пробелами
Идентификатор состояния не может содержать пробелов, но `state "Подпись" as id` даёт читаемую подпись при безопасном идентификаторе. По-русски это нужно почти всегда, потому что естественные состояния у нас — словосочетания: «ожидает оплаты», «на согласовании».
stateDiagram-v2
state "Ожидает проверки" as проверка
state "Нужны правки" as правки
[*] --> проверка
проверка --> правки: проверяющий возражает
правки --> проверка: автор исправил
проверка --> [*]: согласовано3. Составные состояния
Состояние может содержать собственный автомат. Используйте это, когда у этапа есть осмысленные внутренние шаги, которые на верхнем уровне только мешали бы: здесь — всё, что происходит внутри обработки.
stateDiagram-v2
[*] --> ВОчереди
ВОчереди --> Обработка: взял обработчик
state Обработка {
[*] --> Проверка
Проверка --> Преобразование: схема подходит
Преобразование --> Запись: строки сопоставлены
Запись --> [*]
}
Обработка --> Успех: без ошибок
Обработка --> Сбой: исключение
Сбой --> ВОчереди: повторить
Успех --> [*]4. Псевдосостояния выбора
`<<choice>>` — это развилка, зависящая от условия, а не от события. Она оставляет решение видимым, не притворяясь, что это состояние, в котором объект находится.
stateDiagram-v2
state оценка <<choice>>
[*] --> Подана
Подана --> оценка: рассчитать риск
оценка --> Одобрена: балл < 40
оценка --> РучнаяПроверка: балл >= 40
РучнаяПроверка --> Одобрена: аналитик согласен
РучнаяПроверка --> Отклонена: аналитик отказал
Одобрена --> [*]
Отклонена --> [*]5. Параллельные области
Два дефиса на отдельной строке делят составное состояние на области, активные одновременно. Это единственное, что диаграмма состояний умеет, а блок-схема по-настоящему не может.
stateDiagram-v2
[*] --> Регистрация
state Регистрация {
[*] --> ПочтаНеПодтверждена
ПочтаНеПодтверждена --> ПочтаПодтверждена: перешёл по ссылке
--
[*] --> ПрофильПустой
ПрофильПустой --> ПрофильЗаполнен: форма отправлена
}
Регистрация --> Активен: оба шага завершены
Активен --> [*]Справочник синтаксиса диаграммы состояний
Используйте `stateDiagram-v2`, а не `stateDiagram`. Рисуются оба, но v2 — это активно развиваемый движок раскладки, и составные с параллельными состояниями он обрабатывает заметно лучше.
| Синтаксис | Значение |
|---|---|
| stateDiagram-v2 | Открывает диаграмму. `stateDiagram` ещё работает, но использует старую раскладку. |
| [*] --> A | Начальное состояние — точка входа. |
| A --> [*] | Конечное состояние. |
| A --> B | Переход без названного события. |
| A --> B: событие | Переход, подписанный вызвавшим его событием. |
| state "Подпись" as id | Читаемая подпись с идентификатором без пробелов. |
| state A { ... } | Составное состояние с собственным автоматом внутри. |
| -- | Внутри составного состояния делит его на параллельные области. |
| state x <<choice>> | Точка ветвления по условию. |
| state f <<fork>> / <<join>> | Разделение на параллельные переходы и слияние обратно. |
| note right of A: текст | Прикрепляет заметку. Есть и `note left of`. |
| direction LR | Раскладывает автомат слева направо вместо сверху вниз. |
Шесть ошибок, ломающих диаграмму состояний
Воспроизведены на Mermaid 11.12.2. Первые четыре останавливают отрисовку. Последние две хуже: они спокойно рисуются и выдают диаграмму, которая означает не то, что вы написали.
Что вы видите
Диаграмма рисуется, но вместо одного состояния появляется несколько прямоугольников
Почему
Пробел внутри идентификатора состояния. По-русски это самая лёгкая ошибка из возможных, потому что почти ни одно наше состояние не умещается в одно слово. Mermaid ничего не отвергает и не считает остаток описанием: он создаёт отдельный прямоугольник на каждое слово. Измерено по выданным идентификаторам: `[*] --> Ожидает оплаты` даёт два состояния, `Ожидает` и `оплаты`, и только первое висит на стрелке; второе остаётся ни с чем не связанным. Из трёх слов выйдет три прямоугольника, и диаграмма молча расползётся вширь. Описание действительно существует, но требует двоеточия — `ожидает: ждёт поступления оплаты` — именно с ним эту ошибку и путают.
Решение
Объявите состояние через `state "Подпись" as id` и всегда ссылайтесь на него по идентификатору.
stateDiagram-v2
[*] --> Ожидает оплаты
Ожидает оплаты --> ЗакрытstateDiagram-v2
state "Ожидает оплаты" as ожидание
[*] --> ожидание
ожидание --> ЗакрытЧто вы видите
Parse error, заканчивается на: got 'INVALID'
Почему
Дефис в идентификаторе состояния. Имена через дефис напрашиваются сами — `в-работе`, `пред-одобрен`, — но дефис читается как начало стрелки перехода.
Решение
Одно слово или подчёркивания для идентификатора, а читаемый текст — в подпись в кавычках.
stateDiagram-v2
[*] --> в-работе
в-работе --> ЗакрытstateDiagram-v2
state "В работе" as вРаботе
[*] --> вРаботе
вРаботе --> ЗакрытЧто вы видите
Parse error внутри составного состояния
Почему
Составное состояние открыто через `{` и не закрыто. Закрывающая фигурная скобка должна стоять на отдельной строке.
Решение
Закройте блок.
stateDiagram-v2
[*] --> Внешнее
state Внешнее {
[*] --> ВнутреннееstateDiagram-v2
[*] --> Внешнее
state Внешнее {
[*] --> Внутреннее
}Что вы видите
Lexical error on line N. Unrecognized text.
Почему
Разделитель параллельных областей написан с неверным числом дефисов. Их ровно два, на отдельной строке, внутри составного состояния. Три дефиса — это совсем другой токен.
Решение
Используйте ровно `--`.
stateDiagram-v2
state Обе {
[*] --> A
---
[*] --> B
}stateDiagram-v2
state Обе {
[*] --> A
--
[*] --> B
}Что вы видите
Parse error on line 1, заканчивается на: got 'ID'
Почему
Несуществующий суффикс версии. Есть `stateDiagram` и `stateDiagram-v2`, и больше ничего: `-v3` падает на первой строке.
Решение
Используйте `stateDiagram-v2`.
stateDiagram-v3
[*] --> ЧерновикstateDiagram-v2
[*] --> ЧерновикЧто вы видите
Диаграмма рисуется, но узел выбора нарисован как обычное состояние
Почему
Объявление `<<choice>>` идёт после переходов, которые его используют. Mermaid создаёт состояние при первом упоминании, и стереотип, добавленный позже, не меняет уже созданное.
Решение
Объявляйте псевдосостояния до переходов, которые на них ссылаются.
stateDiagram-v2
[*] --> оценка
оценка --> Одобрена
оценка --> Отклонена
state оценка <<choice>>stateDiagram-v2
state оценка <<choice>>
[*] --> оценка
оценка --> Одобрена
оценка --> ОтклоненаЗаметки о рендеринге
Измерено на том Mermaid 11.12.2, который использует сайт.
Пробел в идентификаторе наказывается здесь тише всего
Сравнение типов стоит запомнить, потому что одна и та же оплошность карается по-разному. В блок-схеме пробел внутри идентификатора узла даёт Parse error — вас предупредили сразу. В диаграмме состояний не даёт ничего: диаграмма рисуется, а состояние раскалывается надвое. Это разница между ошибкой, которая себя показывает, и ошибкой, которая молчит. А поскольку по-русски почти ни одно название состояния не умещается в одно слово, единственная реальная защита — писать `state "…" as id` по привычке, не раздумывая.
Высота растёт примерно на 114 пикселей на состояние
Измерено: три состояния дают viewBox около 91×348, сорок состояний — 100×4566, то есть примерно 114 пикселей высоты на состояние. Как и в блок-схемах, ширина почти не меняется: конечные автоматы растут вниз. Когда жизненный цикл длинный и слабо ветвится, обычное решение — написать `direction LR` внутри диаграммы.
И stateDiagram, и stateDiagram-v2 рисуются — и это ловушка
Часто пишут, что без `stateDiagram-v2` ничего не нарисуется. В 11.12.2 это неправда: оба ключевых слова рисуются без ошибок. Разница в качестве раскладки, особенно для составных и параллельных состояний, и при использовании старого варианта никакого предупреждения нет. Если составное состояние выглядит тесным, а стрелки идут странными путями, проверьте, каким ключевым словом вы открыли диаграмму, прежде чем переписывать её.
Подписи — это HTML, поэтому экспорт в PNG перерисовывает
Как и в блок-схемах, диаграммах классов и ER, подписи состояний рисуются внутри `<foreignObject>` в SVG. Браузеры отказываются растрировать это на canvas, поэтому экспорт в PNG на этом сайте сначала перерисовывает диаграмму подписями обычным SVG-текстом. PNG получается правильным и в полном размере; типографика лишь чуть отличается от экранной.
Тема меняет цвета, но никогда — геометрию
Светлая и тёмная темы дают одинаковый viewBox для одного и того же исходника, так что конечный автомат не может перекомпоноваться при смене темы.
Когда лучше взять другую диаграмму
Если ваши подписи — глаголы: проверить, отправить, повторить, — вы описываете процесс, а не жизненный цикл, и честный выбор здесь блок-схема. Самый ясный сигнал: вы не можете ответить на вопрос «что именно находится в этом состоянии?».
Если у нескольких компонентов свой жизненный цикл, а интересно как раз их взаимодействие, лучше сделать по диаграмме состояний на компонент плюс диаграмму последовательности для обмена, чем один гигантский автомат.
А если каждое состояние связано с каждым, диаграмма превратится в клубок, как её ни рисуй. Обычно это значит, что то, что вы назвали состояниями, на самом деле свободно сочетающиеся признаки; в таком случае таблица допустимых сочетаний скажет куда больше, чем картинка.
Другие типы диаграмм
Автор Dominik Malsch · Обновлено: