【问题标题】:Update rect width when changing data size更改数据大小时更新矩形宽度
【发布时间】:2021-10-25 16:19:47
【问题描述】:

我正在尝试实现这个条形图示例https://bl.ocks.org/LemoNode/73dbb9d6a144476565386f48a2df2e3b。但是,我没有一年中每个月的数据,而是 2021 年的数据,直到当前月份。即八月和前几年我有所有月份的数据。当我通过选择年份触发更新功能时,条形宽度没有更新(见下图)。

我尝试过使用 x 域函数,但没有成功。任何提示将不胜感激。

这里是复制我的问题的 plnkr(请单击预览按钮并更改年份以重现问题):

https://plnkr.co/edit/kou3SFerDMTeKkkM?open=lib%2Fscript.js

<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>   
<style>

body {
    padding-top: 25px;
    margin: auto;
    width: 650px;
    font: 18px arial;
}   

</style>
</head>

<body>

<b>Dynamic bar-chart example.</b>
<svg id="chart" width="650" height="420"></svg>

Choose year: 
<select id="year"></select>

<input type="checkbox" id="sort">   
Toggle sort 

<script>

d3.csv("data.csv").then(d => chart(d));

function chart(csv) {

    csv.forEach(function(d) {
        var dates = d.date.split("-");
        d.year = dates[0]; d.month = dates[1];
        d.value = +d.value;
        return d;
    })

    var months = [...new Set(csv.map(d => d.month))],
        years  = [...new Set(csv.map(d => d.year))];

    var options = d3.select("#year").selectAll("option")
        .data(years)
    .enter().append("option")
        .text(d => d)

    var svg = d3.select("#chart"),
        margin = {top: 25, bottom: 10, left: 25, right: 25},
        width = +svg.attr("width") - margin.left - margin.right,
        height = +svg.attr("height") - margin.top - margin.bottom;

    var x = d3.scaleBand()
        .range([margin.left, width - margin.right])
        .padding(0.1)
        .paddingOuter(0.2)
    
    var y = d3.scaleLinear()
        .range([height - margin.bottom, margin.top])

    var xAxis = g => g
        .attr("transform", "translate(0," + (height - margin.bottom) + ")")
        .call(d3.axisBottom(x).tickSizeOuter(0))

    var yAxis = g => g
        .attr("transform", "translate(" + margin.left + ",0)")
        .call(d3.axisLeft(y))

    svg.append("g")
        .attr("class", "x-axis")

    svg.append("g")
        .attr("class", "y-axis")

    update(d3.select("#year").property("value"), 0)

    function update(year, speed) {

        var data = csv.filter(f => f.year == year)
    
        y.domain([0, d3.max(data, d => d.value)]).nice()

        svg.selectAll(".y-axis").transition().duration(speed)
            .call(yAxis);

        data.sort(d3.select("#sort").property("checked")
            ? (a, b) => b.value - a.value
            : (a, b) => months.indexOf(a.month) - months.indexOf(b.month))

        x.domain(data.map(d => d.month))

        svg.selectAll(".x-axis").transition().duration(speed)
            .call(xAxis)

        var bar = svg.selectAll(".bar")
            .data(data, d => d.month)

        bar.exit().remove();

        bar.enter().append("rect")
            .attr("class", "bar")
            .attr("fill", "steelblue")
            .attr("width", x.bandwidth())
            .merge(bar)
        .transition().duration(speed)
            .attr("x", d => x(d.month))
            .attr("y", d => y(d.value))
            .attr("height", d => y(0) - y(d.value))
    }

    chart.update = update;
}

var select = d3.select("#year")
    .style("border-radius", "5px")
    .on("change", function() {
        chart.update(this.value, 750)
    })

var checkbox = d3.select("#sort")
    .style("margin-left", "45%")
    .on("click", function() {
        chart.update(select.property("value"), 750)
    })

</script>
</body>

【问题讨论】:

    标签: javascript d3.js bar-chart


    【解决方案1】:

    目前你有:

    bar.enter().append("rect")
        .attr("class", "bar")
        .attr("fill", "steelblue")
        .attr("width", x.bandwidth())
        .merge(bar)
      .transition().duration(speed)
        .attr("x", d => x(d.month))
        .attr("y", d => y(d.value))
        .attr("height", d => y(0) - y(d.value))
    

    您只是设置新矩形的宽度。 2019 年数据集中的月份比 2018 年多,因此 2019 年的 x.bandwidth() 小于 2018 年。这意味着您还需要更新现有矩形的宽度。所以你只需要在合并后移动更新宽度的行:

    bar.enter().append("rect")
        .attr("class", "bar")
        .attr("fill", "steelblue")
        .merge(bar)
      .transition().duration(speed)
        .attr("width", x.bandwidth())
        .attr("x", d => x(d.month))
        .attr("y", d => y(d.value))
        .attr("height", d => y(0) - y(d.value))
    

    另外,我建议您查看join,而不是使用进入/合并/退出。使用起来更容易。

    【讨论】:

    • 谢谢丹,非常感谢您的解释。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-27
    • 2014-05-02
    • 1970-01-01
    • 1970-01-01
    • 2018-08-25
    • 1970-01-01
    • 2021-12-24
    相关资源
    最近更新 更多