Skip to content

Instantly share code, notes, and snippets.

@duhaime
Forked from Fil/.block
Created September 11, 2018 10:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save duhaime/5721183a3fa4d2f735d3277b3007a068 to your computer and use it in GitHub Desktop.
Save duhaime/5721183a3fa4d2f735d3277b3007a068 to your computer and use it in GitHub Desktop.
visualizing map distortion d3v4
license: mit
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="//d3js.org/d3.v4.min.js"></script>
<script src="//d3js.org/d3-geo-projection.v2.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<style>
svg {
margin: 22px;
}
select {
margin-left: 20px;
}
path.foreground {
fill: none;
stroke: #333;
stroke-width: 1.5px;
}
path.graticule {
fill: none;
stroke: #aaa;
stroke-width: .5px;
}
#left {
cursor: move;
}
#left .land {
fill: #d7c7ad;
stroke: #a5967e;
}
#right .land {
fill: #cfcece;
stroke: #a5967e;
}
#left circle {
fill: #d8355e;
}
#right circle {
stroke: #d8355e;
fill: none;
}
</style>
</head>
<body>
<svg id="left"></svg>
<svg id="right"></svg>
<select></select>
<script>
var map_width = 400;
var map_height = 400;
var center = [-90, 37];
var scale0 = (map_width - 1) / 2 / Math.PI * 6
var scale1 = (map_width - 1) / 2 / Math.PI * 3
var zoom = d3.zoom()
.on("zoom", zoomed);
var projectionLeft = d3.geoAitoff()
.center(center)
var projectionRight = d3.geoOrthographic()
.center(center)
.translate([map_width/5, map_height / 5])
.scale(scale1)
.clipAngle(90)
var pathLeft = d3.geoPath()
.projection(projectionLeft);
var pathRight = d3.geoPath()
.projection(projectionRight);
function zoomed() {
projectionLeft
.translate([d3.event.transform.x, d3.event.transform.y])
.scale(d3.event.transform.k)
var newCenter = projectionLeft.invert([map_width/2,map_height/2]);
projectionRight .rotate([-newCenter[0], -newCenter[1]])
update();
}
function update() {
d3.selectAll("#left path")
.attr("d", pathLeft);
d3.selectAll("#right path")
.attr("d", pathRight);
d3.selectAll("#left circle")
.attr('transform', function(d,i) {
return 'translate(' + [ d.x, d.y ] + ')';
})
d3.selectAll("#right circle")
.attr('transform', function(d,i) {
try {
var latlon = projectionLeft.invert([d.x, d.y])
return 'translate(' + projectionRight(latlon) + ')';
} catch(e) {
return 'translate(-100,-100)';
}
})
}
var graticule = d3.geoGraticule();
var svgLeft = d3.select("#left")
.attr("width", map_width)
.attr("height", map_height);
var svgRight = d3.select("#right")
.attr("width", map_width + 40)
.attr("height", map_height);
svgLeft.append("path")
.datum(graticule)
.attr("class", "graticule")
.attr("d", pathLeft);
svgRight.append("path")
.datum(graticule)
.attr("class", "graticule")
.attr("d", pathRight);
d3.json("world-110m.json", function(error,world) {
if (error) throw error;
svgLeft.insert("path", ".graticule")
.datum(topojson.feature(world, world.objects.land))
.attr("class", "land")
.attr("d", pathLeft);
svgRight.insert("path", ".graticule")
.datum(topojson.feature(world, world.objects.land))
.attr("class", "land")
.attr("d", pathRight);
var points = generateRect(100, 25, 25, map_width - 50, map_height - 50);
svgLeft.selectAll("circle")
.data(points)
.enter().append("circle")
.attr('r', 3)
svgRight.selectAll("circle")
.data(points)
.enter().append("circle")
.attr('r', 2)
svgLeft
.call(zoom)
.call(
zoom.transform,
d3.zoomIdentity.translate(map_width/2,map_height/2)
.scale(scale0)
)
;
});
var projections = {
"Aitoff": d3.geoAitoff().scale(90),
"Boggs Eumorphic": d3.geoBoggs().scale(90),
"Craster Parabolic (Putnins P4)": d3.geoCraster().scale(90),
"Cylindrical Equal-Area": d3.geoCylindricalEqualArea().scale(120),
"Eckert I": d3.geoEckert1().scale(95),
"Eckert III": d3.geoEckert3().scale(105),
"Eckert IV": d3.geoEckert4().scale(105),
"Eckert V": d3.geoEckert5().scale(100),
"Equidistant Cylindrical (Plate Carrée)": d3.geoEquirectangular().scale(90),
"Fahey": d3.geoFahey().scale(75),
"Foucaut Sinusoidal": d3.geoFoucaut().scale(80),
"Gall (Gall Stereographic)": d3.geoCylindricalStereographic().scale(70),
"Ginzburg VIII (TsNIIGAiK 1944)": d3.geoGinzburg8().scale(75),
"Kavraisky VII": d3.geoKavrayskiy7().scale(90),
"Larrivée": d3.geoLarrivee().scale(55),
"McBryde-Thomas Flat-Pole Sine (No. 2)": d3.geoMtFlatPolarSinusoidal().scale(95),
"Mercator": d3.geoMercator().scale(50),
"Miller Cylindrical I": d3.geoMiller().scale(60),
"Mollweide": d3.geoMollweide().scale(100),
"Natural Earth": d3.geoNaturalEarth().scale(100),
"Nell-Hammer": d3.geoNellHammer().scale(120),
"Quartic Authalic": d3.geoHammer().coefficient(Infinity).scale(95),
"Robinson": d3.geoRobinson().scale(90),
"Sinusoidal": d3.geoSinusoidal().scale(90),
"van der Grinten (I)": d3.geoVanDerGrinten().scale(50),
"Wagner VI": d3.geoWagner6().scale(90),
"Wagner VII": d3.geoWagner7().scale(90),
"Winkel Tripel": d3.geoWinkel3().scale(90),
"Wiechel": d3.geoWiechel().scale(90) };
var selector = d3.select("select")
selector.selectAll("option")
.data(Object.keys(projections))
.enter().append("option")
.attr('value', function(d) { return d }).text(function(d) { return d })
selector.on("change", function(d) {
console.log("sup", d3.event)
var proj = d3.event.target.selectedOptions[0].value;
projectionLeft = projections[proj].center(center);
pathLeft = d3.geoPath()
.projection(projectionLeft);
svgLeft
.call(zoom)
.call(
zoom.transform,
d3.zoomIdentity.translate(map_width/2,map_height/2)
.scale(scale0)
)
;
})
function generateRect(num, x, y, width, height) {
var points = []
var sideNum = Math.floor(num/4) + 1;
// top
d3.range(sideNum).forEach(function(i) {
points.push({ x: x + i * width/sideNum, y: y })
})
// right
d3.range(sideNum).forEach(function(i) {
points.push({ x: x + width, y: y + i * height/sideNum })
})
// bottom
d3.range(sideNum).forEach(function(i) {
points.push({ x: x + width - i * width/sideNum, y: y + height })
})
// left
d3.range(sideNum).forEach(function(i) {
points.push({ x: x, y: y + height - i * height/sideNum })
})
return points;
}
</script>
</body>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-67666917-1', 'auto');
ga('send', 'pageview');
</script>
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment