score:2
your assumption is right: d3 uses great circle distances to draw lines: this means that any path between two points using a d3 geoprojection and geopath follows the shortest real world path between those two points. this means:
- that the same path between two points aligns with other geographic points and features no matter the projection
- that the anti-meridian can be accounted for
- and the resulting map more accurately depicts lines.
to draw straight lines and/or lines that follow parallels (meridians are the shortest path between two points that fall on them - so paths follow this already, assuming an unrotated graticule) there are a few possibilities.
the easiest solution is to use a cylindrical projection like a mercator to create a custom geotransform. d3.geotransforms do not use spherical geometry, unlike d3.geoprojections, instead they use cartesian data. consequently they don't sample along lines to create curved lines: this is unecessary when working with cartesian data. this allows us to use spherical geometry for the geojson vertices within the geotransform while still keeping straight lines on the map:
var transform = d3.geotransform({
point: function(x, y) {
var projection = d3.geomercator();
this.stream.point(...projection([x,y]));
}
});
as seen below:
var projection = d3.geomercator();
var transform = d3.geotransform({
point: function(x, y) {
var projection = d3.geomercator();
this.stream.point(...projection([x,y]));
}
});
var color = ["steelblue","orange"]
var geojson = {type:"linestring",coordinates:[[-160,60],[30,45]]};
var geojson2 = {type:"polygon",coordinates:[[[-160,60,],[-80,60],[-100,30],[-160,60]]]}
var svg = d3.select("body")
.append("svg")
.attr("width",960)
.attr("height",500);
svg.selectall(null)
.data([projection,transform])
.enter()
.append("path")
.attr("d", function(d) {
return d3.geopath().projection(d)(geojson)
})
.attr("fill","none")
.attr("stroke",function(d,i) { return color[i]; } )
.attr("stroke-width",1);
svg.selectall(null)
.data([projection,transform])
.enter()
.append("path")
.attr("d", function(d) {
return d3.geopath().projection(d)(geojson2)
})
.attr("fill","none")
.attr("stroke",function(d,i) { return color[i]; } )
.attr("stroke-width",2);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
the orange lines use the transform, the blue lines use a plain mercator
in some cases you could set the precision of the projection (which regulates the adaptive sampling) to some absurdly high number, this will work for some lines, but not others due to things like anti-meridian cutting:
var projection = d3.geomercator().precision(1000000);
var transform = d3.geotransform({
point: function(x, y) {
var projection = d3.geomercator();
this.stream.point(...projection([x,y]));
}
});
var color = ["steelblue","orange"]
var geojson = {type:"linestring",coordinates:[[-160,60],[30,45]]};
var geojson2 = {type:"polygon",coordinates:[[[-160,60,],[-80,60],[-100,30],[-160,60]]]}
var svg = d3.select("body")
.append("svg")
.attr("width",960)
.attr("height",500);
svg.selectall(null)
.data([projection,transform])
.enter()
.append("path")
.attr("d", function(d) {
return d3.geopath().projection(d)(geojson)
})
.attr("fill","none")
.attr("stroke",function(d,i) { return color[i]; } )
.attr("stroke-width",1);
svg.selectall(null)
.data([projection,transform])
.enter()
.append("path")
.attr("d", function(d) {
return d3.geopath().projection(d)(geojson2)
})
.attr("fill","none")
.attr("stroke",function(d,i) { return color[i]; } )
.attr("stroke-width",2);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
neither approach works if you want to draw lines that are aligned with parallels on a non-cylindrical projection. for a cylindrical projection parallels are straight. the above approaches will only create straight lines. if the parallels aren't projected straight, such as the aitoff, the lines will not align with the graticule.
to have a line follow a parallel you will need to sample points along your paths because the projected parallels will not all be straight and parallels don't follow great circle distance. therefore neither the default projection nor the method above will work in these instances.
when sampling you will need to treat the data as cartesian - essentially using a cylindrical projection (plate carree) to have lines follow parallels.
Source: stackoverflow.com
Related Query
- Curved geojson polygon edges on map projections
- D3 - Large GeoJSON File does not show draw map properly using projections
- Using d3 to map geojson distribution data with projections
- Updating d3 chart added when geojson polygon is clicked to leaflet map
- Center a map in d3 given a geoJSON object
- Is it possible to determine if a GeoJSON point is inside a GeoJSON polygon using JavasScript?
- Displaying map using d3.js and geojson
- Drawing already projected geoJSON map in d3.js
- D3.js map projections on a canvas image
- d3.js: How to convert edges from lines to curved paths in a network visualization by drawing a quadratic Bezier curve?
- Geojson map with D3 only rendering a single path in a feature collection
- Drawing map with d3js from openstreetmap geojson
- Create a curved border around a d3 map projection
- D3.js: Set fitExtent or fitSize (or center and scale programmatically) for map with multiple geoJSON files
- Find in which polygon a GeoJSON point lies in, in NodeJS
- Geojson map not showing up
- Venue/Indoor Map using D3.js and Geojson
- Classify lon/lat coordinate into geojson polygon using Javascript
- Getting NaN values in svg path 'd' attr when trying to map geojson data
- GeoJson Map in Angular2
- Bangalore geojson map with d3 js
- Getting the centroid of each polygon from a GeoJson multipolygon in d3.js
- How to display each state name in d3 india map using GeoJSON
- How can I scale my map to fit my svg size with d3 and geojson path data
- D3 Force Graph With Arrows and Curved Edges - shorten links so arrow doesnt overlap nodes
- Plot network of nodes and edges on map using D3.js
- How to align points on the outer edges of polygon for thicker border in svg?
- Focusing on geojson in D3.js map
- Displaying some text on States on Map using D3.js and GeoJson
- D3 Map XML Polygon ids to JSON data
More Query from same tag
- Uncaught TypeError: n.getMonth is not a function in d3 bar chart
- second d3.js triggered from first doesn't fully iterate over X axis
- d3.js - .exit().remove() a group element is not working
- d3v4 - zooming (Equivalent to d3.zoom.x)
- Showing connected nodes on mouseover shows crossed links
- How to add a title for a NVD3.js graph
- math to svg coordinate translation in javascript
- Created A Bar Chart But Height Is Not Reciprocating Changes
- Don't show negative sign d3 axis labels
- Drawing LineStrings d3
- Change label text color in row chart
- How to display total count on top of the stacked bar chart
- d3 transition not following path
- Spread D3.js legend on two columns
- Interpolation of Colors
- D3 line graph with date slider
- D3 v4 - make a horizontal bar chart with fixed width
- Looking for a better way to alter the color of axis components in d3.js v4
- Adding hover effect in d3 word cloud
- Remove Non-SVG Slider
- d3.js - is it possible to draw and Histogram without the .map?
- interpreting the d3 centering force
- d3.json in d3-ng2-service?
- Convert a value to the existing xScale
- d3.js Multi-Series Graph with JSON
- Transition of triangle svg path in D3.js
- Draw line with d3.js using separate, fixed x & y input arrays
- How do I resize SVG images on a map as the zoom level changes?
- Making a responsive angled svg shape with pattern
- Specify a maximum size in d3 circle packer