从 json 文件构建 bar 的工具提示值

Constructing a tooltip values of bar from json file

我目前正在努力使工具提示正常工作。这是页面的样子 [见下面的照片 1],我正在尝试为每个栏分配它的 y 值。 y 值存储在 resumeperday.json [见下文] 中,其中每天都有 'time' 和 'y' 属性。 time 属性是日期,y 是当天有多少订单。 resumeperday.json 文件作为 dataset 变量存储在 index.html 文件中。我正在尝试解析它的 y 值,它是所有三个不同订单的总和(每个日期都有 3 个不同的值),并在鼠标悬停时将其显示在栏上。当我使用这行代码时

  .html(function(d) {
        return "<strong>Number of orders:</strong> <span style='color:red'>" + d3.max(dataset, function(d) {
                        return d3.max(d, function(d) {
                            return d.y0 + d.y;
                        });
                    }) + "</span>";
        })

问题: 它只显示每个柱的 123(这是订单的最大值),我正在尝试构建一个函数,它将 return 根据悬停的特定柱的值。

这是 index.html 代码:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Pizza orders</title>
        <script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
        <script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
        <script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
        <script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
        <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
        <style>
        .axis path,
.axis line {
    fill: none;
    stroke: black;
    shape-rendering: crispEdges;
}

.axis text {
    font-family: sans-serif;
    font-size: 11px;
}

.dot {
  stroke: #000;
}


.legend {
                padding: 5px;
                font: 10px sans-serif;
                background: yellow;
                box-shadow: 2px 2px 1px #888;
            }
.d3-tip {
  line-height: 1;
  font-weight: bold;
  padding: 12px;
  background: rgba(0, 0, 0, 0.8);
  color: #fff;
  border-radius: 2px;
}

/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
  box-sizing: border-box;
  display: inline;
  font-size: 10px;
  width: 100%;
  line-height: 1;
  color: rgba(0, 0, 0, 0.8);
  content: "BC";
  position: absolute;
  text-align: center;
}

