javascript - 需要帮助从数组中为国家/地区着色,保留其余默认颜色

标签 javascript d3.js colors

我需要一些帮助,从我创建的数组中获取数据,然后仅对数组中存在的国家/地区进行着色,而不在数组中的其余国家/地区我希望保留为默认颜色。我正在使用 D3 来完成所有这些工作,并且我非常确定我可以通过 D3 实现我需要的目标,但不确定如何实现。

我想要做的是通过 data2 数组获取国家/地区代码,并根据它们的排名将它们着色为深红色到绿色。

我的数组:

var data2 = [{name:"United Kingdom", country_code: 826, rank: 1},{name:"United States", country_code: 840, rank: 2},{name:"Sweden", country_code: 752, rank: 3},
{name:"Canada", country_code: 124, rank: 4},{name:"Germany", country_code: 276, rank: 5},{name:"South Korea", country_code: 410, rank: 6},
{name:"Australia", country_code: 036, rank: 7},{name:"Italy", country_code: 380, rank: 8},
{name:"Ireland", country_code: 372, rank: 9},{name:"Jamaica", country_code: 388, rank: 10},
{name:"India", country_code: 356, rank: 11},{name:"Mexico", country_code: 484, rank: 12},{name:"France", country_code: 250, rank: 13},
{name:" Japan", country_code: 392, rank: 14},{name:"Finland", country_code: 246, rank: 15},
{name:"Spain", country_code: 724, rank: 16},{name:"Russia", country_code: 643, rank: 17},
{name:"Philippines", country_code: 608, rank: 18},{name:"Romania", country_code: 642, rank: 19},
{name:"Ukraine", country_code: 804, rank: 20}]

目前,我只是为我的 map 着色

 var country = g.selectAll(".country").data(topo);
  country.enter().insert("path")
      .attr("class", "country")
      .attr("d", path)
      .attr("id", function(d,i) { return d.id; })
      .attr("title", function(d,i) { return d.properties.name; })
      .style("fill", function(d, i) {return d.properties.color; });

看到的问题是,我正在使用一组数据来创建 map ,并想使用另一组数据 data2 在特定国家/地区进行着色。

我尝试了以下方法,但没有成功。

var color = d3.scale.category10();
feature.data(data2.features)
             .enter().append("path")
             .attr("class", "feature")
             .attr("d", path)
             .style("fill", function (d,i) { return color(i) });

提前感谢任何提供帮助的人。

如果需要,我可以发布所有代码,但除非需要,否则我不想填满页面,

完整代码:

    <!DOCTYPE html>
<meta charset="utf-8">
<title>D3 World Map Template | TechSlides</title>
<style>
.country:hover{
  stroke: #fff;
  stroke-width: 1.5px;
}
.text{
  font-size:10px;
  text-transform:capitalize;
}
#container {
  margin:10px 10%;
  border:2px solid #000;
  border-radius: 5px;
  height:100%;
  overflow:hidden;
  background: #F0F8FF;
}
.hidden { 
  display: none; 
}
div.tooltip {
  color: #222; 
  background: #fff; 
  padding: .5em; 
  text-shadow: #f5f5f5 0 1px 0;
  border-radius: 2px; 
  box-shadow: 0px 0px 2px 0px #a6a6a6; 
  opacity: 0.9; 
  position: absolute;
}
.graticule {
  fill: none;
  stroke: #bbb;
  stroke-width: .5px;
  stroke-opacity: .5;
}
.equator {
  stroke: #ccc;
  stroke-width: 1px;
}

</style>
</head>
<body>

  <h1>World Map Template with D3.js</h1>
  <p>Responsive D3 World Map with zoom and pan limits, graticule and equator lines, optimized TopoJSON with country names and colors, geo translation functions, geo coordinate plotting functions for points and text, and much more.  For a full list of features, please go <a href="http://techslides.com/d3-map-starter-kit/">back to article</a>.</p>


  <div id="container"></div>

<script src="js/d3.min.js"></script>
<script src="js/topojson.v1.min.js"></script>
<script>
d3.select(window).on("resize", throttle);

var zoom = d3.behavior.zoom()
    .scaleExtent([1, 9])
    .on("zoom", move);


var width = document.getElementById('container').offsetWidth;
var height = width / 2;

var topo,projection,path,svg,g;

var graticule = d3.geo.graticule();

var tooltip = d3.select("#container").append("div").attr("class", "tooltip hidden");

setup(width,height);

function setup(width,height){
  projection = d3.geo.mercator()
    .translate([(width/2), (height/2)])
    .scale( width / 2 / Math.PI);

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

  svg = d3.select("#container").append("svg")
      .attr("width", width)
      .attr("height", height)
      .call(zoom)
      .on("click", click)
      .append("g");

  g = svg.append("g");

}

