1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/imwangshijiang-liteflow-editor-client

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
README.md

LiteFlow визуальный редактор фронтенда

LiteFlow визуальное редактирование

Этот проект представляет собой фронтенд для визуального редактора логики LiteFlow. Для доступа к проекту backend перейдите по ссылке LiteFlow визуальный редактор backend.

Шаги запуска проекта

    1. Установка зависимостей:
$ yarn
    1. Запуск сервиса:
$ yarn start

Далее представлено описание реализации LiteFlow логического визуального редактирования.

01-Введение

Как разработчик фронтенда, нам следует уделить особое внимание трем ключевым элементам фронтенд-разработки: данным (Model), представлению (View) и логике (Control), то есть "MVC". При реализации LiteFlow логического визуального редактирования, мы также можем использовать знания о "трех элементах MVC" для систематического разбиения, объединения, дизайна и реализации.

LiteFlow логическое визуальное редактирование и реализация.png1. Модель данных (Model): моделирование операторов (Operator) EL-выражений, в этом проекте EL-выражения моделируются в виде дерева, состоящего из узлов ELNode; 2. Представление (View): использование узлов (Node) и ребер (Edge) AntV X6 для визуализации узлов ELNode, то есть через Nodes & Edges реализуется LiteFlow логическое визуальное редактирование; 3. Логика управления (Control): реализация операций CRUD (создание, чтение, обновление, удаление) модели ELNode.Я очень ценю этот "кадр MVC", так как он позволяет мне легко разбивать и объединять системы. Поэтому в этой статье и в серии статей я буду использовать этот "кадр MVC" для обсуждения.

В этом введении мы кратко рассмотрим "три элемента MVC" для LiteFlow логического визуального редактирования:

1. Модель данных (Model)

LiteFlow моделирует исполняемые логические процессы, включая следующие две части:

Liteflow процесс моделирования: логические компоненты + логическое редактирование.png

    1. Логические компоненты (узлы компонентов): типы логических компонентов включают:
      ① Последовательные компоненты: для THEN, WHEN;
      ② Ветвящиеся компоненты: для SWITCH, IF ...;
      ③ Циклические компоненты: для FOR, WHILE ...;
    1. Логическая компоновка: компоновка компонентов с помощью выражений EL (Expression Language):
      ① Последовательная компоновка: THEN;
      ② Параллельная компоновка: WHEN;
      ③ Выборочная компоновка: SWITCH;
      ④ Условная компоновка: IF;
      ⑤ Циклическая компоновка: FOR, WHILE и т.д.

А для логической компоновки "логических компонентов" используются выражения EL, например, пример выражения EL:

<chain name="chain1">
    THEN(
        a,
        WHEN(b, c, d),
        e
    );
</chain>
```В этом примере "THEN" и "WHEN" являются ключевыми словами выражений EL, которые обозначают последовательную и параллельную компоновку соответственно, а "a", "b", "c", "d", "e" — это пять логических компонентов, которые вместе образуют комбинацию последовательной и параллельной компоновки — то есть сначала выполняется компонент "a", затем параллельно выполняются компоненты "b", "c", "d", а затем выполняется компонент "e".

А наша модель данных (Model) представляет собой моделирование операторов (Operator) выражений EL:! [LiteFlow логическая визуализация компоновки и реализации 1. Модель данных (Model). png](. /docs/assets/LiteFlow%20логическая%20визуализация%20компоновки%20и%20реализации%20-%20Модель%20данных%20(Model). png)- EL выражение: логическая компоновка [LiteFlow](https://liteflow.cc/) осуществляется с помощью EL выражений, например, вот этот пример, который мы упоминали ранее:
```typescript
<chain name="chain1">
    THEN(
        a,
        WHEN(b, c, d),
        e
    );
</chain>
  • Деревянная структура: текстовое разбиение LiteFlow позволяет нам получить деревянную структуру (т. е. AST абстрактного синтаксического дерева);
  • JSON представление: мы можем упростить эту структуру и получить упрощённое JSON представление:
{
  type: "THEN",
  children: [
    { type: "NodeComponent", id: "a" },
    {
      type: "WHEN",
      children: [
        { type: "NodeComponent", id: "b" },
        { type: "NodeComponent", id: "c" },
        { type: "NodeComponent", id: "d" },
      ],
    },
    { type: "NodeComponent", id: "e" },
  ]
}
  • Построение модели: после анализа вышеупомянутых шагов, мы можем создать следующую модель ELNode:
/**
 * Модельное представление EL выражения: сущность данных на самом деле представляет собой деревянную структуру.
 * Например, последовательная компоновка (THEN):
 {
   type: ConditionTypeEnum.THEN,
   children: [
     { type: NodeTypeEnum.COMMON, id: 'a' },
     { type: NodeTypeEnum.COMMON, id: 'b' },
     { type: NodeTypeEnum.COMMON, id: 'c' },
     { type: NodeTypeEnum.COMMON, id: 'd' },
   ],
 }
 */
