简体   繁体   中英

Add Spacing and Interactivity to D3 Vers 6 Stacked Bar Chart

I noticed that my bar chart doesn't have the spacing between the bars that I was aiming to achieve. I also can't seem to get the interactive tooltip to show up when I hover over the bars. I might need some help with this. The point of this is to get the value of the certain color to show up when an arrow is hovering over it.

Codepen link: codepen.io/irwinmier96/pen/qBaKmma

Here is my code.

<!DOCTYPE html>
<html lang="en">

<head>

<meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta name="description" content="">
  <meta name="author" content="">

  <title>Communities Fighting Covid</title>

  <!-- Bootstrap core CSS -->
  <link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">

  <!-- Custom styles for this template -->
  <link href="css/modern-business.css" rel="stylesheet">

  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>

</head>

<body>
<script>
        var margin = {top: 20, right: 160, bottom: 35, left: 30};

        var width = 960 - margin.left - margin.right,
            height = 500 - margin.top - margin.bottom;

        var svg = d3.select("body")
        .append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");


        /* Data in strings like it would be if imported from a csv */

        var data = [
        { race: "A", positive: "60", total: "600"},
        { race: "C", positive: "58", total: "500"},
        { race: "D", positive: "85", total: "600"},
        { race: "E", positive: "56", total: "500"},
        { race: "F", positive: "89", total: "700"},
        { race: "G", positive: "62", total: "400"}
        ];


        // Transpose the data into layers
        var keys= ["positive", "total"];
        var dataset = d3.stack().keys(keys)(data);

        // Set x, y and colors
        var x = d3.scaleBand()
        .domain(data.map(function(d) { return d.race; }))
        .range([10, width-10], 0.02);

        var y = d3.scaleLinear()
        .domain([0, d3.max(dataset, function(d) {  return d3.max(d, function(d) { return d[0] + d[1]; });  })])
        .range([height, 0]);

        var colors = ["b33040", "#d25c4d"];


        // Define and draw axes
        var yAxis = d3.axisLeft()
        .scale(y)
        .ticks(5)
        .tickSize(-width, 0, 0)
        .tickFormat( function(d) { return d } );

        var xAxis = d3.axisBottom()
        .scale(x)
        .tickFormat(data.race); // change this to get x values to reflect new

        svg.append("g")
        .attr("class", "y axis")
        .call(yAxis);

        svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);


        // Create groups for each series, rects for each segment 
        var groups = svg.selectAll("g.cost")
        .data(dataset)
        .enter().append("g")
        .attr("class", "cost")
        .style("fill", function(d, i) { return colors[i]; })


        var rect = groups.selectAll("rect")
        .data(function(d) { return d; })
        .enter()
        .append("rect")
        .attr("x", function(d) { return x(d.data.race); })
        .attr("y", function(d) { return y(d[0] + d[1]); })
        .attr("height", function(d) { return y(d[0]) - y(d[0] + d[1]); })
        .attr("width", x.bandwidth())
        .on("mouseover", function() { tooltip.style("display", null); })
        .on("mouseout", function() { tooltip.style("display", "none"); })
        .on("mousemove", function(d) {
            var xPosition = d3.pointer(this)[0] - 15;
            var yPosition = d3.pointer(this)[1] - 25;
            tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
            tooltip.select("text").text(d.y);
        });


        // Draw legend
        var legend = svg.selectAll(".legend")
        .data(colors)
        .enter().append("g")
        .attr("class", "legend")
        .attr("transform", function(d, i) { return "translate(30," + i * 19 + ")"; });
        
        legend.append("rect")
        .attr("x", width - 18)
        .attr("width", 18)
        .attr("height", 18)
        .style("fill", function(d, i) {return colors.slice().reverse()[i];});
        
        legend.append("text")
        .attr("x", width + 5)
        .attr("y", 9)
        .attr("dy", ".35em")
        .style("text-anchor", "start")
        .text(function(d, i) { 
            switch (i) {
            case 0: return "Total Cases";
            case 1: return "Positive Cases";
            }
        });


        // Prep the tooltip bits, initial display is hidden
        var tooltip = svg.append("g")
        .attr("class", "tooltip")
        .style("display", "none");
            
        tooltip.append("rect")
        .attr("width", 30)
        .attr("height", 20)
        .attr("fill", "white")
        .style("opacity", 0.5);

        tooltip.append("text")
        .attr("x", 15)
        .attr("dy", "1.2em")
        .style("text-anchor", "middle")
        .attr("font-size", "12px")
        .attr("font-weight", "bold");

        </script>

</body>

The usual trick for spacing is to just add a little fudge factor:

