Blazor WebAssembly: соединительные линии в SVG
Demo | GitHub
Рис 1. Blazor Webassembly соединительные линии в SVG. Соединительные линии автоматически перестраиваются при изменении положения объектов.
В статье описан способ реализации соединительных линий между SVG объектами. Соединительные линии автоматически перестраиваются при изменении положения объектов. Попутно рассмотрен метод OnParametersSet.
Предыдущая статья «Blazor WebAssembly: Drag and Drop в SVG».
Что получится в итоге
В итоге получиться Blazor компонент Connector. Пример использования:
Листинг 1. Использование компонента Connector
Рис 2. Результат листинга 1. Точки соединены плавной линией.
Connector принимает на вход
координаты начальной и конечной точки,
направление входа в точку: сверху, справа, снизу, слева.
При этом, при динамическом изменении входных параметров, Connector перестраивает соединительную линию (см. рис. 1).
Если вам просто нужно готовое решение, статью читать не обязательно — скопируйте код компонента Connector из GitHub.
Основная идея
В SVG есть встроенная возможность рисовать плавные линии — элемент Path. Path поддерживает разные варианты рисования линий. Для соединительный линий, подходит реализованная в Path кубическая кривая Безье.
Что бы нарисовать кубическую кривую Безье нужно 4 точки (рис 3):
точка начала, точка конца,
опорная точка начала и опорная точка конца.
Рис 3. Кубическая кривая Безье нарисованная SVG элементом path. Синим отмечены координаты начальной и конечной точки, красным опорные точки.
От положения опорных точке зависит вид кривой. На рис 4 первая опорная точка задрана вверх.
Рис 4. Кубическая кривая Безье нарисованная SVG элементом path. Первая опорная точка задрана вверх.
Blazor компонент Connector
В листинге 1 показано использование компонента Connector. Connector отображается на странице как SVG элемент path.
@code {
[Parameter] public Direction Dir1 { get; set; } = Direction.Right;
[Parameter] public double X1 { get; set; }
[Parameter] public double Y1 { get; set; }
[Parameter] public Direction Dir2 { get; set; } = Direction.Left;
[Parameter] public double X2 { get; set; }
[Parameter] public double Y2 { get; set; }
// reference points
double c1x;
double c1y;
double c2x;
double c2y;
…
public enum Direction {
Top,
Right,
Bottom,
Left
}
…
Листинг 2. Компонент Connector.
При рисовании соединительных линий:
точка начала и конца (X1, Y1; X2, Y2) (на рис 3 отмечены синим) заданы,
опорные точки (c1x, c1y; c2x, c2y) (на рис 3 отмечены красным) нужно рассчитывать.
Пусть соединительная линия может подходить к точке только с 4-х сторон (см. enum Direction в листинге 2):
сверху,
справа,
снизу,
слева.
Рассчитаем опорные точки для соединений слева и справа.
Рис 5. Расчет опорных точек для соединений слева и права. 70 — это произвольный коэффициент, подобран на глаз, никакого сакрального смысла нет,
Если соединение «справа» (на рис 5 к верхней синей точке соединительная линия подходит справа) , то координата опорной точки по Y равна Y1 (c1y = Y1). Координата по X зависит X1: c1x = X1 + 70. 70 — это произвольный коэффициент, подобранный на глаз.
По аналогии рассчитываются опорные точки для соединений сверху и снизу.
Код реализации алгоритма смотрите на GitHub.
Динамическое перестроение соединительной линии при обновлении параметров. Метод OnParametersSet
При изменении значений входных параметров Connector должен пересчитывать опорные точки c1x, c1y; c2x, c2y.
Сигналом (событием) к пересчету может служить вызов set-теров входных параметров — листинг 3.
...
@code {
[Parameter] public Direction Dir1 {
get { ... }
set { ... calc(); };
} = Direction.Right;
[Parameter] public double X1 {
get { ... }
set { ... calc(); };
}
[Parameter] public double Y1 {
get { ... }
set { ... calc(); };
}
...
Листинг 3. Компонент Connector. Пересчет опорных точек в set-рах. Не лучший вариант.
Это не лучший вариант. Допустим параметры Connector-ора изменяются все разом:
@code {
Direction Dir1;
double X1;
double Y1;
Direction Dir2;
double X2;
double Y2;
void Update() {
Dir1 = Direction.Left;
X1 = 100;
Y1 = 100;
Dir1 = Direction.Right;
X1 = 200;
Y1 = 200;
}
...
Листинг 4. Единовременное обновление входных параметров Connector
Для каждого входного параметра будет вызван set-тер, т.е. метод Calc будет вызван 6 раз.
Решить эту проблему можно с помощью OnParametersSet.
...
@code {
[Parameter] public Direction Dir1 { get; set; } = Direction.Right;
[Parameter] public double X1 { get; set; }
[Parameter] public double Y1 { get; set; }
...
protected override void OnParametersSet() {
calc();
}
...
Листинг 5. Компонент Connector. Расчет опорных точек в методе OnParametersSet
Для листинга 4 метод OnParametersSet будет вызван один раз.
OnParametersSet используется не только для таких случаев, подробнее в документации Avoid unnecessary rendering of component subtrees.
Connector готов. С помощью Connector и Draggable из предыдущей статьи можно сделать подводные растения, или светильники IKEA — рис 1.