Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to append a text element with inline tspan children?

Tags:

svg

d3.js

Starting with a DOM that already contains something like

<svg id="svg0" width="600" height="300" xmlns="http://www.w3.org/2000/svg" version="1.1">

</svg>

...I want to programmatically modify the element in d3.select("#svg0") so that I end up with

<svg id="svg0" width="600" height="300" xmlns="http://www.w3.org/2000/svg" version="1.1">
<text x="20" y="20">
Lorem ipsum 
<tspan style="alignment-baseline:text-before-edge">dolor</tspan>
sit amet</text>
</svg>

This is as far as I can get:

var $svg = d3.select("#svg0");
$svg.append("text").text("Lorem ipsum ")
                   .attr({x:"20", y:"20"});

It looks as though the rest should be easy, but I've spent the last two hours trying all the "obvious" things to finish this without success.1

What does one have to do to finish the task described above?

1I've tried far too many things to describe them all. Suffice it to say that the text method, when used as a setter, wipes out whatever textContent the text object had before. This means that, effectively, this method can be called only once, which precludes solutions relying on calling .text(...) a second time to add the " sit amet" fragment.)

like image 297
kjo Avatar asked Oct 07 '13 02:10

kjo


2 Answers

Normally you would think to use the html function for this, but from the docs:

Note: as its name suggests, selection.html is only supported on HTML elements. SVG elements and other non-HTML elements do not support the innerHTML property, and thus are incompatible with selection.html. Consider using XMLSerializer to convert a DOM subtree to text. See also the innersvg polyfill, which provides a shim to support the innerHTML property on SVG elements.

Here's with the polyfill: http://jsfiddle.net/GNGF5/

And if you don't want to do that, you can hack it up using multiple tspan elements w/ a transform, as seen here: http://jsfiddle.net/cAuCM/

var $svg = d3.select("#svg0");
var $text = $svg.append("text");
var $tspan1 = $text.append('tspan');
var $tspan2 = $text.append('tspan');
var $tspan3 = $text.append('tspan');

$text.attr('transform', 'translate(0, 18)');
$tspan1.text('Lorem ipsum');
$tspan2.text('dolor').style('alignment-baseline', 'text-before-edge');
$tspan3.text('sit amet');
like image 138
Langdon Avatar answered Nov 16 '22 20:11

Langdon


Here's how to do it with Snap.svg:

var paper = Snap("#svg0");
var t1 = paper.text(50, 50, "Snap");
var t2 = paper.text(50, 70, ["S","n","a","p"]);
<script src="https://cdn.jsdelivr.net/snap.svg/0.1.0/snap.svg-min.js"></script>
<svg id="svg0" width="600" height="300" xmlns="http://www.w3.org/2000/svg" version="1.1">
</svg>
like image 2
Pavel Chuchuva Avatar answered Nov 16 '22 22:11

Pavel Chuchuva