在D3中添加图表图例

我无法添加图表图例到我的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; } 

但是我没有太多的运气。

有人熟悉将图例添加到图表能够提供最佳的方式吗? 我没有find这个在线的许多资源。

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

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

目前,当您尝试使用矩形样式时会出现错误:

 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专注于数据转换并对select进行操作。 因此,首先select一组节点,然后绑定数据

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

一旦你input了select,你可以添加节点和dynamic应用属性。 请注意,要避免在其他顶部创build矩形,设置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

好的,下面是一个方法: 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 dy; }); var xExtents = d3.extent(d3.merge(dataset), function (d) { return dx; }); 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(dx); }) .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(dx); }) .y(function (d) { return yScale(dy); }) ); // add circles pathContainers.selectAll('circle') .data(function (d) { return d; }) .enter().append('circle') .attr('cx', function (d) { return xScale(dx); }) .attr('cy', function (d) { return yScale(dy); }) .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>