Імпорт/експорт - Rete.js

Імпорт/експорт

МодуліСтруктури даних3D Конфігуратор

З коробки редактор може обробляти будь-які об’єкти JS як вузли та з’єднання, за умови, що вони містять обов’язкове поле «id» для обох. Крім того, з’єднання повинні мати поля source та target. Ці об’єкти можуть бути як звичайними об’єктами з даними, так і об’єктами, що містять методи. Докладніше див. у гайді Структури даних.

Поточна версія редактора не підтримує імпорт/експорт за замовчуванням через деякі обмеження:

  • Процес серіалізації вузлів/з'єднань до JSON може бути складним
  • Порядок імпорту вузлів може відрізнятися залежно від структури вашого графа

Дійсні JSON об’єкти

Припустімо, у нас є простий приклад, де вузол є дійсним JSON об’єктом

ts
import { NodeEditor, BaseSchemes, getUID } from 'rete'

const editor = new NodeEditor<BaseSchemes>()

const node = { id: getUID(), label: 'Label' }

await editor.addNode(node)

У цьому випадку ми можемо легко експортувати такі вузли в JSON, щоб зберегти їх, наприклад, у базі даних.

Недійсні JSON об’єкти

Об’єкти, які не є дійсними JSON, наприклад екземпляри класів, об’єкти з функціями або об’єкти з циклічними посиланнями, можуть бути викликом. Відмова від них означала б втрату переваг використання JS.

Наприклад, класи вузлів можна використовувати для створення вузлів, що забезпечує більш надійну та зручну взаємодію за допомогою методів і забезпечує гнучкість використання різних парадигм.

ts
import { ClassicPreset } from 'rete'

const node = new ClassicPreset.Node('Label')

node.addOutput('port', new ClassicPreset.Output(socket, 'Label'))

await editor.addNode(node)

Хоча серіалізація та десеріалізація можуть бути одним із способів перетворення таких об’єктів на дійсні JSON, цей підхід може не працювати в складних сценаріях.

Експорт та імпорт вузлів

Якщо ви хочете експортувати граф, ви можете використовувати наступний код як довідник. Зверніть увагу, що це не повністю функціональний код, а наближений, який допоможе вам реалізувати власні функції імпорту/експорту відповідно до ваших конкретних вимог.

ts
const data = { nodes: [] }
const nodes = editor.getNodes()

for (const node of nodes) {
  data.nodes.push({
    id: node.id,
    label: node.label,
    inputs: /// ....
    controls: /// ....
    outputs: /// ....
  })
}

Щоб зробити зворотну трансформацію, ми повинні ініціалізувати екземпляри вузлів, входи, виходи та контроли на основі наданих об’єктів.

ts
for (const { id, label, inputs, outputs, controls } of data.nodes) {
  const node = new ClassicPreset.Node(label);

  node.id = id;

  /// ... inputs
  /// ... controls
  /// ... outputs

  await editor.addNode(node)
}

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

Крім того, імпорт або експорт входів і виходів може не завжди бути необхідним, якщо вони статичні, і ми знаємо тип вузла. У таких випадках ми можемо просто зберегти назву вузла та відповідні дані, які можна використовувати для створення екземплярів вузлів із заздалегідь визначеними портами. Перегляньте приклади 3D Конфігуратор і Модулі з реалізацією цього підходу.

Порядок імпорту вузлів

Іншою проблемою під час імпорту графа може бути порядок, у якому необхідно імпортувати вузли. У простих випадках порядок буде таким же, як і порядок, у якому вони були додані до редактора.

ts
const graph = /// завантажений з БД дійсний JSON об’єкт

for (const node of graph.nodes) {
  await editor.addNode(node)
}

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

Давайте подивимося на приклад імпортування графа, де певні вузли мають поле parent, що вказує на їх зв’язок з іншим вузлом. У результаті ці вузли потрібно імпортувати після того, як їх батьківський вузол буде створено.

ts
async function importForParent(nodes, parent = undefined) {
  const nodes = nodes.filter(node => node.parent === parent)

  for (const node of nodes) {
    await editor.addNode(node)
    await importForParent(nodes, node.id)
  }
}

const graph = /// завантажений з БД дійсний JSON об’єкт

await importForParent(graph.nodes)

Оскільки цей підхід складніший і існує кілька способів його виконання, метод імпорту буде різним залежно від конкретного випадку використання.