d3.json("data/world-topo-min.json", function(error, world) {

  var countries = topojson.feature(world, world.objects.countries).features;

  topo = countries;
  draw(topo);

});

function draw(topo) {

  svg.append("path")
     .datum(graticule)
     .attr("class", "graticule")
     .attr("d", path);


  g.append("path")
   .datum({type: "LineString", coordinates: [[-180, 0], [-90, 0], [0, 0], [90, 0], [180, 0]]})
   .attr("class", "equator")
   .attr("d", path);


  var country = g.selectAll(".country").data(topo);

  country.enter().insert("path")
      .attr("class", "country")
      .attr("d", path)
      .attr("id", function(d,i) { return d.id; })
      .attr("title", function(d,i) { return d.properties.name; });
  //offsets for tooltips
  var offsetL = document.getElementById('container').offsetLeft+20;
  var offsetT = document.getElementById('container').offsetTop+10;

  //tooltips
  country
    .on("mousemove", function(d,i) {

      var mouse = d3.mouse(svg.node()).map( function(d) { return parseInt(d); } );

      tooltip.classed("hidden", false)
             .attr("style", "left:"+(mouse[0]+offsetL)+"px;top:"+(mouse[1]+offsetT)+"px")
             .html(d.properties.name);

      })
      .on("mouseout",  function(d,i) {
        tooltip.classed("hidden", true);
      }); 


  //EXAMPLE: adding some capitals from external CSV file
  d3.csv("data/country-capitals.csv", function(err, capitals) {

    capitals.forEach(function(i){
      addpoint(i.CapitalLongitude, i.CapitalLatitude, i.CapitalName );
    });

  });

}


function redraw() {
  width = document.getElementById('container').offsetWidth;
  height = width / 2;
  d3.select('svg').remove();
  setup(width,height);
  draw(topo);
}


function move() {

  var t = d3.event.translate;
  var s = d3.event.scale; 
  zscale = s;
  var h = height/4;


  t[0] = Math.min(
    (width/height)  * (s - 1), 
    Math.max( width * (1 - s), t[0] )
  );

  t[1] = Math.min(
    h * (s - 1) + h * s, 
    Math.max(height  * (1 - s) - h * s, t[1])
  );

  zoom.translate(t);
  g.attr("transform", "translate(" + t + ")scale(" + s + ")");

  //adjust the country hover stroke width based on zoom level
  d3.selectAll(".country").style("stroke-width", 1.5 / s);

}



var throttleTimer;
function throttle() {
  window.clearTimeout(throttleTimer);
    throttleTimer = window.setTimeout(function() {
      redraw();
    }, 200);
}


//geo translation on mouse click in map
function click() {
  var latlon = projection.invert(d3.mouse(this));
  console.log(latlon);
}


//function to add points and text to the map (used in plotting capitals)
function addpoint(lat,lon,text) {

  var gpoint = g.append("g").attr("class", "gpoint");
  var x = projection([lat,lon])[0];
  var y = projection([lat,lon])[1];

  gpoint.append("svg:circle")
        .attr("cx", x)
        .attr("cy", y)
        .attr("class","point")
        .attr("r", 1.5);

  //conditional in case a point has no associated text
  if(text.length>0){

    gpoint.append("text")
          .attr("x", x+2)
          .attr("y", y+2)
          .attr("class","text")
          .text(text);
  }

}

var data2 = [{name:"United Kingdom", country_code: 826, rank: 1},{name:"United States", country_code: 840, rank: 2},{name:"Sweden", country_code: 752, rank: 3},
{name:"Canada", country_code: 124, rank: 4},{name:"Germany", country_code: 276, rank: 5},{name:"South Korea", country_code: 410, rank: 6},
{name:"Australia", country_code: 036, rank: 7},{name:"Italy", country_code: 380, rank: 8},
{name:"Ireland", country_code: 372, rank: 9},{name:"Jamaica", country_code: 388, rank: 10},
{name:"India", country_code: 356, rank: 11},{name:"Mexico", country_code: 484, rank: 12},{name:"France", country_code: 250, rank: 13},
{name:" Japan", country_code: 392, rank: 14},{name:"Finland", country_code: 246, rank: 15},
{name:"Spain", country_code: 724, rank: 16},{name:"Russia", country_code: 643, rank: 17},
{name:"Philippines", country_code: 608, rank: 18},{name:"Romania", country_code: 642, rank: 19},
{name:"Ukraine", country_code: 804, rank: 20}];

    d3.json("world-map.json", function(json) {
                //Merge the rank in data2 and GeoJSON in a single array
                //Loop through once for each "rank" data value
                for (var i = 0; i < data2.length; i++) {
                    //Grab country name
                    var data2CountryCode = data2[i].country_code;
            console.log(data2CountryCode);
                    //Grab data value, and convert from string to float
                    var datarank = +data2[i].rank;
                        console.log(datarank);
                    //Find the corresponding country inside the GeoJSON
                    for (var j = 0; j < json.features.length; j++) {

                        //We'll check the official ISO country code
                        var jsonCountryCode = json.features[j].properties.un_a3;
                        console.log(jsonCountryCode);

                        if (data2CountryCode == jsonCountryCode) {

                            //Copy the data2 rank value into the GeoJSON, with the name "color"
                            json.features[j].properties.labelrank = datarank;

                            //Stop looking through the JSON
                            break;

                        }
                    }
                }

var color = d3.scale.quantize()
            .range(["Lime","GreenYellow","LawnGreen","LightGreen","LimeGreen","Green","DarkGreen","Yellow","Gold",
            "GoldenRod","DarkGoldenRod","Orange"    
,"DarkOrange","Coral","Red","OrangeRed","Tomato","Crimson","DarkRed","Brown"])
.domain([(d3.min(data2, function(d) { return d.rank; })),(d3.max(data2, function(d) { return d.rank; }))
]); 

               var country = g.selectAll(".country")
                   .data(json.features) //in my example, json.features
                   .enter()
                   .append("path")
                   .attr("d", path)
                   .style("fill", function(d) {

                        //Get data value
                        var value = d.properties.labelrank;

                        if (value) {
                            //If value exists…
                            return color(value);
                        } else {
                            //If value is undefined…
                            return "#ccc";
                        }

 });
}); 