/* Style northward tooltips differently */
.d3-tip.n:after {
  margin: -1px 0 0 0;
  top: 100%;
  left: 0;
}-align: center;
}
        </style>
    </head>
    <body>
        <div>
            <div class="btn-group pull-right">
                <button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown">
                         Pizza orders per hour <span class="caret"></span>
                </button>
                <ul class="dropdown-menu" role="menu">
                    <li><a class="m" value="2018-07-15" href="#">2018-07-15</a></li>
                    <li><a class="m" value="2018-07-16" href="#">2018-07-16</a></li>
                    <li><a class="m" value="2018-07-17" href="#">2018-07-17</a></li>
                    <li><a class="m" value="2018-07-18" href="#">2018-07-18</a></li>
                    <li><a class="m" value="2018-07-19" href="#">2018-07-19</a></li>
                    <li><a class="m" value="2018-07-20" href="#">2018-07-20</a></li>
                    <li><a class="m" value="2018-07-21" href="#">2018-07-21</a></li>
                </ul>
            </div>

        <div id="mbars">
        </div>
        </div>
        <script type="text/javascript">
        var w = 700;                        //width
        var h = 600;                        //height
        var padding = {top: 40, right: 40, bottom: 40, left:25};
        var dataset;
        var tip = d3.tip()
        .attr('class', 'd3-tip')
        .offset([-10, 0])
        .html(function(d) {
        return "<strong>Number of orders:</strong> <span style='color:red'>" + d3.min(dataset, function(d) {
                        return d3.min(d, function(d) {
                            return d.y0 + d.y;
                        });
                    }) + "</span>";
        })
        //Set up stack method
        var stack = d3.layout.stack();

        d3.json("resumeperday.json",function(json){
            dataset = json;

            //Data, stacked
            stack(dataset);

            var color_hash = {
                    0 : ["50-70₪","#0000FF"],
                    1 : ["70.00-120₪","#FF0000"],
                    2 : ["120+₪","#04B404"]

            };


            //Set up scales
            var xScale = d3.time.scale()
                .domain([new Date(dataset[0][0].time),d3.time.day.offset(new Date(dataset[0][dataset[0].length-1].time),2)])
                .rangeRound([0, w-padding.left-padding.right]);

            var yScale = d3.scale.linear()
                .domain([0,             
                    d3.max(dataset, function(d) {
                        return d3.max(d, function(d) {
                            return d.y0 + d.y;
                        });
                    })
                ])
                .range([h-padding.bottom-padding.top,0]);

            var xAxis = d3.svg.axis()
                           .scale(xScale)
                           .orient("bottom")
                           .ticks(d3.time.days,1);

            var yAxis = d3.svg.axis()
                           .scale(yScale)
                           .orient("left")
                           .ticks(10);



            //Easy colors accessible via a 10-step ordinal scale
            var colors = d3.scale.category10();

            //Create SVG element
            var svg = d3.select("#mbars")
                        .append("svg")
                        .attr("width", w)
                        .attr("height", h);

            svg.call(tip);


            // Add a group for each row of data
            var groups = svg.selectAll("g")
                .data(dataset)
                .enter()
                .append("g")
                .attr("class","rgroups")
                .attr("transform","translate("+ (padding.left) + "," + (h - padding.bottom) +")")
                .style("fill", function(d, i) {
                    return color_hash[dataset.indexOf(d)][1];
                })
                .on('mouseover', tip.show)
                .on('mouseout', tip.hide);

            // Add a rect for each data value
            var rects = groups.selectAll("rect")
                .data(function(d) { return d; })
                .enter()
                .append("rect")
                .attr("width", 2)
                .style("fill-opacity",1e-6);


            rects.transition()
                 .duration(function(d,i){
                     return 500 * i;
                 })
                 .ease("linear")
                .attr("x", function(d) {
                    return xScale(new Date(d.time));
                })
                .attr("y", function(d) {
                    return -(- yScale(d.y0) - yScale(d.y) + (h - padding.top - padding.bottom)*2);
                })
                .attr("height", function(d) {
                    return -yScale(d.y) + (h - padding.top - padding.bottom);
                })
                .attr("width", 15)
                .style("fill-opacity",1);

                svg.append("g")
                    .attr("class","x axis")
                    .attr("transform","translate(40," + (h - padding.bottom) + ")")
                    .call(xAxis);


                svg.append("g")
                    .attr("class","y axis")
                    .attr("transform","translate(" + padding.left + "," + padding.top + ")")
                    .call(yAxis);

                // adding legend

                var legend = svg.append("g")
                                .attr("class","legend")
                                .attr("x", w - padding.right - 65)
                                .attr("y", 25)
                                .attr("height", 100)
                                .attr("width",100);

                legend.selectAll("g").data(dataset)
                      .enter()
                      .append('g')
                      .each(function(d,i){
                        var g = d3.select(this);
                        g.append("rect")
                            .attr("x", w - padding.right - 30)
                            .attr("y", i*25 + 10)
                            .attr("width", 10)
                            .attr("height",10)
                            .style("fill",color_hash[String(i)][1]);

                        g.append("text")
                         .attr("x", w - padding.right - 15)
                         .attr("y", i*25 + 20)
                         .attr("height",30)
                         .attr("width",100)
                         .style("fill",color_hash[String(i)][1])
                         .text(color_hash[String(i)][0]);
                      });

                svg.append("text")
                .attr("transform","translate(5,20) rotate(0)")
                .attr("font-weight","bold")
                .text("Pizza Orders");

            svg.append("text")
               .attr("class","xtext")
               .attr("x",w/2 - padding.left)
               .attr("y",h - 5)
               .attr("text-anchor","middle")
               .attr("font-weight","bold")
               .text("Days");

            svg.append("text")
            .attr("class","title")
            .attr("x", (w / 2))             
            .attr("y", 20)
            .attr("text-anchor", "middle")
            .attr("font-weight","bold")         
            .style("font-size", "16px") 
            .style("text-decoration", "underline")  
            .text("Number of Pizza Orders per day");

            //On click, update with new data            
            d3.selectAll(".m")
                .on("click", function() {
                    var date = this.getAttribute("value");

                    var str;
                    if(date == "2018-07-15"){
                        str = "15.json";
                    }else if(date == "2018-07-16"){
                        str = "16.json";
                    }else if(date == "2018-07-17"){
                        str = "17.json";
                    }else if(date == "2018-07-18"){
                        str = "18.json";
                    }else if(date == "2018-07-19"){
                        str = "19.json";
                    }
                    else if(date == "2018-07-20"){
                        str = "20.json";
                    }else{
                        str = "21.json";
                    }

                    d3.json(str,function(json){

                        dataset = json;
                        stack(dataset);

                        console.log(dataset);

                        xScale.domain([new Date(0, 0, 0,dataset[0][0].time,0, 0, 0),new Date(0, 0, 0,dataset[0][dataset[0].length-1].time,0, 0, 0)])
                        .rangeRound([0, w-padding.left-padding.right]);

                        yScale.domain([0,               
                                        d3.max(dataset, function(d) {
                                            return d3.max(d, function(d) {
                                                return d.y0 + d.y;
                                            });
                                        })
                                    ])
                                    .range([h-padding.bottom-padding.top,0]);

                        xAxis.scale(xScale)
                             .ticks(d3.time.hour,1)
                             .tickFormat(d3.time.format("%H"));

                        yAxis.scale(yScale)
                             .orient("left")
                             .ticks(10);

                         groups = svg.selectAll(".rgroups")
                            .data(dataset);

                            groups.enter().append("g")
                            .attr("class","rgroups")
                            .attr("transform","translate("+ padding.left + "," + (h - padding.bottom) +")")
                            .style("fill",function(d,i){
                                return color(i);
                            });


                            rect = groups.selectAll("rect")
                            .data(function(d){return d;});

                            rect.enter()
                              .append("rect")
                              .attr("x",w)
                              .attr("width",1)
                              .style("fill-opacity",1e-6);

                        rect.transition()
                            .duration(1000)
                            .ease("linear")
                            .attr("x",function(d){
                                return xScale(new Date(0, 0, 0,d.time,0, 0, 0));
                            })
                            .attr("y",function(d){
                                return -(- yScale(d.y0) - yScale(d.y) + (h - padding.top - padding.bottom)*2);
                            })
                            .attr("height",function(d){
                                return -yScale(d.y) + (h - padding.top - padding.bottom);
                            })
                            .attr("width",15)
                            .style("fill-opacity",1);

                        rect.exit()
                           .transition()
                           .duration(1000)
                           .ease("circle")
                           .attr("x",w)
                           .remove();

                        groups.exit()
                           .transition()
                           .duration(1000)
                           .ease("circle")
                           .attr("x",w)
                           .remove();


                        svg.select(".x.axis")
                           .transition()
                           .duration(1000)
                           .ease("circle")
                           .call(xAxis);

                        svg.select(".y.axis")
                           .transition()
                           .duration(1000)
                           .ease("circle")
                           .call(yAxis);

                        svg.select(".xtext")
                           .text("Hours")
                           .attr("font-weight","bold");

                        svg.select(".title")
                        .text("Number of Pizza Orders per hour on " + date)
                        .attr("font-weight","bold");
                    });         
                });


        });

        </script>
    </body>
