Sitemap
CodeX

Everything connected with Tech & Code. Follow to join our 1M+ monthly readers

JavaScript text editor for SVG

3 min readApr 22, 2022

--

Demo | GitHub

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(' ', '&nbsp;')}

</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

How to support the project

  • Start using the flowchart editor Dgrm.net.
    Tell me what you think. Comments, private messages, on GitHub.
    I read everything, I keep a list of proposals.
  • Tell your friends.
  • Give a star on GitHub.

--

--

No responses yet