Playing with the parameters for d3.geoSatellite()
.
Focusing just on the U.S. at the moment. Hope to expand it for the whole world at some point.
Check out this block by Elijah Meeks for another satellite projection explorer tool.
<!DOCTYPE html>
<html>
<head>
<style>
html, body {
font-family: monospace;
color: #333;
}
.container {
position: relative;
}
#controls {
position: absolute;
top: 0;
padding: 25px 25px 25px 25px;
opacity: 0.5;
transition: opacity 0.1s;
}
#controls:hover {
opacity: 1;
}
.control {
display: inline-block;
position: relative;
}
.control input {
width: 75px;
}
.control .label {
text-transform: uppercase;
font-size: 10px;
color: #555;
position: absolute;
bottom: 100%;
text-shadow: -2px -2px 1px #fff,
-2px -1px 1px #fff,
-2px 0px 1px #fff,
-2px 1px 1px #fff,
-2px 2px 1px #fff,
-1px -2px 1px #fff,
-1px -1px 1px #fff,
-1px 0px 1px #fff,
-1px 1px 1px #fff,
-1px 2px 1px #fff,
0px -2px 1px #fff,
0px -1px 1px #fff,
0px 1px 1px #fff,
0px 2px 1px #fff,
1px -2px 1px #fff,
1px -1px 1px #fff,
1px 0px 1px #fff,
1px 1px 1px #fff,
1px 2px 1px #fff,
2px -2px 1px #fff,
2px -1px 1px #fff,
2px 0px 1px #fff,
2px 1px 1px #fff,
2px 2px 1px #fff;
}
</style>
</head>
<body>
<div class="container">
<div id="controls">
<div class="control">
<span class="label">Distance</span>
<input id="distance" type="number" value="1.11" step="0.01" min="0" max="5">
</div>
<div class="control">
<span class="label">Tilt</span>
<input id="tilt" type="number" value="21.7" step="0.1" min="0" max="100">
</div>
<div class="control">
<span class="label">Scale</span>
<input id="scale" type="number" value="5500" step="10">
</div>
<div class="control">
<span class="label">Yaw</span>
<input id="yaw" type="number" value="70.8" step="0.05">
</div>
<div class="control">
<span class="label">Pitch</span>
<input id="pitch" type="number" value="-39.95" step="0.05">
</div>
<div class="control">
<span class="label">Roll</span>
<input id="roll" type="number" value="-87.43" step="0.05">
</div>
<div class="control">
<span class="label">cX</span>
<input id="cx" type="number" value="1.15" step="0.05">
</div>
<div class="control">
<span class="label">cY</span>
<input id="cy" type="number" value="10.2" step="0.05">
</div>
</div>
<canvas id="map"></canvas>
</div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-geo-projection.v2.min.js"></script>
<script src="https://unpkg.com/topojson@3"></script>
<script>
var width = 960,
height = 960,
drawMap = function() {}
var canvas = d3.select('canvas#map')
.attr('width', width)
.attr('height', height);
var context = canvas.node().getContext('2d');
var projection = d3.geoSatellite()
.precision(.1);
var controls = d3.select('#controls');
controls.selectAll('input').on('change', updateProjection);
var graticule = d3.geoGraticule().step([3, 3]);
var path = d3.geoPath()
.projection(projection)
.pointRadius(2)
.context(context);
d3.json('topo.json', function (error, topo) {
if (error) throw error;
var states = topojson.feature(topo, topo.objects.states),
urbanAreas = topojson.feature(topo, topo.objects['urban-areas']),
populatedPlaces = topojson.feature(topo, topo.objects['populated-places']);
drawMap = function() {
context.clearRect(0, 0, width, height);
// Graticule
context.save();
context.beginPath();
path(graticule());
context.strokeStyle = '#777';
context.stroke();
context.restore();
// States
context.save();
context.globalAlpha = 0.8;
context.beginPath();
path(states);
context.strokeStyle = '#555';
context.fillStyle = '#eee';
context.stroke();
context.fill();
context.restore();
// Urban areas
context.save();
context.beginPath();
context.globalAlpha = 0.8;
path(urbanAreas);
context.fillStyle = '#999';
context.fill();
// Populated Places
context.save();
context.beginPath();
path(populatedPlaces);
context.strokeStyle = 'darkred';
context.stroke();
context.restore();
context.save();
context.font = '12px monospace';
context.textAlign = 'center';
context.fillStyle = '#333';
context.shadowColor = '#fff';
context.shadowBlur = 2;
populatedPlaces.features.forEach(function(place) {
var p = projection(place.geometry.coordinates);
context.fillText(place.properties.NAME, p[0], p[1] - 7);
});
context.restore();
};
updateProjection();
});
function updateProjection() {
projection
.distance(controls.select('#distance').node().value)
.tilt(controls.select('#tilt').node().value)
.scale(controls.select('#scale').node().value)
.rotate([
controls.select('#yaw').node().value,
controls.select('#pitch').node().value,
controls.select('#roll').node().value
])
.center([
controls.select('#cx').node().value,
controls.select('#cy').node().value
])
.clipAngle(Math.acos(1 / controls.select('#distance').node().value) * 180 / Math.PI - 1e-6);
drawMap();
}
</script>
</body>
</html>
#!/usr/bin/env bash
####
# Setup
mkdir -p tmp zip geojson
####
# Download data and convert to GeoJSON
# States
if [ ! -e zip/states.zip ]; then
curl -L -o zip/states.zip 'http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_1_states_provinces.zip'
fi
if [ ! -e geojson/states.json ]; then
unzip -o -d tmp zip/states.zip
mapshaper tmp/ne_10m_admin_1_states_provinces.shp -o geojson/states.json
fi
# Populated places
if [ ! -e zip/populated-places.zip ]; then
curl -L -o zip/populated-places.zip 'http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_populated_places.zip'
fi
if [ ! -e geojson/populated-places.json ]; then
unzip -o -d tmp zip/populated-places.zip
mapshaper tmp/ne_10m_populated_places.shp -o geojson/populated-places.json force
fi
# Urban areas
if [ ! -e zip/urban-areas.zip ]; then
curl -L -o zip/urban-areas.zip 'http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_urban_areas.zip'
fi
if [ ! -e geojson/urban-areas.json ]; then
unzip -o -d tmp zip/urban-areas.zip
mapshaper tmp/ne_10m_urban_areas.shp -o geojson/urban-areas.json force
fi
####
# Combine data into TopoJSON\
mapshaper \
-i geojson/states.json \
geojson/populated-places.json \
geojson/urban-areas.json \
combine-files \
-filter 'ADM0NAME == "United States of America" && ADM1NAME !== "Alaska" && ADM1NAME !== "Hawaii" && SCALERANK < 4' target=populated-places \
-filter 'admin == "United States of America"' target=states \
-clip states target=urban-areas \
-simplify 8% \
-o topo.json format=topojson target=* force
####
# Clean up
rm -rf tmp