skip to Main Content

I’m trying to add a tooltip popup to show the year and the value when I hover the mouse over the bar. But for some reason, all the options I have tried do not work. Anyone have any solutions?

I have tried a variation of this link here but have had no luck. In many cases, the tooltip does not appear in the right location.

Could someone help to create a minimalistic solution?

HTML

            <div class="bar-chart-container">
                <svg class="bar-chart"></svg>
            </div>

JAVASCRIPT

// Bar chart
function startBarChartAnimation() {
    if (isInViewport(document.querySelector(".bar-chart-container"))) {
        const data = [
            { year: "2019", value: 11 },
            { year: "2020", value: 10 },
            { year: "2021", value: 23 },
            { year: "2022", value: 37.4 },
        ];

        const svg = d3.select(".bar-chart");
        const margin = { top: 20, right: 20, bottom: 20, left: 60 };
        const width = parseInt(window.getComputedStyle(document.querySelector(".bar-chart-container")).width) - margin.left - margin.right;
        const height = parseInt(window.getComputedStyle(document.querySelector(".bar-chart-container")).height) - margin.top - margin.bottom;

        svg.attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom);

        // Add the gradient definition
        const gradient = svg.append("defs")
            .append("linearGradient")
            .attr("id", "bar-gradient")
            .attr("gradientUnits", "userSpaceOnUse")
            .attr("x1", 0)
            .attr("y1", 0)
            .attr("x2", width)
            .attr("y2", 0);

        gradient.append("stop")
            .attr("offset", "0%")
            .attr("stop-color", "#80bede");

        gradient.append("stop")
            .attr("offset", "100%")
            .attr("stop-color", "#acd6d9");

        const x = d3.scaleLinear()
            .domain([0, d3.max(data, d => d.value)])
            .range([0, width]);

        const y = d3.scaleBand()
            .domain(data.map(d => d.year))
            .range([0, height])
            .padding(0.3);

        const g = svg.append("g")
            .attr("transform", `translate(${margin.left},${margin.top})`);

        // Create and append the bars
        g.selectAll(".bar")
            .data(data)
            .enter()
            .append("rect")
            .attr("class", "bar")
            .attr("y", d => y(d.year))
            .attr("height", y.bandwidth())
            .attr("fill", "url(#bar-gradient)")
            .attr("width", 0)
            .transition()
            .duration((d, i) => 500 + i * 200)
            .attr("width", d => x(d.value))

        g.append("g")
            .call(d3.axisLeft(y))
            .call(g => g.selectAll("line").remove()) // Remove y-axis lines
            .call(g => g.selectAll("path").remove()) // Remove y-axis lines
            .call(g => g.selectAll("text") // Change font color of y-axis labels
                .style("fill", "#bbbbbb") // Change the fill color here
            );


        // Remove the scroll event listener once the animation is triggered
        window.removeEventListener("scroll", startBarChartAnimation);
    }
}

window.addEventListener("scroll", startBarChartAnimation);

2

