私はスイスのマップをレンダリングしようとしているD3.js
とTopoJSON
。基になる JSON はここにあります。最初にこのチュートリアルに従おうとしましたが、リモートで地図のように見えるものをレンダリングできなかったので、ここでこの質問と実際の例へのリンクを見つけました。私が現在使用しているこのコードを取得した場所から:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<style>
path {
fill: #ccc;
}
</style>
</head>
<body>
<h1>topojson simplified Switzerland</h1>
<script>
var width = window.innerWidth,
height = window.innerHeight;
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var projection = d3.geo.mercator()
.scale(500)
.translate([-900, 0]);
var path = d3.geo.path()
.projection(projection);
d3.json("ch-cantons.json", function(error, topology) {
if (error) throw error;
svg.selectAll("path")
.data(topojson.feature(topology, topology.objects.cantons).features).enter().append("path").attr("d", path);
});
</script>
</body>
</html>
以来JSON
(貼り付け/コピーした後、それを正しくレンダリングするいくつかのオンラインプラットフォーム上で確認)と間違って行くことができる唯一の少しのコードがあるルックスの[OK]を、私はエラーが投影パラメータであると仮定します。少しいじってもうまくいきませんでした。ですから、どんな助けでも大歓迎です!
その通りです。エラーは投影法にあります。ただし、エラーは、データが投影されているか投影されていないか (緯度経度ペア) によって異なります。
WGS84 にあるデータ、つまり緯度経度のペアがある場合、次の問題が発生します。
投影法を使用して、データ ソースのみを変更すると、次のような結果が得られます (右側の空の海を削りました)。
To center a Mercator properly, you need to know the center coordinate of your area of interest. This generally can be fairly general, for Switzerland I might try 47N 8.25E.
Once you have this coordinate you need to place it in the middle. One way is to rotate on the x axis and center on the y:
var projection = d3.geo.mercator()
.scale(3500)
.rotate([-8.25,0])
.center([0,47])
.translate([width/2,height/2])
Note that the x rotation is negative, you are spinning the globe underneath the projection.
The other option is to rotate on both x and y, this is likely the preferred option as you approach the poles - as Mercator distortion becomes unworkable at high latitudes. This approach would look like:
var projection = d3.geo.mercator()
.scale(4000)
.rotate([-8.25,-47])
.center([0,0])
.translate([width/2,height/2])
Note again the negative rotation values. The second option requires a higher scale value as this method essentially treats Switzerland as though it were at zero,zero on a Mercator projection - and along the equator land sizes are minimized.
Using the second of these projections, I get:
So you'll have to dial in the scale a bit, but now you should be able to see your data (assuming your data is in proper lat long pairs).
Based on the comment below, which includes a linked json file, we can see that this is your problem.
There are two potential solutions to this:
Option one is the easiest, you'll unproject the data - which requires knowing the current projection. In GIS software this will generally be projecting it as WGS84, which is arguably not really a projection but a datum. Once you have your lat long pairs, you follow the steps above for unprojected data.
Option two skips a d3.geoProjection altogether. Instead, we'll create a transform function that will convert the projected coordinates to the desired SVG coordinates.
A geo projection looks like:
function scale (scaleFactor) {
return d3.geo.transform({
point: function(x, y) {
this.stream.point(x * scaleFactor, (y * scaleFactor);
}
});
}
And is used like a projection:
var path = d3.geo.path().projection(scale(0.1));
It simply takes a stream of x,y coordinates that are already cartesian and transforms them in a specified manner.
To translate the map so it is centered you'll need to know the center coordinate. You can find this with path.bounds
:
var bounds = path.bounds(features);
var centerX = (bounds[0][0] + bounds[1][0])/2;
var centerY = (bounds[0][1] + bounds[1][1])/2;
Path.bounds returns the top left corner and bottom right corner of a feature. This is the key part, you can make an autoscaling function, there are plenty of examples out there, but I like manually scaling often. If the map is centered, this is easy. For your map, your geoTransform might look like:
function scale (scaleFactor,cx,cy,width,height) {
return d3.geo.transform({
point: function(x, y) {
this.stream.point((x-cx) * scaleFactor + width/2, (y-cy) * scaleFactor +height/2);
}
});
}
ここcx
とcy
SVG要素の幅と高さを参照してくださいあなたの機能および幅と高さの真ん中を参照してください-私たちはSVGポイント[0,0]でクラスタ化された機能を望んでいません。
全体として、次のようなものになります (0.002 の倍率で):
更新された JSbin は次のとおりです: http://jsbin.com/wolamuzeze/edit?html,output
幅/高さはあなたのケースではウィンドウ サイズに関連しているため、スケールはウィンドウ サイズに依存していることに注意してください。これは、ズーム レベルを自動的に設定することで最もよく対処できますが、ラベルがある場合などに問題が発生する可能性があります。
この回答も役立つかもしれません: SVG (またはまったく) に合わせて d3 v4 マップをスケーリングする
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加