【问题标题】:Dynamically adjust bubble radius of counties?动态调整县域气泡半径?
【发布时间】:2015-07-11 19:10:30
【问题描述】:

按照县气泡示例,为每个县添加气泡很容易。示例中是这样添加的:

svg.append("g")
      .attr("class", "bubble")
    .selectAll("circle")
      .data(topojson.feature(us, us.objects.counties).features
        .sort(function(a, b) { return b.properties.population - a.properties.population;     }))
    .enter().append("circle")
      .attr("transform", function(d) { return "translate(" + path.centroid(d) + ")"; })
      .attr("r", function(d) { return radius(d.properties.population); })
    .append("title")
      .text(function(d) {
        return d.properties.name
            + "\nPopulation " + formatNumber(d.properties.population);
      });

但是,我需要根据动态变化的变量更新半径,而不是使用 json 文件(人口)中的变量(因此我不能像示例中所做的那样事先将其放入 json 文件中)。单击需要访问 FIPS 的县时,我会调用 updateRadii()。

var currFIPS,
    flowByFIPS;

var g = svg.append("g");

queue()
    .defer(d3.json, "us.json")
    .defer(d3.csv, "census.csv", function(d) {
        return {
            work: +d.workplace,
            home: +d.residence,
            flow: +d.flow
        }
    })
    .await(ready);

function ready(error, us, commute) {
    // Counties
    g.append("g")
        .attr("class", "counties")
      .selectAll("path")
        .data(topojson.feature(us, us.objects.counties).features)
      .enter().append("path")
        .attr("d", path)
        .on("click", function(d) {
            // Get FIPS of selected county
            currFIPS = d.id;

            // Filter on selected county (i.e., grab
            // people who work in the selected county)
            var data = commute.filter(function(d) { 
                return d.work == currFIPS;
            });

            // Create d3.map for where these people live
            flowByFIPS = d3.map(data, function(d) { 
                return d.home;
            });

            // Update radii at "home" counties to reflect flow
            updateRadii();
        });

    // Bubbles
    g.append("g")
        .attr("class", "counties")
      .selectAll("circle")
        .data(topojson.feature(us, us.objects.counties).features)
      .enter().append("circle")
        .attr("id", function(d) { return d.id; })
        .attr("transform", function(d) { 
            return "translate(" + path.centroid(d) + ")"; 
        })
        .attr("r", 0);  // invisible before a county is clicked
}

function updateRadii() {
    svg.selectAll(".counties circle")
        .transition()
        .duration(300)
        .attr("r", function(d) { 
            return flowByFIPS.get(d.id).flow 
        });
}

根据错误代码,我认为圆圈没有附加 id(FIPS 代码)。我如何让他们有一个身份证? (我尝试使用.each 将圆圈与路径嵌套,如answer 中所述,但无法正常工作。)

请注意,上面的代码适用于更新路径(而不是圆圈)上的填充。例如,子updateRadii();updateFill();,函数为:

function updateFill() {
    svg.selectAll(".counties path")
        .transition()
        .duration(300)
        .attr("fill", function(d) { 
            return flowByFIPS.get(d.id).color;  // e.g., "#444"
        });
}

【问题讨论】:

    标签: d3.js


    【解决方案1】:

    这里的问题是您没有在更新函数中为 d3 提供数据。我会建议您在点击时更新从文件加载的数据,然后从那里更新 svg。

    var update = function() {
      g.selectAll(".country")
      .data(data)
      .attr("r", function(d) { return d.properties.flow_pct });
    };
    
    var data = topojson.feature(us, us.objects.counties).features;
    data.forEach(function(x) { x.properties.flow_pct = /* calc the value */; })
    
    g.append("g")
    .attr("class", "counties")
    .selectAll(".country")
    .data(data)
    .enter()
      .append("circle")
      .attr("class", "country")
      .attr("transform", function(d) { 
        return "translate(" + path.centroid(d) + ")"; 
      })
      .on("click", function(d) {
    
        // more code
        data.forEach(function(x) { x.properties.flow_pct = /* calc the NEW value */; })
    
        update();
      });
    
    update();
    

    我已尝试使用与以前一样多的代码,但仍试图将其限制一下。该流程现在更像 d3,因为更新功能适用于更改的数据。

    这种方法的另一个优点是首次渲染和未来更新使用相同的逻辑来查找半径。

    【讨论】:

    • 感谢您的尝试。我认为data 的编写方式仍然只是 json 文件,其中没有 flow_pct。我会更新问题以使事情更清楚。
    • 实际上,当 json 被解析时,它就变成了另一个 javascript 对象。 data.forEach(function(x) { x.properties.flow_pct = /* calc the value */; }) 将使用您喜欢的 flow_pct 来丰富数据。
    • 啊,好吧。 flow_pct 被点击过滤。我添加了更多的细节。也许我的问题会更清楚。 (请注意,例如,我将 flow_pct 简化为 flow。)
    【解决方案2】:

    事实证明这是一个显而易见的解决方案。我忘了检查不存在流的情况。如果将updateRadii() 更改为以下代码,则上面的代码有效:

    function updateRadii() {
        svg.selectAll(".counties circle")
            .transition()
            .duration(300)
            .attr("r", function(d) {
                if (currFIPS == d.id) {
                    return 0;
                }
    
                var county = flowByFIPS.get(d.id);
    
                if (typeof county === "undefined") {
                    return 0;
                } else {
                    return county.flow; 
                }
            });
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-06
      • 1970-01-01
      • 2016-03-25
      • 2017-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-26
      相关资源
      最近更新 更多