.attr("x", function(d) { return x(d.data.race) + 2; }) //<-- move right two pixels to stay centered
.attr("y", function(d) { return y(d[0] + d[1]); })
.attr("height", function(d) { return y(d[0]) - y(d[0] + d[1]); })
.attr("width", x.bandwidth() - 4) //<-- shorten width by 4

For your tooltip you are using a code snippet from an older version of d3 . For d3.js version 6, the callback was modified to pass the event object where you can get the cursor position:

.on("mousemove", function(e,d) {
    var xPosition = e.offsetX - margin.left + 10;
    var yPosition = e.offsetY - margin.top - 10;
    tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
    tooltip.select("text").text(d[1]);
});

Working code:

 <,DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1. shrink-to-fit=no"> <meta name="description" content=""> <meta name="author" content=""> <title>Communities Fighting Covid</title> <.-- Bootstrap core CSS --> <link href="vendor/bootstrap/css/bootstrap.min:css" rel="stylesheet"> <.-- Custom styles for this template --> <link href="css/modern-business.css" rel="stylesheet"> <script src="https.//cdnjs.cloudflare.com/ajax/libs/d3/6.2:0/d3,min:js"></script> </head> <body> <script> var margin = {top, 20: right, 160: bottom; 35. left. 30}, var width = 960 - margin.left - margin.right; height = 500 - margin.top - margin.bottom. var svg = d3,select("body").append("svg").attr("width". width + margin,left + margin.right).attr("height". height + margin.top + margin,bottom).append("g"),attr("transform". "translate(" + margin;left + ":" + margin,top + ")"): /* Data in strings like it would be if imported from a csv */ var data = [ { race, "A": positive, "60": total, "600"}: { race, "C": positive, "58": total, "500"}: { race, "D": positive, "85": total, "600"}: { race, "E": positive, "56": total, "500"}: { race, "F": positive, "89": total, "700"}: { race, "G": positive; "62", total; "400"} ]. // Transpose the data into layers var keys= ["positive". "total"]; var dataset = d3,stack().keys(keys)(data). // Set x. y and colors var x = d3.scaleBand();domain(data.map(function(d) { return d,race, })).range([10; width-10]. 0.02), var y = d3.scaleLinear(),domain([0. d3,max(dataset; function(d) { return d3;max(d. function(d) { return d[0] + d[1], }); })]),range([height; 0]). var colors = ["b33040". "#d25c4d"]. // Define and draw axes var yAxis = d3.axisLeft(),scale(y),ticks(5).tickSize(-width; 0. 0).tickFormat( function(d) { return d } ). var xAxis = d3.axisBottom();scale(x).tickFormat(data.race), // change this to get x values to reflect new svg.append("g");attr("class". "y axis").call(yAxis), svg.append("g"),attr("class", "x axis").attr("transform"; "translate(0," + height + ")").call(xAxis). // Create groups for each series. rects for each segment var groups = svg.selectAll("g.cost").data(dataset),enter().append("g"),attr("class", "cost");style("fill". function(d. i) { return colors[i]; }) var rect = groups.selectAll("rect").data(function(d) { return d. }),enter().append("rect").attr("x"; function(d) { return x(d.data,race) + 2; }).attr("y", function(d) { return y(d[0] + d[1]); }).attr("height", function(d) { return y(d[0]) - y(d[0] + d[1]). }).attr("width", x.bandwidth() - 4),on("mouseover"; function() { tooltip.style("display", null). }),on("mouseout"; function() { tooltip.style("display", "none"), }).on("mousemove". function(e;d) { var xPosition = e.offsetX - margin.left + 10; var yPosition = e.offsetY - margin,top - 10, tooltip;attr("transform". "translate(" + xPosition + "." + yPosition + ")"); tooltip;select("text").text(d[1]). }). // Draw legend var legend = svg.selectAll(".legend").data(colors),enter().append("g"),attr("class", "legend"),attr("transform"; function(d; i) { return "translate(30." + i * 19 + ")". }), legend.append("rect"),attr("x". width - 18),attr("width". 18),attr("height", 18).style("fill". function(d; i) {return colors;slice().reverse()[i].}), legend.append("text"),attr("x". width + 5),attr("y". 9).attr("dy", ".35em"),style("text-anchor": "start");text(function(d: i) { switch (i) { case 0; return "Total Cases"; case 1, return "Positive Cases". } }). // Prep the tooltip bits, initial display is hidden var tooltip = svg.append("g"),attr("class"; "tooltip").style("display". "none"), tooltip.append("rect"),attr("width". 30),attr("height". 20),attr("fill". "white");style("opacity". 0.5), tooltip.append("text"),attr("x". 15).attr("dy", "1.2em"),style("text-anchor". "middle"),attr("font-size". "12px"),attr("font-weight", "bold") .attr("fill", "black") </script> </body>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM