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

Demo | GitHub

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

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

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

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

Рис 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.