</script>
</body>
</html>

最佳答案

好的,让我们一步一步来:

首先,我们将获取数据2中每个国家/地区的排名值,并将该值作为新属性推送到您的 GeoJSON 中。这是我从 Scott Murray 那里获得的代码(我看到在您的代码中您使用“topo”作为参数名称,但这里我使用“json”):

        d3.json("yourgeojsonfile.json", function(json) {

                //Merge the rank in data2 and GeoJSON in a single array

                //Loop through once for each "rank" data value
                for (var i = 0; i < data2.length; i++) {

                    //Grab country name
                    var data2CountryCode = data2[i].country_code;

                    //Grab data value, and convert from string to float
                    var dataValue = +data2[i].rank;

                    //Find the corresponding country inside the GeoJSON
                    for (var j = 0; j < json.features.length; j++) {

                        //We'll check the official ISO country code
                        var jsonCountryCode = json.features[j].properties.iso_a3;

                        if (data2CountryCode == jsonCountryCode) {

                            //Copy the data2 rank value into the GeoJSON, with the name "color"
                            json.features[j].properties.color = dataValue;

                            //Stop looking through the JSON
                            break;

                        }
                    }       
                }
        //the rest of your code
});

检查您的 Geojson 中是否有 ISOa3,或任何其他国家/地区代码以匹配 data2 中的国家/地区代码。 现在,我们在 GeoJSON 中有一个名为“color”的属性,它与 data2 中的“rank”相匹配。下一步很简单:

var country = g.selectAll(".country")
                   .data(topo.features) //in my example, json.features
                   .enter()
                   .append("path")
                   .attr("d", path)
                   .style("fill", function(d) {

                        //Get data value
                        var value = d.properties.color;

                        if (value) {
                            //If value exists…
                            return color(value);
                        } else {
                            //If value is undefined…
                            return "#ccc";
                        }

                    });

因此,如果 d.properties.color 有值,它将根据 var color = d3.scale.category10() 进行填充。如果没有值,它将填充#ccc,或任何你想要的。 最后,如果您想将它们从红色填充为绿色,请不要使用 d3.scale.category10()。相反,使用:

var color = d3.scale.quantize()
            .range([ //put your colors here as an array ])
            .domain([d3.min(data2, function(d) { return d.rank; }),
                     d3.max(data2, function(d) { return d.rank; })
]);

对于颜色,我推荐 Cynthia Brewer 的调色板:

http://colorbrewer2.org/

编辑:只有在阅读完整代码后,我才意识到您正在使用 TopoJSON。我的解决方案中的代码适用于 GeoJSON,而不是 TopoJSON。

关于javascript - 需要帮助从数组中为国家/地区着色,保留其余默认颜色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35676105/

相关文章:

javascript - 我怎样才能使这个功能在 Javascript 中更快?

javascript - 为什么我的项目没有在 React 中排序(重新渲染)?

javascript - 错误 : value of <"rect"> = "NaN", 错误:值 <"text"> = "Nan"

javascript - D3 可折叠树 - 一次折叠一个级别

javascript - 在具有相关数据的 Jquery 数据表中打开弹出窗口不起作用

python - 如何关闭 python simpleHTTPserver?

javascript - 根据 Javascript 中的名称生成颜色

Android Material 默认颜色

objective-c - 如何在 iOS 灰度中切换,而不是蓝色?

javascript - 当 JavaScript 属性更改时执行特殊逻辑