如何在d3.js中将堆叠条形图的图例放置在下面

时间:2019-03-24 00:52:19

标签: d3.js

我试图将图例放在堆积的条形图对齐块的下方。无法正确过渡。下面是我拥有的代码,此刻,图例出现在左上角,我要执行的操作是将其正确放置在堆积条下方的tranistion,是否有任何建议建议我如何进行转换以便适合svg也一样任何建议都会被采纳

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>D3 Example</title>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
    <style>
    </style>
</head>
<style>

</style>
<body>

<div class="canvas">

</div>

<script>

    var data = [
        {month: "Q1-2016", apples: 3840, bananas: 1920, cherries: -1960},
        {month: "Q2-2016", apples: 1600, bananas: 1440, cherries: -960},
        {month: "Q3-2016", apples:  640, bananas:  960, cherries: -640},
        {month: "Q4-2016", apples:  320, bananas:  480, cherries: -640},
        {month: "Q5-2016", apples: 3840, bananas: 1920, cherries: -1960},
        {month: "Q6-2016", apples: 1600, bananas: 1440, cherries: -960},
        {month: "Q7-2016", apples:  640, bananas:  960, cherries: -640},
        {month: "Q8-2016", apples:  320, bananas:  480, cherries: -640},
        {month: "Q9-2016", apples: 3840, bananas: 1920, cherries: -1960},
        {month: "Q10-2016", apples: 1600, bananas: 1440, cherries: 960},
        {month: "Q11-2016", apples:  640, bananas:  960, cherries: -640},
        {month: "Q12-2016", apples:  320, bananas:  480, cherries: -640},
    ];

    var series = d3.stack()
        .keys(["apples", "bananas", "cherries"])
        .offset(d3.stackOffsetDiverging)
        (data);

    var margin = {top: 20, right: 30, bottom: 30, left: 60},
        width = 900,
        height = 600,
        padding = 40,
        svg = d3.select(".canvas").append('svg').attr('height', height).attr('width',width);

    var x = d3.scaleBand()
        .domain(data.map(function(d){return d.month;}))
        .rangeRound([margin.left, width-margin.right])
        .padding(0.1);

    var y = d3.scaleLinear()
        .domain([d3.min(series, stackMin), d3.max(series, stackMax)])
        .rangeRound([height - margin.bottom, margin.top]);

    var colors = ["#66b3ff", "#b3d9ff", "#99ddff", "#99ffdd"];
    var z = d3.scaleOrdinal(colors);

    //create and call the axes
    const xAxis = d3.axisBottom(x);
    const yAxis = d3.axisLeft(y);
    console.log(series);

    svg.append('g')
        .selectAll('g')
        .data(series)
        .enter().append('g')
        .attr('fill', function (d) {
            return z(d.key);
        })
        .selectAll('rect')
        .data(function(d){ return d; })
        .enter().append('rect')
        .attr('width', x.bandwidth)
        .attr('x', function(d){ return x(d.data.month)})
        .attr("y", function(d) { return y(d[1]); })
        .attr("height", function(d) { return y(d[0]) - y(d[1]); })


    svg.append("g")
        .attr("transform", "translate(0," + y(0) + ")")
        .call(d3.axisBottom(x));

    svg.append("g")
        .attr("transform", "translate(" + margin.left + ",0)")
        .call(d3.axisLeft(y));

    var legend = svg.append('g')
        .attr('class', 'legend')
        .attr('transform', 'translate(' + (padding + 12) + ',0)');

    legend.selectAll('rect')
        .data(series)
        .enter()
        .append('rect')
        .attr('x', 0)
        .attr('y', function(d,i){
            return i * 18;
        })
        .attr('width', 12)
        .attr('height', 12)
        .attr('fill', function(d,i){
            return z(i);
        });

    legend.selectAll('text')
        .data(series)
        .enter()
        .append('text')
        .text(function(d){
            return d.key;
        })
        .attr('x', -18)
        .attr('y', function(d, i){
            return i * 18;
        })
        .attr('text-anchor', 'start')
        .attr('alignment-baseline', 'hanging');



    function stackMin(serie) {
        return d3.min(serie, function(d) { return d[0]; });
    }

    function stackMax(serie) {
        return d3.max(serie, function(d) { return d[1]; });
    }




</script>
</body>
</html>

1 个答案:

答案 0 :(得分:1)

