Jas*_*ins 11 javascript svg geojson d3.js topojson
我试图让这个美国规模的地图变小.要么是我的SVG,要么是手动.
这是我最简单的代码:
function initializeMapDifferent(){
var svg = d3.select("#map").append("svg")
.attr("width", 1000)
.attr("height", 500);
d3.json("https://d3js.org/us-10m.v1.json", function (error, us){
svg.append("g")
.attr("class", "states")
.selectAll("path")
.data(topojson.feature(us, us.objects.states).features)
.enter().append("path")
.attr("fill", "gray")
.attr("d", d3.geoPath());
});
}
Run Code Online (Sandbox Code Playgroud)
我尝试过类似的东西:
var path = d3.geoPath()
.projection(d3.geoConicConformal()
.parallels([33, 45])
.rotate([96, -39])
.fitSize([width, height], conus));
Run Code Online (Sandbox Code Playgroud)
但每次我在路径变量中添加任何东西时,我都会从D3的内部部分得到NAN错误.谢谢你的帮助!
And*_*eid 14
关键问题是您的数据已经预测.D3 geoProjections使用未投影的数据,或使用lat long对.WGS84数据中的数据.本质上,d3 geoProjection采用球面坐标并将它们转换为平面笛卡尔x,y坐标.
您的数据不符合这一点 - 它已经是平面的.你可以看到最明显的原因是因为阿拉斯加不应该在那里(除非有人改变了阿拉斯加的长对子,这是不太可能的).已投影数据的其他迹象和症状可能是涵盖整个星球的特征,以及NaN误差.
这是一个复合投影,很难取消投影,但您可以在d3.js中显示已投影的数据.
最简单的是,您可以将投影定义为null:
var path = d3.geoPath(null);
Run Code Online (Sandbox Code Playgroud)
这将从geojson几何中获取x,y数据并将其显示为x,y数据.但是,如果您的x,y坐标超过svg的宽度和高度,则地图将不会包含在您的svg中(如您在示例中所示 .attr("d", d3.geoPath());).
此问题中的特定文件是预先投影以适合960x600地图,因此这是空投影的理想选择 - 它的设计考虑了尺寸.它的单位是像素,所有坐标都在所需的尺寸范围内.但是,大多数投影几何体使用具有米等单位的坐标系,因此要素坐标的边界框可能是数百万个单位.在这些情况下,空投影将不起作用 - 它将地图单位值转换为没有缩放的像素值.
对于d3,空投影通常与geojson/topojson一起使用,该投影使用d3投影预先投影以适合指定的视口.有关示例,请参阅命令行制图(该示例使用未投影的源文件 - 在投影数据上使用d3投影产生的相同问题同时适用于浏览器和命令行).预先投影文件以使用空投影的主要优点是性能.
如果您只需要缩放和居中功能,则可以使用geoIdentity.这实现了一个几何图形变换但是具有标准投影方法,如scale,translate以及最重要的- fitSize/ fitExtent.因此,我们可以将投影设置为地理位置:
var projection = d3.geoIdentity();
Run Code Online (Sandbox Code Playgroud)
这与当前使用的空投影相同,它从geojson几何中获取x,y数据并将其显示为没有变换的x,y数据 - 将geojson中的每个坐标视为像素坐标.但是,我们可以将fitSize应用于此(或fitExtent),它将自动缩放并将数据转换为指定的边界框:
var projection = d3.geoIdentity()
.fitSize([width,height],geojsonObject);
Run Code Online (Sandbox Code Playgroud)
要么
var projection = d3.geoIdentity()
.fitExtent([[left,top],[right,bottom]], geojsonObject);
Run Code Online (Sandbox Code Playgroud)
请记住,大多数预测数据使用地理惯例,y = 0位于底部,y值随着向北移动而增加.在svg/canvas坐标空间中,y = 0位于顶部,y值随着向下移动而增加.所以,我们经常需要翻转y轴:
var projection = d3.geoIdentity()
.fitExtent([width,height],geojsonObject)
.reflectY(true);
Run Code Online (Sandbox Code Playgroud)
这个特殊的数据集:https : //d3js.org/us-10m.v1.json是用d3投影投影的,因此当d3投影投影到svg或画布坐标空间时,其y轴已被翻转.
geoIdentity演示
var width = 600;
var height = 300;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("https://d3js.org/us-10m.v1.json", function (error, us){
var featureCollection = topojson.feature(us, us.objects.states);
var projection = d3.geoIdentity()
.fitExtent([[50,50],[600-50,300-50]], featureCollection)
var path = d3.geoPath().projection(projection)
svg.append("g")
.attr("class", "states")
.selectAll("path")
.data(featureCollection.features)
.enter().append("path")
.attr("fill", "gray")
.attr("d", path);
});Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.6.0/d3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/2.2.0/topojson.js"></script>Run Code Online (Sandbox Code Playgroud)
如果您想要更多地控制数据的显示方式,可以使用a geoTransform.
来自Mike Bostock:
但是,如果几何体已经是平面的呢?也就是说,如果您只想获取投影几何体,但仍然可以平移或缩放它以适合视口,那该怎么办?
您可以实现自定义几何变换,以获得对投影过程的完全控制.
geoTransform假设您不想更改投影类型,使用a 相对简单.例如,如果要缩放数据,可以使用以下方法实现缩放功能geoTransform:
function scale (scaleFactor) {
return d3.geoTransform({
point: function(x, y) {
this.stream.point(x * scaleFactor, y * scaleFactor);
}
});
}
var path = d3.geoPath().projection(scale(0.2));
Run Code Online (Sandbox Code Playgroud)
但是,在缩小时,这会将所有内容缩放到左上角.为了使事物保持中心,您可以添加一些代码来使投影居中:
function scale (scaleFactor,width,height) {
return d3.geoTransform({
point: function(x, y) {
this.stream.point( (x - width/2) * scaleFactor + width/2 , (y - height/2) * scaleFactor + height/2);
}
});
}
var path = d3.geoPath().projection(scale(0.2,width,height))
Run Code Online (Sandbox Code Playgroud)
geoTransform演示:
以下是使用您的文件和geoTransform的示例:
var width = 600;
var height = 300;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
function scale (scaleFactor,width,height) {
return d3.geoTransform({
point: function(x, y) {
this.stream.point( (x - width/2) * scaleFactor + width/2 , (y - height/2) * scaleFactor + height/2);
}
});
}
d3.json("https://d3js.org/us-10m.v1.json", function (error, us){
var path = d3.geoPath().projection(scale(0.2,width,height))
svg.append("g")
.attr("class", "states")
.selectAll("path")
.data(topojson.feature(us, us.objects.states).features)
.enter().append("path")
.attr("fill", "gray")
.attr("d", path);
});Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.6.0/d3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/2.2.0/topojson.js"></script>Run Code Online (Sandbox Code Playgroud)
在某些情况下,此方法很有用.但它需要您知道用于创建数据的投影.使用QGIS/ArcGIS甚至是mapshaper,您可以更改数据的投影,使其"投影"为WGS84(又名EPSG 4326).转换后,您将获得未投影的数据.
在Mapshaper中,使用shapefile非常简单,将shapefile的.dbf,.shp和.prj文件拖入窗口.在mapshaper中打开控制台并输入proj wgs84.
如果您不知道用于创建数据的投影,则无法取消投影 - 您不知道应用了哪些转换以及使用了哪些参数.
一旦取消投影,您可以正常使用常规d3投影,因为您在正确的坐标空间中具有坐标:经度纬度对.
如果您还有未投影的数据并希望在同一个地图中混合使用,则取消投影非常有用.或者,您可以投影未投影的数据,以便两者使用相同的坐标系.将地图中不匹配的坐标系统与d3相结合并不容易,而d3可能不是正确的载体.如果您确实希望使用d3复制特定投影以匹配已使用未投影功能投影的要素,则此问题可能很有用.
您可以检查功能的几何形状是否符合纬度和经度的限制.例如,如果您要记录:
d3.json("https://d3js.org/us-10m.v1.json", function (error, us){
console.log(topojson.feature(us, us.objects.states).features);
});
Run Code Online (Sandbox Code Playgroud)
您将很快看到值超过+/- 90度N/S和+/- 180度E/W. 不太可能是拉长对.
或者,您可以将数据导入到mapshaper.org等在线服务中,并与另一个您知道未注册(或使用WGS84"预测")的topojson/geojson进行比较.
如果处理geojson,您可能很幸运地看到定义投影的属性,例如:"name": "urn:ogc:def:crs:OGC:1.3:CRS84"(CRS代表坐标参考系统)或EPSG编号:EPSG:4326(EPSG代表欧洲石油调查组).
此外,如果您的数据投影为空投影但不是标准投影(缩放/缩小以确保您没有查看错误的区域),您可能正在处理投影数据.同样,如果您的视口完全由一个功能覆盖(并且您没有放大).NaN坐标也是一个潜在的指标.但是,这些预测数据的最后指标也可能意味着其他问题.
最后,数据源还可以指示数据已经在元数据或其使用方式中进行了预测:查看此块,我们可以看到在geoPath定义时未使用任何投影.
| 归档时间: |
|
| 查看次数: |
2926 次 |
| 最近记录: |