Как использовать JavaScript-библиотеку Mermaid для создания блок-схем

Если вы недавно искали онлайн-инструмент для построения диаграмм, то, возможно, заметили, что большинство из них используют функцию перетаскивания. Хотя это полезно для людей, которые не умеют программировать, поддерживать его может быть сложно. Также может быть немного сложно манипулировать, поскольку приходится перемещать все эти фигуры в редакторе, и это не так интуитивно понятно, когда пытаешься расположить линии и прямоугольники так, чтобы они не перекрывались.

К счастью, есть решения, которые пошли другим путем. Они основаны на библиотеках, которые могут организовать фигуры и линии для вас. Вместо этого вам нужно предоставить сценарий, разработанный специально для этого инструмента, в котором описывается, какие фигуры вы хотите видеть и их взаимосвязи.

В этой статье мы поговорим о популярном инструменте построения диаграмм на основе скриптов под названием Mermaid. Вы узнаете, как работает Mermaid и как вы можете использовать его для создания блок-схем. Мы также расскажем о том, как стилизовать ваши блок-схемы в Mermaid. К концу работы вы сможете использовать этот полезный инструмент для создания собственных блок-схем.

содержание

  • Что такое русалка?
  • Начало работы с Mermaid
  • Как создать блок-схему в Mermaid
  • Узлы и формы в Mermaid
  • Как придать прическе русалочий вид
  • Вывод

Что такое русалка?

Mermaid - это библиотека JavaScript, которая преобразует письменные описания сущностей и взаимосвязей в диаграммы. Это похоже на кодирование диаграммы. Инструкции также совместимы с Markdown.

Mermaid - не единственный инструмент такого рода. Есть и другие, такие как PlantUML, которые существуют дольше. Но написание сценариев с помощью Mermaid требует очень легкого обучения, и это во многом отличает его от аналогичных инструментов:

  • В отличие от других инструментов, таких как PlantUML, Mermaid создан для Интернета. Он совместим с узлами, и диаграммы отображаются в виде измененных SVG-файлов со вставленными "иностранными объектами". Они в большей степени соответствуют фреймворкам HTML и CSS.
  • Кроме того, по сравнению с другими библиотеками сценариев результирующие диаграммы более привлекательны визуально, поскольку в них используются передовые алгоритмы размещения фигур и стрелок.
  • Mermaid также активно использует Markdown для создания надписей и совсем недавно начала использовать объектное форматирование JavaScript для описания фигур.
  • Он также имеет мощную поддержку, активно поддерживается и использует хорошо известные надежные графические библиотеки JS, такие как d3.js, cytospace.js и dagre-d3.

По сравнению с наиболее распространенными инструментами построения диаграмм с помощью перетаскивания, Mermaid обладает теми же преимуществами, что и другие инструменты построения диаграмм на основе сценариев. Со скриптом мы можем говорить о контроле версий, возможности повторного использования и многих других терминах, связанных с программированием и автоматизацией, которые могут быть невозможны с помощью инструментов перетаскивания.

Проблемы с русалкой

Конечно, это не идеальный инструмент. Одна из главных проблем, связанных с Mermaid и многими другими инструментами построения диаграмм на основе сценариев, заключается в том, что это инструмент WYSIWYG: результаты Mermaid предсказать практически невозможно, а после этого их трудно получить для настройки.

Кроме того, для каждой диаграммы, которую вы можете создать с помощью Mermaid, предусмотрены определенные формы и стрелки - количество новых фигур или взаимосвязей ограничено.

Некоторыми другими ограничениями являются:

  • Как и в случае с другими инструментами, основанными на скриптах, этот скрипт нелегко отлаживать, а для больших диаграмм он может быть очень запутанным.
  • Даже если синтаксис обычно очень интуитивно понятен, вам придется изучить другой синтаксис для каждого типа диаграмм.
  • Специально для Mermaid, если вы хотите постобработать полученную диаграмму, вы должны найти соответствующие инструменты, которые могут считывать измененные SVG-файлы Mermaid.

Но если вы используете Mermaid для тех случаев, когда он работает хорошо, к вашим услугам будет отличный инструмент.

Mermaid позволяет создавать около 21 типа диаграмм, каждая из которых имеет свои собственные синтаксические правила. В этом руководстве мы более подробно рассмотрим синтаксис блок-схем, с которым я недавно работал. Это руководство предназначено для тех, кто знаком со сценариями, хочет построить блок-схемы и получить краткое представление о синтаксисе Mermaid, прежде чем углубиться в изучение полной документации.

Чтобы сосредоточить внимание на синтаксисе Mermaid, я не буду вдаваться в подробности использования JavaScript в сочетании с Mermaid и вместо этого буду ссылаться на соответствующую документацию Mermaid, где это применимо.

Я также остановлюсь на нескольких незначительных проблемах, которые я заметил при использовании последней версии инструмента (версия 11), чтобы помочь вам избежать потенциальных ошибок.

