Search code examples
javascriptd3.jssvgparallel-coordinates

Issue adding multiple text elements to svg elements


Working with a D3-based code for parallel coordinates, I'm trying to add some text:

  g_data.select(".label")
      .text(dimensionLabels)   //visible
  g_data.select(".sublabel1")
      .text(dimensionSublabels1)   //not visible
  g_data.select(".sublabel2")
      .text(dimensionSublabels2)   //not visible

to the previously created svg:text and svg:tspan elements:

var g_data = pc.svg.selectAll(".dimension").data(pc.getOrderedDimensionKeys());
  // Enter
  g_data.enter()
    .append("svg:g")
      .attr("class", "dimension")
      .attr("transform", function(p) { return "translate(" + position(p) + ")"; })
      .style("opacity", 0)
    .append("svg:g")
      .attr("class", "axis")
      .attr("transform", "translate(0,0)")
      .each(function(d) {
        var axisElement = d3.select(this).call( pc.applyAxisConfig(axis, __.dimensions[d]) );

        axisElement.selectAll("path")
            .style("fill", "none")
            .style("stroke", "#222")
            .style("shape-rendering", "crispEdges");

        axisElement.selectAll("line")
            .style("fill", "none")
            .style("stroke", "#222")
            .style("shape-rendering", "crispEdges");
      })


    .append('svg:text')      //1st part of label
        .attr({
            "text-anchor": "middle",
            "y": -40,
            "x": 0,
            "dy": 0,
            "class": "label"
      })
    .append('svg:tspan')      //2nd part of label
        .attr({
            "x": 0,
            "dy": 17,
            "class": "sublabel1"
      })
    .append('svg:tspan')      //3rd part of label
        .attr({
            "x": 0,
            "dy": 14,
            "class": "sublabel2"
      })

The problem is that this works only partially for a reason I can't explain: only one of the text labels can be displayed at a time.

More concretely, for the case above, the text will only be added to the ".label" class svg, and the two others are invisible. But if I comment out the first two lines (as below), than sublabel1 becomes visible, and so on.

  //g_data.select(".label")
  //    .text(dimensionLabels)  //with this part commented, the next label becomes visible
  g_data.select(".sublabel1")
      .text(dimensionSublabels1)  //visible
  g_data.select(".sublabel2")
      .text(dimensionSublabels2)  //not visible

Could anyone help figure out what may be causing this, and what I could do to have all labels displayed at the same time? Many thanks!


Solution

  • Be careful about chaining calls to append. append returns the appended element, so chaining appends will create a nested structure.

    <text class="label">
        <tspan class="sublabel1">
            <tspan class="sublabel2"></tspan>
        </tspan>
    </text>
    

    It's important to note that setting the text of a text element will delete any tspans inside, presumably because tspans count as text.

    You want something like this

    <text>
        <tspan class="label"></tspan>
        <tspan class="sublabel1"></tspan>
        <tspan class="sublabel2"></tspan>
    </text>
    

    Therefore, create a text node, save that to a variable, and then append tspans to that variable.

    example: https://jsfiddle.net/guanzo/b2q2nm54/1/