81

I'm looking to append html onto a rectangle in D3 to give me a multiple line tooltip. The bottom part is how I'm adding a rectangle which may be part of the problem. The top is the code that should work in my world.

 newRect.().html(" <textArea font-family=Verdana font-size=20 fill=blue > Test " + "</br>" + "Test2 </textArea>");

Which does insert a text field into the SVG, it just doesn't display:
HTML:

<rect id="rectLabel" x="490" y="674" width="130" height="160" fill="red">
    <textarea fill="blue" font-size="20" font-family="Verdana"> Test </br>Test2 </textarea>
</rect>

I have a mouse over function which runs the following:

    newRect = svg.append("rect")
    .attr("x", xCor)
    .attr("y", yCor)
    .attr("width", 130)
    .attr("height", 160)
    .attr("fill", "red")
    .attr("id", "rectLabel");

I think I should be doing this but it doesn't work. It just removes the g.node that I'm trying to append to.

    newRect = $(this).enter().append("rect")
    .attr("x", xCor)
    .attr("y", yCor)
    .attr("width", 130)
    .attr("height", 160)
    .attr("fill", "red")
    .attr("id", "rectLabel");

Question: Why doesn't my text appear? Ive tried .html, .textArea. I want a multiple line label so I don't think .text will work correct? Also, how should I be appending the rectangle?

royhowie
  • 11,075
  • 14
  • 50
  • 67
gbam
  • 1,454
  • 4
  • 18
  • 30

2 Answers2

148

A rect can't contain a text element. Instead transform a g element with the location of text and rectangle, then append both the rectangle and the text to it:

var bar = chart.selectAll("g")
    .data(data)
  .enter().append("g")
    .attr("transform", function(d, i) { return "translate(0," + i * barHeight + ")"; });

bar.append("rect")
    .attr("width", x)
    .attr("height", barHeight - 1);

bar.append("text")
    .attr("x", function(d) { return x(d) - 3; })
    .attr("y", barHeight / 2)
    .attr("dy", ".35em")
    .text(function(d) { return d; });

http://bl.ocks.org/mbostock/7341714

Multi-line labels are also a little tricky, you might want to check out this wrap function.

Adam Pearce
  • 9,243
  • 2
  • 38
  • 35
  • I wanted my text box to appear on mouse over so I was creating a function to do that. But this ends up being a g.node and won't let me append to it. So should I be doing this when I create the data then just showing and hiding it or ? – gbam Dec 17 '13 at 21:32
  • The could work. Or attach the mouse listener to the g element, you'll be able to easily append from there. – Adam Pearce Dec 17 '13 at 21:59
  • Ahh, I'm guessing since I put my mouse listener on the node is why it is giving me g.node for my call to this? – gbam Dec 17 '13 at 22:40
  • g.node is what you want, append the text to that. – Adam Pearce Dec 17 '13 at 22:55
9

Have you tried the SVG text element?

.append("text").text(function(d, i) { return d[whichevernode];})

rect element doesn't permit text element inside of it. It only allows descriptive elements (<desc>, <metadata>, <title>) and animation elements (<animate>, <animatecolor>, <animatemotion>, <animatetransform>, <mpath>, <set>)

Append the text element as a sibling and work on positioning.

UPDATE

Using g grouping, how about something like this? fiddle

You can certainly move the logic to a CSS class you can append to, remove from the group (this.parentNode)

cbayram
  • 2,259
  • 11
  • 9
  • While this worked to append the element as a sibling (The sibling part was what I was doing wrong), there's got to be a more elegant solution thank hacking it onto the end? – gbam Dec 17 '13 at 21:44
  • After hours of tearing my hair out trying to map a touch event for a rect to specific text object (easy in v3, not so much in v4), your fiddle introduced me to `nextSibling`, which finally solved problem. Thank you! – Martin Apr 06 '17 at 08:46