2012-11-26 4 views
35

d3js 차트에 차트 범례를 추가하는 데 문제가 있습니다. D3에 차트 범례 추가

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

답변

30

.

Uncaught TypeError: Cannot read property '1' of undefined 

이유를 : 스타일 사각형을 시도 할 때

현재 당신은 오류가없는 데이터 바인딩

D3는 데이터 변환에 초점을 맞추고 선택에 동작하는 것을
legend.append("rect") 
     /*...*/ 
     .style("fill", function(d) { 
     // d <---- is undefined 
     return color_hash[dataset.indexOf(d)][1] 
     }); 

공지 사항이 없습니다. 그래서, 첫번째 노드 세트를 선택하고 다음 enter과 선택을 입력하면, 당신은 노드를 추가하고 동적 속성을 적용 할 수있는 데이터

legend.selectAll('rect') 
     .data(dataset) 
     .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

+0

아하! 한 가지 주요한 문제점은 아직 : 글꼴은 있지만, .legend의 배경과 테두리 스타일은 적용되지 않습니다. 나는 div div요소가 다른 div와 같은 방식으로 스타일 될 수 있다고 가정합니다. 이것은 틀린가? – darko

+0

@ddarko, 틀 렸습니다. CSS (선택기)를 사용하여 SVG 요소를 스타일링하는 경우 CSS 속성 이름이 아닌 [SVG 속성] (https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute) 만 사용할 수 있습니다. [이 책] (http://chimera.labs.oreilly.com/books/1230000000345/ch03.html#_styling_svg_elements)에서 제안했듯이 스타일 시트에서 SVG에 특정한 규칙을 구별하기 위해'svg '선택자에게 :'svg .legend {...}' –

11

좋아, 여기 한 가지 방법이있다 : 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> 
+0

jm-에 대한 내 코멘트보기 – darko

+0

아니요, 배경과 테두리는 적용 할 수 없습니다. SVG 요소의 CSS. SVG의 주요 스타일 속성은 뇌졸중, 채우기, 글꼴 패밀리 및 글꼴 크기입니다. 원하는 크기, 배경 및 테두리를 가진 각 범례 항목에 대해 또 다른'svg : rect'를 만들어야합니다. 또는 HTML로 전체 범례를 만들 수 있습니다.이 IMO는 더 쉬운 옵션입니다. SVG 요소 안에 중첩 된 HTML을 가질 수도 있지만, SVG 요소 위에 중첩 된 형제 노드로 만들 수도 있습니다. – meetamit

+0

jsbin의 약간 편집 된 버전 ('push()'를 통해 추가 된 포인트) http://jsbin.com/isuris/437/edit –