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

现在,我正致力于按州对电动汽车 5 年的数据进行可视化。每个州的颜色会根据特定年份注册的电动汽车数量而变化。

问题 :

每次我点击下拉菜单中的 year 时,它​​都会在它下面创建另一个 map svg。我怎样才能让它在同一个(现有的) map svg 上重新渲染数据?

背景:

我有定义 svg 尺寸的全局变量。我也有两个功能:

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

  • 到目前为止我尝试过的:

    console.log(year) 在 d3 color.domain 方法之后,正确的年份在那时被存储为年份变量。

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

    我的代码:
    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();
    

    感谢您的输入。

    最佳答案

    您的主要问题是您在 drawMap 函数中做了太多事情。里面的很多东西只需要做一次,而不是每次你切换几年。这就是为什么你会得到多张 map 。每次调用 drawMap 时,此代码都会创建一个新的 svg

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

    如果你只是把它移出 drawMap 函数,你只会得到一个 svg。

    每次绘制 map 时,您也会获得“us-states.json”文件。这在技术上可能会起作用,但会导致许多您真正不需要的缓慢网络请求。只需在页面加载时发出一次请求。这是对您的代码的一个相当大的重组更改,因为基本上之后的所有内容都需要从回调中调用。

    最后,进行这些更改后,您需要更改绘制状态的代码,以使它们正确更新。现在,您可以在“输入”选择上执行所有操作,这只会在新路径上运行。由于您将编辑现有路径,因此您的代码需要看起来更像这样:
    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 函数保持较小。

    关于javascript - D3 - 在美国 map 上呈现多年值(value)的州数据,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36897494/

    10-11 13:55