访问 topojson 对象以更改 d3.js 中的地图国家/地区属性
Access topojson object to change map country properties in d3.js
我正在构建一个 Web 应用程序来显示世界各国之间的不同趋势和统计数据。使用 d3,我能够加载 topojson 文件并投影世界地图。
var countryStatistics = [];
var pathList = [];
function visualize(){
var margin = {top: 100, left: 100, right: 100, bottom:100},
height = 800 - margin.top - margin.bottom,
width = 1200 - margin.left - margin.right;
//create svg
var svg = d3.select("#map")
.append("svg")
.attr("height", height + margin.top + margin.bottom)
.attr("width", width + margin.left + margin.right)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//load topojson file
d3.queue()
.defer(d3.json, "world110m.json")
.await(ready)
var projection = d3.geoMercator()
.translate([ width / 2, height / 2 ])
.scale(180)
//pass path lines to projection
var path = d3.geoPath()
.projection(projection);
function ready (error, data){
console.log(data);
//we pull the countries data out of the loaded json object
countries = topojson.feature(data, data.objects.countries).features
//select the country data, draw the lines, call mouseover event to change fill color
svg.selectAll(".country")
.data(countries)
.enter().append("path")
.attr("class", "country")
.attr("d", path)
.on('mouseover', function(d) {
d3.select(this).classed("hovered", true)
//this function matches the id property in topojson country, to an id in (see below)
let country = matchPath(this.__data__.id);
console.log(country)
})
.on('mouseout', function(d) {
d3.select(this).classed("hovered", false)
})
//here I push the country data into a global array just to have access and experimentalism.
for (var i = 0; i < countries.length; i++) {
pathList.push(countries[i]);
}
}
};
matchPath() 函数用于让我将路径数据匹配到 countryStatistics,以便在鼠标悬停在某个国家/地区时显示。
function matchPath(pathId){
//to see id property of country currently being hovered over
console.log("pathID:" + pathId)
//loop through all countryStatistics and return the country with matching id number
for(var i = 0; i < countryStatistics.length; i++){
if(pathId == countryStatistics[i].idTopo){
return countryStatistics[i];
}
}
}
问题: 这行得通,但只在一个方向上。我可以从每个 topojson 路径获取我的统计数据......但我无法根据数据获取和操作各个路径。
我想要的是有一个按钮可以 select 来自 countryStatistics 的某个 属性,并构建一个 domain/range 比例并根据以下条件设置颜色渐变数据值。我坚持的步骤是获取统计数据和路径数据接口。
我看到了两个可能的解决方案,
1:有一种方法可以在渲染过程中将拓扑路径数据连接到统计数据,我可以调用一个函数来重绘sgv...
2:我建立了一个包含所有路径数据和统计数据的新对象。在这种情况下,我可以只提取 topojson.objects.countries 数据而忽略其余数据吗?
我该如何实现?任何指针,下一步将不胜感激。
(我在这个项目中所处的位置...http://conspiracytime.com/globeApp)
TopoJSON 是一个非常强大的工具。它有自己的 CLI(命令行界面)来生成您自己的 TopoJSON 文件。
该 CLI 允许您创建一个包含拓扑和要合并的数据的唯一文件。
即使它在 v3.0.2 中,first versión 对我来说看起来很清楚。这是一个示例,说明如何通过通用 id
属性将 csv
文件与 json
合并。
# Simplified versión from https://bl.ocks.org/luissevillano/c7690adccf39bafe583f72b044e407e8
# note is using TopoJSON CLI v1
topojson \
-e data.csv \
--id-property CUSEC,cod \
-p population=+t1_1,area=+Shape_area \
-o cv.json \
-- cv/shapes/census.json
有一个包含 cod
列的 data.csv
文件和一个包含名为 CUSEC
的 属性 的 census.json
文件。
- 使用 --id-property
您可以指定哪些属性将在合并中使用。
- 使用 属性 -p
,您可以即时创建新属性 。
这是对整个数据使用一个唯一文件(具有一个唯一 请求)的可靠解决方案。这种最好的情况并不总是可能的,所以下一个可能是另一种解决方案。
回到JavaScript
,您可以通过以下方式创建一个可通过公共属性访问的新变量。让你的数据格式:
// countryStatistics
{
"idTopo": "004",
"country": "Afghanistan",
"countryCode": "afg",
// ..
},
你的 TopoJSON 文件结构:
{"type":"Polygon","arcs":[[0,1,2,3,4,5]],"id":"004"},
{"type":"MultiPolygon","arcs":[[[6,7,8,9]],[[10,11,12]]],"id":"024"} // ...
此类情况的常见解决方案是创建一个 Array
变量,该变量可由 idTopo
:
访问
var dataById = [];
countryStatistics.forEach(function(d) {
dataById[d.idTopo] = d;
});
然后,该变量将具有下一个结构:
[
004:{
"idTopo": "004",
"country": "Afghanistan",
"countryCode": "afg",
//...
},
008: {
//...
}
]
从这里,您可以通过其 idTopo
属性访问属性,如下所示:
dataById['004'] // {"idTopo":"004","country":"Afghanistan","countryCode":"afg" ...}
您可以决定遍历 Topo 数据并将这些属性添加到每个特征:
var countries = topojson
.feature(data, data.objects.countries)
.features.map(function(d) {
d.properties = dataById[d.id];
return d
});
或者在你需要的时候使用这个数组
// ...
.on("mouseover", function(d) {
d3.select(this).classed("hovered", true);
console.log(dataById[d.id]);
});
我正在构建一个 Web 应用程序来显示世界各国之间的不同趋势和统计数据。使用 d3,我能够加载 topojson 文件并投影世界地图。
var countryStatistics = [];
var pathList = [];
function visualize(){
var margin = {top: 100, left: 100, right: 100, bottom:100},
height = 800 - margin.top - margin.bottom,
width = 1200 - margin.left - margin.right;
//create svg
var svg = d3.select("#map")
.append("svg")
.attr("height", height + margin.top + margin.bottom)
.attr("width", width + margin.left + margin.right)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//load topojson file
d3.queue()
.defer(d3.json, "world110m.json")
.await(ready)
var projection = d3.geoMercator()
.translate([ width / 2, height / 2 ])
.scale(180)
//pass path lines to projection
var path = d3.geoPath()
.projection(projection);
function ready (error, data){
console.log(data);
//we pull the countries data out of the loaded json object
countries = topojson.feature(data, data.objects.countries).features
//select the country data, draw the lines, call mouseover event to change fill color
svg.selectAll(".country")
.data(countries)
.enter().append("path")
.attr("class", "country")
.attr("d", path)
.on('mouseover', function(d) {
d3.select(this).classed("hovered", true)
//this function matches the id property in topojson country, to an id in (see below)
let country = matchPath(this.__data__.id);
console.log(country)
})
.on('mouseout', function(d) {
d3.select(this).classed("hovered", false)
})
//here I push the country data into a global array just to have access and experimentalism.
for (var i = 0; i < countries.length; i++) {
pathList.push(countries[i]);
}
}
};
matchPath() 函数用于让我将路径数据匹配到 countryStatistics,以便在鼠标悬停在某个国家/地区时显示。
function matchPath(pathId){
//to see id property of country currently being hovered over
console.log("pathID:" + pathId)
//loop through all countryStatistics and return the country with matching id number
for(var i = 0; i < countryStatistics.length; i++){
if(pathId == countryStatistics[i].idTopo){
return countryStatistics[i];
}
}
}
问题: 这行得通,但只在一个方向上。我可以从每个 topojson 路径获取我的统计数据......但我无法根据数据获取和操作各个路径。
我想要的是有一个按钮可以 select 来自 countryStatistics 的某个 属性,并构建一个 domain/range 比例并根据以下条件设置颜色渐变数据值。我坚持的步骤是获取统计数据和路径数据接口。
我看到了两个可能的解决方案,
1:有一种方法可以在渲染过程中将拓扑路径数据连接到统计数据,我可以调用一个函数来重绘sgv...
2:我建立了一个包含所有路径数据和统计数据的新对象。在这种情况下,我可以只提取 topojson.objects.countries 数据而忽略其余数据吗?
我该如何实现?任何指针,下一步将不胜感激。
(我在这个项目中所处的位置...http://conspiracytime.com/globeApp)
TopoJSON 是一个非常强大的工具。它有自己的 CLI(命令行界面)来生成您自己的 TopoJSON 文件。
该 CLI 允许您创建一个包含拓扑和要合并的数据的唯一文件。
即使它在 v3.0.2 中,first versión 对我来说看起来很清楚。这是一个示例,说明如何通过通用 id
属性将 csv
文件与 json
合并。
# Simplified versión from https://bl.ocks.org/luissevillano/c7690adccf39bafe583f72b044e407e8
# note is using TopoJSON CLI v1
topojson \
-e data.csv \
--id-property CUSEC,cod \
-p population=+t1_1,area=+Shape_area \
-o cv.json \
-- cv/shapes/census.json
有一个包含 cod
列的 data.csv
文件和一个包含名为 CUSEC
的 属性 的 census.json
文件。
- 使用 --id-property
您可以指定哪些属性将在合并中使用。
- 使用 属性 -p
,您可以即时创建新属性 。
这是对整个数据使用一个唯一文件(具有一个唯一 请求)的可靠解决方案。这种最好的情况并不总是可能的,所以下一个可能是另一种解决方案。
回到JavaScript
,您可以通过以下方式创建一个可通过公共属性访问的新变量。让你的数据格式:
// countryStatistics
{
"idTopo": "004",
"country": "Afghanistan",
"countryCode": "afg",
// ..
},
你的 TopoJSON 文件结构:
{"type":"Polygon","arcs":[[0,1,2,3,4,5]],"id":"004"},
{"type":"MultiPolygon","arcs":[[[6,7,8,9]],[[10,11,12]]],"id":"024"} // ...
此类情况的常见解决方案是创建一个 Array
变量,该变量可由 idTopo
:
var dataById = [];
countryStatistics.forEach(function(d) {
dataById[d.idTopo] = d;
});
然后,该变量将具有下一个结构:
[
004:{
"idTopo": "004",
"country": "Afghanistan",
"countryCode": "afg",
//...
},
008: {
//...
}
]
从这里,您可以通过其 idTopo
属性访问属性,如下所示:
dataById['004'] // {"idTopo":"004","country":"Afghanistan","countryCode":"afg" ...}
您可以决定遍历 Topo 数据并将这些属性添加到每个特征:
var countries = topojson
.feature(data, data.objects.countries)
.features.map(function(d) {
d.properties = dataById[d.id];
return d
});
或者在你需要的时候使用这个数组
// ...
.on("mouseover", function(d) {
d3.select(this).classed("hovered", true);
console.log(dataById[d.id]);
});