Skip to content

Instantly share code, notes, and snippets.

@Andrew-Reid
Last active October 14, 2016 01:32
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 Andrew-Reid/d72ffa31194b494d4f388972beba466b to your computer and use it in GitHub Desktop.
Save Andrew-Reid/d72ffa31194b494d4f388972beba466b to your computer and use it in GitHub Desktop.
Basic Weather Fronts - markers along topojson lines

Just a basic attempt to create front symbology on topojson lines. The implementation could be much better. For example, by taking three points along the line where markers are to be added, a marker that accounts for the general shape of the curve could be used, minimizing the problem of one marker for all curves types. Four markers are used here, two for each of cold and warm fronts. Two so that the direction of the marker can be clear. All four are shown here, but I changed my drawing direction halfway through making the lines, so both warm fronts and both cold fronts appear to point in the same direction.

Used Dustin Larimer's block to get started, though a stack overflow question got me going further with getting the points along the line.

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.
<!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>
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