Ajout d'une légende dans D3

j'ai de la difficulté à ajouter une légende de carte à ma carte d3js. Voici mon approche actuelle:

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

Alors j'essaie de style .legend catégorie:

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

mais je n'ai pas beaucoup de chance.

est-ce que quelqu'un est familier avec l'ajout de légendes aux cartes? Je ne trouve pas beaucoup de ressources pour cela en ligne.

Voici mon graphique: http://jsbin.com/ewiwag/2/edit

37
demandé sur VividD 2012-11-27 01:51:54

2 réponses

vous devez lier les données aux noeuds (rectangles et éléments de texte) qui composent la légende.

Actuellement vous obtenez une erreur en essayant de style rectangles:

Uncaught TypeError: Cannot read property '1' of undefined 

La raison: il n'y a pas de données lié

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

notez que D3 se concentre sur la transformation des données et opère sur les sélections. Ainsi, tout d'abord sélectionner un ensemble de noeuds et ensuite lier les données

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

une fois que vous entrez la sélection avec enter, vous pouvez ajouter des noeuds et appliquer propriétés de façon dynamique. Notez que pour éviter de créer des rectangles au-dessus des autres, lors de la définition du y propriété passez le i compteur et le multiplier par un entier.

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

Voici l'exemple fixe:http://jsbin.com/ubafur/3

31
répondu jaime 2012-11-27 00:48:46

Ok, voici une façon de le faire: http://jsbin.com/isuris/1/edit

Désolé, j'avais à faire trop de changements pour être en mesure de l'expliquer. Voyez si vous pouvez le comprendre. Si vous avez des questions, posez-les dans les commentaires et je modifierai la réponse.

<!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>
12
répondu meetamit 2017-10-13 14:18:49