问题
I just made a D3js globe localisator, which looks like this :
If you look carefully, the red square looks ugly since it doesn't follow the Earth's curve. I have the area bounding box in decimal degrees :
var bb = {W:-5.0, N:50.0, E:10.0, S:40.0 }
And I draw the lines as follow:
svg.append("path")
.datum({type: "LineString", coordinates:
[[-5, 40], [-5, 50], [10, 50], [10, 40], [-5, 40]]
})
.attr("d", path);
For larger areas, it's even the opposite curve from expectations (for a bounding box):
How to add rather elegant spherical arcs ?
回答1:
Given a known decimal degrees bounding box (dig in start here for bb) such as :
bounds = [[-50.8,20.0][30,51.5]];
WNES0 = bounds[0][0], // West "W":-50.8
WNES1 = bounds[1][2], // North "N": 51.5
WNES2 = bounds[1][0], // East "E": 30
WNES3 = bounds[0][3], // South "S": 20.0
Some maths are needed.
// *********** MATH TOOLKIT ********** //
function parallel(φ, λ0, λ1) {
if (λ0 > λ1) λ1 += 360;
var dλ = λ1 - λ0,
step = dλ / Math.ceil(dλ);
return d3.range(λ0, λ1 + .5 * step, step).map(function(λ) { return [normalise(λ), φ]; });
}
function normalise(x) {
return (x + 180) % 360 - 180;
}
Then, let's both calculate the polygon's coordinates and project it:
// *********** APPEND SHAPES ********** //
svg.append("path")
.datum({type: "Polygon", coordinates: [
[[WNES0,WNES3]]
.concat(parallel(WNES1, WNES0, WNES2))
.concat(parallel(WNES3, WNES0, WNES2).reverse())
]})
.attr("d", path)
.style({'fill': '#B10000', 'fill-opacity': 0.3, 'stroke': '#B10000', 'stroke-linejoin': 'round'})
.style({'stroke-width': 1 });
180th meridian crossing: Boxes upon the 180th meridian need special management. By example, localising a set of pacific island between 155⁰ East and -155 West initially gives....
...with correct rotation (+180⁰) : ... and with correct boxing:Localisator now perfect ! Live demo on blocks
var bb = { "item":"India", "W": 67.0, "N":37.5, "E": 99.0, "S": 5.0 },
localisator("body", 200, bb.item, bb.W, bb.N, bb.E, bb.S);
+1 welcome.
回答2:
You can use d3's built in graticule generator for this:
var bb = {W: -5.0, N: 50.0, E: 10.0, S: 40.0 };
var arc = d3.geo.graticule()
.majorExtent([[bb.W, bb.S], [bb.E, bb.N]]);
Then use the outline function of the graticule generator to draw the path:
svg.append("path")
.attr("class", "arc")
.attr("d", path(arc.outline()));
Full working example can be found here.
来源:https://stackoverflow.com/questions/25415885/d3-geo-spherical-arcs-rather-than-straight-lines-for-parallels