Having trouble adding a tooltip to my D3 bar chart?

411 Views Asked by At

I'm working on a fairly simple bar chart and want to add a tooltip so that when a user hovers over each individual bar they can see the exact Size of the technology (values on y-axis). After much research online I still cannot get it to work. I'm now using d3-tip (https://openbase.com/js/d3-tip/documentation) which has tutorials that seem to make the process easier but still no luck. Any help on this issue would be greatly appreciated. I've attached my .js and .html files below. Thank you!

Javascript

import * as d3 from "d3";
import d3Tip from "d3-tip";
d3.tip = d3Tip;

// DATA //

let data = [
  {
    Technology: "Hydropower",
    Size: 33,
    Carbon: 350
  },
  {
    Technology: "Coal",
    Size: 15,
    Carbon: 754
  },
  {
    Technology: "Ground PV",
    Size: 19,
    Carbon: 905
  },
  {
    Technology: "Large Hydropower",
    Size: 14,
    Carbon: 142
  },
  {
    Technology: "Roof Solar",
    Size: 3,
    Carbon: 263
  },
  {
    Technology: "Nuclear",
    Size: 0.3,
    Carbon: 475
  },
  {
    Technology: "Ethanol",
    Size: 50.3,
    Carbon: 374
  },
  {
    Technology: "Onshore Wind",
    Size: 0.4,
    Carbon: 224
  }
];

// PLOTTING //

const svg = d3.select("svg"),
  margin = { top: 100, right: 20, bottom: 100, left: 20 },
  width = svg.attr("width") - margin.left - margin.right,
  height = svg.attr("height") - margin.top - margin.bottom;

const xScale = d3.scaleBand().range([0, width]).padding(0.4),
  yScale = d3.scaleLinear().range([height, 0]);

const g = svg
  .append("g")
  .attr("transform", "translate(" + 100 + "," + 100 + ")");

xScale.domain(
  data.map(function (d) {
    return d.Technology;
  })
);
yScale.domain([
  0,
  d3.max(data, function (d) {
    return d.Size;
  })
]);

g.append("g")
  .attr("transform", "translate(0," + height + ")")
  .call(d3.axisBottom(xScale));

g.append("g")
  .call(
    d3
      .axisLeft(yScale)
      .tickFormat(function (d) {
        return d + " kW";
      })
      .ticks(10)
  )
  .append("text")
  .attr("y", 6)
  .attr("dy", "0.71em")
  .attr("text-anchor", "end");

g.append("text")
  .attr("transform", "translate(" + width / 2 + " ," + (height + 40) + ")")
  .style("text-anchor", "middle")
  .text("Technology");

g.append("text")
  .attr("transform", "rotate(-90)")
  .attr("x", 0 - height / 2)
  .attr("y", 0 - margin.left - 40)
  .style("text-anchor", "middle")
  .text("Size (kW)");

// var tip = d3
//   .tip()
//   .attr("class", "d3-tip")
//   .html(function (d) {
//     return (
//       "<strong>Size:</strong> <span style='color:red'>" + d.Size + "</span>"
//     );
//   });

g.selectAll("bar")
  .data(data)
  .enter()
  .append("g")
  .attr("class", "bar")
  .append("rect")
  .attr("x", function (d) {
    return xScale(d.Technology);
  })
  .attr("y", function (d) {
    return yScale(d.Size);
  })
  .attr("width", xScale.bandwidth())
  .attr("height", function (d) {
    return height - yScale(d.Size);
  });
// .on("mouseover", tip.show)
// .on("mouseout", tip.hide);

HTML

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="style.css" />
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Sofia">

    <title>Land Usage Comparison</title>
    <meta charset="UTF-8" />

    <script src="d3.min.js"></script>
    <script src="land.js"></script>
  </head>

  <body>
    <header>
      <h1>
        Land Usage Comparison
        <!-- <img src="logo.svg" alt="Discover the World" -->
      </h1>

      <p name="valueX" id="landusage">
        <label
          ><input type="checkbox" name="elecprod" value="1" /><span
            >ELectricity Produced</span
          ></label
        >
        <label
          ><input type="checkbox" name="carbonemissions" value="2" /><span
            >Carbon Emissions</span
          ></label
        >
      </p>

      <p></p>
    </header>

    <svg width="960" height="600"></svg>

    <div id="tooltip" class="hidden">
      <p><strong>Size Value</strong></p>
      <p><span id="value">100</span><p>
    </div>

  </body>
</html>
1

There are 1 best solutions below

0
Hungnn On BEST ANSWER

Sorry, I can't resolve exactly your problem, but if you just want to show a tooltip for bar-chart using D3 lib. Please check this tutorial: Animated bar chart with D3

Maybe, it doesn't depend on d3-tip lib. Checking two events are: .on("mouseover", onMouseOver) and .on("mouseout", onMouseOut).

In my opinion, you must custom onMouseOver when a user hovers over each individual, and custom onMouseOut when a user hovers out a bar.

Please, attention to these two functions:

function onMouseOver(d, i) {

d3.select(this).attr('class', 'highlight');
d3.select(this)
  .transition()
  .duration(400)
  .attr('width', x.bandwidth() + 5)
  .attr("y", function(d) { return y(d.value) - 10; })
  .attr("height", function(d) { return height - y(d.value) + 10; });

g.append("text")
 .attr('class', 'val') // add class to text label
 .attr('x', function() {
     return x(d.year);
 })
 .attr('y', function() {
     return y(d.value) - 15;
 })
 .text(function() {
     return [ '$' +d.value];  // Value of the text
 });
}

function onMouseOut(d, i) {
    d3.select(this).attr('class', 'bar');
    d3.select(this)
      .transition()
      .duration(400)
      .attr('width', x.bandwidth())
      .attr("y", function(d) { return y(d.value); })
      .attr("height", function(d) { return height - y(d.value); });

    d3.selectAll('.val')
      .remove()
}

And finally, add it to build a chart

g.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.on("mouseover", onMouseOver)
.on("mouseout", onMouseOut)
.attr("x", function(d) { return x(d.year); })
.attr("y", function(d) { return y(d.value); })
.attr("width", x.bandwidth())
.transition()
.ease(d3.easeLinear)
.duration(400)
.delay(function (d, i) {
    return i * 50;
})
.attr("height", function(d) { return height - y(d.value); });

Remember to handle it and I hope that it can help you. Good luck,