Streamlines are the family of curves tangent to the velocity of the flow. They can be seen as the path that a particle would follow. They are widely used to show wind fields.

Calculating these streamlines is not so easy, so I made this library that does the job and makes really simple to draw them.

You can find the whole code here

Basically, after reading the GeoTIFF data, the code is

var lines = rastertools.streamlines(uData,vData, geoTransform);
lines.features.forEach(function(d) {
  context.beginPath();
  context.strokeStyle = "#000000";
  path(d);
  context.stroke();
});
  • The streamlines function returns an array of paths
  • The array is iterated for each element and directly drawn

These streamlines have the problem that the direction isn’t indicated. To do it, the easiest way is using the svg-path-properties library:

You can find the whole code here

The important part of the code grows to:

var path2 = d3.geoPath()
    .projection(projection);
var lines = rastertools.streamlines(uData,vData, geoTransform);
lines.features.forEach(function(d) {
  var properties = spp.svgPathProperties(path2(d));
  var arrowPos = properties.getPropertiesAtLength(properties.getTotalLength()/2);
  var arrowDegrees = Math.atan(arrowPos.tangentY/arrowPos.tangentX);
  context.beginPath();
  context.strokeStyle = "#000000";
  path(d);
  context.stroke();
  context.beginPath();
  context.moveTo(arrowPos.x, arrowPos.y);
  context.lineTo(arrowPos.x-10*arrowPos.tangentX + 6*arrowPos.tangentY,arrowPos.y-10*arrowPos.tangentY - 6*arrowPos.tangentX);
  context.moveTo(arrowPos.x, arrowPos.y);
  context.lineTo(arrowPos.x-10*arrowPos.tangentX - 6*arrowPos.tangentY,arrowPos.y-10*arrowPos.tangentY + 6*arrowPos.tangentX);
  context.stroke();
});
  • Since the defined geoPath included the context, a ne path is created with the name path2. This will make easy to get the svg path for every streamline
  • The svgPathProperties function allows us to get the position of the middle of the line and the direction. Note that the problems of the barbs with direction doesn’t exist here
    • The streamline is written with the direction of the wind directly
    • There is a [parameter to change it](https://github.com/rvec(iana/raster-streamlines) called flip
  • The arrows are drawn using the basic Canvas lineTo function

SVG

Of course, it’s possible to get the same result but using SVG instead of Canvas.

You can find the whole code here

The important part is:

var lines = rastertools.streamlines(uData,vData, geoTransform);
lines.features.forEach(function(d) {
  var properties = spp.svgPathProperties(path(d));
  var arrowPos = properties.getPropertiesAtLength(properties.getTotalLength()/2);
  var arrowDegrees = Math.atan(arrowPos.tangentY/arrowPos.tangentX);

  svg.insert("path", ".streamline")
      .datum(d)
      .attr("d", path)
      .style("fill", "None")
      .style("stroke", "#777");

  svg.insert("path", ".streamline")
      .attr("d", "M"+arrowPos.x+","+arrowPos.y
            +"L"+(arrowPos.x-10*arrowPos.tangentX + 6*arrowPos.tangentY)+","+(arrowPos.y-10*arrowPos.tangentY - 6*arrowPos.tangentX)
            +"M"+arrowPos.x+","+arrowPos.y
            +"L"+(arrowPos.x-10*arrowPos.tangentX - 6*arrowPos.tangentY)+","+(arrowPos.y-10*arrowPos.tangentY + 6*arrowPos.tangentX))
      .style("fill", "None")
      .style("stroke", "#777");
});
  • The stramline is inserted directly, since is an SVG paths
  • To create the small arrow, an SVG path is used wint lineTo and moveTo instructions