Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@MichaelCurrie
Forked from ThomasThoren/README.md
Created June 12, 2017 02:05
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 MichaelCurrie/8ace079d92d97c17ca838700a17c2ae7 to your computer and use it in GitHub Desktop.
Save MichaelCurrie/8ace079d92d97c17ca838700a17c2ae7 to your computer and use it in GitHub Desktop.
Map distance scales

Example of how to create dynamic map distance scales.

<!DOCTYPE html>
<head>
<title>Map distance scales</title>
<meta charset="utf-8">
<style>
body {
padding: 0;
margin: 0;
font-family: helvetica, arial, sans-serif;
}
.parishes {
fill: white;
stroke: #777;
stroke-opacity: 0.5;
stroke-width: 0.5px;
opacity: 0.8;
}
.parish-border {
fill: none;
stroke: #353535;
stroke-opacity: 0.4;
stroke-width: 0.5px;
opacity: 0.8;
}
.state-border {
fill: none;
stroke: #585858;
}
.distance-scale {
font-size: 11px;
line-height: 11px;
position: absolute;
font-weight: 500;
text-transform: uppercase;
color: #000;
}
.distance-scale-line {
stroke: #000;
stroke-width: 1;
stroke-opacity: 1;
opacity: 1;
fill: #000;
}
</style>
</head>
<body>
<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 width = 960,
height = 500;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var projection1 = d3.geo.albers()
.center([0, 31.2])
.rotate([91.6, 0]) // Rotate CCW (looking down onto North Pole)
.parallels([29, 33])
.translate([width * 0.1, height / 2])
.scale(1000);
var projection2 = d3.geo.albers()
.center([0, 31.2])
.rotate([91.6, 0]) // Rotate CCW (looking down onto North Pole)
.parallels([29, 33])
.translate([width * 0.25, height / 2])
.scale(2000);
var projection3 = d3.geo.albers()
.center([0, 31.2])
.rotate([91.6, 0]) // Rotate CCW (looking down onto North Pole)
.parallels([29, 33])
.translate([width * 0.5, height / 2])
.scale(3000);
var projection4 = d3.geo.albers()
.center([0, 31.2])
.rotate([91.6, 0]) // Rotate CCW (looking down onto North Pole)
.parallels([29, 33])
.translate([width * 0.8, height / 2])
.scale(4000);
var map_path1 = d3.geo.path().pointRadius(2).projection(projection1);
var map_path2 = d3.geo.path().pointRadius(2).projection(projection2);
var map_path3 = d3.geo.path().pointRadius(2).projection(projection3);
var map_path4 = d3.geo.path().pointRadius(2).projection(projection4);
queue()
.defer(d3.json, "parishes.json")
.await(ready);
function pixelLength(this_topojson, this_projection, miles) {
// topojson = topojson.feature(districts, districts.objects['afghanistan-districts'])
// Calculates the window pixel length for a given map distance.
// Not sure if math is okay, given arcs, projection distortion, etc.
var actual_map_bounds = d3.geo.bounds(this_topojson);
var radians = d3.geo.distance(actual_map_bounds[0], actual_map_bounds[1]);
var earth_radius = 3959; // miles
var arc_length = earth_radius * radians; // s = r * theta
var projected_map_bounds = [
this_projection(actual_map_bounds[0]),
this_projection(actual_map_bounds[1])
];
var projected_map_width = projected_map_bounds[1][0] - projected_map_bounds[0][0];
var projected_map_height = projected_map_bounds[0][1] - projected_map_bounds[1][1];
var projected_map_hypotenuse = Math.sqrt(
(Math.pow(projected_map_width, 2)) + (Math.pow(projected_map_height, 2))
);
var pixels_per_mile = projected_map_hypotenuse / arc_length;
var pixel_distance = pixels_per_mile * miles;
return pixel_distance;
}
function ready(error, data) {
if (error) throw error;
// First multiple
var map1 = svg.append("g")
.attr("class", "parishes")
.attr("id", "map1")
.attr("transform", "translate(0, -90)");
map1.selectAll("path")
.data(topojson.feature(data, data.objects.parishes).features)
.enter().append("path")
.attr("d", map_path1);
map1.append("path")
.datum(topojson.mesh(data, data.objects.parishes, function(a, b) { return a !== b; }))
.attr("class", "parish-border")
.attr("d", map_path1);
map1.append("path")
.datum(topojson.mesh(data, data.objects.parishes, function(a, b) { return a === b; }))
.attr("class", "state-border")
.attr("d", map_path1);
// Second multiple
var map2 = svg.append("g")
.attr("class", "parishes")
.attr("id", "map2")
.attr("transform", "translate(0, -60)");
map2.selectAll("path")
.data(topojson.feature(data, data.objects.parishes).features)
.enter().append("path")
.attr("d", map_path2);
map2.append("path")
.datum(topojson.mesh(data, data.objects.parishes, function(a, b) { return a !== b; }))
.attr("class", "parish-border")
.attr("d", map_path2);
map2.append("path")
.datum(topojson.mesh(data, data.objects.parishes, function(a, b) { return a === b; }))
.attr("class", "state-border")
.attr("d", map_path2);
// Third multiple
var map3 = svg.append("g")
.attr("class", "parishes")
.attr("id", "map3")
.attr("transform", "translate(0, -30)");
map3.selectAll("path")
.data(topojson.feature(data, data.objects.parishes).features)
.enter().append("path")
.attr("d", map_path3);
map3.append("path")
.datum(topojson.mesh(data, data.objects.parishes, function(a, b) { return a !== b; }))
.attr("class", "parish-border")
.attr("d", map_path3);
map3.append("path")
.datum(topojson.mesh(data, data.objects.parishes, function(a, b) { return a === b; }))
.attr("class", "state-border")
.attr("d", map_path3);
// Fourth multiple
var map4 = svg.append("g")
.attr("class", "parishes")
.attr("id", "map4");
map4.selectAll("path")
.data(topojson.feature(data, data.objects.parishes).features)
.enter().append("path")
.attr("d", map_path4);
map4.append("path")
.datum(topojson.mesh(data, data.objects.parishes, function(a, b) { return a !== b; }))
.attr("class", "parish-border")
.attr("d", map_path4);
map4.append("path")
.datum(topojson.mesh(data, data.objects.parishes, function(a, b) { return a === b; }))
.attr("class", "state-border")
.attr("d", map_path4);
// Distance scale
// Line path generator
var line = d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.interpolate("basis");
// Scale1
var pixels_per_hundred_1 = pixelLength(topojson.feature(data, data.objects['parishes']), projection1, 100);
var distance_scale1 = svg.selectAll("#distance-scale1")
.data([pixels_per_hundred_1])
.enter().append("g")
.attr("class", "distance-scale")
.attr("id", "distance-scale1")
.attr("transform", "translate(-35, 0)")
.attr("width", function(d) { return d; });
distance_scale1.append('text')
.attr("x", width * 0.1)
.attr("y", height * 0.1)
.attr("text-anchor", "start")
.text("100 miles");
distance_scale1.append('path')
.attr("class", "distance-scale-line")
.attr("d", function(d, i) {
var lineData = [
{"x": width * 0.1, "y": height * 0.1 + 10},
{"x": width * 0.1 + d, "y": height * 0.1 + 10}
];
return line(lineData);
});
// Scale2
var pixels_per_hundred_2 = pixelLength(topojson.feature(data, data.objects['parishes']), projection2, 100);
var distance_scale2 = svg.selectAll("#distance-scale2")
.data([pixels_per_hundred_2])
.enter().append("g")
.attr("class", "distance-scale")
.attr("id", "distance-scale2")
.attr("transform", "translate(-70, 0)")
.attr("width", function(d) { return d; });
distance_scale2.append('text')
.attr("x", width * 0.25)
.attr("y", height * 0.1)
.attr("text-anchor", "start")
.text("100 miles");
distance_scale2.append('path')
.attr("class", "distance-scale-line")
.attr("d", function(d, i) {
var lineData = [
{"x": width * 0.25, "y": height * 0.1 + 10},
{"x": width * 0.25 + d, "y": height * 0.1 + 10}
];
return line(lineData);
});
// Scale3
var pixels_per_hundred_3 = pixelLength(topojson.feature(data, data.objects['parishes']), projection3, 100);
var distance_scale3 = svg.selectAll("#distance-scale3")
.data([pixels_per_hundred_3])
.enter().append("g")
.attr("class", "distance-scale")
.attr("id", "distance-scale3")
.attr("transform", "translate(-110, 0)")
.attr("width", function(d) { return d; });
distance_scale3.append('text')
.attr("x", width * 0.5)
.attr("y", height * 0.1)
.attr("text-anchor", "start")
.text("100 miles");
distance_scale3.append('path')
.attr("class", "distance-scale-line")
.attr("d", function(d, i) {
var lineData = [
{"x": width * 0.5, "y": height * 0.1 + 10},
{"x": width * 0.5 + d, "y": height * 0.1 + 10}
];
return line(lineData);
});
// Scale4
var pixels_per_hundred_4 = pixelLength(topojson.feature(data, data.objects['parishes']), projection4, 100);
var distance_scale4 = svg.selectAll("#distance-scale4")
.data([pixels_per_hundred_4])
.enter().append("g")
.attr("class", "distance-scale")
.attr("id", "distance-scale4")
.attr("transform", "translate(-140, 0)")
.attr("width", function(d) { return d; });
distance_scale4.append('text')
.attr("x", width * 0.8)
.attr("y", height * 0.1)
.attr("text-anchor", "start")
.text("100 miles");
distance_scale4.append('path')
.attr("class", "distance-scale-line")
.attr("d", function(d, i) {
var lineData = [
{"x": width * 0.8, "y": height * 0.1 + 10},
{"x": width * 0.8 + d, "y": height * 0.1 + 10}
];
return line(lineData);
});
}
// Allows iframe on bl.ocks.org.
d3.select(self.frameElement).style("height", height + "px");
</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