Показ портов и роли
Порт — это то, чем заканчивается линия и за что пользователь берётся, чтобы начать соединение. Здесь описано, как порты рисуются, чем источник отличается от приёмника, как линия останавливается у порта и как сохранить рабочими кнопки внутри блоков.
Один порт — один кружок
Порт — это один кружок. Он же конец линии и он же ручка, которую тянет пользователь; его размер, обводка и цвета не меняются, когда соединение появляется или исчезает. Во время жеста сверху применяются только поля из ports.connect.*, зависящие от состояния.
Если порт нарисован кружком, отдельная точка-ручка для того же порта скрывается, поэтому ничего не рисуется дважды.
Какие порты рисуются
Решает ports.show:
false— кружков нет.trueили'connected'— кружок на каждом порту, у которого есть хотя бы одно соединение. Это значение по умолчанию.'all'— кружок на каждом объявленном нескрытом порту, соединён он или нет. Нужен, когда у каждой строки списка должно быть видно, куда можно подключить линию.
Порты строк, прокрученных за край, подчиняются clipToScrollParents, как и раньше. ports.fadeEdge (px) гасит порт на этом расстоянии до видимого края прокручиваемой области, чтобы порт не появлялся и не пропадал рывком.
Стили по ролям
Кружок порта оформляется слоями, каждый перекрывает предыдущий:
ports.*— стиль группы.ports.source/ports.target— по роли (connect: 'source' | 'target'у порта). Каждый — стиль с состояниями, как иports.ports.connected— порты, у которых есть хотя бы одно соединение.styleв описании порта (v-vl-port="{ id, style: { fill } }").ports.sync: 'marker'— обводка кружка берётся от маркера соединения, включая его состояние hover.ports.connect.<состояние>— состояние жеста:source,candidate,target,invalid.
Кружок получает классы vl-port--source / vl-port--target, vl-port--connected, vl-port--<состояние> и собственный className порта. Классы роли и connected добавляются, когда включено создание соединений, ports.show равен 'all' или задан один из ports.source, ports.target, ports.connected; иначе разметка такая же, как без этих возможностей.
Порт, нарисованный вами
ports.render: 'svg'— по умолчанию: кружок рисует библиотека.ports.render: 'dom'— библиотека не рисует ни кружок, ни ручку. Порт — ваш собственный элемент (цельv-vl-port, обычно маленький<span>в строке). Библиотека запускает жест с него, ставит на негоdata-vl-connect-stateиaria-pressed="true"на источник. Требуетinteraction.connect.enabled. Концы линий по-прежнему считаются по положению порта.- Слот
#port— в компоненте Vue отрисовывается для каждого подключаемого порта, а не только для соединённых. Параметры слота:{ blockId, portId, point, role, connected, state, hovered };role—'source' | 'target' | 'both',connected— число соединений,state—'idle'или состояние жеста,hovered— находится ли указатель над блоком порта.stateиhoveredзаполняются, когда включено создание соединений илиports.showравен'all'.ports.slotPointerEvents: falseделает содержимое слота прозрачным для указателя.
Линия останавливается у порта
По умолчанию линия идёт в центр порта, под кружок. Чтобы остановить её у края:
lines.endGap— число или{ start, end }в px: линия заканчивается на этом расстоянии до порта вдоль нормали стороны.ports.clearance— число в px или'auto', то есть радиус кружка плюс ширина его обводки. Прибавляется кendGap.
Сам порт остаётся на месте: укорачивается только линия. События layout по-прежнему сообщают настоящую точку порта.
Стороны по ролям
ports.sides: { source: 'right', target: 'left' } задаёт сторону по роли, а не для каждого порта. Применяется к портам без своего side, к концу соединения, перешедшему на целый блок, и к линии предпросмотра жеста, начатого с блока.
Концы, перенесённые на запасной блок
Соединение, у которого конец оказался на запасном блоке (Запасные концы), можно пометить:
lines: { proxied: { start: 'circle', end: { shape: 'diamond', size: 8 } } }proxied.start / proxied.end — описания маркеров, применяемые только к перенесённому концу. Блок, принявший линии, получает data-vl-proxy-count="N" с числом перенесённых на него линий, чтобы значок вроде «+3» можно было нарисовать в CSS или в шаблоне.
Кнопки и ссылки внутри блоков
Сам блок может быть источником или приёмником соединения (from: 'block', to: 'block'). Интерактивные элементы внутри него должны продолжать работать, поэтому нажатие или клик, начавшиеся на элементе, подходящем под interaction.connect.ignore, не начинают, не завершают и не отменяют соединение. Селектор по умолчанию:
button, a, input, select, textarea, [contenteditable], [data-vl-ignore]Задайте свой селектор строкой или false, чтобы отключить проверку. stopPropagation в ваших обработчиках не нужен.
Роли блоков
connect: 'source' | 'target' | 'both' | false у блока проверяется при начале и при завершении жеста, для from: 'block' и to: 'block' во всех режимах, включая клавиатуру и startConnect / completeConnect. Блок без роли берёт её из своих портов, если роль задана у каждого порта; иначе он 'both'.
Атрибуты на блоках
Чтобы оформить всю строку без :has(), библиотека ставит атрибуты на элемент блока:
data-vl-connect-state—source,candidate,targetилиinvalidво время жеста (побеждает самое сильное состояние блока или его портов).data-vl-hover—pointer, пока указатель над блоком,line, пока указатель над линией, которая в него входит. Ставится, только если включеныinteraction.hover,interaction.highlightили создание соединений.data-vl-connecting— на контейнере, пока идёт жест.data-vl-proxy-count— см. выше.
Атрибуты снимаются, когда состояние заканчивается и при уничтожении движка.
Группы линий и совпадающие линии
connection.kindвместе сlines.kinds: { [kind]: ConnectionStyle }— один стиль для группы соединений. Он лежит между стилем группы и собственнымstyleсоединения.lines.overlap: 'offset'— линия, совпадающая с другой (те же концы и путь), сдвигается в сторону на 3 px за шаг (чередуя стороны; для bezier и прямых линий), чтобы были видны обе. По умолчанию'stack': линии рисуются друг поверх друга.markers.<позиция>.units: 'px'—sizeмаркера в пикселях, не зависит от толщины линии. По умолчанию'stroke'масштабируется вместе с толщиной.
Обратная связь жеста
interaction.connect.dimOthers—true(прозрачность 0,35) или число: остальные линии притушены, пока идёт жест.- Событие движка
connect:candidate—{ from, candidate, valid }при каждой смене кандидата (candidateравенnull, если под указателем ничего нет). Вconnect:startприходитvia('drag','click','keyboard'или'api'). block:mouseenter/block:mouseleaveнесутvia: 'line', когда вызваны наведением на линию, входящую в блок. Когда указатель заходит в сам блок, данные — только{ blockId }.- В Vue
useVisualLinkerConnect(linker)возвращает жест в виде ref-ов; см. Низкоуровневый composable.