Рис 1. Текстовый редактор SVG с поддержкой выделения, копирования, вставки. Работает на пк и мобильных.
Рис 1. Текстовый редактор SVG с поддержкой выделения, копирования, вставки. Работает на пк и мобильных.

Demo | GitHub

<< предыдущая статья

Статья про редактор текста как на рисунке. Исходный код прилагается.

Многострочный текст в SVG

В SVG нет символа переноса строки. Для многострочного текста в SVG используется <tspan>.

Рис 2. Многострочный текст, третья строка пустая
Рис 2. Многострочный текст, третья строка пустая
<text x="0" y="0">
    <tspan x="0" y="0">Line 1</tspan>
    <tspan x="0" y="20px">Line 2</tspan>
    <!-- Line 3 is empty
    <tspan x="0" y="40px"></tspan> -->
    <tspan x="0" y="60px">Line 4</tspan>
</text>

Листинг 1. Многострочный текст в SVG. Третья строка пустая. Высота строки 20px.

Положение элементов <tspan> задается относительно верхнего края <text>. Значение атрибута ‘y’ надо рассчитывать.

Расчетов атрибута ‘y’ можно избежать. Листинг 2 дает тот же результат. Используется атрибут ‘dy’ с фиксированным значением. ‘dy’ указывает положение относительно предыдущего элемента.

<text x="0" y="0">
    <tspan x="0" dy="0">Line 1</tspan>
    <tspan x="0" dy="20px">Line 2</tspan>
    <tspan x="0" dy="20px" visibility="hidden">.</tspan>
    <tspan x="0" dy="20px">Line 4</tspan>
</text>

Листинг 2. Многострочный текст в SVG. Третья строка пустая. Высота строки 20px. Отступ задается относительно предыдущего элемента.

Формируем многострочную разметку на JavaScript

Функция ниже делает разметку с фиксированным атрибутом ‘dy’. Разметка получается как в листинге 2.

/**
 * create multiline tspan markup
 * @param {string} str
 * @param {number} lineHeight
 * @returns {string}
 */
function svgStrToTspan(str, lineHeight) {
    return str.split('\n').map((t, i) => {
        return `<tspan
            x="0"
            dy="${i === 0 ? '0' : `${lineHeight}px`}"
            ${t.length === 0 ? 'visibility="hidden"' : ''}>
 
                ${t.length === 0
                    ? '.'
                    : escapeHtml(t).replaceAll(' ', '&nbsp;')}
 
            </tspan>`;
    }).join('');
}

Листинг 3. Функция делает многострочную разметку

На рисунке 1 при добавлении строки текст смещается вверх. Таким образом текст всегда по центру круга. Листинге 4 показывает как это реализовано:

/**
 * @param {SVGTextElement} textEl target text element
 * @param {string} str
 * @param {{lineHeight:number, verticalMiddle?:number}} param
 * @returns {void}
 */
export function svgTextDraw(textEl, str, param) {
    textEl.innerHTML = svgStrToTspan(str, param.lineHeight);
    if (param.verticalMiddle != null) {
        textEl.y.baseVal[0].value =
            param.verticalMiddle - textEl.getBBox().height / 2;
    }
}

Листинг 4. Функция вставляет текст в SVG. При указании verticalMiddle текст центрируется по вертикали.

Редактор текста

Редактор должен поддерживать все стандартные возможности:

  • навигацию по тексту, выделение, вставку, копирование;

  • автозамену, проверку правописания;

  • работать на пк и мобильных.

Для стандартных возможностей есть стандартная <textarea>.

Алгоритм работы редактора:

  • Прозрачная <textarea> располагается над текстом.
    Шрифт <textarea> тоже прозрачный;

  • При вводе вызывается svgTextDraw из листинга 4;

  • Размеры и положение <textarea> пересчитываются.

Алгоритм реализован в функции textareaCreate. Код функции в отдельном файле на GitHub.

Редактор можно сделать для любого элемента <text>:

const textEditor = textareaCreate(
    // {SVGTextElement}
    textEl,
    // text params
    { lineHeight: 20, verticalMiddle: 10 },
    // init value
    'init text',
    // onchange
    val => {...},
    // onblur
    val => {...});
…
// delete textarea
textEditor.remove();

Листинг 5. Создание редактора текста для <text>

Другие статьи про dgrm.net

Как поддержать проект

  • Начните использовать редактор блок схем Dgrm.net.
    Расскажите что думаете. Любым способом: комментарии, личные сообщения, на GitHub.
    Все читаю, веду список предложений.

  • Расскажите знакомым.

  • Ставьте звездочки на GitHub.

Комментарии (4)


  1. bipiem
    22.04.2022 12:54

    SVG + table \ database

    Хочется создать динамическую связь SVG (app.dgrm.net, а лучше draw.io) с google Sheets или с Excel (или с БД). Чтобы как в связке с visio + excel: поменял данные в excel и они тут же изменились на схеме в visio (и наоборот).
    И тут также: поменял данные в google Sheets \ Excel и они тут же изменились на схеме app.dgrm.net  \ drawio. Есть такие интеграции?

    Хороший пример интеграции draw.io с редактором VS Code:

    Editing the Diagram and its XML Side by Side

    Что-то подобное бы, но редактировать table \ database и видеть изменения в .svg \ .drawio. И наоборот.


    1. Alex_BBB Автор
      22.04.2022 13:33

      1. bipiem
        22.04.2022 16:07

        GraphViz, Mermaid, PlantUML – это генераторы схем из скрипта. Для простых схем это работает, но сложные схемы как правило требуют ручной корректировки размещения «проблемных элементов». Кроме того, технология

        1 Таблица

        2 GraphViz, Mermaid, PlantUML и т.п.

        3 Векторный рисунок

        все равно требует переход «таблица - скрипт» (почему-то с переносами слов проблемы).

        Связка  google Sheets + Draw.io показана тут:

        Карта процессов верхнего уровня компании и матрица RACI c помощью drawio и google sheets

         

        Главное же, что нужно реализовать именно связку с «полной строкой данных», как это работает в visio+excel. Т.е. по клику на объект на схеме мы «проваливаемся» в объект таблицы (в общем случае, базы данных), где есть как видимые на схеме атрибуты (называние фигуры, например), так и не видимые на схеме (все поля строки).

        Примерно, как на любой интерактивной карте местности: выбрали на схеме svg графический объект и активировали (отобразили) карточку объекта: что там размещено (какие магазины по этому адресу), какие события там были (в зависимости от тематики карты). В принципе и простенький гео – инструмент подошёл бы (саму гео-карту не использовать), но интересна задача привязывать информацию (в виде отдельных полей) к структурной схеме и схеме workflow.

        В общем, чтобы получилось упрощенное подобие ARIS (BPM). Аналитическую часть (контроль уникальности имени экземпляра объекта и т.п.) – потом сделать можно путем анализа таблицы \ БД.  


        1. KhodeN
          23.04.2022 13:36

          D3