</html>

resumeperday.json 文件:

[
    [
        {
            "time": "2018-07-15",
            "y": 27
        },
        {
            "time": "2018-07-16",
            "y": 23
        },
        {
            "time": "2018-07-17",
            "y": 28
        },
        {
            "time": "2018-07-18",
            "y": 20
        },
        {
            "time": "2018-07-19",
            "y": 22
        },
        {
            "time": "2018-07-20",
            "y": 27
        },
        {
            "time": "2018-07-21",
            "y": 21
        }
    ],
    [
        {
            "time": "2018-07-15",
            "y": 29
        },
        {
            "time": "2018-07-16",
            "y": 26
        },
        {
            "time": "2018-07-17",
            "y": 31
        },
        {
            "time": "2018-07-18",
            "y": 27
        },
        {
            "time": "2018-07-19",
            "y": 31
        },
        {
            "time": "2018-07-20",
            "y": 65
        },
        {
            "time": "2018-07-21",
            "y": 37
        }
    ],
    [
        {
            "time": "2018-07-15",
            "y": 17
        },
        {
            "time": "2018-07-16",
            "y": 16
        },
        {
            "time": "2018-07-17",
            "y": 16
        },
        {
            "time": "2018-07-18",
            "y": 15
        },
        {
            "time": "2018-07-19",
            "y": 22
        },
        {
            "time": "2018-07-20",
            "y": 31
        },
        {
            "time": "2018-07-21",
            "y": 23
        }
    ]
]

[照片 1] 只有那个特定柱线“123”是正确的。

问题是您按颜色对矩形进行了分组。 如果您将鼠标悬停在一个矩形上,您将获得属于该颜色组的数据。您没有指示您正在悬停的栏。

Select 按 class 而非元素类型分组。

var groups = svg.selectAll(".rgroups")
                .data(dataset)
                .enter()
                .append("g")
                .attr("class","rgroups")
                .attr("transform","translate("+ (padding.left) + "," + (h - padding.bottom) +")")
                .style("fill", function(d, i) {
                    return color_hash[dataset.indexOf(d)][1];
                })
                .on('mouseover', tip.show)
                .on('mouseout', tip.hide);

您必须转换您的数据集,以便您有一个 object/array 代表特定柱的所有数据。 d3.nest 可能会有帮助。

然后为每个柱构建一个 g,并将矩形添加到此 g。然后在工具提示中,您将获得属于该柱的数据。

仔细查看 .d3-tip.n:after 的样式。有错误。