需要帮助使用d3.js创建堆积条形图

时间:2012-05-13 02:05:44

标签: javascript d3.js

我目前正在尝试使用d3.js将此(mbostock.github.com/d3/ex/stack.html)垂直堆积条形图转换为水平堆积条形图,但我没有运气。如果有人有d3.js水平堆积条形图的例子,或者知道如何正确修改下面的代码或指向正确的方向,这将是一个很大的帮助。

var margin = 20,
 width = 960,
 height = 500 - .5 - margin,
 mx = m,
 my = d3.max(data, function(d) {
   return d3.max(d, function(d) {
     return d.y0 + d.y;
   });
 }),
 mz = d3.max(data, function(d) {
   return d3.max(d, function(d) {
     return d.y;
  });
 }),
 x = function(d) { return d.x * width / mx; },
 y0 = function(d) { return height - d.y0 * height / my; },
 y1 = function(d) { return height - (d.y + d.y0) * height / my; },
 y2 = function(d) { return d.y * height / mz; }; // or `my` to not rescale

var vis = d3.select("#chart")
.append("svg")
.attr("width", width)
.attr("height", height + margin);

var layers = vis.selectAll("g.layer")
.data(data)
.enter().append("g")
.style("fill", function(d, i) { return color(i / (n - 1)); })
.attr("class", "layer");

var bars = layers.selectAll("g.bar")
.data(function(d) { return d; })
.enter().append("g")
.attr("class", "bar")
.attr("transform", function(d) { return "translate(" + x(d) + ",0)"; });

 bars.append("rect")
.attr("width", x({x: .9}))
.attr("x", 0)
.attr("y", height)
.attr("height", 0)
 .transition()
.delay(function(d, i) { return i * 10; })
.attr("y", y1)
.attr("height", function(d) { return y0(d) - y1(d); });

2 个答案:

答案 0 :(得分:1)

技巧是:将它与垂直堆叠条形图几乎相同,但在堆叠之前反转x和y值,然后在堆叠后再次返回。请注意以下代码中的注释。

我的博客文章:http://datashaman.github.io/2014/01/26/horizontal-stacked-bar-chart-d3/

演示以下代码:http://bl.ocks.org/datashaman/8621955

