block by thomasthoren 550b2ce8b1e2470e75b2

Shaded relief map

Full Screen

Converts shaded relief .tif to .png and uses that for texture underneath a vector layer.

Sources

index.html

<!DOCTYPE html>
<html>
<head>
<title>Shaded relief</title>
<meta charset="utf-8">
<style>

  body {
    padding: 0;
    margin: 0;
  }

  .parishes {
    fill: none;
    stroke: white;
    stroke-width: 1px;
    stroke-opacity: 1;
  }

  .raster {
    fill: none;
    opacity: 1;
  }

  .country-border {
    fill: none;
    stroke: red;
    stroke-width: 5px;
    stroke-opacity: 0.7;
  }

</style>
</head>
<body>
<svg id="map"></svg>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/queue.v1.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script>

  var map_width = 600,
      map_height = 600;

  var svg = d3.select("#map")
    .attr("width", map_width)
    .attr("height", map_height);

  var la_vector_projection = d3.geo.mercator()
    .scale(1)
    .translate([0, 0]);

  var la_vector_path = d3.geo.path()
    .projection(la_vector_projection);

  queue()
    .defer(d3.json, "louisiana.json")
    .await(ready);

  function ready(error, louisiana) {
    if (error) throw error;

    var parishes = topojson.feature(louisiana, louisiana.objects.louisiana);

    var b = la_vector_path.bounds(parishes),
        s = 1 / Math.max((b[1][0] - b[0][0]) / map_width, (b[1][1] - b[0][1]) / map_height),
        t = [(map_width - s * (b[1][0] + b[0][0])) / 2, (map_height - s * (b[1][1] + b[0][1])) / 2];

    // Update the projection to use computed scale & translate.
    la_vector_projection
      .scale(s)
      .translate(t);

    // Raster
    var raster_width = (b[1][0] - b[0][0]) * s;
    var raster_height = (b[1][1] - b[0][1]) * s;

    var rtranslate_x = (map_width - raster_width) / 2;
    var rtranslate_y = (map_height - raster_height) / 2;

    // Shaded relief, Louisiana
    // svg.append("clipPath")
    //   .attr("id", "la_clip")
    // .append("use")
    //   .attr("xlink:href", "#louisiana");
    svg.append("image")
      .attr("clip-path", "url(#la_clip)")
      .attr("xlink:href", "louisiana-crop.png")
      .attr("class", "raster")
      .attr("width", raster_width)
      .attr("height", raster_height)
      .attr("transform", "translate(" + rtranslate_x + ", " + rtranslate_y + ")");
    // svg.append("use")
    //     .attr("xlink:href", "#louisiana");

    // Draw parishes
    svg.append("path")
      .datum(parishes)
      .datum(parishes, function(a, b) { return a !== b; })
      .attr("class", "parishes")
      .attr("id", "louisiana")  // For shaded relief
      .attr("d", la_vector_path);
  }

  // Allows iframe on bl.ocks.org.
  d3.select(self.frameElement).style("height", map_height + "px");

</script>
</body>
</html>

Makefile


.PHONY: all clean

.SECONDARY:

# Download 90-meter SRTM tiles for Louisiana
zip/srtm_%.zip:
	@mkdir -p $(dir $@)
	@curl -sS -o $@.download 'http://srtm.csi.cgiar.org/SRT-ZIP/SRTM_V41/SRTM_Data_GeoTiff/$(notdir $@)'
	@mv $@.download $@
zip/tl_2015_us_county.zip:
	@mkdir -p $(dir $@)
	@curl -sS -o $@.download 'ftp://ftp2.census.gov/geo/tiger/TIGER2015/COUNTY/$(notdir $@)'
	@mv $@.download $@

