问题:
我正在尝试创建美国的交互式地图,其中显示州,县和国家边界。县根据数据着色,悬停在州上应该突出显示州内的所有县,州应该是可点击的。我希望通过在状态形状内部具有县形状的SVG来实现这一点,在美国形状内部。
我可以基于CENSUS县形状文件生成县地图,我可以通过使用TopoJSON命令行准备文件并使用D3中的以下代码,根据外部CSV中的数据来设置状态:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
path {
fill: none;
stroke-linejoin: round;
stroke-linecap: round;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script>
var width = 960,
height = 600;
var path = d3.geo.path()
.projection(d3.geo.albersUsa());
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("counties_pa.json", function(error, us) {
if (error) return console.error(error);
var color = d3.scale.threshold()
.domain([1, 10, 50, 100, 500, 1000, 2000, 5000])
.range(["#fff7ec", "#fee8c8", "#fdd49e", "#fdbb84", "#fc8d59", "#ef6548", "#d7301f", "#b30000", "#7f0000"]);
svg.append('g').attr('class','counties').selectAll("path").data(topojson.feature(us, us.objects.cb_2014_us_county_20m).features).enter().append('path').attr('d',path).attr('style',function(d){return 'fill:'+color(d.properties.population / d.properties.area * 2.58999e6);});
});
</script>
这在视觉上是可接受的(除了它没有离散的州/国界) - 但在功能上是不合适的。为了将CSS应用于状态悬停的县,县需要处于状态形状或以某种方式分组。
我尝试了什么:
我现在在做什么:
以某种方式组合状态TopoJSON文件和县TopoJSON文件并将状态嵌套在县中,然后使用D3进行渲染。
以某种方式使用d3获取非嵌套状态和县数据,并将其嵌套在客户端级别的客户端上。
最后,我想了解最有效,最快速的渲染过程,以实现我想要的功能。
提前感谢您的帮助。
答案 0 :(得分:2)
我对你的数据源进行了试探,这就是你想要实现的目标:http://bl.ocks.org/benlyall/55bc9474e6d531a1c1fe
基本上,我使用以下命令行生成了TopoJSON文件:
topojson -o counties_pa.json --id-property=+GEOID -p -e POP01.txt --id-property=+STCOU -p population=+POP010210D,area=ALAND,state=+STATEFP,county=+COUNTYFP cb_2014_us_county_20m.shp cb_2014_us_state_20m.shp
对此的一些解释:
-o counties_pa.json
设置输出文件的名称--id-property=+GEOID
将输入文件中的该属性用作每个输出几何的id
-p
表示包含输入文件中的所有属性-e POP01.txt
将从文件POP01.txt
中提取外部数据。此文件是根据http://www.census.gov/support/USACdataDownloads.html#POP POP01.xls
电子表格生成的csv文件
--id-property=+STCOU
表示外部文件(POP01.txt
)中的id属性位于STCOU列中。这用于匹配输入文件中的匹配id
(如上所述,位于GEOID
属性中)-p population=+POP010210D,area=ALAND,state=+STATEFP,county=+COUNTYFP
在输出文件中明确列出了我想要的属性,因此不包含任何额外的内容。 POP010210D是2010年人口普查时人口的列名,因此我只是将其用于演示目的。cb_2014_us_county_20m.shp cb_2014_us_state_20m.shp
是两个输入文件。一个用于县形状,一个用于状态形状。它们将以文件名命名的单独属性添加到输出文件中。我是这样做的,因为您似乎根据人口密度为您的县区着色,因此人口和面积都需要在输出文件中。人口从POP01
电子表格中提取,并根据GEOID
(只是与县号连接的州号)链接到每个县。
我只是在寻找一种快速简便的方法来重新创建数据集,然后将状态边界添加到其中,以便我可以发布答案。不确定这与原始数据的匹配程度如何,但似乎可以用于演示目的。
从那以后,我把你的代码上面的内容更新为:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
path {
fill: none;
stroke-linejoin: round;
stroke-linecap: round;
}
path.state {
fill: none;
stroke: black;
stroke-width: .5px;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script>
var width = 960,
height = 600;
var path = d3.geo.path()
.projection(d3.geo.albersUsa());
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("counties_pa.json", function(error, us) {
if (error) return console.error(error);
var color = d3.scale.threshold()
.domain([1, 10, 50, 100, 500, 1000, 2000, 5000])
.range(["#fff7ec", "#fee8c8", "#fdd49e", "#fdbb84", "#fc8d59", "#ef6548", "#d7301f", "#b30000", "#7f0000"]);
svg.append('g')
.attr('class','counties')
.selectAll("path")
.data(topojson.feature(us, us.objects.cb_2014_us_county_20m).features).enter()
.append('path')
.attr('d', path)
.attr("id", function(d) { return "county-" + d.id; })
.attr("data-state", function(d) { return d.properties.state; })
.attr('style',function(d) {
return 'fill:'+color(d.properties.population / d.properties.area * 2.58999e6);
})
.on("mouseover", hoverCounty)
.on("mouseout", outCounty);
svg.append('g')
.attr('class', 'states')
.selectAll("path")
.data(topojson.feature(us, us.objects.cb_2014_us_state_20m).features).enter()
.append("path")
.attr("class", "state")
.attr("id", function(d) { return "state-" + d.id; })
.attr("d", path);
});
function hoverCounty(county) {
d3.selectAll("path[data-state='" + county.properties.state + "']").style("opacity", .5);
}
function outCounty(county) {
d3.select(".counties").selectAll("path").style("opacity", null);
}
</script>
新的和有趣的代码是:
为每个县添加data-state
属性以确定它属于哪个州:
.attr("data-state", function(d) { return d.properties.state; })
添加状态边界(我将状态组合到topojson
命令行中的TopoJSON文件中)
svg.append('g')
.attr('class', 'states')
.selectAll("path")
.data(topojson.feature(us, us.objects.cb_2014_us_state_20m).features).enter()
.append("path")
.attr("class", "state")
.attr("id", function(d) { return "state-" + d.id; })
.attr("d", path);
});
添加了悬停处理程序,以便您了解我如何确定将县分组为州:
function hoverCounty(county) {
d3.selectAll("path[data-state='" + county.properties.state + "']").style("opacity", .5);
}
function outCounty(county) {
d3.select(".counties").selectAll("path").style("opacity", null);
}
将这些悬停处理程序绑定到每个县,以便在适当的时间执行:
.on("mouseover", hoverCounty)
.on("mouseout", outCounty);