jsFiddle:http://jsfiddle.net/datashaman/rBfy5/2/

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <style>
        .bar {
        }
        .axis path,
        .axis line {
            fill: none;
            stroke: black;
            shape-rendering: crispEdges;
        }
        .axis text {
            font-family: sans-serif;
            font-size: 11px;
        }

        #tooltip {
            position: absolute;
            text-align: center;
            width: 40px;
            height: auto;
            padding: 10px;
            background-color: white;
            -webkit-border-radius: 10px;
            -moz-border-radius: 10px;
            border-radius: 10px;
            -webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
            -moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
            box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
            pointer-events: none;
        }

        #tooltip.hidden {
            display: none;
        }

        #tooltip p {
            margin: 0;
            font-family: sans-serif;
            font-size: 16px;
            line-height: 20px;
        }
        </style>
    </head>
    <body>
        <script src="http://d3js.org/d3.v3.min.js"></script>

        <div id="tooltip" class="hidden">
            <p><span id="value">100</span></p>
        </div>

        <script>
        var margins = {
                top: 12,
                left: 48,
                right: 24,
                bottom: 24
            },
            legendPanel = {
                width: 240
            },
            width = 700 - margins.left - margins.right - legendPanel.width,
            height = 100 - margins.top - margins.bottom,
            dataset = [
                {
                    data: [
                        { month: 'Aug', count: 123 },
                        { month: 'Sep', count: 234 },
                        { month: 'Oct', count: 345 }
                    ],
                    name: 'Series #1'
                },
                {
                    data: [
                        { month: 'Aug', count: 235 },
                        { month: 'Sep', count: 267 },
                        { month: 'Oct', count: 573 }
                    ],
                    name: 'Series #2'
                }

            ],
            series = dataset.map(function(d) { return d.name; }),
            dataset = dataset.map(function(d) {
                return d.data.map(function(o, i) {
                    // Structure it so that your numeric
                    // axis (the stacked amount) is y
                    return {
                        y: o.count,
                        x: o.month
                    };
                });
            }),
            stack = d3.layout.stack();

        stack(dataset);

        var dataset = dataset.map(function(group) {
            return group.map(function(d) {
                // Invert the x and y values, and y0 becomes x0
                return {
                    x: d.y,
                    y: d.x,
                    x0: d.y0
                };
            });
        }),
        svg = d3.select('body')
            .append('svg')
                .attr('width', width + margins.left + margins.right + legendPanel.width)
                .attr('height', height + margins.top + margins.bottom)
            .append('g')
                .attr('transform', 'translate(' + margins.left + ',' + margins.top + ')'),
        xMax = d3.max(dataset, function(group) {
            return d3.max(group, function(d) {
                return d.x + d.x0;
            });
        }),
        xScale = d3.scale.linear()
            .domain([0, xMax])
            .range([0, width]),
        months = dataset[0].map(function(d) { return d.y; }),
        _ = console.log(months),
        yScale = d3.scale.ordinal()
            .domain(months)
            .rangeRoundBands([0, height], .1),
        xAxis = d3.svg.axis()
            .scale(xScale)
            .orient('bottom'),
        yAxis = d3.svg.axis()
            .scale(yScale)
            .orient('left'),
        colours = d3.scale.category10(),
        groups = svg.selectAll('g')
            .data(dataset)
            .enter()
            .append('g')
                .style('fill', function(d, i) {
                    return colours(i);
                }),
        rects = groups.selectAll('rect')
            .data(function(d) { return d; })
            .enter()
                .append('rect')
                    .attr('x', function(d) { return xScale(d.x0); })
                    .attr('y', function(d, i) { return yScale(d.y); })
                    .attr('height', function(d) { return yScale.rangeBand(); })
                    .attr('width', function(d) { return xScale(d.x); })
                    .on('mouseover', function(d) {
                        var xPos = parseFloat(d3.select(this).attr('x')) / 2 + width / 2;
                        var yPos = parseFloat(d3.select(this).attr('y')) + yScale.rangeBand() / 2;

                        d3.select('#tooltip')
                            .style('left', xPos + 'px')
                            .style('top', yPos + 'px')
                            .select('#value')
                            .text(d.x);

                        d3.select('#tooltip').classed('hidden', false);
                    })
                    .on('mouseout', function() {
                        d3.select('#tooltip').classed('hidden', true);
                    })

        svg.append('g')
            .attr('class', 'axis')
            .attr('transform', 'translate(0,' + height + ')')
            .call(xAxis);

        svg.append('g')
            .attr('class', 'axis')
            .call(yAxis);

        svg.append('rect')
            .attr('fill', 'yellow')
            .attr('width', 160)
            .attr('height', 30 * dataset.length)
            .attr('x', width + margins.left)
            .attr('y', 0);

        series.forEach(function(s, i) {
            svg.append('text')
                .attr('fill', 'black')
                .attr('x', width + margins.left + 8)
                .attr('y', i * 24 + 24)
                .text(s);
            svg.append('rect')
                .attr('fill', colours(i))
                .attr('width', 60)
                .attr('height', 20)
                .attr('x', width + margins.left + 90)
                .attr('y', i * 24 + 6);
        });
    </script>
</body>
</html>

答案 1 :(得分:-1)

尝试Frank Guerino的例子: http://bl.ocks.org/2141479 - 水平条形图 和 http://bl.ocks.org/2354192 - 多个D3自上而下自下而上堆积条形图(不含d3.layout.stack) 将水平代码与Crimea示例或Multiple D3 Top Down示例相结合,您应该在轨道上。主要是你需要寻找的是如何在水平设置中计算坐标。其余的与其他堆栈示例相同。 最好的问候!