Демо | Гитхаб

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

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

SVG не имеет символа разрыва строки. Для многострочного текста SVG использует ‹tspan›.

<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. Третья строка пуста. Высота строки составляет 20 пикселей.

Положение элементов ‹tspan› относительно верхнего края ‹текста›. Значение атрибута «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› также прозрачный;
  • При вводе вызывается 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.