Question

I want to add legends in a div so that it gets auto scroll when number of scatter plots increases. following is my sample code

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

        .legend1 {
            width:45px;
            height: 5px;
            padding: 0px;
            overflow: auto;
            font: 10px sans-serif;
            background: yellow;
            border: 1px solid #bbb;
            background-color: #cccccc;
            box-shadow: 2px 2px 1px #888;
        }

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

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

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

var now = d3.time.hour.utc(new Date);

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

var color_hash = {  0 : ["A", "red"],
                    1 : ["B", "green"],
                    2 : ["C", "Yellow"],
                    3 : ["D", "orange"],
                    4 : ["F", "blue"],
                    5 : ["G", "pink"],
                    6 : ["H", "grey"],
                    7 : ["I", "purple"],
                    8 : ["J", "Coral"],
                    9 : ["K", "Crimson"],
                    10 : ["L", "DarkOliveGreen"],
                    11 : ["M", "DarkSeaGreen"],
                    12 : ["N", "DarkRed"],
                    13 : ["O", "DarkKhaki"],
                    14 : ["P", "Chocolate"],
                    15 : ["Q", "Black"]

                  }                      

// 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");

/* var legend = d3.select("body").append("div")
   .attr("class", "legend")
   .attr('transform', 'translate(-20,50)'); */
// add legend   
 var legend = svg.append("g")
                  .attr("class", "legend1")
                  .attr('transform', 'translate(-20,50)')     


legend.selectAll('rect')
  .data(dataset)
  .enter()
  .append("rect")
  .attr("x", w - 75)
  .attr("y", function(d, i){ return i *  20;})
  .attr("width", 5)
  .attr("height", 5)
  .style("fill", function(d) { 
    var color = color_hash[dataset.indexOf(d)][1];
    return color;
  })

legend.selectAll('text')
  .data(dataset)
  .enter()
  .append("text")
  .attr("x", w - 65)
  .attr("width", 5)
  .attr("height", 5)
  .attr("y", function(d, i){ return i *  20 + 5;})
  .text(function(d) {
    var text = color_hash[dataset.indexOf(d)][0];
    return text;
  });


    </script>
</body>

How to place legends in div with specified hieght and width with scroll when the number of series increases

Was it helpful?

Solution

You can solve this by putting the chart and legend into two separate <div>'s.

First we will add them:

<body>
    <div id="chart" class="chart"></div>
    <div id="legend" class="legend"></div>
</body>

Second, we will set their styles (I did it here manually but you can use setAttribute(...) in your script).

.legend {
      overflow: auto;
      height: 200px;  
      width: 50px;  
        }

.chart {
     float: left;
       }

Setting overflow: auto is what makes the div scrollable. float: left makes the <div>'s display side-by-side.

Last, we will change the d3 script to reflect this by creating svg elements for each div.

var svg = d3.select("#chart")
    .append("svg")
    .attr("width", w)
    .attr("height", h);

var svg2 = d3.select("#legend")
    .append("svg")
    .attr("width", 30)
    .attr("height", 20*dataset.length);

You can see the result here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top