【问题标题】:Add Spacing and Interactivity to D3 Vers 6 Stacked Bar Chart为 D3 Vers 6 堆叠条形图添加间距和交互性
【发布时间】:2021-01-06 23:16:33
【问题描述】:

我注意到我的条形图没有我想要达到的条形之间的间距。当我将鼠标悬停在栏上时,我似乎也无法显示交互式工具提示。我可能需要一些帮助。这样做的目的是让某个颜色的值在箭头悬停在它上面时显示出来。

Codepen 链接:codepen.io/irwinmier96/pen/qBaKmma

这是我的代码。

<!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>

【问题讨论】:

标签: javascript html css d3.js


【解决方案1】:

通常的间距技巧是添加一点软糖因素:

.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

对于您的工具提示,您使用的是来自旧版本 d3 的代码 sn-p。对于d3.js 版本 6,回调被修改为传递事件对象,您可以在其中获取光标位置:

.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]);
});

工作代码:

<!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>

【讨论】:

  • 您好,感谢您的回答,我能够创建空间,但工具提示仍然无法在我这边工作。还有其他选择吗,因为当我悬停在栏上时,数字没有悬停。我正在使用相同的代码。
  • @IrwinMier,您使用的是哪个版本的d3
  • 我想不管这个版本是什么,但应该是版本6 cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-15
  • 1970-01-01
  • 1970-01-01
  • 2015-06-25
相关资源
最近更新 更多