Blazor WebAssembly: соединительные линии в SVG

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Demo | GitHub

Рис 1. Blazor Webassembly соединительные линии в SVG. Соединительные линии автоматически перестраиваются при изменении положения объектов.
Рис 1. Blazor Webassembly соединительные линии в SVG. Соединительные линии автоматически перестраиваются при изменении положения объектов.

В статье описан способ реализации соединительных линий между SVG объектами. Соединительные линии автоматически перестраиваются при изменении положения объектов. Попутно рассмотрен метод OnParametersSet.

Предыдущая статья "Blazor WebAssembly: Drag and Drop в SVG".

Что получится в итоге

В итоге получиться Blazor компонент Connector. Пример использования:

<svg xmlns="http://www.w3.org/2000/svg">

    <circle cx="85" cy="100" r="15" fill="#04dcd2" stroke="#fff" />
    <circle cx="315" cy="250" r="15" fill="#04dcd2" stroke="#fff" />
    <Connector 
        X1=100 Y1=100 
        Dir1=Direction.Right
                
        X2=300 Y2=250
        Dir2=Direction.Left />

</svg>

Листинг 1. Использование компонента Connector

Рис 2. Результат листинга 1. Точки соединены плавной линией.
Рис 2. Результат листинга 1. Точки соединены плавной линией.

Connector принимает на вход

  • координаты начальной и конечной точки,

  • направление входа в точку: сверху, справа, снизу, слева.

При этом, при динамическом изменении входных параметров, Connector перестраивает соединительную линию (см. рис. 1).

Если вам просто нужно готовое решение, статью читать не обязательно - скопируйте код компонента Connector из GitHub.

Основная идея

В SVG есть встроенная возможность рисовать плавные линии - элемент Path. Path поддерживает разные варианты рисования линий. Для соединительный линий, подходит реализованная в Path кубическая кривая Безье.

Что бы нарисовать кубическую кривую Безье нужно 4 точки (рис 3):

  • точка начала, точка конца,

  • опорная точка начала и опорная точка конца.

Рис 3. Кубическая кривая Безье нарисованная SVG элементом path. Синим отмечены координаты начальной и конечной точки, красным опорные точки.
Рис 3. Кубическая кривая Безье нарисованная SVG элементом path. Синим отмечены координаты начальной и конечной точки, красным опорные точки.

От положения опорных точке зависит вид кривой. На рис 4 первая опорная точка задрана вверх.

Рис 4. Кубическая кривая Безье нарисованная SVG элементом path. Первая опорная точка задрана вверх.
Рис 4. Кубическая кривая Безье нарисованная SVG элементом path. Первая опорная точка задрана вверх.

Blazor компонент Connector

В листинге 1 показано использование компонента Connector. Connector отображается на странице как SVG элемент path.

<path d="M @X1 @Y1 C @c1x @c1y, @c2x @c2y, @X2 @Y2" />

@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. Расчет опорных точек для соединений слева и права. 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-ора изменяются все разом:

<button @onclick=Update>Update</button>
<svg xmlns="http://www.w3.org/2000/svg">

    <Connector 
        X1=X1 Y1=Y1 
        Dir1=Dir1
                
        X2=X2 Y2=Y2
        Dir2=Dir2 />

</svg>

@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.

Источник: https://habr.com/ru/post/582874/


Интересные статьи

Интересные статьи

В этой статье мы расскажем, как оптимизировать крупный проект в «Битрикс24» и увеличить его производительность в 3 раза, изменяя настройки MySQL и режим питания CPU. Дано Корпоративн...
Прежде, чем начинать разговор о принципах проектирования расширяемого API, следует обсудить гигиенический минимум. Огромное количество проблем не случилось бы, если бы разработчики API ...
Эта статья для тех, кто собирается открыть интернет-магазин, но еще рассматривает варианты и думает по какому пути пойти, заказать разработку магазина в студии, у фрилансера или выбрать облачный серви...
Эта публикация написана после неоднократных обращений как клиентов, так и (к горести моей) партнеров. Темы обращений были разные, но причиной в итоге оказывался один и тот же сценарий, реализу...
Если Вы используете в своих проектах инфоблоки 2.0 и таблицы InnoDB, то есть шанс в один прекрасный момент столкнуться с ошибкой MySQL «SQL Error (1118): Row size too large. The maximum row si...