Fig 1. SVG text editor with support for selection, copy, paste. Works on PC and mobile.
The article describes how to make a text editor. Source code is attached.
Multiline text in SVG
SVG does not have a line break character. For multiline text SVG uses <tspan>
.
Fig 2. Multiline text, third line is empty
<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>
Listing 1. Multiline text in SVG. The third line is empty. The line height is 20px.
The position of the <tspan>
elements is relative to the top edge of the <text>
. The value of the 'y' attribute must be calculated.
The 'y' attribute calculations can be avoided. Listing 2 gives the same result. The 'dy' attribute is used with a fixed value. 'dy' indicates the position relative to the previous element.
<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>
Listing 2. Multiline text in SVG. The third line is empty. The line height is 20px. The indent is set relative to the previous element.
Forming multi-line markup with JavaScript
The function below renders markup with a fixed 'dy' attribute. The markup is obtained as in Listing 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('');
}
Listing 3. Function makes multi-line markup
In Figure 1, when you add a line, the text moves up. Thus the text is always in the center of the circle. Listing 4 shows how this is implemented:
/**
* @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;
}
}
Listing 4. The function inserts text into SVG. When specifying verticalMiddle , the text is centered vertically.
Text editor
The editor must support all standard features:
- text navigation, selection, insertion, copying;
- autocorrect, spell check;
- work on PC and mobile
For standard features, there is a standard <textarea>
.
The algorithm of the editor:
- A transparent
<textarea>
is positioned above the text. The<textarea>
font is also transparent; - On input, the svgTextDraw from Listing 4 is called;
- The dimensions and position of the
<textarea>
are recalculated.
The algorithm is implemented in the textareaCreate function. Function code in a separate file on GitHub.
An editor can be attached to any <text>
element:
const textEditor = textareaCreate(
// {SVGTextElement}
textEl,
// text params
{ lineHeight: 20, verticalMiddle: 10 },
// init value
'init text',
// onchange
val => {...},
// onblur
val => {...});
…
// delete textarea
textEditor.remove();
Listing 5. Creating a text editor for <text>
Other articles about dgrm.net
- JavaScript SVG diagram editor 3.9 KB (open source library)
- JavaScript diagram editor that renders diagrams from PNG images (open source)
- JavaScript text editor for SVG
- Flowchart editor UI
- JavaScript: Zoom like in maps for SVG/HTML
Top comments (0)