Skip to content

Instantly share code, notes, and snippets.

@renecnielsen
Last active July 5, 2017 12:33
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 renecnielsen/d69a519688ec284190cc592e68fe6292 to your computer and use it in GitHub Desktop.
Save renecnielsen/d69a519688ec284190cc592e68fe6292 to your computer and use it in GitHub Desktop.
Projection explorer
license: gpl-3.0
height: 620
border: no
<!DOCTYPE html>
<meta charset="utf-8">
<head>
<title>Geo (projection configuration)</title>
</head>
<style>
body {
font-family: "Helvetica Neue", Helvetica, sans-serif;
font-size: 12px;
color: #333;
margin: 10px;
}
#description {
margin: 20px 0;
font-size: 16px;
line-height: 24px;
color: #555;
}
#menu {
position: absolute;
top: 20px;
left: 30px;
}
#menu .item {
margin-bottom: 12px;
}
#menu .item input {
width: 100px;
}
#menu select {
margin-top: 4px;
}
#menu .item .value {
font-weight: bold;
}
#menu .item span, #menu .item input {
vertical-align: middle;
}
#menu .item .low {
display: inline-block;
width: 30px;
text-align: right;
}
svg {
border: 1px solid #eee;
}
.map path {
fill: #45716a;
stroke: #777;
}
.projection-center {
fill: red;
}
.graticule path {
fill: none;
stroke: #eee;
}
.circles path {
fill: none;
stroke: #aaa;
}
</style>
<body>
<div id="menu">
<div class="projection-type item">
<div><select name="type" value="150"></select></div>
</div>
<div class="slider item">
<div class="label">scale (<span class="value">120</span>)</div>
<div><span class="low">0</span> <input type="range" name="scale" min="0" max="400" value="120"> <span>400</span></div>
</div>
<div class="slider item">
<div class="label">translate (x) (<span class="value">480</span>)</div>
<div><span class="low">0</span> <input type="range" name="translateX" min="0" max="960" value="480"> <span>960</span></div>
</div>
<div class="slider item">
<div class="label">translate (y) (<span class="value">250</span>)</div>
<div><span class="low">0</span> <input type="range" name="translateY" min="0" max="500" value="250"> <span>500</span></div>
</div>
<div class="slider item">
<div class="label">center (lon) (<span class="value">0</span>)</div>
<div><span class="low">-180</span> <input type="range" name="centerLon" min="-180" max="180" value="0"> <span>180</span></div>
</div>
<div class="slider item">
<div class="label">center (lat) (<span class="value">0</span>)</div>
<div><span class="low">-90</span> <input type="range" name="centerLat" min="-90" max="90" value="0"> <span>90</span></div>
</div>
<div class="slider item">
<div class="label">rotate (&lambda;) (<span class="value">0</span>)</div>
<div><span class="low">-180</span> <input type="range" name="rotateLambda" min="-180" max="180" value="0"> <span>180</span></div>
</div>
<div class="slider item">
<div class="label">rotate (&phi;) (<span class="value">0</span>)</div>
<div><span class="low">-180</span> <input type="range" name="rotatePhi" min="-180" max="180" value="0"> <span>180</span></div>
</div>
<div class="slider item">
<div class="label">rotate (&gamma;) (<span class="value">0</span>)</div>
<div><span class="low">-180</span> <input type="range" name="rotateGamma" min="-180" max="180" value="0"> <span>180</span></div>
</div>
</div>
<svg width="960px" height="500px">
<g class="graticule"><path></path></g>
<g class="circles"></g>
<g class="map"></g>
<circle class="projection-center" r="4"></circle>
</svg>
<div id="description">
<div>Explore <a href="https://d3js.org/" target="_blank">D3</a>'s geographic projections and their <a href="https://github.com/d3/d3-geo/blob/master/README.md#projection_scale" target="_blank">scale</a>, <a href="https://github.com/d3/d3-geo/blob/master/README.md#projection_translate" target="_blank">translate</a>, <a href="https://github.com/d3/d3-geo/blob/master/README.md#projection_center" target="_blank">center</a> and <a href="https://github.com/d3/d3-geo/blob/master/README.md#projection_rotate" target="_blank">rotate</a> parameters. The red dot indicates the <a href="https://github.com/d3/d3-geo/blob/master/README.md#projection_center" target="_blank">projection center</a>.</div>
<div>To demonstrate area distortion (e.g. Mercator) grey circles with the same radius have also been added.</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script>
<script>
var geojson;
var projectionTypes = [
'AzimuthalEqualArea',
'AzimuthalEquidistant',
'Gnomonic',
'Orthographic',
'Stereographic',
'Albers',
'ConicConformal',
'ConicEqualArea',
'ConicEquidistant',
'Equirectangular',
'Mercator',
'TransverseMercator'
];
var projection;
var geoGenerator = d3.geoPath()
.projection(projection);
var graticule = d3.geoGraticule();
var circles = [
[-135, 0], [-90, 0], [-45, 0], [0, 0], [45, 0], [90, 0], [135, 0], [180, 0],
[0, -70], [0, -35], [0, 35], [0, 70],
[180, -70], [180, -35], [180, 35], [180, 70],
];
var geoCircle = d3.geoCircle().radius(10).precision(1);
var state = {
type: 'AzimuthalEqualArea',
scale: 120,
translateX: 480,
translateY: 250,
centerLon: 0,
centerLat: 0,
rotateLambda: 0.1,
rotatePhi: 0,
rotateGamma: 0
}
function initMenu() {
d3.select('#menu')
.selectAll('.slider.item input')
.on('input', function(d) {
var attr = d3.select(this).attr('name');
state[attr] = this.value;
d3.select(this.parentNode.parentNode).select('.value').text(this.value);
update()
});
d3.select('#menu .projection-type select')
.on('change', function(d) {
state.type = this.options[this.selectedIndex].value;
update()
})
.selectAll('option')
.data(projectionTypes)
.enter()
.append('option')
.attr('value', function(d) {return d;})
.text(function(d) {return d;});
}
function update() {
// Update projection
projection = d3['geo' + state.type]()
geoGenerator.projection(projection);
projection
.scale(state.scale)
.translate([state.translateX, state.translateY])
.center([state.centerLon, state.centerLat])
.rotate([state.rotateLambda, state.rotatePhi, state.rotateGamma])
// Update world map
var u = d3.select('g.map')
.selectAll('path')
.data(geojson.features)
u.enter()
.append('path')
.merge(u)
.attr('d', geoGenerator)
// Update projection center
var projectedCenter = projection([state.centerLon, state.centerLat]);
d3.select('.projection-center')
.attr('cx', projectedCenter[0])
.attr('cy', projectedCenter[1]);
// Update graticule
d3.select('.graticule path')
.datum(graticule())
.attr('d', geoGenerator);
// Update circles
u = d3.select('.circles')
.selectAll('path')
.data(circles.map(function(d) {
geoCircle.center(d);
return geoCircle();
}));
u.enter()
.append('path')
.merge(u)
.attr('d', geoGenerator);
}
d3.json('ne_110m_land.json', function(err, json) {
geojson = json;
initMenu();
update();
})
</script>
</body>
</html>
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