Этот проект представляет собой фронтенд для визуального редактора логики LiteFlow. Для доступа к проекту backend перейдите по ссылке LiteFlow визуальный редактор backend.
$ yarn
$ yarn start
Далее представлено описание реализации LiteFlow логического визуального редактирования.
Как разработчик фронтенда, нам следует уделить особое внимание трем ключевым элементам фронтенд-разработки: данным (Model), представлению (View) и логике (Control), то есть "MVC". При реализации LiteFlow логического визуального редактирования, мы также можем использовать знания о "трех элементах MVC" для систематического разбиения, объединения, дизайна и реализации.
1. Модель данных (Model): моделирование операторов (Operator) EL-выражений, в этом проекте EL-выражения моделируются в виде дерева, состоящего из узлов ELNode;
2. Представление (View): использование узлов (Node) и ребер (Edge) AntV X6 для визуализации узлов ELNode, то есть через Nodes & Edges реализуется LiteFlow логическое визуальное редактирование;
3. Логика управления (Control): реализация операций CRUD (создание, чтение, обновление, удаление) модели ELNode.Я очень ценю этот "кадр MVC", так как он позволяет мне легко разбивать и объединять системы. Поэтому в этой статье и в серии статей я буду использовать этот "кадр MVC" для обсуждения.
В этом введении мы кратко рассмотрим "три элемента MVC" для LiteFlow логического визуального редактирования:
LiteFlow моделирует исполняемые логические процессы, включая следующие две части:
А для логической компоновки "логических компонентов" используются выражения 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>
{
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" },
]
}
/**
* Модельное представление 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](https://liteflow.cc/):
- 1. Последовательные: последовательная компоновка (THEN), параллельная компоновка (WHEN);
- 2. Ветвления: выборочная компоновка (SWITCH), условная компоновка (IF);
- 3. Циклы: цикл FOR, цикл WHILE.
Я также написал статью: [Liteflow логика визуализации](https://juejin.cn/post/7357231056288972840), если вас интересует эта тема, рекомендую прочитать её.
## 3. Управление логикой (Control)
%20-%20CRUD.png)
Визуализация логики [LiteFlow](https://liteflow.cc/) включает в себя реализацию операций CRUD (создание, чтение, обновление, удаление) для модели ELNode:

Для удобства использования мы реализовали добавление узлов через перетаскивание (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;
}
Вспомним, что мы упомянули в вводной части, как фронтенд-разработчику, нам нужно особенно уделить внимание трем элементам — данным (Model), представлению (View) и логике (Control), то есть "MVC". В дальнейшем я буду использовать знания о "трех элементах MVC" для разбора, объединения, проектирования и реализации системы визуализации логики LiteFlow:
А "данные", или "модель", или "модель данных", или "концептуальная модель" являются частью, которую нам нужно проанализировать и спроектировать перед разработкой. Конкретно для моделирования логики визуализации LiteFlow, наша цель — создать модель для операторов (Operator) EL-выражений, и в конечном итоге мы создали модель EL-выражений, которая состоит из дерева узлов ELNode:
Логическая компоновка LiteFlow осуществляется с помощью 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".
LiteFlow моделирует исполняемые логические процессы, включая следующие две части:
Разбивая EL-выражения LiteFlow на текстовые элементы, мы получаем деревянную структуру:
Деревянная структура выше получена из 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 представление:
```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 представляют нашу целевую форму, а также стандартный формат обмена данными между клиентской и серверной сторонами.
.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:

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

Далее мы будем использовать узлы (Node) и ребра (Edge) библиотеки AntV X6 для визуализации ELNode, то есть через Nodes & Edges реализуем визуализацию логики [LiteFlow](https://liteflow.cc/):
## 1. Суть: "Два узла и одна линия"
Если мы сведем суть визуализации логики [LiteFlow](https://liteflow.cc/) к одной фразе, то это будет "два узла и одна линия". Поскольку, если рассматривать элементы визуализации, то любая схема в конечном итоге сводится к "двум узлам и одной линии" - то есть узлам и соединяющим их линиям, а также текстовым меткам на этих узлах и линиях.
Визуализация логики [LiteFlow](https://liteflow.cc/) осуществляется путем комбинации узлов и линий. Например, ниже приведен пример визуализации корневого узла Chain логики [LiteFlow](https://liteflow.cc/):

Визуализация корневого узла 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.
Если вы хотите последовательно выполнить компоненты a, b, c, d, вы можете использовать ключевое слово THEN
. Важно помнить, что THEN
должно быть написано заглавными буквами.
<chain name="chain1">
THEN(a, b, c, d);
</chain>
{
"type": "THEN",
"children": [
{ "type": "NodeComponent", "id": "a" },
{ "type": "NodeComponent", "id": "b" },
{ "type": "NodeComponent", "id": "c" },
{ "type": "NodeComponent", "id": "d" },
]
}
┌─────────────────┐
┌──▶│ NodeOperator │
│ └─────────────────┘
│ ┌─────────────────┐
├──▶│ NodeOperator │
┌─────────┐ ┌─────────────────┐ │ └─────────────────┘
│ Chain │───▶│ ThenOperator │──┤ ┌─────────────────┐
└─────────┘ └─────────────────┘ ├──▶│ NodeOperator │
│ └─────────────────┘
│ ┌─────────────────┐
└──▶│ NodeOperator │
└─────────────────┘
```
#### 4. Визуализация и реализация дизайна
### 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. Визуальное проектирование и реализация
### 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. Визуальное проектирование и реализация

### 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. Визуальное проектирование и реализация

### 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. Визуальное Дизайн и Реализация

# 04-Операционная Логика Глава (Управление)
Вспоминая содержание, упомянутое в [Главе Введение](https://juejin.cn/spost/7365694439568343080), как разработчику фронтенда, нам нужно уделить особое внимание трём элементам: данным (Модель), представлению (Вид) и логике (Управление), то есть "MVC". Я также буду использовать знаний о "трёх элементах MVC" для разбора, объединения, проектирования и реализации системы визуализации логики LiteFlow:
В [статье о модели данных](https://juejin.cn/spost/7366557738267426850), мы завершили работу по моделированию операторов (Оператор) для EL-выражений, и в итоге EL-выражения были представлены в виде дерева, состоящего из узлов ELNode:

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

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

Мы разбиваем логику "компоновки" на операции "создание, чтение, обновление, удаление" (CRUD), которые в данном контексте означают "добавление, удаление, изменение, чтение" для структуры дерева ELNode:-增删改查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/) визуального редактора логики представлен страницей с классической «трёхколоночной» структурой: левая, центральная и правая колонки, а также верхняя панель инструментов. Страница состоит из следующих четырёх панелей: левая панель «Материала», центральная панель «Канвас», правая панель «Настройки» и верхняя панель «Инструменты».
- 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 Создание с помощью перетаскивания
На левой панели материалов можно перетащить необходимые логические компоненты на центральную панель канваса для добавления новых логических компонентов:
Вот реализация перетаскивания узлов на холст с использованием 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. Добавление узла рядом с узлом: вставка узла перед или после существующего узла;

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

Здесь реализован компонент 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 Изменение через перетаскивание
В левой области материалов можно перетащить нужный логический компонент на узел компонента в центральной области рисования, чтобы заменить этот узел компонента:

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

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

## 4. Удаление (Delete)
### 4.1 Удаление через панель инструментов
В центральной области рисования на панели инструментов узла есть кнопка удаления, с помощью которой можно легко удалить логический компонент:

### 4.2 Удаление через сочетание клавиш
В центральной области рисования можно удалить компоненты с помощью сочетания клавиш `backspace` или `delete`. Например, здесь я выбрал все компоненты с помощью `ctrl + a`, а затем нажал `delete` для удаления:
Эта реализация довольно проста, код реализации приведен ниже:
```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 )