Цей гайд містить більш детальне вивчення функціональних можливостей плагіна rete-connection-plugin
, що забезпечує взаємодію користувача зі з’єднаннями.
Коли користувач натискає на сокет, з’єднання, що слідує за курсором, називається псевдоз’єднанням, яке є об’єктом із додатковою властивістю isPseudo: true
.
Можливо, ви вже бачили таке використання попередньо встановлених налаштувань, яке дозволяє користувачам додавати з’єднання, клацаючи/натискаючи вхідний/вихідний роз’єм і клацаючи/відпускаючи вихідний/вхідний роз’єм:
connection.addPreset(ConnectionPresets.classic.setup())
який еквівалентний наведеному нижче коду:
import { ClassicFlow } from 'rete-connection-plugin'
connection.addPreset(() => new ClassicFlow())
Якщо вхідне гніздо вже підключено, клацання або натискання на ньому призведе до видалення підключення та заміни його на псевдоз’єднання.
Якщо ви віддаєте перевагу альтернативному методу додавання підключень, ви можете скористатися BidirectFlow
. У цьому режимі додавання вузла здійснюється клацанням миші на вхідному/вихідному сокеті та перетягуванням псевдоз’єднання на сокет протилежного типу.
import { ClassicFlow } from 'rete-connection-plugin'
connection.addPreset(() => new BidirectFlow())
Крім того, використовуючи дані початкового сокета, ви можете вибрати певний флоу або взагалі вимкнути взаємодію з певним сокетом
connection.addPreset(({ nodeId, side, key }) => {
if (isReadonly(nodeId, side, key)) return undefined
if (usesBidirect(nodeId, side, key)) return new BidirectFlow()
return new ClassicFlow()
})
Якщо існуючі флоу не відповідають вашим потребам, ви можете реалізувати власне рішення, посилаючись на вихідний код існуючих.
Покращення поведінки існуючих пресетів може включати відстеження подій connectionpick
і connectiondrop
connection.addPipe(context => {
if (context.type === 'connectionpick') { // коли користувач натискає на сокет
const { socket } = context.data
}
if (context.type === 'connectiondrop') { // коли користувач натискає на сокет або будь-яку область
const { socket, initial, created } = context.data
}
return context
})
Подію connectionpick
можна запобігти
connection.addPipe(context => {
if (context.type === 'connectionpick') {
if (readonly) return
}
return context
})
За замовчуванням, коли користувач створює з’єднання за допомогою UI, плагін додає з’єднання як об’єкт, а не екземпляр класу, наприклад ClassicPreset.Connection
. Якщо ви хочете налаштувати процес додавання цих з’єднань, укажіть опцію makeConnection
у ClassicFlow
або BidirectFlow
.
import { getSourceTarget } from 'rete-connection-plugin'
connection.addPreset(() => new ClassicFlow({
makeConnection(from, to, context) {
const [source, target] = getSourceTarget(from, to) || [null, null];
const { editor } = context;
if (source && target) {
editor.addConnection(
new MyConnection(
editor.getNode(source.nodeId),
source.key,
editor.getNode(target.nodeId),
target.key
)
);
return true; // переконайтеся, що підключення було успішно додано
}
}
}))
Крім того, використання getSourceTarget
є важливим у цьому випадку, оскільки параметри from
і to
несуть дані про початковий і кінцевий сокети, які не обов’язково можуть збігатися з вихідним і вхідним сокетами.
Кожне з’єднання пов’язано з початковою та кінцевою точками, безпосередньо з’єднаними з сокетом (за винятком псевдоз’єднань, де кінцева точка залежить від позиції курсору). За замовчуванням початковою точкою є права сторона вихідного сокету, а початковою – ліва сторона вхідного сокету. Зміна розміру сокета спричинить зміщення початкової/кінцевої точки з’єднання.
Щоб налаштувати початкову та кінцеву позицію з’єднання, ви можете вказати getDOMSocketPosition
з цими координатами зсуву відносно центру сокета.Цей метод використовується за замовчуванням, коли параметр socketPositionWatcher
не вказано.
import { getDOMSocketPosition } from 'rete-render-utils'
render.addPreset(Presets.classic.setup({
socketPositionWatcher: getDOMSocketPosition({
offset({ x, y }, nodeId, side, key) {
return {
x: x + 10 * (side === 'input' ? -1 : 1),
y: y
}
},
})
}))
У цьому сценарії обчислення позиції сокета покладається на елементи DOM. Бувають випадки, коли такий підхід може виявитися неефективним через продуктивність або інші нюанси реалізації (наприклад, у прикладі LOD, де потрібне відображення з’єднань, навіть якщо фактичні сокети відсутні в DOM).
Щоб використовувати ваш підхід до розрахунку для початкової/кінцевої позиції з’єднання, ви можете розширити абстрактний клас BaseSocketPosition
та імплементувати метод calculatePosition
.
import { BaseSocketPosition } from 'rete-render-utils'
type Position = { x: number, y: number }
type Side = 'input' | 'output'
export class ComputedSocketPosition<S extends Schemes, K> extends BaseSocketPosition<S, K> {
async calculatePosition(nodeId: string, side: Side, key: string): Promise<Position | null> {
if (!this.area) return null
return {
x: side === 'input' ? 0 : getNodeWith(nodeId)
y: 0
}
}
}
render.addPreset(Presets.classic.setup({
socketPositionWatcher: new ComputedSocketPosition()
}))
де calculatePosition
має повернути позицію відносно позиції вузла, або null
, якщо її неможливо обчислити