我想创建一个欧洲的等值区域地图,可以缩放。 我还希望看到当用户双击某个国家/地区时,相关国家/地区会被缩放并划分为多个区域(NUTS 2),每个区域都会根据第二项措施进行着色。
假设欧洲由5个国家组成:Country1,...,Country5。 每个国家都根据第一项措施着色(假设居民人数)。 当用户双击Country4时,地图将被缩放,以便Country4位于屏幕的中心并完全查看。相邻的国家可能会被裁剪和模糊。
Country4现在显示为由其区域(R1,...,R6)组成。这些地区根据第二项措施(假设人均收入)着色。 在第二种情况下,我希望未选择的国家(因此国家1,2,3和5)仍然按照措施1着色。
所以我想要一些like this,但能够双击并更详细地查看每个国家。
我该怎么办? 我找不到可能对我有用的例子。
我发现these json files和this one我认为它们很有用(但我不知道如何使用它们)。
谢谢
我发现this file代表nuts2(地区),this代表nuts0(国家/地区)。
我如何合并两者?我们的想法是从nuts2.json
开始并添加nuts0.json
的信息,但我如何处理geometries
和arcs
?我不想创造不一致的地方..
答案 0 :(得分:3)
这是一个非常广泛的问题,包含几个问题和目标(地图缩放,等值线创建,两个分层地图),因此,任何答案都将是广泛的 - 但不一定无益。我的答案不会解决问题中的每个问题,但应该有助于创建您的预期最终愿景。我将重点关注似乎是关键问题:
我还希望看到当用户双击一下时 国家,有关国家被缩放并划分为区域, 每个都根据第二项措施着色。
授予您说"还"这表明这是次要的,但你的图片和标题似乎更关注两层效应,并且有许多关于等值区的例子和问题,但在交互式两层地图上却很少。
我认为关键的挑战是细分区域,为此,您需要在父区域和子区域之间使用某种公共标识符。在您的geojson或topojson中,您可以根据需要添加必要的标识符。理想情况下,您的geojson可能如下所示:
父/国家:
{
"type":"Feature",
"properties"{ "country":NAME ... },
"geometry": { ... }
}
儿童/地区:
{
"type":"Feature",
"properties"{ "country":NAME, "regionName": NAME ... },
"geometry": { ... }
}
单击某个国家/地区(或双击等任何其他事件)时,您希望根据共享标识符绘制子区域:
country.on("click", function(d) {
// remove other regions
d3.selectAll(".region").remove();
// filter out relevant regions of a geojson of all regions
var countryRegions = geojson.features.filter(function(region) {
return region.properties.country == d.properties.country;
})
// append the regions
svg.selectAll(".region")
.data(countryRegions)
.enter()
.append()
.attr("class",".region")
})
如果您的geojson文件具有标准化命名,则可以使用文件名作为共享属性,执行以下操作:
country.on("click", function(d) {
// remove other regions
d3.selectAll(".region").remove();
// get appropriate geojson:
d3.json(d.properties.country+".json", function(error, regions) {
// draw region features
})
})
您可以通过在点击/其他事件中添加类似:country.style("opacity",0.4)
的内容来提高点击/其他事件的国家/地区的透明度,模糊会增加一点复杂性。要么应该增强两个分层效果。在与国家打交道时不需要裁剪 - 国家很少重叠,无论如何,新特征通常都是在旧特征之上绘制的(这消除了由于坐标不精确造成的任何视觉重叠)。
这就是两层效应,使用相同的原则,您可以轻松创建三层地图,用子区域填充选定区域。
在此基础上,我将简要介绍缩放:
使用包含区域的geojson / topojson,然后可以更改投影以反映要素的范围 - 这使您可以缩放到这些要素:
projection.fitSize([width,height],geojsonObject);
请注意,如果过滤一系列功能,fitSize的fitExtent将无效,除非您将功能放在功能集中(并且都需要v4):
var featureCollection = {type:"FeatureCollection",features:features};
要完成平滑缩放,您需要使用transition.attrTween转换投影。这有点棘手,因为您需要插入投影平移和投影比例(并且取决于地图投影和类型,可能是旋转)。
或者,您可以通过操纵svg进行缩放,但有很多关于如何实现此效果的示例和问题(我在下面的示例中使用了其他方法)。
以上内容可让您:缩放到区域,绘制相关区域,以及区域/视图之间的过渡。
我创建了一个简单的通用示例,使用虚拟地理数据,operational here,(使用单击事件),关键部分在下面评论得更多(除了转换函数,请参阅看到它的例子)。此示例需要大量调整以匹配您的预期数据和可视化。
我使用的是一些未在下面的代码中声明的变量(有关完整代码,请参阅example),但它们大部分都是标准的:geoPath(path
), geoProjection(projection
),宽度,高度等,还有baseProjection
这是起始投影。我也使用虚拟数据,因此我使用d3.geoIdentity
而不是更标准的投影。
// get the parent geojson
d3.json("geojson.json", function(error, geojson) {
if (error) throw error;
// get the regions:
d3.json("geojsonSubdivisions.json", function(error, subdivisions) {
if (error) throw error;
// a color scale for the countries:
var color = d3.scaleLinear().range(["steelblue","darkblue"]).domain([0,4]);
// a color scale for the regions:
var subdivisionColor = ["lightsalmon","salmon","coral"];
// refine the two projections, one for the default/base, and one for the current
baseProjection.fitSize([width,height],geojson);
projection.fitSize([width,height],geojson);
// append the countries:
svg.append("g")
.attr("class", "topLevel")
.selectAll("path")
.data(geojson.features)
.enter()
.append("path")
.attr("fill",function(d,i) { return color(i); })
.attr("opacity",0.7)
.attr("d", path)
.style("stroke","black")
.style("stroke-width",0)
// style on mouseover:
.on("mouseover", function() {
d3.select(this)
.style("stroke-width",15)
.raise();
})
// undo mouseover styles:
.on("mouseout", function(d,i) {
d3.select(this)
.style("stroke-width", 0 );
})
// now zoom in when clicked and show subdivisions:
.on("click", function(d) {
// remove all other subdivisions:
d3.selectAll(".subdivision")
.remove();
// get new features:
var features = subdivisions.features.filter(function(feature) { return feature.id == d.id });
// draw new features
svg.selectAll(null)
.data(features)
.enter()
.append("path")
.attr("class","subdivision")
.attr("fill", function(d,i) { return subdivisionColor[i] })
.attr("d", path)
.style("stroke","black")
.style("stroke-width",0)
.on("click", function() {
zoom(projection,baseProjection); // zoom out when clicked
d3.selectAll(".subdivision")
.remove(); // remove regions when clicked
})
// style on mouseover
.on("mouseover", function() {
d3.select(this)
.style("stroke-width",5)
.raise(); // raise it so stroke is not under anything
})
// undo style changes on mouseout
.on("mouseout", function(d,i) {
d3.select(this)
.style("stroke-width", 0 );
})
.raise()
// make a feature collection of the regions:
var featureCollection = { "type":"FeatureCollection", "features": features }
// zoom to the selected area:
// if current projection is default projection:
if ( projection.translate().toString() === baseProjection.translate().toString() && projection.scale() === baseProjection.scale() ) {
zoom(baseProjection,projection.fitExtent([[50,50],[width-50,height-50]],featureCollection));
}
// current projection != default, zoom out and then in:
else {
// provide an end projection point for the transition:
var endProjection = d3.geoIdentity()
.reflectY(true)
.fitExtent([[50,50],[width-50,height-50]],featureCollection)
zoom(projection,endProjection,baseProjection);
}
});
});
});