Home > front end >  d3.js looping through array not rendering to create multiple tspans elements
d3.js looping through array not rendering to create multiple tspans elements

Time:01-29

Building a D3 property that renders text. My loop prints to console.log() just fine and the loop before works ok too. Below we are looking at the label array[] that I will loop through, loop through links then through label e.g.

Data:

links: [
      {
        id: 1,
        source: 1,
        target: 2,
        type: 'Foo',
        label: ['Jim', 'Phil'],
        since: 2010,
      }
]

D3 snippet:

const edgelabels = zoomContainer
  .selectAll('.edgelabel')
  .data(links)
  .enter()
  .append('text')
  .style('pointer-events', 'none')
  .attr('class', 'edgelabel')
  .attr('id', function (d, i) {
    return 'edgelabel'   i;
  })
  .attr('font-size', 10)
  .attr('fill', '#aaa');
edgelabels
  .append('textPath')
  .attr('xlink:href', function (d, i) {
    return '#edgepath'   i;
  })
  .style('text-anchor', 'middle')
  .style('pointer-events', 'none')
  .attr('startOffset', '50%')
  .append('tspan')
  .text((d) => d.label)
 // .text((d) => d.label.forEach((x) => x))
  .attr('x', -10)
  .attr('dx', 10)
  .attr('dy', 22);

The above renders this:

<text  id="edgelabel0" font-size="10" fill="#aaa" style="pointer-events: none;" transform="rotate(0)">

<textPath xlink:href="#edgepath0" startOffset="50%" style="text-anchor: middle; pointer-events: none;">

<tspan x="-10" dx="10" dy="22">
Jim,Phil
</tspan>

</textPath>

</text>

But what I want is this:

<text  id="edgelabel0" font-size="10" fill="#aaa" style="pointer-events: none;" transform="rotate(0)">

<textPath xlink:href="#edgepath0" startOffset="50%" style="text-anchor: middle; pointer-events: none;">

<tspan x="-10" dx="10" dy="22">
Jim
</tspan>

<tspan x="-10" dx="10" dy="22">
Phil
</tspan>

</textPath>

</text>

So the label array items are in their own <tspan>.

Ive replaced .text((d) => d.label) with .text((d) => d.label.forEach((x) => { return x;})) and that seems to console.log() correctly, separating "Jim" and "Phil". However, the <tspan> remains empty and not adding another <tspan> for additional items in the array.

I've looked into using .each for the approach as that would be preferable to d3 so it seems and maybe that was part of the issue? Any help from somebody with more d3 experience would be appreciated. thanks

Here is a demo (lines 196/197)

CodePudding user response:

No need to use any looping techniques... hope this helps somebody else.

const edgelabels = zoomContainer
      .selectAll('.edgelabel')
      .data(links)
      .enter()
      .append('text')
      .style('pointer-events', 'none')
      .attr('class', 'edgelabel')
      .attr('id', function (d, i) {
        return 'edgelabel'   i;
      })
      .attr('font-size', 10)
      .attr('fill', '#aaa');
    edgelabels
      .append('textPath')
      .attr('xlink:href', function (d, i) {
        return '#edgepath'   i;
      })
      .style('text-anchor', 'middle')
      .style('pointer-events', 'none')
      .attr('startOffset', '50%')
      .selectAll('tspan.textPath')
      .data((d, i) => d.label)
      .enter()
      .append('tspan')
      .attr('class', 'text')
      .text((d) => d)
      .attr('x', -10)
      .attr('dx', 10)
      .attr('dy', 22);
  • Related