我正在尝试缩小美国地图。要么是我的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());
});
}
我已经尝试过类似的东西:
var path = d3.geoPath()
.projection(d3.geoConicConformal()
.parallels([33, 45])
.rotate([96, -39])
.fitSize([width, height], conus));
但是每次我在路径变量中添加任何内容时,我都会从D3的内部收到NAN错误。谢谢你的帮助!
关键问题是您的数据 已经被 投影。D3 geoProjections使用未投影的数据或成对的数据。WGS84基准中的数据。实质上,d3
geoProjection会采用球面坐标并将其转换为平面笛卡尔x,y坐标。
您的数据与此不符-
它已经是平面的。您可以看到最明显的原因是阿拉斯加不在应有的位置(除非有人更改了阿拉斯加的长对,这不太可能)。已经投影的数据的其他迹象和症状可能是覆盖整个星球以及NaN错误的特征。
由于这是一个复合投影,因此很难取消投影,但是您可以在d3.js中显示已经投影的数据。
最简单的是,您可以将投影定义为null:
var path = d3.geoPath(null);
这将从geojson几何中获取x,y数据,并将其显示为x,y数据。但是,如果您的x,y坐标超出了svg的宽度和高度,则地图将不会包含在svg中(如在示例中使用找到的
.attr("d", d3.geoPath());
)。
这个问题中的特定文件已预先投影以适合960x600地图,因此这对于空投影非常理想-
设计时要考虑到尺寸。它的单位是像素,所有坐标都在所需的尺寸之内。但是,大多数投影的几何图形都使用以米为单位的坐标系,因此要素坐标的边界框可能跨越数百万个单位。在这些情况下,空投影将不起作用-
它将地图单位值转换为没有缩放比例的像素值。
对于d3,geojson / topojson通常使用空投影,该投影使用d3投影进行预投影以适合指定的视口。有关示例(示例使用未投影的源文件在投影数据上使用d3投影所引起的相同问题在浏览器和命令行中均适用)。预投影文件以用于null投影的主要优点是性能。
如果只需要缩放要素并使其居中,则可以使用geoIdentity。这实现了geoTransform,但具有标准的投影方法,例如和scale
,translate
最重要的是-
fitSize
/ fitExtent
。因此,我们可以将投影设置为geoIdentity:
var projection = d3.geoIdentity();
当前,这与上面使用的null投影相同,它从geojson几何中获取x,y数据,并将其显示为x,y数据,且不进行任何转换-
将geojson中的每个坐标视为像素坐标。但是,我们可以将fitSize应用于此(或fitExtent),这将自动缩放数据并将其转换为指定的边界框:
var projection = d3.geoIdentity()
.fitSize([width,height],geojsonObject);
要么
var projection = d3.geoIdentity()
.fitExtent([[left,top],[right,bottom]], geojsonObject);
请记住,大多数投影数据使用地理惯例,y = 0位于底部,y值随着向北移动而增加。在svg /画布坐标空间中,y =
0位于顶部,y值随着向下移动而增加。因此,我们经常需要翻转y轴:
var projection = d3.geoIdentity()
.fitExtent([width,height],geojsonObject)
.reflectY(true);
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);
});
<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>
如果您想进一步控制数据的显示方式,可以使用geoTransform
。
但是,如果您的几何图形已经是平面的,该怎么办?也就是说,如果您只想采用投影的几何形状,但仍将其平移或缩放以适合视口怎么办?
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));
不过,这会在缩小时将所有内容缩放到左上角。为了使内容居中,可以添加一些代码来使投影居中:
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))
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);
});
<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>
在某些情况下,此方法很有用。但是,这需要您了解用于创建数据的投影。使用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);
});
您将很快看到值超过+/- 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坐标也是潜在的指标。但是,这些预测数据的最后指标也可能意味着其他问题。
问题内容: 是否有仅css的解决方案将图像缩放到边框(保持纵横比)?如果图像大于容器,则此方法有效: 问题答案: 不,没有唯一的CSS双向方式可以做到这一点。您可以添加 对于一个元素,使其始终具有100%的宽度,并自动将其高度缩放为长宽比, 或 反之: 始终缩放到最大高度和相对宽度。为此,您需要确定纵横比是高于还是低于容器,而CSS无法做到这一点。 原因是CSS不知道页面的外观。它会预先设置规则,
问题内容: 在JavaScript / jQuery中,如何缩放固定宽度Div内的可变长度文本行,以使一行始终适合Div内(作为一行)? 谢谢。 问题答案: 这有点骇人听闻,但可以满足您的要求。 将其放置在页面底部,该位置将不会移动页面上的其他元素。 然后执行以下操作:
如何设置视图以在地图框或传单中查看地图上的所有标记?就像谷歌地图API对? 例如:
我有一个表单,允许用户上传图像。 加载映像后,我们对其执行一些缩放,以便在将其传递回服务器之前减小其文件大小。 为此,我们将其放置在画布上并在画布上进行操作。 这段代码将在画布上呈现缩放后的图像,画布大小为320 x 240px: ... 哪里有帆布。宽度和画布。高度是图像高度和宽度x,是基于原始图像大小的比例因子。 但当我使用代码时: ...我只得到画布上图像的一部分,在这种情况下是左上角。我需
你知道吗?
这是一个vue组件,其父级以2 x 4偶数布局渲染其中8个组件。图像大于其网格容器。我想它收缩,以适应容器,同时保持其纵横比。但是,对象拟合对img标记没有影响,图像被渲染为全尺寸,从而大幅扭曲网格并扰乱我的布局。 当img标记被注释掉时,它的父div格式为正确的大小并填充它的网格容器。