|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<style> |
|
.graticule { |
|
fill: none; |
|
stroke: #ddd; |
|
stroke-width: 0.5px; |
|
stroke-opacity: 0.5; |
|
} |
|
.land { |
|
fill: #a8ddb5; |
|
} |
|
.boundary { |
|
fill: none; |
|
stroke: #fff; |
|
stroke-width: 0.5px; |
|
} |
|
.front { |
|
fill:none; |
|
stroke-width: 4; |
|
stroke: #000; |
|
} |
|
.front-marker { |
|
fill:black; |
|
fill-opacity: 1; |
|
stroke:black; |
|
stroke-width: 1 |
|
} |
|
</style> |
|
<body> |
|
<svg width="960" height="500"> |
|
|
|
<defs><marker id="warm-up" viewBox="0 0 24 24" refX="0" refY="15" |
|
orient="auto" markerWidth="24" markerHeight="24"> |
|
<path d="M2 14 L22 14 A10 10 0 0 0 2 14" /> |
|
</marker></defs> |
|
|
|
<defs><marker id="warm-down" viewBox="0 0 24 24" refX="12" refY="13" |
|
orient="auto" markerWidth="24" markerHeight="24"> |
|
<path d="M2 14 L22 14 A10 10 0 0 1 2 14" /> |
|
</marker></defs> |
|
|
|
<defs><marker id="cool-down" viewBox="0 0 24 24" refX="12" refY="11" |
|
orient="auto" markerWidth="24" markerHeight="24"> |
|
<polygon points="2 11, 22 12, 11 23" |
|
</marker></defs> |
|
|
|
<defs><marker id="cool-up" viewBox="0 0 24 24" refX="12" refY="13" |
|
orient="auto" markerWidth="24" markerHeight="24"> |
|
<polygon points="2 11, 22 11, 12 1" /> |
|
</marker></defs> |
|
|
|
</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(1700) |
|
.rotate([78, 0]) |
|
.center([0,35]) |
|
.translate([width / 2, height / 2]) |
|
.precision(.1); |
|
|
|
var path = d3.geoPath() |
|
.projection(projection); |
|
|
|
var g = svg.append("g"); |
|
var g2 = svg.append("g"); |
|
|
|
// Add globe outline and graticule |
|
g.append("path") |
|
.datum({type: "Sphere"}) |
|
.attr("class", "sphere") |
|
.attr("d", path) |
|
.attr("fill", "#43a2ca") |
|
.attr("stroke", "black"); |
|
|
|
g.append("path") |
|
.datum(d3.geoGraticule()) |
|
.attr("class", "graticule") |
|
.attr("d", path); |
|
|
|
// Add world map |
|
d3.json("world.json", function(error, world) { |
|
if (error) throw error; |
|
|
|
g.insert("path", ".land") |
|
.datum(topojson.feature(world, world.objects.land)) |
|
.attr("class", "land") |
|
.attr("d", path); |
|
|
|
g.insert("path", ".boundary") |
|
.datum(topojson.mesh(world, world.objects.countries, function(a, b) { return a !== b; })) |
|
.attr("class", "boundary") |
|
.attr("d", path); |
|
|
|
}); |
|
|
|
d3.json("fronts.json", function(error, fronts) { |
|
// Add the fronts |
|
var paths = g2.selectAll("path") |
|
.data(topojson.feature(fronts, fronts.objects.fronts).features) |
|
.enter().append("path") |
|
.attr("d", path) |
|
.attr("class", "front") |
|
.attr("id",function(d,i) { return "b" + i }); |
|
|
|
// Figure out how many markers and how often they need to be displayed |
|
paths.each(function(d,i) { |
|
var currentPath = d3.select("#b" + i).node(); |
|
var totalLength = currentPath.getTotalLength(); |
|
var numberOfSymbols = Math.round(totalLength/50); |
|
var spacingOfSymbols = totalLength/numberOfSymbols; |
|
var intialSpacng = spacingOfSymbols/2; |
|
console.log(currentPath); |
|
var j = 0; |
|
|
|
// For each marker that needs to be added, append a line with a marker. |
|
while ( j < numberOfSymbols) { |
|
|
|
var markerType; |
|
if (i % 4 == 0) { markerType = "#warm-down"; } |
|
if (i % 4 == 1) { markerType = "#cool-down"; } |
|
if (i % 4 == 2) { markerType = "#warm-up"; } |
|
if (i % 4 == 3) { markerType = "#cool-up"; } |
|
|
|
var p1 = currentPath.getPointAtLength( (spacingOfSymbols/2 - 5) + (spacingOfSymbols * j) ); |
|
var p2 = currentPath.getPointAtLength( (spacingOfSymbols/2 + 5) + (spacingOfSymbols * j) ); |
|
|
|
var m = (p2.y - p1.y) / (p1.x - p2.x); |
|
|
|
var line = g2.append("line") |
|
.attr("x1",p1.x) |
|
.attr("x2",p2.x) |
|
.attr("y1",p1.y) |
|
.attr("y2",p2.y) |
|
.attr("stroke-width",1) |
|
.attr("opacity",1) |
|
.attr("class","front-marker") |
|
.attr("marker-end","url("+markerType+")"); |
|
j++; |
|
} |
|
}); |
|
}) |
|
|
|
|
|
|
|
|
|
</script> |