Search code examples
javascriptjqueryhtmld3.jstooltip

D3.js radar chart tooltip


Based on this example of a D3.js radar chart, I'm trying to have a more advanced type of tooltips. Instead of just a number, I want to show a list of names and numbers, some of them based on my dataset.

The problem is in this part of the code:

blobCircleWrapper.selectAll(".radarInvisibleCircle")
                        .data(function(d,i) { return d; })
                        .enter().append("circle")
                        .attr("class", "radarInvisibleCircle")
                        .attr("r", cfg.dotRadius*1.5)
                        .attr("cx", function(d,i){ return rScale(d.value) * Math.cos(angleSlice*i - Math.PI/2); })
                        .attr("cy", function(d,i){ return rScale(d.value) * Math.sin(angleSlice*i - Math.PI/2); })
                        .style("fill", "none")
                        .style("pointer-events", "all")
                        .on("click", function(d,i) {   // TOOLTIP WITH SUBJECTS AND AVERAGES HERE
                            newX =  parseFloat(d3.select(this).attr('cx')) - 10;
                            newY =  parseFloat(d3.select(this).attr('cy')) - 10;

                            tooltip
                                .attr('x', newX)
                                .attr('y', newY)
                                .html(d.value+ "<br>" + "To:")
                                .transition().duration(200)
                                .style('opacity', 1);
                        })
                        .on("mouseout", function(){
                            tooltip.transition().duration(200)
                                .style("opacity", 0);
                        });


                    //Set up the small tooltip for when you hover over a circle
                    var tooltip = g.append("text")
                        .attr("class", "tooltip")
                        .style("opacity", 0);

The tooltip is set for the circles of the radar, and when I try to create a div element instead of the textelement, the tooltip stops showing, although the element is created and well positioned. I was trying something like this:

var tooltip = g.append("div")
                        .attr("class", "tooltip")
                        .style("opacity", 0);

I'm sure I'm missing some attributes here, but is there a way to have more complete tooltips? Thank you.


Solution

  • You're using a <div> as tooltip. Thus, you have some different rules here.

    First, you cannot append a div to a SVG (I suppose that the g selection in your snippet is a SVG group). You'll have to append the div to the body (or any other HTML element).

    Second, as you're appending the div to the HTML, you cannot set the x and y positions as attributes. Instead of that, you'll have to use event.pageX and event.pageY, with an absolute position for the div.

    Here is a very simple demo with the basics os what I just said:

    var tip = d3.select("body")
        .append("div")
        .attr("class", "tip")
        .style("opacity", 0);
    
    d3.select("svg")
        .selectAll("foo")
        .data(d3.range(7))
        .enter()
        .append("circle")
        .attr("cx", d => 20 + d * 40)
        .attr("cy", 50)
        .attr("r", 15)
        .attr("fill", "teal")
        .on("mousemove", (d, i) => {
            tip.html("This is the<br>circle number " + i)
                .style("left", d3.event.pageX + 10 + "px")
                .style("top", d3.event.pageY + "px")
                .style("opacity", 1)
        }).on("mouseout", () => {
            tip.style("opacity", 0)
        })
    .tip{
      position: absolute;
      padding: 10px;
      background: lightgray;
      border: 1px solid black;
      pointer-events: none;
    }
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <svg></svg>