Skip to content

Instantly share code, notes, and snippets.

@armollica
Last active January 6, 2018 13:20
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save armollica/e1ae83935b0028587f1e26cf66b9d190 to your computer and use it in GitHub Desktop.
Save armollica/e1ae83935b0028587f1e26cf66b9d190 to your computer and use it in GitHub Desktop.
Playing with the Satellite Projection
height: 960

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.

#!/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
<!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>
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