# Unzip
tif/srtm_%.tif: zip/srtm_%.zip
	@mkdir -p $(dir $@)
	@rm -rf tmp && mkdir tmp
	@unzip -q -o -d tmp $<
	@cp tmp/* $(dir $@)
	@rm -rf tmp
shp/tl_2015_us_county.shp: zip/tl_2015_us_county.zip
	@mkdir -p $(dir $@)
	@rm -rf tmp && mkdir tmp
	@unzip -q -o -d tmp $<
	@cp tmp/* $(dir $@)
	@rm -rf tmp

# Extract Louisiana from U.S.
shp/louisiana.shp: shp/tl_2015_us_county.shp
	@mkdir -p $(dir $@)
	@ogr2ogr \
		-f 'ESRI Shapefile' \
		-t_srs "EPSG:4326" \
		$@ $< \
		-dialect sqlite \
		-sql "SELECT Geometry, \
				STATEFP \
			FROM tl_2015_us_county \
			WHERE STATEFP = '22'"

# Convert to GeoJSON
geojson/louisiana.json: shp/louisiana.shp
	@mkdir -p $(dir $@)
	@ogr2ogr \
		-f 'GeoJSON' \
		$@ $<

# Convert to TopoJSON
topojson/louisiana.json: geojson/louisiana.json
	@mkdir -p $(dir $@)
	@topojson \
		--properties \
		--no-quantization \
		-o $@ \
		-- $<

# Simplify TopoJSON
louisiana.json: topojson/louisiana.json
	@mkdir -p $(dir $@)
	@topojson \
		--properties \
		--spherical \
		-q 1e8 \
		-s 1e-10 \
		-o $@ \
		-- $<

# Merge tiles
tif/louisiana-merged.tif: \
	tif/srtm_17_07.tif \
	tif/srtm_18_07.tif \
	tif/srtm_19_07.tif \
	tif/srtm_17_06.tif \
	tif/srtm_18_06.tif \
	tif/srtm_19_06.tif \
	tif/srtm_17_05.tif \
	tif/srtm_18_05.tif \
	tif/srtm_19_05.tif

	@mkdir -p $(dir $@)
	@gdal_merge.py \
		-o $@ \
		-init "255" \
		tif/srtm_*.tif

# Convert to Mercator, from WGS 84
tif/louisiana-reprojected.tif: tif/louisiana-merged.tif
	@mkdir -p $(dir $@)
	@gdalwarp \
		-co "TFW=YES" \
		-s_srs "EPSG:4326" \
		-t_srs "EPSG:3857" \
		$< \
		$@

# Crop to Louisiana shape
tif/louisiana-cropped.tif: tif/louisiana-reprojected.tif shp/louisiana.shp
	@mkdir -p $(dir $@)
	@# Use nodata=255 to ignore white.
	@gdalwarp \
		-cutline shp/louisiana.shp \
		-crop_to_cutline \
		-dstalpha \
		-srcnodata 255 \
		-dstnodata 255 \
		tif/louisiana-reprojected.tif $@

tif/louisiana-color-crop.tif: tif/louisiana-cropped.tif
	@rm -rf tmp && mkdir -p tmp
	@gdaldem \
		hillshade \
		$< tmp/hillshade.tmp.tif \
		-z 5 \
		-az 315 \
		-alt 60 \
		-compute_edges
	@gdal_calc.py \
		-A tmp/hillshade.tmp.tif \
		--outfile=$@ \
		--calc="255*(A>220) + A*(A<=220)"
	@gdal_calc.py \
		-A tmp/hillshade.tmp.tif \
		--outfile=tmp/opacity_crop.tmp.tif \
		--calc="1*(A>220) + (256-A)*(A<=220)"
	@rm -rf tmp
tif/louisiana-color.tif: tif/louisiana-reprojected.tif
	@rm -rf tmp && mkdir -p tmp
	@gdaldem \
		hillshade \
		$< tmp/hillshade.tmp.tif \
		-z 5 \
		-az 315 \
		-alt 60 \
		-compute_edges
	@gdal_calc.py \
		-A tmp/hillshade.tmp.tif \
		--outfile=$@ \
		--calc="255*(A>220) + A*(A<=220)"
	@gdal_calc.py \
		-A tmp/hillshade.tmp.tif \
		--outfile=tmp/opacity_crop.tmp.tif \
		--calc="1*(A>220) + (256-A)*(A<=220)"
	@rm -rf tmp

louisiana-crop.png: tif/louisiana-color-crop.tif
	@convert \
		-resize x670 \
		$< $@
louisiana.png: tif/louisiana-color.tif
	@convert \
		-resize x670 \
		$< $@

clean:
	@rm -f *.json louisiana*.png
	@rm -rf geojson
	@rm -rf shp
	@rm -rf tif
	@rm -rf topojson

all: louisiana.png \
	louisiana-crop.png \
	louisiana.json