为什么图形D3.js上的条形显示顺序不正确?

时间:2019-12-12 18:49:38

标签: javascript d3.js

我无法创建并排的条形图。

我将在这里放置我的代码和一张图像,这些图像以不同的颜色并排放置。我是D3.js的新手,不知道为什么会这样。

现在的图表:

enter image description here

在我的jsonFile中,我有两个推销员,其中显示了每个推销员的销售历史。例如,我需要在一月份显示卖方A和卖方B的上一年的销售历史记录,但是正如您在上图中所看到的,这不是正在发生的情况。酒吧在错误的地方。

我的HTML代码:

.
var sales = [
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Jan",
        "Vendas_Ano": 21611.950000000004,
        "Vendas_Ant": 16033.31
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Fev",
        "Vendas_Ano": 48108.08,
        "Vendas_Ant": 51142.299999999996
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Mar",
        "Vendas_Ano": 13427.280000000004,
        "Vendas_Ant": 21274.129999999997
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Apr",
        "Vendas_Ano": 28553.83,
        "Vendas_Ant": 15228.569999999998
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Mai",
        "Vendas_Ano": 19639.59,
        "Vendas_Ant": 10291.359999999999
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Jun",
        "Vendas_Ano": 22530.840000000007,
        "Vendas_Ant": 21905.29
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Jul",
        "Vendas_Ano": 20216.759999999995,
        "Vendas_Ant": 8276
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Ago",
        "Vendas_Ano": 39832.04,
        "Vendas_Ant": 49810.810000000005
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Set",
        "Vendas_Ano": 12861.52,
        "Vendas_Ant": 24425.32
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Out",
        "Vendas_Ano": 9227.34,
        "Vendas_Ant": 17804.65
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Nov",
        "Vendas_Ano": 0,
        "Vendas_Ant": 9993.34
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Dez",
        "Vendas_Ano": 0,
        "Vendas_Ant": 36568.7
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Jan",
        "Vendas_Ano": 22681.14,
        "Vendas_Ant": 28587.71
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Fev",
        "Vendas_Ano": 31382.11,
        "Vendas_Ant": 37637.420000000006
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Mar",
        "Vendas_Ano": 32453.779999999995,
        "Vendas_Ant": 32993.12
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Apr",
        "Vendas_Ano": 23445.4,
        "Vendas_Ant": 30835.75
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Mai",
        "Vendas_Ano": 16471.71,
        "Vendas_Ant": 18028.07
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Jun",
        "Vendas_Ano": 11617.470000000001,
        "Vendas_Ant": 22651.53
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Jul",
        "Vendas_Ano": 24699.44,
        "Vendas_Ant": 34152.28999999999
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Ago",
        "Vendas_Ano": 35476.94000000001,
        "Vendas_Ant": 22069.699999999997
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Set",
        "Vendas_Ano": 37462.92,
        "Vendas_Ant": 23120.08
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Out",
        "Vendas_Ano": 22042.140000000003,
        "Vendas_Ant": 28449.95
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Nov",
        "Vendas_Ano": 0,
        "Vendas_Ant": 30755.050000000003
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Dez",
        "Vendas_Ano": 0,
        "Vendas_Ant": 22838.64
    }
]
var charnecaData = [];
    var joaoData = [];

    for (var i = 0; i < sales.length; i++) {
        if (sales[i]["vendnm"] === "CHARNECA") {
            charnecaData.push(sales[i]);
        } else {
            joaoData.push(sales[i]);
        }
    }

    //functions for toggling between data
    function change(value) {
        if (value === 'lastYear') {
            update(charnecaData);
        } else if (value === 'currentYear') {
            update(joaoData);
        } else {
            update(sales);
        }
    }

    function update(data) {

        xChart.domain(data.map(function (d) { return d.MonthAbrev; }));

        yChart.domain([0, d3.max(data, function (d) { return +d.Vendas_Ant; })]);

        var barWidth = width / data.length;

        var bars = chart.selectAll(".bar")
            .remove()
            .exit()
            .data(data)

        bars.enter()
            .append("rect")
            .attr("class", "bar")
            .attr("x", function (d, i) { return i * barWidth + 1 })
            .attr("y", function (d) { return yChart(d.Vendas_Ant); })
            .attr("height", function (d) { return height - yChart(d.Vendas_Ant); })
            .attr("width", barWidth - 5)
            .attr("fill", function (d) {
                if (d.vendnm === 'CHARNECA') {
                    return "rgb(251,180,174)";
                } else {
                    return "rgb(179,205,227)";
                }
            })
            .on("mouseover", function (a) {
                chart.append("text")
                    .attr("class", "title-text")
                    .style("fill", "rgb(44, 160, 44)")
                    .text(a.vendnm + ' - ' +
                        a.MonthAbrev + ' - ' +
                        Number(Math.round(a.Vendas_Ant * 100) / 100).toLocaleString("es-ES", { minimumFractionDigits: 2 }) + '€'
                    )
                    .attr("text-anchor", "middle")
                    .attr("x", 400)
                    .attr("y", 50);
            })
            .on("mouseout", function (a) {
                chart.select(".title-text").remove();
            })

        //left axis
        chart.select('.y')
            .call(yAxis)
        //bottom axis
        chart.select('.xAxis')
            .attr("transform", "translate(0," + height + ")")
            .call(xAxis)
            .selectAll("text")
            .style("text-anchor", "end")
            .attr("dx", "-.8em")
            .attr("dy", ".15em")
            .attr("transform", function (d) {
                return "rotate(-65)";
            });

    }//end update

    var margin = { top: 20, right: 20, bottom: 30, left: 50 };
    var width = 600;
    var height = 300;

    var chart = d3.select(".chart")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    var xChart = d3.scaleBand()
        .range([0, width]);

    var yChart = d3.scaleLinear()
        .range([height, 0]);

    var xAxis = d3.axisBottom(xChart);
    var yAxis = d3.axisLeft(yChart);

    chart.append("g")
        .attr("class", "y axis")
        .call(yAxis)

    chart.append("g")
        .attr("class", "xAxis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis)
        .selectAll("text")
        .style("text-anchor", "end")
        .attr("dx", "-.8em")
        .attr("dy", ".15em")
        .attr("transform", function (d) {
            return "rotate(-65)";
        });

    update(sales);

正如我所说的,我是D3.js的新手,我正在根据以下代码进行此测试:https://bl.ocks.org/syncopika/f1c9036b0deb058454f825238a95b6be

我已经对其进行了多次比较,以了解自己在做什么错,但我无法解决问题。

预先感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

首先scaleBand()具有为每个点提供宽度的功能:

var barWidth = xChart.bandwidth()/2;

然后,您需要使用xChart()函数来获取每个数据点的x坐标,而不是根据特定数据点的索引进行计算。

稍加调整坐标,最终结果将归结为以下代码行:

        .attr("x", function (d, i) { return xChart(d.MonthAbrev) + barWidth*((d.vendnm == 'CHARNECA')?0.2:1) })

我希望这会有所帮助,如果不是您要的内容,请告诉我。

var sales = [
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Jan",
        "Vendas_Ano": 21611.950000000004,
        "Vendas_Ant": 16033.31
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Fev",
        "Vendas_Ano": 48108.08,
        "Vendas_Ant": 51142.299999999996
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Mar",
        "Vendas_Ano": 13427.280000000004,
        "Vendas_Ant": 21274.129999999997
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Apr",
        "Vendas_Ano": 28553.83,
        "Vendas_Ant": 15228.569999999998
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Mai",
        "Vendas_Ano": 19639.59,
        "Vendas_Ant": 10291.359999999999
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Jun",
        "Vendas_Ano": 22530.840000000007,
        "Vendas_Ant": 21905.29
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Jul",
        "Vendas_Ano": 20216.759999999995,
        "Vendas_Ant": 8276
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Ago",
        "Vendas_Ano": 39832.04,
        "Vendas_Ant": 49810.810000000005
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Set",
        "Vendas_Ano": 12861.52,
        "Vendas_Ant": 24425.32
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Out",
        "Vendas_Ano": 9227.34,
        "Vendas_Ant": 17804.65
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Nov",
        "Vendas_Ano": 0,
        "Vendas_Ant": 9993.34
    },
    {
        "vendnm": "CHARNECA",
        "MonthAbrev": "Dez",
        "Vendas_Ano": 0,
        "Vendas_Ant": 36568.7
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Jan",
        "Vendas_Ano": 22681.14,
        "Vendas_Ant": 28587.71
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Fev",
        "Vendas_Ano": 31382.11,
        "Vendas_Ant": 37637.420000000006
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Mar",
        "Vendas_Ano": 32453.779999999995,
        "Vendas_Ant": 32993.12
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Apr",
        "Vendas_Ano": 23445.4,
        "Vendas_Ant": 30835.75
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Mai",
        "Vendas_Ano": 16471.71,
        "Vendas_Ant": 18028.07
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Jun",
        "Vendas_Ano": 11617.470000000001,
        "Vendas_Ant": 22651.53
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Jul",
        "Vendas_Ano": 24699.44,
        "Vendas_Ant": 34152.28999999999
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Ago",
        "Vendas_Ano": 35476.94000000001,
        "Vendas_Ant": 22069.699999999997
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Set",
        "Vendas_Ano": 37462.92,
        "Vendas_Ant": 23120.08
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Out",
        "Vendas_Ano": 22042.140000000003,
        "Vendas_Ant": 28449.95
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Nov",
        "Vendas_Ano": 0,
        "Vendas_Ant": 30755.050000000003
    },
    {
        "vendnm": "JOÃO LUIS",
        "MonthAbrev": "Dez",
        "Vendas_Ano": 0,
        "Vendas_Ant": 22838.64
    }
]
var charnecaData = [];
    var joaoData = [];

    for (var i = 0; i < sales.length; i++) {
        if (sales[i]["vendnm"] === "CHARNECA") {
            charnecaData.push(sales[i]);
        } else {
            joaoData.push(sales[i]);
        }
    }

    //functions for toggling between data
    function change(value) {
        if (value === 'lastYear') {
            update(charnecaData);
        } else if (value === 'currentYear') {
            update(joaoData);
        } else {
            update(sales);
        }
    }

    function update(data) {

        xChart.domain(data.map(function (d) { return d.MonthAbrev; }));

        yChart.domain([0, d3.max(data, function (d) { return +d.Vendas_Ant; })]);

        var barWidth = xChart.bandwidth()/2;

        var bars = chart.selectAll(".bar")
            .remove()
            .exit()
            .data(data)

        bars.enter()
            .append("rect")
            .attr("class", "bar")
            .attr("x", function (d, i) { return xChart(d.MonthAbrev) + barWidth*((d.vendnm == 'CHARNECA')?0.2:1) })
            .attr("y", function (d) { return yChart(d.Vendas_Ant); })
            .attr("height", function (d) { return height - yChart(d.Vendas_Ant); })
            .attr("width", barWidth - 5)
            .attr("fill", function (d) {
                if (d.vendnm === 'CHARNECA') {
                    return "rgb(251,180,174)";
                } else {
                    return "rgb(179,205,227)";
                }
            })
            .on("mouseover", function (a) {
                //console.log(a)
                chart.append("text")
                    .attr("class", "title-text")
                    .style("fill", "rgb(44, 160, 44)")
                    .text(a.vendnm + ' - ' +
                        a.MonthAbrev + ' - ' +
                        Number(Math.round(a.Vendas_Ant * 100) / 100).toLocaleString("es-ES", { minimumFractionDigits: 2 }) + '€'
                    )
                    .attr("text-anchor", "middle")
                    .attr("x", 400)
                    .attr("y", 50);
            })
            .on("mouseout", function (a) {
                chart.select(".title-text").remove();
            })

        //left axis
        chart.select('.y')
            .call(yAxis)
        //bottom axis
        chart.select('.xAxis')
            .attr("transform", "translate(0," + height + ")")
            .call(xAxis)
            .selectAll("text")
            .style("text-anchor", "end")
            .attr("dx", "-.8em")
            .attr("dy", ".15em")
            .attr("transform", function (d) {
                return "rotate(-65)";
            });

    }//end update

    var margin = { top: 20, right: 20, bottom: 30, left: 50 };
    var width = 600;
    var height = 300;

    var chart = d3.select(".chart")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    var xChart = d3.scaleBand()
        .range([0, width]);

    var yChart = d3.scaleLinear()
        .range([height, 0]);

    var xAxis = d3.axisBottom(xChart);
    var yAxis = d3.axisLeft(yChart);

    chart.append("g")
        .attr("class", "y axis")
        .call(yAxis)

    chart.append("g")
        .attr("class", "xAxis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis)
        .selectAll("text")
        .style("text-anchor", "end")
        .attr("dx", "-.8em")
        .attr("dy", ".15em")
        .attr("transform", function (d) {
            return "rotate(-65)";
        });

    update(sales);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<head>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
</head>

<style>
    .radio {
        text-align: center;
    }

    .row {
        text-align: center;
    }
</style>

<body>

    <div class='container'>
        <div class='row'>
            <div class='radio'>
                <label class='radio-inline'>
                    <input type="radio" name="gender" value="lastYear" onclick='change(this.value)'> Last Year
                </label>
                <label class='radio-inline'>
                    <input type="radio" name="gender" value="currentYear" onclick='change(this.value)'> Current Year
                </label>
                <label class='radio-inline'>
                    <input type="radio" name="gender" value="both" onclick='change(this.value)' checked> Both
                </label>
            </div>
            <svg class='chart'>
            </svg>
        </div>
    </div>
</body>