DEV Community

Alexey Boyko
Alexey Boyko

Posted on • Edited on

JavaScript text editor for SVG

SVG text editor with support for selection, copy, paste. Works on PC and mobile
Fig 1. SVG text editor with support for selection, copy, paste. Works on PC and mobile.

Demo | GitHub

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

Multiline text, third line is empty
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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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('');
}
Enter fullscreen mode Exit fullscreen mode

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;
    }
}
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)