
Статья про редактор текста как на рисунке. Исходный код прилагается.
Многострочный текст в 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. Третья строка пустая. Высота строки 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(' ', ' ')} </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
JavaScript редактор диаграмм, который открывает диаграммы из PNG картинок (open source)
JavaScript редактор текста для SVG
