D3 - 渲染多年'美国地图上的国家数据价值

时间:2016-04-27 18:00:39

标签: javascript jquery json d3.js svg

我是编程新手,我一直在使用O' Reilly 交互式数据可视化一书中的示例。

现在,我正在研究5年的可视化问题。国家对电动汽车的数据。每个州的颜色根据特定年份的注册电动车辆数量而变化。

问题

每次我点击下拉菜单中的year,它都会在其下方创建另一个地图svg。如何让它在同一(现有)地图svg上重新渲染数据?

背景

我有全局变量来定义svg的维度。我还有两个功能:

  • drawMap有一个year参数并构建svg,将数据从csv加载到us_map.json,并创建所有状态边界。
  • clickEventMap将事件侦听器附加到每个年份按钮,然后调用drawMap函数,该函数通过与按钮上的年份匹配的年份。最后,我致电drawMap(2013),以便页面默认为2013年数据,然后致电clickEventMap()

到目前为止我尝试了什么:

在p3 console.log(year)方法之后

color.domain,并且正确的年份在此时存储为年变量。

此外,如果我在调用drawMap()时手动更改参数,我可以成功更改现有地图上呈现的数据。

我的代码:

var w = 1200;
var h = 800;
var barpadding = 1;

var drawMap = function(year) {

  var svg = d3.select("body")
  .append("svg")
  .attr("height", h)
  .attr("width", w);

  var projection = d3.geo.albersUsa()
                         .translate([w/2, h/2]) 
                         .scale([1600]);   

  var path = d3.geo.path()
                   .projection(projection);

  var color = d3.scale.quantize()   
                    .range(["rgb(237, 248, 233)", "rgb(186, 228, 179)", "rgb(116,196,118)", "rgb(49, 163, 84)", "rgb(0, 109, 44)"]);


  color.domain([
    d3.min(data, function(d) {return d["electric_vehicles_" + year];}),
    d3.max(data, function(d) { return d["electric_vehicles_" + year];})

  ]);

  console.log(year);

  d3.json("us-states.json", function(json) {  
    for (var i = 0; i < data.length; i ++) {  
      var dataState = data[i].state;         
      var dataValue = parseFloat(data[i]["electric_vehicles_" + year]);  
      for (var j = 0; j < json.features.length; j++) {   
        var jsonState = json.features[j].properties.name;
        if (dataState === jsonState) {                    
          json.features[j].properties.value = dataValue;
          break;
        }
      }
    }

    var stateView = function() {
    console.log("State clicked.");
    location.href="/states/1";  

    svg.selectAll("path")
      .data(json.features)
      .enter()
      .append("path")
      .attr("d", path)
      .style("fill", function(d) {
        var value = d.properties.value;
        if (value) {
          return color(value);
        }
        else {
          return "#ccc";
        }
      })
      .on("mouseover", function(d, i) {
        d3.select(this)
        .style("fill-opacity", 0.5);
      })
      .on("mouseout", function(d, i) {
        d3.selectAll("path")
        .style("fill-opacity", 1);
      })
      .on("click", function() {
        stateView();
      });
  });
});
};

var clickEventMap = function() {
  $("#map2013").on("click", function() {
    // var year = 2013;
    drawMap(2013);
  });

  $("#map2012").on("click", function() {
    // var year = 2012;
    drawMap(2012);
  });

  $("#map2011").on("click", function() {
    // var year = 2011;
    drawMap(2011);
  });

  $("#map2010").on("click", function() {
    // var year = 2010;
    drawMap(2010);
  });

  $("#map2009").on("click", function() {
    // var year = 2009;
    drawMap(2009);
  });
};

drawMap(2013);
clickEventMap();

感谢您的意见。

1 个答案:

答案 0 :(得分:0)

您的主要问题是您在drawMap功能中做得太多了。很多东西只需要做一次,而不是每次切换多年。这就是您获得多个地图的原因。每次调用drawMap

时,此代码都会创建一个新的svg
var svg = d3.select("body")
  .append("svg")
  .attr("height", h)
  .attr("width", w);

如果你只是将其移出drawMap函数,你将只获得一个svg。

你也得到了&#39; us-states.json&#39;每次绘制地图时都会生成文件。这可能在技术上有效,但会导致许多您真正不需要的慢速网络请求。只需在页面加载时发出一次请求。这对您的代码来说是一次非常重大的重组更改,因为基本上所有内容都需要在回调中调用。

最后,在进行这些更改后,您需要更改绘制状态的代码以使其正确更新。现在,您可以在&#34;输入&#34;选择,只能在新路径上运行。由于您将编辑现有路径,因此您的代码需要看起来更像这样:

var paths = svg.selectAll("path")
    .data(json.features)
    .enter()
    .append("path")
    .attr("d", path)
    .on("mouseover", function(d, i) {
        d3.select(this)
            .style("fill-opacity", 0.5);
    })
    .on("mouseout", function(d, i) {
        d3.selectAll("path")
            .style("fill-opacity", 1);
    })
    .on("click", function() {
        stateView();
    });

paths.style("fill", function(d) {
    var value = d.properties.value;
    if (value) {
        return color(value);
    } else {
        return "#ccc";
    }
});

Mike Bostocks的文章Thinking with JoinsThree Little Circles都是了解d3更新的重要资源。

基本上,只考虑一下你需要做什么,以及每次点击新年时需要改变什么(更新你的色标和为每个州设置填充样式)。尝试将曾经发生过的所有内容都拉到init函数中,并使drawMap函数保持较小。