export default abstract class ELNode {
   // Тип узла: может быть типом компоновки или типом компонента
   public type: ConditionTypeEnum | NodeTypeEnum;
}  // Подузлы текущего узла: тип компоновки имеет подузлы, тип компонента не имеет
   public children? : ELNode[];
   // Родительский узел текущего узла
   public parent? : ELNode;
   // Условие узла:主要用于SWITCH/IF/FOR/WHILE等编排类型
   public condition? : ELNode;
   // Идентификатор узла компонента
   public id? : string;
   // Свойства узла компоновки: можно установить id/tag и т. д.
   public properties? : Properties;
 }
 ```## 2. Визуализация представлений (View)```При реализации визуализации логики [LiteFlow](https://liteflow.cc/) мы используем графический редактор [AntV X6](https://x6.antv.vision/zh/) — не только потому, что он удобен и часто используется, но и потому, что у нас есть опыт его применения. Если вас интересует этот вопрос, вы можете ознакомиться со статьей, которую я написал ранее: [«AntV X6»: быстрый старт с использованием AntV X6 для визуализации графов](https://juejin.cn/post/7326766014258855972).

![Liteflow логика визуализации](./docs/assets/Liteflow%20логика%20визуализации.png)

На данный момент мы реализовали следующие три типа/шесть видов визуализации логики [LiteFlow](https://liteflow.cc/):

- 1. Последовательные: последовательная компоновка (THEN), параллельная компоновка (WHEN);
- 2. Ветвления: выборочная компоновка (SWITCH), условная компоновка (IF);
- 3. Циклы: цикл FOR, цикл WHILE.

Я также написал статью: [Liteflow логика визуализации](https://juejin.cn/post/7357231056288972840), если вас интересует эта тема, рекомендую прочитать её.

## 3. Управление логикой (Control)

![LiteFlow логика визуализации - управление логикой (Control) - CRUD](./docs/assets/LiteFlow%20логика%20визуализации%20-%20управление%20логикой%20(Control)%20-%20CRUD.png)

Визуализация логики [LiteFlow](https://liteflow.cc/) включает в себя реализацию операций CRUD (создание, чтение, обновление, удаление) для модели ELNode:

![LiteFlow ContextPad.gif](./docs/assets/LiteFlow-ContextPad.gif)

Для удобства использования мы реализовали добавление узлов через перетаскивание (Drag & Drop) и добавление узлов через контекстное меню (ContextPad) на холсте.Для реализации CRUD операций для ELNode мы можем определить следующие методы в классе ELNode:

```typescript
export default abstract class ELNode {
  /////// Продолжение шага 1. Модель данных (Model)
  /**
   * Добавление дочернего узла
   * @param child Дочерний узел
   * @param index Указание позиции
   */
  public appendChild(child: ELNode, index?: number);

  /**
   * Удаление указанного дочернего узла
   * @param child Дочерний узел
   */
  public removeChild(child: ELNode): boolean;
  
  /**
   * Создание нового узла
   * @param parent Родительский узел
   */
  public create(parent: ELNode, type?: NodeTypeEnum): ELNode;

  /**
   * Удаление текущего узла
   */
  public remove(): boolean;

  /**
   * Преобразование в формат данных графа X6
   * @param previous Предыдущий узел
   * @param cells Массив ячеек
   * @param options Запись произвольных данных
   */
  public toCells(
    previous?: Node,
    cells?: Cell[],
    options?: Record<string, any>,
  ): Cell[] | Node;
  
  /**
   * Преобразование в строку EL выражения
   */
  public toEL(): string;
}

02-Модель данных (Model)

Вспомним, что мы упомянули в вводной части, как фронтенд-разработчику, нам нужно особенно уделить внимание трем элементам — данным (Model), представлению (View) и логике (Control), то есть "MVC". В дальнейшем я буду использовать знания о "трех элементах MVC" для разбора, объединения, проектирования и реализации системы визуализации логики LiteFlow:

Визуализация и проектирование логики LiteFlowА "данные", или "модель", или "модель данных", или "концептуальная модель" являются частью, которую нам нужно проанализировать и спроектировать перед разработкой. Конкретно для моделирования логики визуализации LiteFlow, наша цель — создать модель для операторов (Operator) EL-выражений, и в конечном итоге мы создали модель EL-выражений, которая состоит из дерева узлов ELNode:Визуализация и проектирование логики LiteFlow 1. Модель данных (Model)

1. EL-выражения

Логическая компоновка LiteFlow осуществляется с помощью EL-выражений, например, пример EL-выражения:

<chain name="chain1">
    THEN(
        a,
        WHEN(b, c, d),
        e
    );
</chain>

Визуализация и проектирование логики LiteFlow - EL-выражения

В этом примере "THEN" и "WHEN" являются ключевыми словами EL-выражений, которые обозначают последовательную и параллельную компоновку соответственно, а "a", "b", "c", "d", "e" — это пять логических компонентов, которые вместе образуют комбинацию последовательной и параллельной компоновки — то есть сначала выполняется компонент "a", затем параллельно выполняются компоненты "b", "c", "d", а затем выполняется компонент "e".

LiteFlow моделирует исполняемые логические процессы, включая следующие две части:

Моделирование процессов LiteFlow: логические компоненты + логическая компоновка

    1. Логические компоненты (узлы компонентов): типы логических компонентов включают:
    • ① Последовательные компоненты: для THEN, WHEN;
    • ② Ветвящиеся компоненты: для SWITCH, IF ...;
    • ③ Циклические компоненты: для FOR, WHILE ...;- 2. Логическая компоновка: компоновка компонентов с помощью EL-выражений:
    • ① Последовательная компоновка: THEN;
    • ② Параллельная компоновка: WHEN;
    • ③ Выборочная компоновка: SWITCH;
    • ④ Условная компоновка: IF;
    • ⑤ Циклическая компоновка: FOR, WHILE и т.д. В этом проекте наша первоочередная задача — это моделирование операторов (Operator) EL-выражений, в конечном итоге мы моделируем EL-выражения в виде дерева, состоящего из узлов ELNode.## 2. Деревянная структура:

Разбивая EL-выражения LiteFlow на текстовые элементы, мы получаем деревянную структуру:

LiteFlow логическая визуализация - EL выражение vs AST синтаксическое дерево.png

Деревянная структура выше получена из AST (абстрактного синтаксического дерева). Полное AST синтаксическое дерево, полученное с помощью AST explorer, представлено ниже:

{
  "type": "Program",
  "start": 0,
  "end": 34,
  "body": [
    {
      "type": "ExpressionStatement",
      "start": 0,
      "end": 34,
      "expression": {
        "type": "CallExpression",
        "start": 0,
        "end": 33,
        "callee": {
          "type": "Identifier",
          "start": 0,
          "end": 4,
          "name": "THEN"
        },
        "arguments": [
          {
            "type": "Identifier",
            "start": 8,
            "end": 9,
            "name": "a"
          },
          {
            "type": "CallExpression",
            "start": 13,
            "end": 26,
            "callee": {
              "type": "Identifier",
              "start": 13,
              "end": 17,
              "name": "WHEN"
            },
            "arguments": [
              {
                "type": "Identifier",
                "start": 18,
                "end": 19,
                "name": "b"
              },
              {
                "type": "Identifier",
                "start": 21,
                "end": 22,
                "name": "c"
              },
              {
                "type": "Identifier",
                "start": 24,
                "end": 25,
                "name": "d"
              }
            ],
            "optional": false
          },
          {
            "type": "Identifier",
            "start": 30,
            "end": 31,
            "name": "e"
          }
        ],
        "optional": false
      }
    }
  ],
  "sourceType": "module"
}
```## 3. JSON представление

Мы можем упростить это AST синтаксическое дерево и получить упрощённое JSON представление:![LiteFlow логика визуального редактирования — AST синтаксическое дерево vs JSON представление.png](./docs/assets/LiteFlow логика визуального редактирования — AST синтаксическое дерево vs JSON представление.png)

```typescript
{
  type: "THEN",
  children: [
    { type: "NodeComponent", id: "a" },
    {
      type: "WHEN",
      children: [
        { type: "NodeComponent", id: "b" },
        { type: "NodeComponent", id: "c" },
        { type: "NodeComponent", id: "d" },
      ],
    },
    { type: "NodeComponent", id: "e" },
  ]
}

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

4. Создание модели

![LiteFlow логика визуального редактирования — 1. Данные модели (Model).png](./docs/assets/LiteFlow логика визуального редактирования — 1. Данные модели (Model).png)После анализа вышеупомянутых шагов, мы можем создать следующую модель ELNode:

/**
 * Модель представления EL-выражений: сущность данных представляет собой древовидную структуру.
 * Например, последовательное выполнение (THEN):
 * (1) Форма EL-выражения: THEN(a, b, c, d)
 * (2) Форма представления JSON:
 * {
 *   type: ConditionTypeEnum.THEN,
 *   children: [
 *     { type: NodeTypeEnum.COMMON, id: 'a' },
 *     { type: NodeTypeEnum.COMMON, id: 'b' },
 *     { type: NodeTypeEnum.COMMON, id: 'c' },
 *     { type: NodeTypeEnum.COMMON, id: 'd' },
 *   ],
 * }
 * (3) Представление с использованием модели узлов ELNode:
 *                                           ┌─────────────────┐
 *                                       ┌──▶│  NodeOperator   │
 *                                       │   └─────────────────┘
 *                                       │   ┌─────────────────┐
 *                                       ├──▶│  NodeOperator   │
 *   ┌─────────┐    ┌─────────────────┐  │   └─────────────────┘
 *   │  Chain  │───▶│  ThenOperator   │──┤   ┌─────────────────┐
 *   └─────────┘    └─────────────────┘  ├──▶│  NodeOperator   │
 *                                       │   └─────────────────┘
 *                                       │   ┌─────────────────┐
 *                                       └──▶│  NodeOperator   │
 *                                           └─────────────────┘
 * */
export default abstract class ELNode {
  // Тип узла: может быть типом композиции или компонентом
  public type: ConditionTypeEnum | NodeTypeEnum;
  // Подузлы текущего узла: тип композиции имеет подузлы, тип компонента — нет
```  public children? : ELNode[];
   // Родительский узел текущего узла
   public parent? : ELNode;
   // Условие для узла типа композиции: используется для типов SWITCH/IF/FOR/WHILE и т. д.
   public condition? : ELNode;
   // Идентификатор компонента
   public id? : string;
   // Свойства узла композиции: можно задать id/tag и т. д.
   public properties? : Properties;
 }
 ```! [LiteFlow логическая визуализация и разработка - модель ELNode - комбинаторные отношения против наследственных отношений. png](. /docs/assets/LiteFlow логическая визуализация и разработка - модель ELNode - комбинаторные отношения против наследственных отношений. png)Для нашей модели ELNode ключевые моменты следующие:1. Комбинаторные отношения: одно EL-выражение, в конечном итоге, состоит из дерева ELNode;
  - Корневой узел этого дерева мы определяем как Chain, а другие EL-операторы (например, THEN/WHEN/SWITCH и другие ключевые слова, а также логические компоненты) являются подузлами этого дерева;
  - Важно отметить, что логические компоненты (NodeComponent) рассматриваются как операторы (Operator) и являются листовыми узлами этого дерева.
2. Наследственные отношения: все EL-операторы (например, THEN/WHEN/SWITCH и другие), включая логические компоненты (NodeComponent), наследуются от ELNode, при этом имеют свои уникальные свойства и реализации методов. ```typescript
 /**
  * Модели операторов EL-выражений, наследование:
                       ┌─────────────────┐
                   ┌──▶│  ThenOperator   │
                   │   └─────────────────┘
                   │   ┌─────────────────┐
                   ├──▶│  WhenOperator   │
                   │   └─────────────────┘
                   │   ┌─────────────────┐
                   ├──▶│  SwitchOperator │
                   │   └─────────────────┘
   ┌──────────┐    │   ┌─────────────────┐
   │  ELNode  │────┼──▶│  IfOperator     │
   └──────────┘    │   └─────────────────┘
                   │   ┌─────────────────┐
                   ├──▶│  ForOperator    │
                   │   └─────────────────┘
                   │   ┌─────────────────┐
                   ├──▶│  WhileOperator  │
 ``````markdown
                  │   └─────────────────┘
                   │   ┌─────────────────┐
                   └──▶│  NodeOperator   │
                       └─────────────────┘
  */
// 1. Последовательные операторы
export { default as ThenOperator } from '. /then-operator';
export { default as WhenOperator } from '. /when-operator';
// 2. Ветвление
export { default as SwitchOperator } from '. /switch-operator';
export { default as IfOperator } from '. /if-operator';
// 3. Циклы
export { default as ForOperator } from '. /for-operator';
export { default as WhileOperator } from '. /while-operator';
// 4. Операторы узлов
export { default as NodeOperator } from '. /node-operator';
```# 03-Представление вида (View)
```Вспомним, что мы упомянули в [введении](https://juejin.cn/spost/7365694439568343080), каким аспектам следует уделить особое внимание в качестве фронтенд-разработчика: данным (Model), представлению (View) и логике (Control), то есть "MVC". В дальнейшем я буду использовать знания о "трех элементах MVC" для разбора, объединения, проектирования и реализации системы визуализации логики LiteFlow:

![LiteFlow логика визуализации проектирования и реализации.png](./docs/assets/Liteflow%20логика%20визуализации%20проектирования%20и%20реализации.png)

В [статье о модели данных](https://juejin.cn/spost/7366557738267426850), мы завершили работу по моделированию операторов (Operator) EL-выражений, в результате чего EL-выражение было преобразовано в дерево, состоящее из узлов ELNode:

![LiteFlow логика визуализации - модель ELNode - отношение композиции против наследования.png](./docs/assets/LiteFlow%20логика%20визуализации%20-%20модель%20ELNode%20-%20отношение%20композиции%20против%20наследования.png)

Далее мы будем использовать узлы (Node) и ребра (Edge) библиотеки AntV X6 для визуализации ELNode, то есть через Nodes & Edges реализуем визуализацию логики [LiteFlow](https://liteflow.cc/):

![Liteflow логика визуализации проектирования.png](./docs/assets/Liteflow%20логика%20визуализации%20проектирования.png)## 1. Суть: "Два узла и одна линия"
Если мы сведем суть визуализации логики [LiteFlow](https://liteflow.cc/) к одной фразе, то это будет "два узла и одна линия". Поскольку, если рассматривать элементы визуализации, то любая схема в конечном итоге сводится к "двум узлам и одной линии" - то есть узлам и соединяющим их линиям, а также текстовым меткам на этих узлах и линиях.![Два узла и одна линия.png](./docs/assets/Два%20узла%20и%20одна%20линия.png)

Визуализация логики [LiteFlow](https://liteflow.cc/) осуществляется путем комбинации узлов и линий. Например, ниже приведен пример визуализации корневого узла Chain логики [LiteFlow](https://liteflow.cc/):

![LiteFlow логика визуализации - дизайн Chain.png](./docs/assets/LiteFlow%20логика%20визуализации%20-%20дизайн%20Chain.png)

Визуализация корневого узла Chain логики [LiteFlow](https://liteflow.cc/) включает:

- Два узла: "начальный узел" и "конечный узел";
- Одну линию: соединяющую "начальный узел" и "конечный узел".

Реализация "двух узлов и одной линии" с помощью AntV X6 также довольно проста, пример реализации приведен ниже:

```typescript
// 1. Сначала: создаем начальный узел
const start: Node = Node.create({
  shape: 'liteflow-start',
  attrs: {
    label: { text: 'Начало' },
  },
});
// bk: Затем: создаем конечный узел
const end: Node = Node.create({
  shape: 'liteflow-end',
  attrs: {
    label: { text: 'Конец' },
  },
});
// 3. В конце: создаем соединение между начальным и конечным узлами
Edge.create({
  shape: 'edge',
  source: start,
  target: end,
});

На самом деле, код выше представляет собой реализацию визуализации логики LiteFlow, другие операторы (включая последовательное выполнение THEN, параллельное выполнение WHEN, условное выполнение IF и т.д.) также используют ту же идею "точка-точка-линия" для реализации:

LiteFlow логика визуализации - параллельное выполнение WHENВот наши визуализации и реализации различных логических операторов LiteFlow.

2. Визуализация логики и её реализация

2.1 Последовательное выполнение: THEN

1. Текстовое выражение (Liteflow EL)

Если вы хотите последовательно выполнить компоненты a, b, c, d, вы можете использовать ключевое слово THEN. Важно помнить, что THEN должно быть написано заглавными буквами.

<chain name="chain1">
    THEN(a, b, c, d);
</chain>

2. JSON представление

{
    "type": "THEN",
    "children": [
        { "type": "NodeComponent", "id": "a" },
        { "type": "NodeComponent", "id": "b" },
        { "type": "NodeComponent", "id": "c" },
        { "type": "NodeComponent", "id": "d" },
    ]
}

3. Представление через модель узлов

                                          ┌─────────────────┐
                                      ┌──▶│  NodeOperator   
                                         └─────────────────┘
                                         ┌─────────────────┐
                                      ├──▶│  NodeOperator   
  ┌─────────┐    ┌─────────────────┐     └─────────────────┘
    Chain  │───▶│  ThenOperator   │──┤   ┌─────────────────┐
  └─────────┘    └─────────────────┘  ├──▶│  NodeOperator   
                                         └─────────────────┘
                                         ┌─────────────────┐
                                      └──▶│  NodeOperator   
                                          └─────────────────┘
```

#### 4. Визуализация и реализация дизайна![LiteFlow Logical Visualization Arrangement - Parallel Arrangement WHEN Design.png](./docs/assets/LiteFlowлогическая_визуализация_компоновки-параллельная_компоновкаWHEN_дизайн2.png)

### 2.3 Выборочная компоновка: SWITCH

#### 1. Текст (Liteflow EL) выражение

Если, согласно компоненту a, выбирается выполнение одного из b, c, d, можно объявить следующим образом:

``` typescript
<chain name="chain1">
    SWITCH(a).to(b, c, d);
</chain>
```

#### 2. JSON-представление

```typescript
{
    "type": "SWITCH",
    "condition": { "type": "SwitchComponent", "id": "x" },
    "children": [
        { "type": "NodeComponent", "id": "a" },
        { "type": "NodeComponent", "id": "b" },
        { "type": "NodeComponent", "id": "c" },
        { "type": "NodeComponent", "id": "d" },
    ]
}
```

#### 3. Представление через модель узлов

```typescript
                                          ┌─────────────────┐
                                      ┌──▶│  NodeOperator   
                                         └─────────────────┘
                                         ┌─────────────────┐
                                      ├──▶│  NodeOperator   
  ┌─────────┐    ┌─────────────────┐     └─────────────────┘
    Chain  │───▶│ SwitchOperator  │──┤   ┌─────────────────┐
  └─────────┘    └─────────────────┘  ├──▶│  NodeOperator   
                                         └─────────────────┘
                                         ┌─────────────────┐
                                      └──▶│  NodeOperator   
                                          └─────────────────┘
```

#### 4. Визуальное проектирование и реализация![LiteFlow логическое визуальное проектирование - выбор SWITCH](./docs/assets/LiteFlow%20логическое%20визуальное%20проектирование%20-%20выбор%20SWITCH.png)

### 2.4 Условное проектирование: IF

#### 1. Текстовое (Liteflow EL) представление

``` typescript
<chain name="chain1">
    IF(x, a);
</chain>
```

#### 2. JSON-представление

```typescript
{
    "type": "IF",
    "condition": { "type": "IfComponent", "id": "x" },
    "children": [
        { "type": "NodeComponent", "id": "a" },
    ]
}
```

#### 3. Представление с помощью модели узлов

```typescript
                                          ┌─────────────────┐
                                      ┌──▶│  NodeOperator   
  ┌─────────┐    ┌─────────────────┐     └─────────────────┘
    Chain  │───▶│    IfOperator   │──┤   ┌─────────────────┐
  └─────────┘    └─────────────────┘  └──▶│  NodeOperator   
                                          └─────────────────┘
```

#### 4. Визуальное проектирование и реализация

![LiteFlow логическое визуальное проектирование - условное проектирование IF](./docs/assets/LiteFlow_логическое_визуальное_проектирование_условное_проектирование_IF.png)

### 2.5 Циклическое проектирование: FOR

#### 1. Текстовое (Liteflow EL) выражение

``` typescript
<chain name="chain1">
    FOR(f).DO(THEN(a, b));
</chain>
```

#### 2. JSON представление

```typescript
{
    "type": "FOR",
    "condition": { "type": "ForComponent", "id": "f" },
    "children": [
        {
            "type": "THEN",
            "children": [
                { "type": "NodeComponent", "id": "a" },
                { "type": "NodeComponent", "id": "b" },
            ]
        }
    ]
}
```#### 3. Представление с помощью модели узлов
```typescript
                                          ┌─────────────────┐
                                      ┌──▶│  NodeOperator   
  ┌─────────┐    ┌─────────────────┐     └─────────────────┘      ┌─────────────────┐
    Chain  │───▶│   ForOperator   │──┤   ┌─────────────────┐  ┌──▶│  NodeOperator   
  └─────────┘    └─────────────────┘  └──▶│  ThenOperator   │──┤   └─────────────────┘
                                          └─────────────────┘     ┌─────────────────┐
                                                               └──▶│  NodeOperator   
                                                                   └─────────────────┘
```
#### 4. Визуальное проектирование и реализация

![LiteFlow Логическая визуализация - Цикл FOR](./docs/assets/LiteFlow逻辑可视化编排-循环编排FOR设计.png)

### 2.6 Цикл WHILE

#### 1. Текст (Liteflow EL) выражение

``` typescript
<chain name="chain1">
    WHILE(x).DO(THEN(a, b));
</chain>
```

#### 2. JSON представление

```typescript
{
    "type": "WHILE",
    "condition": { "type": "WhileComponent", "id": "x" },
    "children": [
        {
            "type": "THEN",
            "children": [
                { "type": "NodeComponent", "id": "a" },
                { "type": "NodeComponent", "id": "b" },
            ]
        }
    ]
}
```

#### 3. Представление через модель узлов```typescript
                                          ┌─────────────────┐
                                      ┌──▶│  NodeOperator   
  ┌─────────┐    ┌─────────────────┐     └─────────────────┘      ┌─────────────────┐
    Chain  │───▶│  WhileOperator  │──┤   ┌─────────────────┐  ┌──▶│  NodeOperator   
  └─────────┘    └─────────────────┘  └──▶│  ThenOperator   │──┤   └─────────────────┘
                                          └─────────────────┘     ┌─────────────────┐
                                                               └──▶│  NodeOperator   
                                                                   └─────────────────┘
```#### 4. Визуальное Дизайн и Реализация

![LiteFlow Логическая Визуализация - Циклическая Компоновка WHILE Дизайн.png](./docs/assets/LiteFlow逻辑可视化编排-循环编排WHILE设计.png)


# 04-Операционная Логика Глава (Управление)

Вспоминая содержание, упомянутое в [Главе Введение](https://juejin.cn/spost/7365694439568343080), как разработчику фронтенда, нам нужно уделить особое внимание трём элементам: данным (Модель), представлению (Вид) и логике (Управление), то есть "MVC". Я также буду использовать знаний о "трёх элементах MVC" для разбора, объединения, проектирования и реализации системы визуализации логики LiteFlow:![LiteFlow логика визуализации и разметки.png](./docs/assets/LiteFlow逻辑编排可视化设计.png)

В [статье о модели данных](https://juejin.cn/spost/7366557738267426850), мы завершили работу по моделированию операторов (Оператор) для EL-выражений, и в итоге EL-выражения были представлены в виде дерева, состоящего из узлов ELNode:

![LiteFlow логика визуализации и разметки - модель ELNode - композиция против наследования.png](./docs/assets/LiteFlow逻辑可视化编排-ELNode模型-组合关系vs继承关系.png)

В [статье о представлении визуализации](https://juejin.cn/spost/7367611991362912308), мы завершили работу по визуализации ELNode с использованием узлов (Node) и ребер (Edge) библиотеки AntV X6:

![Liteflow логика визуализации и разметки.png](./docs/assets/Liteflow逻辑编排可视化设计.png)

Далее мы реализуем "компоновку" (arrangement) части логики визуализации LiteFlow:

![LiteFlow ContextPad.gif](./docs/assets/LiteFlow-ContextPad.gif)

Мы разбиваем логику "компоновки" на операции "создание, чтение, обновление, удаление" (CRUD), которые в данном контексте означают "добавление, удаление, изменение, чтение" для структуры дерева ELNode:![LiteFlow логика визуализации и разметки - логика операций (Control) - CRUD.png](./docs/assets/LiteFlow逻辑可视化编排-操作逻辑篇(Control)-增删改查CRUD.png)

## 1. CRUD для модели ELNode

Реализация CRUD для логики визуализации LiteFlow осуществляется путем вызова соответствующих методов модели ELNode, некоторые из которых определены следующим образом:

```typescript
export default abstract class ELNode {
  /////// Следующий шаг 1. Модель данных (Model)
  /**
   * Добавление дочернего узла
   * @param child Дочерний узел
   * @param index Указанный индекс
   */
  public appendChild(child: ELNode, index?: number);

  /**
   * Удаление указанного дочернего узла
   * @param child Дочерний узел
   */
  public removeChild(child: ELNode): boolean;
  
  /**
   * Создание нового узла
   * @param parent Родительский узел
   */
  public create(parent: ELNode, type?: NodeTypeEnum): ELNode;

  /**
   * Удаление текущего узла
   */
  public remove(): boolean;

  /**
   * Преобразование в формат данных X6
   */
  public toCells(
    previous?: Node,
    cells?: Cell[],
    options?: Record<string, any>,
  ): Cell[] | Node;
  
  /**
   * Преобразование в строку EL-выражения
   */
  public toEL(): string;
}
```

В настоящее время функциональный прототип нашего [LiteFlow](https://liteflow.cc/) визуального редактора логики представлен страницей с классической «трёхколоночной» структурой: левая, центральная и правая колонки, а также верхняя панель инструментов. Страница состоит из следующих четырёх панелей: левая панель «Материала», центральная панель «Канвас», правая панель «Настройки» и верхняя панель «Инструменты».![Логический редактор: панель материалов, панель канваса, панель настроек, панель инструментов.png](./docs/assets/Редактор логики: панель материалов, панель канваса, панель настроек, панель инструментов.png)

- 1. Панель материалов: на левой стороне страницы расположена панель материалов, где представлены различные логические компоненты для выбора, включая:
  ① Компоненты узлов: в реальных проектах узлы будут самыми распространенными. Здесь для удобства представлен только один компонент узла, идентификатор которого генерируется случайным образом в формате "Placeholder[1-9]";
  ② Компоненты последовательности: последовательное выполнение THEN, параллельное выполнение WHEN;
  ③ Компоненты ветвления: выборочное выполнение SWITCH, условное выполнение IF;
  ④ Компоненты цикла: цикл FOR, цикл WHILE.
  Используя перетаскивание компонентов логики из левой панели материалов на центральную панель канваса, можно добавлять и изменять узлы компонентов.- 2. Панель канваса: центральная панель канваса занимает большую часть страницы и представляет собой визуализацию логики всего LiteFlow. В дополнение к основному содержанию «узлы» и «ребра», на панели канваса также расположены кнопки для выполнения операций с логическими компонентами, включая «создание», «удаление», «изменение» и «просмотр». В настоящее время доступны следующие операции:
  ① Доступные операции для узлов: вставка узла перед или после текущего узла, замена текущего узла, удаление текущего узла;
  ② Доступные операции для ребер: вставка узла в месте ребра (аналогично вставке нового узла после текущего узла).- 3. Панель настроек: на правой стороне страницы расположена панель настроек, которая по умолчанию отображает EL-выражение LiteFlow. После выбора определенного логического компонента узла отображаются настраиваемые параметры этого компонента, такие как часто используемые параметры id и tag в LiteFlow.

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

Далее мы рассмотрим операции «создания», «удаления» и «изменения» в [LiteFlow](https://liteflow.cc/) визуальном редакторе логики.

## 2. Создание (Create)

### 2.1 Создание с помощью перетаскивания

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

![Операция создания: 1. Перетаскивание.gif](./docs/assets/Операция%20создания:%201.%20Перетаскивание.gif)Вот реализация перетаскивания узлов на холст с использованием AntV X6 [Addon.Dnd](https://x6.antv.vision/zh/docs/tutorial/basic/dnd):```typescript
const dnd = useMemo(
    () =>
      new Addon.Dnd({
        target: flowGraph,
        scaled: true,
        validateNode: (droppingNode: Node) => {
          const position = droppingNode.getPosition();
          const { node } = droppingNode.getData();
          const cellViewsFromPoint = flowGraph.findViewsFromPoint(
            position.x,
            position.y,
          );
          let cellViews = cellViewsFromPoint.filter((cellView) => cellView.isEdgeView()) || [];
          if (cellViews && cellViews.length) {
            const currentEdge = flowGraph.getCellById(cellViews[0].cell.id) as Edge | null;
            let targetNode = currentEdge.getTargetNode();
            let { model: targetModel } = targetNode?.getData<INodeData>() || {};
            targetModel?.append(ELBuilder.createELNode(node.type, targetModel));
          }
          
          return false;
        },
      }),
    [flowGraph],
  );
```В данном случае реализовано такое дизайнерское решение: добавление узлов возможно только при перетаскивании их на границу существующего узла. Поэтому в методе `validateNode` в конце возвращается `false`.

### 2.2 Добавление через панель быстрого доступа (ContextPad)

На холсте рядом с узлами и ребрами есть кнопки для удобного добавления логических компонентов:
1. Добавление узла рядом с узлом: вставка узла перед или после существующего узла;

![Добавление узла: вставка перед узлом.png](./docs/assets/добавление_узла_вставка_перед_узлом.png)

2. Добавление узла на ребре: вставка узла на месте ребра (аналогично вставке узла после предыдущего узла).

![Добавление узла: вставка на ребре.png](./docs/assets/добавление_узла_вставка_на_ребре.png)

Здесь реализован компонент ContextPad для быстрого добавления узлов — таким образом, можно добавлять компоненты непосредственно на холсте без перетаскивания.

Реализация компонента ContextPad осуществляется с использованием [механизма пользовательских событий](https://x6.antv.vision/zh/docs/tutorial/intermediate/events) в AntV X6. Код, вызывающий ContextPad, представлен ниже:

```typescript
const showContextPad = debounce((info: any) => {
  node.model?.graph?.trigger('graph:showContextPad', info);
}, 100);
const onPrepend = (event: any) => {
  showContextPad({
    x: event.clientX,
    y: event.clientY,
    node,
    scene: 'prepend',
    title: 'вставить перед узлом',
    edge: null,
  });
};
const onAppend = (event: any) => {
  showContextPad({
    x: event.clientX,
    y: event.clientY,
    node,
    scene: 'append',
    title: 'вставить после узла',
    edge: null,
  });
};
```## 3. Изменение (Update)

### 3.1 Изменение через перетаскивание

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

![Изменение: 1. Перетаскивание для замены узла.gif](./docs/assets/изменение: 1. Перетаскивание для замены узла.gif)

### 3.2 Изменение через панель контекста (ContextPad)

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

![Изменение: 2. Кнопка замены.gif](./docs/assets/изменение: 2. Кнопка замены.gif)

### 3.3 Изменение через панель настроек

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

![Изменение: 3. Настройка свойств.gif](./docs/assets/изменение: 3. Настройка свойств.gif)

## 4. Удаление (Delete)

### 4.1 Удаление через панель инструментов

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

![Удаление: 1. Кнопка удаления.gif](./docs/assets/удаление: 1. Кнопка удаления.gif)

### 4.2 Удаление через сочетание клавиш

В центральной области рисования можно удалить компоненты с помощью сочетания клавиш `backspace` или `delete`. Например, здесь я выбрал все компоненты с помощью `ctrl + a`, а затем нажал `delete` для удаления:![Удаление: 2. Удаление с помощью сочетания клавиш.gif](./docs/assets/удаление: 2. Удаление с помощью сочетания клавиш.gif)

Эта реализация довольно проста, код реализации приведен ниже:

```typescript
flowGraph.bindKey(['backspace', 'del'], () => {
  const toDelCells = flowGraph
    .getSelectedCells()
    .filter((cell) => cell.isNode());
  if (toDelCells.length) {
    Modal.confirm({
      title: `Подтвердите удаление выбранных узлов?`,
      content: 'Нажмите "Подтвердить", чтобы удалить, или "Отмена", чтобы вернуться',
      onOk() {
        toDelCells.forEach((node) => {
          const { model } = node.getData() || {};
          model?.remove?.();
        });
        history.push();
      },
    });
  }
  return false;
});
```

При использовании AntV X6 для реализации вышеупомянутых интерактивных функций ключевые API методы вызываются через методы класса `Graph`. Если вы также используете AntV X6 для создания подобных графических визуализационных редакторов, рекомендуем вам хорошо изучить API класса `Graph`.

Комментарии ( 0 )

Вы можете оставить комментарий после Вход в систему

Введение

Визуальный редактор Liteflow фронтенд-проект Развернуть Свернуть
TypeScript и 4 других языков
MIT
Отмена

Обновления

Пока нет обновлений

Участники

все

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://api.gitlife.ru/oschina-mirror/imwangshijiang-liteflow-editor-client.git
git@api.gitlife.ru:oschina-mirror/imwangshijiang-liteflow-editor-client.git
oschina-mirror
imwangshijiang-liteflow-editor-client
imwangshijiang-liteflow-editor-client
master