在D3中添加图表图例

时间:2012-11-26 21:51:55

标签: d3.js legend

我在向d3js图表添加图表图例时遇到问题。这是我目前的做法:

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

legend.append("rect")
  .attr("x", w - 65)
  .attr("y", 25)
  .attr("width", 10)
  .attr("height", 10)
  .style("fill", function(d) { return color_hash[dataset.indexOf(d)][1] });

legend.append("text")
  .attr("x", w - 65)
  .attr("y", 25)
  .text(function(d) { return color_hash[dataset.indexOf(d)][0] + ": " + d; });

然后我试图设置.legend类的样式:

.legend {
            padding: 5px;
            font: 10px sans-serif;
            background: yellow;
            box-shadow: 2px 2px 1px #888;
        }

但我没有太多运气。

是否有人熟悉将图例添加到能够提供最佳方法的图表中?我在网上找不到很多资源。

这是我的整个图表: http://jsbin.com/ewiwag/2/edit

2 个答案:

答案 0 :(得分:37)

您需要将数据绑定到构成图例的节点(矩形和文本元素)。

目前,在尝试设置矩形样式时出现错误:

Uncaught TypeError: Cannot read property '1' of undefined 

原因:没有绑定数据

legend.append("rect")
      /*...*/
      .style("fill", function(d) { 
         // d <---- is undefined
         return color_hash[dataset.indexOf(d)][1] 
      });

请注意,D3专注于数据转换并根据选择进行操作。因此,首先选择一组节点,然后绑定数据

legend.selectAll('rect')
      .data(dataset)
      .enter()

使用enter输入选择后,您可以添加节点并动态应用属性。请注意,为避免在其他人之上创建矩形,设置y属性时会通过i计数器并将其乘以整数。

  /*.....*/
      .append("rect")
      .attr("x", w - 65)
      .attr("y", function(d, i){ return i *  20;})
      .attr("width", 10)
      .attr("height", 10)
      .style("fill", function(d) { 
         var color = color_hash[dataset.indexOf(d)][1];
         return color;
      });

以下是固定示例:http://jsbin.com/ubafur/3

答案 1 :(得分:12)

好的,这是一种方法:http://jsbin.com/isuris/1/edit

抱歉,必须进行太多更改才能解释一切。看看你是否能搞清楚。如果您有任何疑问,请在评论中提问,我将修改答案。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <script type="text/javascript" src="http://mbostock.github.com/d3/d3.js"></script>
    <style type="text/css">

      .axis path,
      .axis line {
        fill: none;
        stroke: black;
        shape-rendering: crispEdges;
      }

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

      .y1 {
        fill: white;
        stroke: orange;
        stroke-width: 1.5px;
      }

      .y2 {
        fill: white;
        stroke: red;
        stroke-width: 1.5px;
      }

      .y3 {
        fill: white;
        stroke: steelblue;
        stroke-width: 1.5px;
      }

      .line {
        fill: none;
        stroke-width: 1.5px;
      }

      div.tooltip {
              position: absolute;
              text-align: center;
              width: 50px;
              height: 10px;
              padding: 5px;
              font: 10px sans-serif;
              background: whiteSmoke;
              border: solid 1px #aaa;
              pointer-events: none;
              box-shadow: 2px 2px 1px #888;
            }

            .legend {
              padding: 5px;
              font: 10px sans-serif;
              background: yellow;
              box-shadow: 2px 2px 1px #888;
            }

            .title {
              font: 13px sans-serif;
            }

    </style>
  </head>
  <body>
    <script type="text/javascript">

    //Width and height
    var w = 500;
    var h = 300;
    var padding = 50;

    var now = d3.time.hour.utc(new Date);
    var dataset = [ [ ],[ ] ];
    dataset[0].push({x: d3.time.hour.utc.offset(now, -5), y: 0});
    dataset[0].push({x: d3.time.hour.utc.offset(now, -4), y: 0});
    dataset[0].push({x: d3.time.hour.utc.offset(now, -3), y: 2});
    dataset[0].push({x: d3.time.hour.utc.offset(now, -2), y: 0});
    dataset[0].push({x: d3.time.hour.utc.offset(now, -1), y: 0});
    dataset[0].push({x: now, y: 0});

    dataset[1].push({x: d3.time.hour.utc.offset(now, -5), y: 3});
    dataset[1].push({x: d3.time.hour.utc.offset(now, -4), y: 1});
    dataset[1].push({x: d3.time.hour.utc.offset(now, -3), y: 3});
    dataset[1].push({x: d3.time.hour.utc.offset(now, -2), y: 1});
    dataset[1].push({x: d3.time.hour.utc.offset(now, -1), y: 5});
    dataset[1].push({x: now, y: 1});

    var color_hash = {  0 : ["apple", "green"],
              1 : ["mango", "orange"],
              2 : ["cherry", "red"]
            }                      

    // Define axis ranges & scales        
    var yExtents = d3.extent(d3.merge(dataset), function (d) { return d.y; });
    var xExtents = d3.extent(d3.merge(dataset), function (d) { return d.x; });

  var xScale = d3.time.scale()
         .domain([xExtents[0], xExtents[1]])
         .range([padding, w - padding * 2]);

  var yScale = d3.scale.linear()
         .domain([0, yExtents[1]])
         .range([h - padding, padding]);


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


  // Define lines
  var line = d3.svg.line()
         .x(function(d) { return x(d.x); })
         .y(function(d) { return y(d.y1, d.y2, d.y3); });

  var pathContainers = svg.selectAll('g.line')
  .data(dataset);

  pathContainers.enter().append('g')
  .attr('class', 'line')
  .attr("style", function(d) {
    return "stroke: " + color_hash[dataset.indexOf(d)][1]; 
  });

  pathContainers.selectAll('path')
  .data(function (d) { return [d]; }) // continues the data from the pathContainer
  .enter().append('path')
    .attr('d', d3.svg.line()
      .x(function (d) { return xScale(d.x); })
      .y(function (d) { return yScale(d.y); })
    );

  // add circles
  pathContainers.selectAll('circle')
  .data(function (d) { return d; })
  .enter().append('circle')
  .attr('cx', function (d) { return xScale(d.x); })
  .attr('cy', function (d) { return yScale(d.y); })
  .attr('r', 3); 

    //Define X axis
  var xAxis = d3.svg.axis()
          .scale(xScale)
          .orient("bottom")
          .ticks(5);

  //Define Y axis
  var yAxis = d3.svg.axis()
          .scale(yScale)
          .orient("left")
          .ticks(5);

  //Add X axis
  svg.append("g")
  .attr("class", "axis")
  .attr("transform", "translate(0," + (h - padding) + ")")
  .call(xAxis);

  //Add Y axis
  svg.append("g")
  .attr("class", "axis")
  .attr("transform", "translate(" + padding + ",0)")
  .call(yAxis);

  // Add title    
  svg.append("svg:text")
       .attr("class", "title")
     .attr("x", 20)
     .attr("y", 20)
     .text("Fruit Sold Per Hour");


  // add legend   
  var legend = svg.append("g")
    .attr("class", "legend")
    .attr("x", w - 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 - 65)
          .attr("y", i*25)
          .attr("width", 10)
          .attr("height", 10)
          .style("fill", color_hash[String(i)][1]);

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

      });
    </script>
  </body>
</html>