Наконец, если вам нужны дополнительные рекомендации по созданию блок-схем в целом, я подготовил отдельный пост, в котором пошагово расскажу вам о процессе. Хотя в примерах в этом посте используется Mermaid, его использование совершенно необязательно.

Начало работы с Mermaid

Вы можете использовать Mermaid несколькими различными способами.

Для тех, кто хорошо разбирается в веб-технологиях, вы можете установить Mermaid в виде пакета или плагина и интегрировать его в приложения, используя Mermaid API, CLI или плагины.

После установки вы сможете отображать диаграммы Mermaid везде, где синтаксис Mermaid включен в ваши файлы HTML или markdown. В официальной документации приведен пример отображения диаграмм с использованием CDN (в стиле ESM).:

<html>
  <body>
    Here is one mermaid diagram:
    <pre class="mermaid">
            graph TD
            A[Client] --> B[Load Balancer]
            B --> C[Server1]
            B --> D[Server2]
    </pre>

    And here is another:
    <pre class="mermaid">
            graph TD
            A[Client] -->|tcp_123| B
            B(Load Balancer)
            B -->|tcp_456| C[Server1]
            B -->|tcp_456| D[Server2]
    </pre>

    <script type="module">
      import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
      mermaid.initialize({ startOnLoad: true });
    </script>
  </body>
</html>

Если вы используете GitHub, Mermaid поддерживается в GitHub markdown. Кроме того, Заира Хира написала полезное руководство для пользователей Visual Studio Code. Проверьте свою среду разработки на наличие доступных плагинов и расширений.

💡
Important Note on CSS Collisions: When installing Mermaid in your project, watch for CSS naming conflicts. Mermaid (version 11) uses fixed classes and IDs to render SVGs, which may overlap with your project’s styles, causing hard-to-detect errors.

Если вы не заинтересованы в прямой интеграции Mermaid в свою программу, отличным вариантом станут онлайн-редакторы и облачные инструменты. Mermaid предоставляет два ключевых инструмента: Mermaid Chart и Mermaid Live.

  • Mermaid Chart - это облачный менеджер проектов, предназначенный для совместной работы и обмена информацией. Он предлагает такие функции, как шаблоны, история версий и возможности презентации, что делает его идеальным для управления проектами.
  • Mermaid Live лучше всего подходит для создания быстрых разовых диаграмм. На рисунке ниже вы можете увидеть изображение Mermaid Live на моем компьютере. Вы можете выбрать диаграмму из списка примеров, изменить ее код в редакторе на вкладке "Код" или вставить свой собственный сценарий. Изменения мгновенно отображаются в окне диаграммы, а диаграммы можно экспортировать в формате PNG или SVG из меню Действия.

Несмотря на то, что Live удобен, это ненадежный способ отслеживать ваши сценарии, поэтому сохраняйте свою работу на сторонних сайтах. Существуют и другие онлайн-редакторы, похожие на Mermaid Live, и в статье Заиры Хиры рассказывается об одном из них.

Из приведенных ниже пояснений следует, что любая установка, которую вы выберете, будет работать одинаково, поскольку мы будем уделять особое внимание коду. Итак, выбирайте свои инструменты и давайте ознакомимся с синтаксисом блок-схемы Mermaid.

Как создать блок-схему в Mermaid

Чтобы создать свою первую диаграмму Mermaid, вы должны указать Mermaid, какой тип диаграммы вы хотите создать. Мы создаем блок-схему, поэтому для начала вы можете просто написать это:

flowchart

Mermaid может распределять фигуры в двух направлениях: сверху вниз (по умолчанию) или влево-вправо. Если вы хотите уточнить направление разметки, вам нужно указать TD для обозначения направления сверху вниз:

flowchart TD

и LR для перемещения влево-вправо:

flowchart LR

Просто имейте в виду, что вы можете выбрать только одно направление для своей блок-схемы (TD или LR).

Как написать комментарий

Теперь, прежде чем мы начнем использовать фигуры, давайте посмотрим, как написать комментарий в блок-схеме Mermaid. Комментарий не будет отображаться на диаграмме - он предназначен только для того, чтобы помочь вам. Вы, вероятно, знаете, насколько они полезны как разработчик.

Чтобы написать комментарий, просто поставьте перед текстом комментария "%%". :

flowchart
%% This is a comment!!!

Как настроить вашу блок-схему

Есть (или были) как минимум три способа настройки ваших блок-схем в Mermaid. Первый из них, с использованием директив, устарел, но все еще работает в некоторых случаях. Второй - это конфигурация frontmatter. Другой - с помощью файла конфигурации.

Если бы вы использовали старые версии Mermaid (<10.5.0), вы могли бы настроить свою диаграмму с помощью директив. Вы делаете это, объявляя оператор, подобный объекту JavaScript, заключенный между символами процентов (%%¦%%%), обычно после объявления типа диаграммы, например, так:

