|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<style> |
|
.rail { |
|
fill:none; |
|
stroke-width: 1; |
|
stroke: #000; |
|
} |
|
.contour { |
|
fill:none; |
|
stroke-width: 0.5; |
|
stroke: #bbb; |
|
|
|
} |
|
.structures { |
|
stroke-width: 20px; |
|
opacity: 0.4; |
|
stroke: #000; |
|
fill:none; |
|
} |
|
.water { |
|
fill: #43a2ca; |
|
} |
|
svg { |
|
background: #a8ddb5; |
|
} |
|
</style> |
|
<body> |
|
<svg width="960" height="500"></svg> |
|
|
|
<script src="https://d3js.org/d3.v4.min.js"></script> |
|
<script src="https://d3js.org/d3-geo-projection.v1.min.js"></script> |
|
<script src="https://d3js.org/topojson.v1.min.js"></script> |
|
|
|
<script> |
|
var svg = d3.select("svg"), |
|
width = +svg.attr("width"), |
|
height = +svg.attr("height"); |
|
|
|
var projection = d3.geoKavrayskiy7() |
|
.scale(1050000) |
|
.rotate([116.41, 0]) |
|
.center([0,51.428]) |
|
.translate([width / 2, height / 2]) |
|
.precision(.1); |
|
|
|
var path = d3.geoPath() |
|
.projection(projection); |
|
|
|
var g = svg.append("g"); |
|
var g2 = svg.append("g"); |
|
|
|
d3.json("spiral.json", function(error, spiral) { |
|
// Add the rail |
|
var paths = g2.selectAll("path") |
|
.data(topojson.feature(spiral, spiral.objects.tracks).features) |
|
.enter().append("path") |
|
.attr("d", path) |
|
.attr("class", "rail") |
|
.attr("id",function(d,i) { return "b" + i }); |
|
|
|
// Figure out how many cross hatches are needed for each track section |
|
paths.each(function(d,i) { |
|
var currentPath = d3.select("#b" + i).node(); |
|
var totalLength = currentPath.getTotalLength(); |
|
var numberOfSymbols = Math.round(totalLength/6); |
|
var spacingOfSymbols = totalLength/numberOfSymbols; |
|
var intialSpacng = spacingOfSymbols/2; |
|
var j = 0; |
|
|
|
// Add each cross hatch at the right angle |
|
while (j < numberOfSymbols) { |
|
var p1 = currentPath.getPointAtLength( (spacingOfSymbols/2 - 5) + (spacingOfSymbols * j) ); |
|
var p2 = currentPath.getPointAtLength( (spacingOfSymbols/2 + 5) + (spacingOfSymbols * j) ); |
|
var p3 = currentPath.getPointAtLength( (spacingOfSymbols/2) + (spacingOfSymbols * j) ); |
|
|
|
var r = 3; // length of cross hatch from line |
|
|
|
var m = (p2.y - p1.y) / (p1.x - p2.x); |
|
m = 1/m; |
|
var k = r / Math.sqrt( 1 + (m*m) ); |
|
|
|
if (m == Infinity) { |
|
p1.x = p3.x; |
|
p1.y = p3.y + r; |
|
|
|
p2.y = p3.y - r; |
|
p2.x = p3.x; |
|
} |
|
|
|
else { |
|
|
|
p1.x = p3.x + k; |
|
p1.y = p3.y + (m * k); |
|
|
|
p2.x = p3.x - k; |
|
p2.y = p3.y - (m * k); |
|
} |
|
|
|
var line = g2.append("line") |
|
.attr("x1",p1.x) |
|
.attr("x2",p2.x) |
|
.attr("y1",p1.y) |
|
.attr("y2",p2.y) |
|
.attr("class", "rail") |
|
.attr("stroke-width",1) |
|
; |
|
j++; |
|
} |
|
}); |
|
}) |
|
|
|
|
|
d3.json("contours.json", function(error, contours) { |
|
// contours |
|
var paths = g.selectAll(".contour") |
|
.data(topojson.feature(contours, contours.objects.contours).features) |
|
.enter().append("path") |
|
.attr("d", path) |
|
.attr("class", "contour") |
|
; |
|
}); |
|
|
|
d3.json("structures.json", function(error, structures) { |
|
// structures - bridges/tunnels/avalanche sheds |
|
var paths = g.selectAll(".structures") |
|
.data(topojson.feature(structures, structures.objects.structures).features) |
|
.enter().append("path") |
|
.attr("d", path) |
|
.attr("class", "structures") |
|
; |
|
}); |
|
|
|
d3.json("water.json", function(error, water) { |
|
// add water |
|
var paths = g.selectAll(".water") |
|
.data(topojson.feature(water, water.objects.water).features) |
|
.enter().append("path") |
|
.attr("d", path) |
|
.attr("class", "water") |
|
; |
|
}); |
|
|
|
</script> |