您的代码中有些错误,所以我尝试修复其中的一些问题。

  1. 您的图表元素(即条形图和轴图)应添加到组中。这样可以根据需要适当地移动/翻译它。我创建一个chart变量,并将这些元素分配给它,而不是直接分配给svg。这也使您在控制台中查看结构时也更容易看到。

  2. 图例区域的高度应在图表中声明和说明。我将其声明为变量legendh,并在y轴范围内进行了说明。

  3. 如果您希望图例组出现在图表下方,则需要将其转换为图表下方。您之前提到的对.attr('transform', 'translate(' + (padding + 12) + ',0)');组的变换使y坐标为0。我将其更改为.attr('transform', 'translate(' + (padding + 12) + ','+ (height - legendh) + ')');。这告诉图例组从顶部向下移动height - legendh数量,从而将其放置在图表下方。

  4. 最后,图例中的颜色与图表/条中的颜色不匹配。这是因为您的小节填充已由d.key控制,但图例填充基于i。我选择使其均匀并使用z(i)获得颜色。

这是工作区:https://bl.ocks.org/akulmehta/80153b35ab7498d30408f92cfa50f356

这是工作代码:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>D3 Example</title>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
    <style>
    </style>
</head>
<style>

</style>
<body>

<div class="canvas">

</div>

<script>

    var data = [
        {month: "Q1-2016", apples: 3840, bananas: 1920, cherries: -1960},
        {month: "Q2-2016", apples: 1600, bananas: 1440, cherries: -960},
        {month: "Q3-2016", apples:  640, bananas:  960, cherries: -640},
        {month: "Q4-2016", apples:  320, bananas:  480, cherries: -640},
        {month: "Q5-2016", apples: 3840, bananas: 1920, cherries: -1960},
        {month: "Q6-2016", apples: 1600, bananas: 1440, cherries: -960},
        {month: "Q7-2016", apples:  640, bananas:  960, cherries: -640},
        {month: "Q8-2016", apples:  320, bananas:  480, cherries: -640},
        {month: "Q9-2016", apples: 3840, bananas: 1920, cherries: -1960},
        {month: "Q10-2016", apples: 1600, bananas: 1440, cherries: 960},
        {month: "Q11-2016", apples:  640, bananas:  960, cherries: -640},
        {month: "Q12-2016", apples:  320, bananas:  480, cherries: -640},
    ];

    var series = d3.stack()
        .keys(["apples", "bananas", "cherries"])
        .offset(d3.stackOffsetDiverging)
        (data);

    var margin = {top: 20, right: 30, bottom: 30, left: 60},
        width = 900,
        height = 500,
        legendh = 100, //determines the height of the legend below the chart
        padding = 40,
        svg = d3.select(".canvas").append('svg').attr('height', height).attr('width',width);

    var x = d3.scaleBand()
        .domain(data.map(function(d){return d.month;}))
        .rangeRound([margin.left, width-margin.right])
        .padding(0.1);

    var y = d3.scaleLinear()
        .domain([d3.min(series, stackMin), d3.max(series, stackMax)])
        .rangeRound([height - margin.bottom - legendh, margin.top]);

    var colors = ["#66b3ff", "#b3d9ff", "#99ddff", "#99ffdd"];
    var z = d3.scaleOrdinal(colors);

    //create and call the axes
    const xAxis = d3.axisBottom(x);
    const yAxis = d3.axisLeft(y);


    var chart = svg.append('g').attr('id','chart'); //make a chart group inside the svg

    chart.append('g')
        .selectAll('g')
        .data(series)
        .enter().append('g')
        .attr('fill', function (d,i) { //because the legend is based on i this should also be based on i
            return z(i);
        })
        .selectAll('rect')
        .data(function(d){ return d; })
        .enter().append('rect')
        .attr('width', x.bandwidth)
        .attr('x', function(d){ return x(d.data.month)})
        .attr("y", function(d) { return y(d[1]); })
        .attr("height", function(d) { return y(d[0]) - y(d[1]); })


    chart.append("g")
        .attr("transform", "translate(0," + y(0) + ")")
        .call(d3.axisBottom(x));

    chart.append("g")
        .attr("transform", "translate(" + margin.left + ",0)")
        .call(d3.axisLeft(y));

    var legend = svg.append('g')
        .attr('class', 'legend')
        .attr('transform', 'translate(' + (padding + 12) + ','+ (height - legendh)  + ')');

    legend.selectAll('rect')
        .data(series)
        .enter()
        .append('rect')
        .attr('x', 0)
        .attr('y', function(d,i){
            return i * 18;
        })
        .attr('width', 12)
        .attr('height', 12)
        .attr('fill', function(d,i){
            console.log(z(i));
            return z(i);
        });

    legend.selectAll('text')
        .data(series)
        .enter()
        .append('text')
        .text(function(d){
            return d.key;
        })
        .attr('x', 15)
        .attr('y', function(d, i){
            return i * 18;
        })
        .attr('text-anchor', 'start')
        .attr('alignment-baseline', 'hanging');



    function stackMin(serie) {
        return d3.min(serie, function(d) { return d[0]; });
    }

    function stackMax(serie) {
        return d3.max(serie, function(d) { return d[1]; });
    }




</script>
</body>
</html>