%%{init: { 'flowchart': {theme:"base", themeVariables:{primarycolor:"#00ff00"} } }%% 
flowchart
    Hello --> World
💡
By the time of this writing, the Mermaid documentation sometimes still refers to directives as a way to configure your diagram. But keep in mind that the use of directives doesn’t work correctly in some renderers.

Метод настройки frontmatter заменил директивный метод начиная с версии 10.5.0. Он основан на формате YAML. В этом случае вам необходимо использовать блок YAML перед инициализацией вашей блок-схемы:

---
title: Hello Title
config:
  theme: base
  themeVariables:
    primaryColor: "#00ff00"
---
flowchart
    Hello --> World

Область применения директив и интерфейсных данных ограничена по сравнению с другими методами настройки. Они применимы только к графику под инструкцией по настройке.

Разработчикам, устанавливающим пакет Mermaid, рекомендуется использовать JavaScript для настройки. Mermaid также настраивается с помощью файла конфигурации JSON, который находится в папке библиотеки. Для получения более подробной информации об этих методах обратитесь к главе документации об использовании API.

Вы можете найти список атрибутов и свойств, на которые вы можете повлиять при настройке вашей схемы, на этой странице документации Mermaid.

Я не буду вдаваться в подробности настройки в этой статье, хотя я мог бы обратиться к ней пару раз, просто чтобы прояснить пару вещей, которые могут быть выполнены только путем настройки инструмента.

Узлы и формы в Mermaid

В документации Mermaid узлы используются как общий термин для обозначения любого шага, добавляемого к блок-схеме. В документации Mermaid представлены фигуры, также называемые формами узлов. Они представляют то, что происходит в этом узле.

Как создать свой первый узел (Форму процесса)

Добавить узел в блок-схему с помощью Mermaid очень просто. Просто придумайте уникальное имя или его идентификатор в соответствии с документацией Mermaid. Для большей ясности я также буду называть этот идентификатор идентификатором узла.

Идентификатор узла должен состоять из одного слова без пробелов и, желательно, без каких-либо других символов, кроме буквенно-цифровых. Идентификатор узла будет сохранен для остальной части скрипта, и вы будете использовать его для запоминания этой формы в других частях скрипта.

Затем добавление узла заключается в простом написании идентификатора узла в объявлении типа диаграммы (здесь это A).:

flowchart
    A

Обратите внимание, что до сих пор мы не объявили никакой формы для этого узла. Если форма не объявлена, то по умолчанию используется прямоугольник, который также является формой процесса.

💡
In Mermaid flowchart syntax, there is no way to declare a node without declaring at least one shape (the process shape)

Текст, который отображается внутри фигуры, является ее меткой. Существуют различные способы пометить фигуру. Если вы не помечаете фигуру, в качестве метки используется идентификатор.

Вы можете использовать свой идентификатор узла настолько подробно, насколько захотите. Вы можете указать более осмысленное имя, которое также можно прочитать как метку:

flowchart
    flowChartProcess

💡
The indentation is not required when scripting with Mermaid, but I am doing it in order to keep the script organized.

Как правило, название должно состоять из одного слова, с некоторыми ограничениями, если не используются буквенно-цифровые символы. Например, использование некоторых символов, таких как пробелы, запрещено, как в этом случае: Процесс создания блок-схемы. В этом случае при отображении может возникнуть ошибка.

💡
There are reserved words and characters, such as the word “end” or the parenthesis “(…)”, that can’t be used as an id as they have specific uses. But you can use any reserved word as labels when labels are specified, as long as the label is enclosed between quotes.

Как объявлять фигуры и метки фигур с помощью Mermaid: два разных синтаксиса

В Mermaid вы объявляете узел с идентификатором. Затем вы определяете форму для этого узла.

Вам нужно знать о двух разных синтаксисах, доступных при объявлении фигур с помощью Mermaid. Они оба доступны и могут сосуществовать в одном скрипте до тех пор, пока интерпретатор обновлен до последней версии.

Давайте рассмотрим несколько способов объявления этих форм. Ниже приведены два примера двух доступных синтаксисов. В следующем примере вы можете увидеть, как они используются для получения аналогичных результатов:

flowchart LR
    flowChartProcess01[Process shape, version 10 syntax declaration, simplest labelling]
    flowChartProcess02["Process shape, version 10 syntax declaration, double-quoted labelling"]
    flowChartProcess03@{ shape: rect, label: "Process shape, version 11 syntax declaration, simplest labelling"}

Обратите внимание, что в приведенном выше примере первый объявленный узел не требовал никаких кавычек. Это произошло потому, что в нем не было специальных символов.

💡
As soon as you need to include reserved characters or words in your label, you must use quotes.

Первые два объявленных узла являются примерами исходного синтаксиса. Даже если это не совсем точно, мы будем называть такой синтаксис синтаксисом версии 10.

Как вы можете видеть из приведенного выше сценария, объявление версии 10 всегда содержит:

  1. идентификатор имени,
  2. за ним следует комбинация символов, которые описывают фигуру и которые действуют как открывающие и закрывающие символы фигуры,
  3. с текстовой пометкой между символами формы.

Открывающие и закрывающие символы фигуры в основном представляют собой комбинацию знаков препинания. Примерами символов, заключающих/ открывающих символы специальной формы, являются круглые скобки, фигурные скобки, "Меньше", "Больше" и косые черты. От того, как вы скомбинируете заключенные символы, зависит, какую форму вы хотите получить. Например, в предыдущем случае форма процесса была объявлена как ID[<МЕТКА>].

💡
When declaring shapes with version 10 syntax, you always must provide a label. If you don’t do that, it will throw an error.

Начиная с версии 11.3, Mermaid представила обновления синтаксиса, направленные на повышение гибкости. Последний пример нашего скрипта, приведенный выше, написан с использованием этого нового синтаксиса.

Для объявления версии 11 вы могли бы использовать синтаксис, подобный объекту JavaScript, следующим образом: ID@{shape: псевдоним формы, метка: "Это метка"}. Мы будем называть такой синтаксис синтаксисом версии 11. В этой версии оба свойства являются необязательными. Если форма не указана, вместо нее будет отображаться прямоугольник. Если вы не добавите метку, то программа визуализации будет использовать идентификатор узла в качестве метки.

В документации приведен список собственных имен для каждой фигуры. Кроме того, вы можете использовать несколько псевдонимов вместо собственного имени в качестве значения фигуры. В этом проекте, для простоты, мы будем придерживаться единственного варианта именования, без привязки к тому, будет ли это имя собственное или псевдоним. Если вы хотите получить полный список, просто обратитесь к документации.

💡
Either using version 10 or version 11, you have to define labels and shapes only once in your script.

Другими словами, если у вас есть узел, который используется в нескольких отношениях в вашем скрипте, вы сможете определить форму только для одного из этих вызовов идентификатора узла, как в следующем примере:

flowchart
    A --> B
    A --> C
    D --> A[one time is enough]
    F --> D
    %%F --> A(uncommenting this will change the shape and the label too)

Но обратите внимание, что в этом примере я закомментировал одну из строк. Если вы раскомментируете эту строку, метка и форма будут обновлены до новых определений для узла A. Как правило, если вы определяете разные формы или надписи для одного и того же узла в разных частях скрипта, последнее определение будет иметь приоритет.

Я обнаружил, что при использовании современного объявления вы должны добавить пробел после двоеточия (¢:¢) перед текстом, иначе интерпретатор не сможет найти текст.

Этот вариант, который я нашел, был неправильным (без пробела между фигурой и текстом): {фигура:текст, надпись:текст} А этот был правильным (пробел после фигуры:): {фигура: текст, надпись: текст}

Беглый взгляд на наиболее типичные формы

Как сообщается в документации Mermaid о фигурах, для создания блок-схем доступно более 40 фигур. В документации Mermaid формы называются в соответствии с их геометрией, а также с тем, что они означают. Некоторые из этих фигур называются только в соответствии с их значением, особенно если в геометрической терминологии нет простого слова, которое можно было бы использовать для описания фигуры.

💡
In case you just want a list of essential shapes to start working on your flowchart but you don’t know which ones to pick, you can check out my article about flowcharts, where I give you some ideas.

Это наиболее распространенные формы, которые вы обычно используете при построении блок-схемы:

Как вы можете видеть из таблицы выше, у нас есть следующие формы:

  • Начальная или конечная точка (некоторые люди представляют такие точки овалами, но в документации Mermaid начальная точка представлена кругом, а конечная точка представлена двумя вложенными кругами)
  • Стрелка (соединитель, показывающий взаимосвязи между фигурами)
  • Параллелограмм (вход или выход)
  • Прямоугольник (процесс)
  • Бриллиант (решение)

Давайте теперь рассмотрим каждую из этих фигур и посмотрим, как сделать их с помощью "Русалки".

Форма Терминатора

Как упоминалось выше, Mermaid использует круги для обозначения начальной и конечной точек вместо овала. Начальная и конечная точки обозначают начальную и конечную точки процесса/системы.

Если мы будем придерживаться документации Mermaid, то способ создания их в Mermaid с использованием версий 10 и 11 выглядит следующим образом:

flowchart TD
    startv10((start v10))
    stopv10(((stop v10)))
    startv11A@{shape: circle, label: Start v11}
    startv11B@{shape: start, label: Start (small circle) v11}
    stopv11@{shape: dbl-circ, label: Stop v11}
    stopv11B@{ shape: framed-circle, label: Stop (small circle) v11 }

В Mermaid v11 есть два типа кругов, которые можно использовать в качестве начальной и конечной точек: маленькие и обычные. Маленькие фигуры не отображают надписи.

Если вы решите использовать овал в качестве конечной формы (начальной/конечной точки), простой круг может приобрести другие значения. Например, это может быть форма соединителя (точка выхода блок-схемы, которая продолжается в отдельной блок-схеме, или другая точка той же блок-схемы). Или это может стать еще одним видом соединителя, который объединяет несколько технологических линий в одну технологическую линию (не как многопроцессорное соединение, а просто как средство уменьшения количества связей, когда вам нужна ясность).

Если вы предпочитаете использовать овал (который в Mermaid называется формой терминала), вы можете создать его с помощью следующего кода:

flowchart TD
    terminalv10([Terminal point v10])
    terminalv11@{ shape: stadium, label: "Terminal point v11" }

Форма стрелки (прямоугольника)

Мы подробнее поговорим об этом позже в этой статье.

Форма ввода/вывода (параллелограмм)

Форму параллелограмма можно использовать как абстракцию для данных, которые доступны для ввода или вывода, а также для используемых или генерируемых ресурсов. Это указывает на то, что на данном этапе рабочего процесса требуется некоторая информация.

Вы можете сделать эту фигуру с русалкой, используя существующие варианты следующим образом:

flowchart TD
    inputoutputv10[/Input / Output v10/]
    inputoutputv11@{ shape: in-out, label: "Input / Output v11"}

Форма процесса (прямоугольник)

Вы можете представить процесс с помощью прямоугольника на блок-схеме. Он представляет собой отдельный шаг в вашем рабочем процессе, такой как выражение (например, x = y * X2), оператор всего блока, такой как "Перебор массива и обновление значений путем умножения на 2", или целый подпроцесс, такой как существующий функция или даже модуль.

Это также называется коробкой (в двух вариантах).:

flowchart TD
    processv10[Process v10]
    processv11@{ shape: rect, label: Process v11 }

Решение (бриллиант) Форма

Решение представлено ромбом. Это абстракция для проверки условия, вопроса "ДА/НЕТ" или "ИСТИННО/ЛОЖНО". Это эквивалент оператора IF/ELSE в программировании.

Используя версии 10 и 11, вы можете создать ромб следующим образом:

flowchart TD
    decisionv10{Decision v10}
    decisionv11@{ shape: diam, label: Decision v11 }

Markdown и HTML в Mermaid

Одной из наиболее полезных функций Mermaid является то, что она использует синтаксис Markdown для обозначения файлов, а также HTML. Я бы посоветовал вам использовать нотацию Markdown, так как HTML-нотация может привести к ошибкам без текста.

Использование двойных кавычек и Markdown позволяет использовать специальные символы в надписях. Но с помощью синтаксиса Markdown вы также можете получить доступ к различным функциям Markdown.

Чтобы использовать Markdown, вы должны заключить свой текст в двойные кавычки (""), за которыми следует обратный тик (""), вот так:

flowchart TD
    flowChartProcess["`**flowChart Process**:
                        - typical shape declaration 
                        - *Markdown-style* labelling`"]

💡
Be aware that not all Markdown functionalities are recognized.

Теперь, когда вы знаете, как использовать некоторые базовые фигуры, а также как использовать Markdown в Mermaid, давайте перейдем к следующему шагу: как нарисовать взаимосвязи между фигурами.

Ребра (взаимосвязи) и метки ребер в Mermaid

Ребра, также называемые в документации Mermaid стрелками или связями, представляют собой соединения между узлами. В соответствии со стандартом ANSI они официально называются формой поточной линии. Это связано с тем, что в некоторых ситуациях связь может не быть стрелкой.

💡
I will refer to them as edges or links here, not arrows.

Нарисовать взаимосвязи между двумя узлами так же просто, как добавить узлы. Чтобы нарисовать простую стрелочную связь между двумя фигурами, вам просто нужно сделать следующее:

flowchart TD
    A --> B

Технически, ссылка в Mermaid - это комбинация линии и маркера. Маркер - это маленький значок, добавляемый в конце строки. Существует несколько типов ссылок / ребер, которые вы можете нарисовать, комбинируя различные типы линий и маркеров, которые предоставляет Mermaid:

flowchart TD
    %% dotted line, triangle marker
    A -.-> B
    %% thick line, triangle marker
    C ==> D
    %% solid cross-edged (solid line, cross marker)
    E --x F
    %% solid circle-edged (solid line, circle marker)
    G --o H
    %% combining circle marker with dotted line
    I -.-o J
    %% hidden
    K ~~~ L

💡
Be aware that “o” and “x” become reserved characters when used as markers. If you need to use them as the first character of the node ID, either leave a space after the edge operator, or use capital letters.

Ребра также могут быть двунаправленными, например:

flowchart TD
    A <--> B

При рисовании ребер вы можете использовать "Синтетический сахар" в своем скрипте, чтобы уменьшить избыточность при определении связей между узлами. Например, если у вас есть узел B, расположенный в середине последовательности, вы можете упростить свой сценарий, связав связи в цепочку вместо многократного указания связей между B и его предыдущим и последующим узлами. Кроме того, операторы могут указывать пересекающиеся связи между одними и теми же узлами.

Следующий сценарий иллюстрирует разницу между подробным синтаксисом (показанным в виде комментариев) и упрощенным синтаксисом с использованием цепочки и операторов:

flowchart TD
    %% ommitting a shape in between (chaining). the same as:
    %% A --> B
    %% B --> C
    A --> B --> C

    %% use of special character. the same as:
    %% D --> F
    %% D --> J
    %% F --> K
    %% J --> K
    D --> F & J --> K

Маркировка ссылок также возможна с помощью синтаксиса Mermaid, и это очень просто сделать. Как описано в комментариях к скрипту, вы можете пометить одну стрелку разными способами: либо вставляя метку между строками (”"), либо используя вертикальные полосы (|...|), расположенные после маркера (или, если маркера нет, после линии оператор) и перед объявлением узла:

flowchart TD
    %% inserting the label between the link operator
    A --"This is a label **between the link operator**"--> B

    %% adding a link label between vertical bars, |...|
    A --> |"This is a label **between special characters**"| B

Оба этих формата поддерживают простые двойные кавычки или маркировку в стиле Markdown. Я обнаружил, что мне удобнее добавлять метки к ссылкам с помощью вертикальных полос.

💡
Edge labelling is subject to the same restrictions as shape labelling when using reserved characters and words.

Теперь, прежде чем перейти к следующему разделу, давайте рассмотрим краткий пример, используя то, что мы уже изучили! Я буду использовать типичный синтаксический формат для примера. Вот он:

flowchart TD
    A["Process A"] --> |"Process A is followed by Process B"|B["Process B"]
    C["Process C"] -.-> |"Process C relates to Process B"| B
    D["Process D"] --> |"Process D is followed by Process C"| C

Подграфы

В Mermaid вы также можете сгруппировать части узлов по подграфам. Вот пример из документации Mermaid о том, как создать синтаксис для подграфа.:

flowchart LR
  subgraph TOP
    direction TB
    subgraph B1
        direction RL
        i1 -->f1
    end
    subgraph B2
        direction BT
        i2 -->f2
    end
  end
  A --> TOP --> B
  B1 --> B2

Обратите внимание, что в этом примере мы также смогли объявить разные направления потока для разных (под) графиков.

Но документация Mermaid также разъясняет предостережение: если узел внутри подграфа соединен с другим узлом за пределами этого подграфа, любое объявление направления подграфа будет переопределено направлением, объявленным для самого внешнего (родительского) подграфа. Опять же, вот пример прямо из документации Mermaid:

 flowchart LR
    subgraph subgraph1
        direction TB
        top1[top] --> bottom1[bottom]
    end
    subgraph subgraph2
        direction TB
        top2[top] --> bottom2[bottom]
    end
    outside --> subgraph1
    outside ---> top2

В приведенном выше случае подграф2 был объявлен как подграф "сверху вниз", но унаследовал направление внешнего подграфа, которое было объявлено как левостороннее. Это произошло из-за соединения между двумя узлами, принадлежащими разным подграфам на разных уровнях описания (подграф2 находится внутри "глобального" подграфа). В этом случае subgraph2 является дочерним элементом глобального подграфа, поэтому он наследует направление is.

Как придать прическе русалочий вид

Стиль в Mermaid очень совместим с CSS.

Давайте начнем со стилизации фигур. Один из способов сделать это - использовать команду style. Она работает следующим образом:

  1. Используйте стиль зарезервированного слова,
  2. за ним следует имя и идентификатор фигуры, которую вы хотите стилизовать,
  3. затем укажите свойства, которые вы хотите изменить, и их новые значения.

Мы реализуем этот шаблон в следующем примере. Давайте предположим, что я хочу провести различие между использованием разных цветов и изменить цвет букв в надписях:

flowchart TD
    A([this should be black with white letters]) --> B([this should be grey with white letters])
    style A fill: black, color: white
    style B fill:grey, color:#fff

Важно понимать, что в Mermaid стили отображаются на уровне узла, а не на уровне формы. Вы также можете применять разные стили для одного и того же узла. Они читаются последовательно в порядке появления, поэтому для двух конкурирующих стилей допустимым будет последний.

Вы можете поместить выражение стиля в любом месте вашего кода, но я бы рекомендовал сделать это в конце скрипта, чтобы вы могли отслеживать все изменения.

💡
Keep in mind that if, when styling, you refer to a non-existing node ID, Mermaid will create a new node without warning you.

Другой полезный способ добавить стиль к вашим блок-схемам, особенно если вы хотите добавить один и тот же стиль к нескольким узлам, - это определить классы. Для этого вы можете использовать специальное слово classDef, например, так:

  1. Напишите classDef в одной строке
  2. за ним следует название, которое вы выбрали для класса
  3. затем следуют атрибуты стиля, которые вы хотите изменить, и их новые значения.

Чтобы применить класс:

  1. Найдите узлы, для которых вы хотите внести изменения
  2. добавьте три двоеточия (:::) в конце объявления узла и, если требуется, в конце выражения для обозначения
  3. добавьте название класса.

Ниже приведен пример того, как добавлять классы к фигурам:

flowchart TD
    A[label A, no class] --> B[label B, class bar]:::bar
    B --> C[label C, class foo]:::foo
    C --> D[label D, class bar]:::bar
    C --> E[label E, class foo]:::foo
    classDef foo fill:green, color:#fff
    classDef bar fill:orange, color:#666

💡
Same as shape declaration, classes can be assigned to a node just once, no matter where in the flowchart. But you can add only one class per node.

К сожалению, этот вид classDef применим только к фигурам, использующим синтаксис версии 10.

В документации не упоминается, что вы также можете стилизовать подграфы. Фактически, имя, которое вы присваиваете подграфу, становится его идентификатором.

Форматы стилей, применимые к фигурам, работают практически одинаково для подграфов. Но использование стиля classDef работает только в том случае, если подграф также является узлом на диаграмме.

В следующем примере показано применение команд style и classDef и то, как вы можете использовать их для добавления стиля к подграфам:

 flowchart LR
    %% applying a class as follow will give an error:
    %% "subgraph subgraph1:::asNode"
    subgraph subgraph1
        direction TB
        top1[top] --> bottom1[bottom]
    end
    subgraph subgraph2
        direction TB
        top2[top] --> bottom2[bottom]
    end
    outside:::asNode --> subgraph1:::asNode
    outside ---> top2

    style subgraph2 fill:orange
    classDef asNode fill:grey, color:orange

Если вы хотите стилизовать края, то вам нужно действовать по-другому. Что действительно сработало для меня, так это использование другого зарезервированного слова linkStyle, которое стилизует линию края.

Проблема с ребрами заключается в том, что у них нет идентификаторов: они рассматриваются скорее как часть массива, поэтому на них следует указывать индекс, который не всегда будет соответствовать нужному ребру. Вот пример, основанный на этом обсуждении:

flowchart TD

A --> B
B --> C
B --> D
D --> E
D --> F

linkStyle default stroke:red
linkStyle 0 stroke-width:4px,stroke:green
linkStyle 3 stroke:blue
linkStyle 4 stroke:blue

Другая проблема, связанная со стилизацией краев, заключается в том, что маркеры не связаны с линиями. Таким образом, этот метод не повлияет на маркер.

В целом, я обнаружил, что в Mermaid не так-то просто применить согласованный стиль оформления краев. Но, возможно, для большинства ваших проектов в оформлении краев нет необходимости.

Помимо выбора стиля линии, документация предполагает, что мы можем применить некоторый стиль к кривизне линии, настроив диаграмму с помощью директив:

%%{ init: { 'flowchart': { 'curve': 'stepBefore' } } }%%
graph LR
A --> B
B --> C
B --> D
D --> E
D --> F

Изменение должно коснуться всех ребер на блок-схеме, и оно должно основываться на библиотеке d3-shape. Но на сегодняшний день я не смог надежно настроить кривизну, используя либо директивный метод, либо метод frontMatter.

Имейте в виду, что в будущем возможности оформления краев с помощью Mermaid могут быть улучшены. Тем временем я предлагаю обратиться к специализированным сообществам с просьбой о том, как лучше оформить ссылки с помощью Mermaid, если это то, что вы хотели бы реализовать в своих диаграммах. Поделитесь со мной своими находками, чтобы дополнить эту статью!

Наконец, есть еще один способ добавить больше стиля, изменив темы, макеты и внешний вид, которые являются заданными форматами стилей, которые вы можете изменять. Они будут влиять на стиль всей диаграммы.

Например, в документации Mermaid об общем синтаксисе есть этот скрипт, использующий метод frontMatter:

---
config:
  layout: elk
  look: handDrawn
  theme: dark
---
flowchart TB
  A[Start] --> B{Decision}
  B -->|Yes| C[Continue]
  B -->|No| D[Stop]

Есть и другие способы добавить стиль, но они более продвинутые. Для простоты я не буду обсуждать эти более продвинутые решения, а вместо этого предложу вам ознакомиться с документацией Mermaid.

Директивы или первостепенная важность?

Как я объяснял ранее в этой статье, вы можете настроить некоторые атрибуты блок-схемы с помощью директив или YAML frontMatter. В документации указано, что директивы устарели.

Эти методы могут быть использованы для настройки внешнего вида всей диаграммы и/или некоторых свойств блок-схемы.

Но мне удалось изменить некоторые свойства блок-схемы с помощью frontMatter, а также директив. Например, взгляните на следующие два примера, где атрибут fill задан на основе темы шаблона, а также изменено пространство узлов:

---
title: Hello Chart
config:
    theme: base
    flowchart:
        nodeSpacing: 200
---
flowchart LR
A --> B
B --> C
B --> D
D --> E
D --> F

%%{init:{'theme': 'base', 'flowchart':{'nodeSpacing': 200}}}%%
graph LR
A --> B
B --> C
B --> D
D --> E
D --> F

Результаты обоих методов почти одинаковы, хотя в данном случае я не смог добавить заголовок к тому, который использует директиву. Должно быть, есть какие-то преимущества в том, чтобы предпочесть подход YAML frontMatter, но имейте в виду, что в некоторых случаях вы все равно можете использовать оба варианта.

Для получения подробной информации о настраиваемых свойствах блок-схемы с использованием этих методов и методов JavaScript ознакомьтесь с документацией Mermaid. Если вам нужны примеры настройки тем, ознакомьтесь с этим ресурсом. На момент написания этой статьи настройка с помощью директив или frontMatter - это то, что я еще не изучал подробно. Я приглашаю вас попробовать и сообщить мне, что вы обнаружите.

Интерактивность

Еще одна вещь, которую вы можете сделать с Mermaid, - это добавить простую интерактивность. Вы можете сделать это, используя следующий шаблон, используя зарезервированные слова click, call и callback, где callback - это название функции обратного вызова:

click nodeId callback "Tooltip when hovering"
click nodeId externalLink "Tooltip when hovering"
click nodeId call callback() "Tooltip when hovering"

Этот вид интерактивности применим, когда вы отрисовали блок-схему Mermaid в HTML и у вас есть связанный с ней файл JavaScript. Но для более простых решений вы также можете выполнять вызовы внешних страниц, используя следующий шаблон, как предлагается в документации:

flowchart LR
    A-->B
    B-->C
    C-->D
    click A callback "Tooltip for a callback"
    click B "https://www.github.com" "This is a tooltip for a link"
    click C call callback() "Tooltip for a callback"

Имейте в виду, что конфигурация всего проекта, а не только конфигурации Mermaid, может помешать вам успешно использовать интерактивные функции. Например, приведенный выше скрипт из этой статьи не может работать.

Посетите рекомендуемый ресурс, указанный в самой документации, для получения рабочего примера всплывающих подсказок, но без ссылок: https://jsfiddle.net/yk4h7qou/2/. Проверьте примеры в документации Mermaid, чтобы увидеть, как работают ссылки, но всплывающие подсказки не работают: https://mermaid.js.org/syntax/flowchart.html#interaction.

Если это то, что вы хотите попробовать, внимательно прочтите документацию, чтобы получить более подробную информацию о том, что вы должны учитывать при внедрении такого рода решений.

Русалка, CSS и SVG

💡
Mermaid documentation makes no reference to how SVGs are structured. Here I have made a quick review on how SVGs are rendered in the most recent versions.

Вы можете пойти дальше функциональных возможностей, предоставляемых Mermaid, воздействуя на SVG-файлы, которые создает инструмент. Результирующий SVG-файл можно стилизовать, изменять формы и т.д. В зависимости от ваших собственных потребностей.

До сих пор я обнаружил, что Mermaid создает SVG, который имеет структуру более высокого уровня, подобную следующей:

svg -----
        |
        (group)
        |
        markers and defs
        |
        group: class root ----
                              |
                              group: clusters (subgraphs)
                              |
                              group: edgePaths (edges)
                              |
                              group: edgeLabels (edge labels)
                              |
                              group: nodes

Все эти элементы SVG могут содержать другие группы для каждого узла, метки, ребра или подграфа, которые вы добавляете на диаграмму. Для каждого из них Mermaid присваивает специальное название, которое не является строго динамическим. Например, он может использовать одно и то же идентификационное имя для всех блок-схем, которые вы создаете на одной странице.

Но вы всегда можете вмешаться в SVG и внести определенные изменения. Например, если у вас нет другого SVG на той же странице, над которой вы работаете, вы можете изменить все формы процесса, используя следующий стиль оформления на своей странице:

<style>
  .cssClass > rect {
    fill: #ff0000;
    stroke: #ffff00;
    stroke-width: 4px;
  }
</style>

Обратите внимание, что это больше о SVG, чем о Mermaid, и подробное изучение этого выходит за рамки данной статьи. Я советую вам прочитать больше о SVG, если вы хотите узнать, как после создания диаграммы дополнить ее дополнительными функциями.

Я также рекомендую прочитать раздел "Использование API Mermaid" в документации Mermaid, чтобы лучше понять, как применять JavaScript к конфигурациям Mermaid и манипулировать диаграммами.

Вывод

В этой статье вы познакомитесь с основами Mermaid для создания блок-схем. Мы рассмотрели обзор Mermaid, синтаксис блок-схем, фигуры, ссылки, подграфы, темы и варианты оформления. Ниже приведены ключевые советы и примеры, в том числе те, которых нет в документации, которые помогут вам освоить синтаксис.

Ознакомившись с этим руководством, вы сможете уверенно использовать Mermaid для интеграции блок-схем в свой рабочий процесс. Блок-схемы - это ценный визуальный инструмент для улучшения понимания, а Mermaid позволяет создавать их быстро и просто.

Чтобы продолжить изучение, загляните в библиотеку Mermaid'а, чтобы узнать о других типах диаграмм, расширенной настройке и интерактивности. Если вам нужна дополнительная помощь, ознакомьтесь с другой моей статьей о создании блок-схем. Приятного программирования!