Answers


  1. Add this to your JavaScript code:

    const tooltip = d3.select(".bar-chart-container")
        .append("div")
        .style("opacity", 0)
        .attr("id", "tooltip");
      const mouseover = function(event, d) {
        tooltip
          .style("opacity", 0.8)//
          .style("top", y(data[d].year)-y.bandwidth()+"px")
          .style("left", x(data[d].value)+"px")
          .html("Year: " + data[d].year+ "<br>Value: "+data[d].value);//
      }
      const mouseleave = function(event,d) {
        tooltip
          .style('opacity', 0)
      }
      g.selectAll(".bar")
        .on("mouseover", mouseover)
        .on("mouseleave", mouseleave)  
    

    And this to your css:

    #tooltip{
      position: absolute;
      background-color: black;
      color:white;
      border: solid;
      border-width: 1px;
      border-radius: 5px;
      width: 120px;
      height: 40px;
      font-size: 90%;
      display:flex;
      align-items:center;
      overflow-x:auto;
    }
    

    It will give you something like this:
    Output of the tooltip

    I know its not so minimalistic but i think you can edit this and make it something you like.

      const data = [
                { year: "2019", value: 11 },
                { year: "2020", value: 10 },
                { year: "2021", value: 23 },
                { year: "2022", value: 37.4 },
            ];
    
            const svg = d3.select(".bar-chart");
            const margin = { top: 20, right: 20, bottom: 20, left: 60 };
            const width = parseInt(window.getComputedStyle(document.querySelector(".bar-chart-container")).width) - margin.left - margin.right;
            const height = parseInt(window.getComputedStyle(document.querySelector(".bar-chart-container")).height) - margin.top - margin.bottom;
    
            svg.attr("width", width + margin.left + margin.right)
                .attr("height", height + margin.top + margin.bottom);
    
            // Add the gradient definition
            const gradient = svg.append("defs")
                .append("linearGradient")
                .attr("id", "bar-gradient")
                .attr("gradientUnits", "userSpaceOnUse")
                .attr("x1", 0)
                .attr("y1", 0)
                .attr("x2", width)
                .attr("y2", 0);
    
            gradient.append("stop")
                .attr("offset", "0%")
                .attr("stop-color", "#80bede");
    
            gradient.append("stop")
                .attr("offset", "100%")
                .attr("stop-color", "#acd6d9");
    
            const x = d3.scaleLinear()
                .domain([0, d3.max(data, d => d.value)])
                .range([0, width]);
    
            const y = d3.scaleBand()
                .domain(data.map(d => d.year))
                .range([0, height])
                .padding(0.3);
    
            const g = svg.append("g")
                .attr("transform", `translate(${margin.left},${margin.top})`);
    
            // Create and append the bars
            g.selectAll(".bar")
                .data(data)
                .enter()
                .append("rect")
                .attr("class", "bar")
                .attr("y", d => y(d.year))
                .attr("height", y.bandwidth())
                .attr("fill", "url(#bar-gradient)")
                .attr("width", 0)
                .transition()
                .duration((d, i) => 500 + i * 200)
                .attr("width", d => x(d.value))
    
            g.append("g")
                .call(d3.axisLeft(y))
                .call(g => g.selectAll("line").remove()) // Remove y-axis lines
                .call(g => g.selectAll("path").remove()) // Remove y-axis lines
                .call(g => g.selectAll("text") // Change font color of y-axis labels
                    .style("fill", "#bbbbbb") // Change the fill color here
                );
      const tooltip = d3.select(".bar-chart-container")
        .append("div")
        .style("opacity", 0)
        .attr("id", "tooltip");
      const mouseover = function(event, d) {
        tooltip
          .style("opacity", 0.8)//
          .style("top", y(data[d].year)-y.bandwidth()+"px")
          .style("left", x(data[d].value)+"px")
          .html("Year: " + data[d].year+ "<br>Value: "+data[d].value);//
      }
      const mouseleave = function(event,d) {
        tooltip
          .style('opacity', 0)
      }
      g.selectAll(".bar")
        .on("mouseover", mouseover)
        .on("mouseleave", mouseleave)  
     
    #tooltip{
      position: absolute;
      background-color: black;
      color:white;
      border: solid;
      border-width: 1px;
      border-radius: 5px;
      width: 120px;
      height: 40px;
      font-size: 90%;
      display:flex;
      align-items:center;
      overflow-x:auto;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script>
    <div class="bar-chart-container">
      <svg class="bar-chart"></svg>
    </div>
    Login or Signup to reply.
  2. if you want to open toltip on hover of bar just append your rect with title element and add your data into text

     const data = [
                { year: "2019", value: 11 },
                { year: "2020", value: 10 },
                { year: "2021", value: 23 },
                { year: "2022", value: 37.4 },
            ];
    
            const svg = d3.select(".bar-chart");
            const margin = { top: 20, right: 20, bottom: 20, left: 60 };
            const width = parseInt(window.getComputedStyle(document.querySelector(".bar-chart-container")).width) - margin.left - margin.right;
            const height = parseInt(window.getComputedStyle(document.querySelector(".bar-chart-container")).height) - margin.top - margin.bottom;
    
            svg.attr("width", width + margin.left + margin.right)
                .attr("height", height + margin.top + margin.bottom);
    
            // Add the gradient definition
            const gradient = svg.append("defs")
                .append("linearGradient")
                .attr("id", "bar-gradient")
                .attr("gradientUnits", "userSpaceOnUse")
                .attr("x1", 0)
                .attr("y1", 0)
                .attr("x2", width)
                .attr("y2", 0);
    
            gradient.append("stop")
                .attr("offset", "0%")
                .attr("stop-color", "#80bede");
    
            gradient.append("stop")
                .attr("offset", "100%")
                .attr("stop-color", "#acd6d9");
    
            const x = d3.scaleLinear()
                .domain([0, d3.max(data, d => d.value)])
                .range([0, width]);
    
            const y = d3.scaleBand()
                .domain(data.map(d => d.year))
                .range([0, height])
                .padding(0.3);
    
            const g = svg.append("g")
                .attr("transform", `translate(${margin.left},${margin.top})`);
    
            // Create and append the bars
         let bar=   g.selectAll(".bar")
                .data(data)
                .enter()
                .append("rect")
                .attr("class", "bar")
                .attr("y", d => y(d.year))
                .attr("height", y.bandwidth())
                .attr("fill", "url(#bar-gradient)")
                .attr("width", 0)
                
                bar.transition()
                .duration((d, i) => 500 + i * 200)
                .attr("width", d => x(d.value))
                 bar.append("title").text((d,i) =>"Year: " + d.year+ "n Value: "+d.value)
                 
            g.append("g")
                .call(d3.axisLeft(y))
                .call(g => g.selectAll("line").remove()) // Remove y-axis lines
                .call(g => g.selectAll("path").remove()) // Remove y-axis lines
                .call(g => g.selectAll("text") // Change font color of y-axis labels
                    .style("fill", "#bbbbbb") // Change the fill color here
                );
        
     
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    <div class="bar-chart-container">
      <svg class="bar-chart"></svg>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search