JavaScript редактор текста для SVG
Статья про редактор текста как на рисунке. Исходный код прилагается.
Многострочный текст в 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