D3.js贴图:一个接一个地改变路径的颜色

时间:2018-03-17 18:44:50

标签: animation d3.js maps

我制作了一张d3.js的地图,现在我想一个接一个地为几个国家着色:

  • 在1 seconde,我希望西班牙可以说是红色,
  • 1.5秒,法国应该是红色(西班牙应保持红色)
  • 在2秒时,德国应该是红色的(西班牙和法国应保持红色)

到目前为止,我可以立刻改变所有国家的颜色。我尝试按照.transition().delay(500)尝试做我想做的事,但它没有用。

到目前为止,这是我的代码:



<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script>
<script>
    var w = 1000;
    var h = 550;

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

    var path = d3.geoPath()
        .projection(d3.geoMercator()
        //.scale(0) 
        //.translate([200, 2100])
        );

    var countries_visited= ['Spain','France','Germany','Poland', 'Finland'] 
    d3.json(
        "https://raw.githubusercontent.com/johan/world.geo.json/master/countries.geo.json",
        function (error, json) {

            //draw svg lines of the boundries
            svg.append("g")
                .attr("class", "black")
                .selectAll("path")
                .data(json.features)
                .enter()
                .append("path")
                .attr("d", path)
                .attr('fill', '#e7d8ad');;

            d3.timeout(function() { 
                d3.selectAll('path')
                //.transition().delay(500)  //should color countries, one after the other
                .attr('fill', colorCountry);
            }, 500);
        }
    );

    function colorCountry(country){
        if (countries_visited.includes(country.properties.name)) {
            return '#c8b98d';
        } else {  // why do I need a else (otherwise set to black
            return '#e7d8ad';
        };

    };
</script>
</body>
&#13;
&#13;
&#13;

作为一个附带问题:为什么我需要colorCountry中的else语句?如果我不添加fill

,国家/地区else会发生变化的原因

2 个答案:

答案 0 :(得分:3)

以下是您的代码的略微修改版本,它一个接一个地显示访问过的国家/地区:

<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script>
<script>

  var w = 1000;
  var h = 550;

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

  var path = d3.geoPath().projection(d3.geoMercator());

  var countries_visited = ['Spain','France','Germany','Poland', 'Finland'];

  d3.json(
    "https://raw.githubusercontent.com/johan/world.geo.json/master/countries.geo.json",
    function (error, json) {

      svg.append("g")
        .attr("class", "black")
        .selectAll("path")
        .data(json.features)
        .enter()
        .append("path")
        .attr("id", function(d) { return d.properties.name; })
        .attr("d", path)
        .attr('fill', '#e7d8ad');

      var delay = 1000;

      countries_visited.forEach( country => {
        d3.selectAll('#' + country)
          .transition().delay(delay)
          .attr('fill', '#c8b98d');
        delay += 500;
      });
    }
  );

</script>
</body>

它包括创建几个独立的过渡。每个访问过的国家一个:

var delay = 1000;

countries_visited.forEach( country => {
  d3.selectAll('#' + country)
    .transition().delay(delay)
    .attr('fill', '#c8b98d');
  delay += 500;
});

每次过渡都有延迟,这会延迟国家的颜色。而且这是过渡本身的创造,增加了申请下一个国家的延迟。

我为每个路径(国家/地区)添加了id,以便在转换过程中轻松选择它并应用新颜色。这是一种回答方问题的方法,只需选择要修改的元素,我们就可以修改已修改国家/地区的fill属性。

答案 1 :(得分:3)

不要从Xavier的answer中删除,你也可以通过设置函数的延迟(而不是增量)来避免使用更多d3惯用法的循环:

d3.selectAll("path")
  .filter(function(d) { return countries_visited.indexOf(d.properties.name) > -1 })
  .transition()
  .delay(function(d) { return countries_visited.indexOf(d.properties.name) * 500 + 1000; })
  .attr("fill","#c8b98d");

这看起来像:

&#13;
&#13;
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script>
<script>

  var w = 1000;
  var h = 550;

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

  var path = d3.geoPath().projection(d3.geoMercator());

  var countries_visited = ['Spain','France','Germany','Poland', 'Finland'];

  d3.json(
    "https://raw.githubusercontent.com/johan/world.geo.json/master/countries.geo.json",
    function (error, json) {

      svg.append("g")
        .attr("class", "black")
        .selectAll("path")
        .data(json.features)
        .enter()
        .append("path")
        .attr("id", function(d) { return d.properties.name; })
        .attr("d", path)
        .attr('fill', '#e7d8ad');

        d3.selectAll("path")
          .filter(function(d) { return countries_visited.indexOf(d.properties.name) > -1 })
          .transition()
          .delay(function(d) { return countries_visited.indexOf(d.properties.name) * 500 + 1000; })
          .attr("fill","#c8b98d");

 
  });

</script>
</body>
&#13;
&#13;
&#13;