Arrows and barbs
When the values are a vector field instead of a scalar field (i.e. wind, wave directions, etc), small arrows or barbs are used.
- Note that we will be using wind values in the examples. The y-axis positive values are from south to north, so the opposite of the raster convention. That’s why some minus signs will appear
Arrows
The most intuitive way to show force and direction of any magnitude is drawing small arrows with the direction and dimensioning or coloring them depending on the module:
Let’s see the most important parts for the Canvas version. You can find the whole code here
- The GeoTIFF data is read as explained in the reading a raster page
- Note that the speed is converted from m/s to knots multiplying by 1.94
- Note that the maxSpd is the maximum speed, calculated to make an authomatic color and size scale. If not, many colors should be used
- Scales for color and size are set
- See how the color scales work at the color scales page
- The size goes from 0.5 to 1.3, which are the scale factors
- If the minumum was zero, small speeds would be difficult to see
- The maximum is bigger than 1, since most of the arrows will be much smaller
- The length or area of the arrows aren’t proportional to speed, which isn’t nice
- d3.range returns an array of positions from 0 to the image size, each barbSize pixels. Very convenient in our case
- For each of these positions in the output image, an arrow will be calculated
- From the image pixel position to a lat-lon position, the projection.invert method must be used
- The GeoTransform is applied to get the pixel position in the original GeoTIFF file
- The wind direction is calculated with the atan2 function, but changing the axis order and the y-axis sign so the 0 degrees start from the north and the original wind speed goes from south to north when positive
- Check the example image to see that the result is correct
- The most important thing to note is which functions are used to set size, direction and position of the arrows
- context.translate() sets the position (origin) to the arrow position. All coordinates will have this origin now
- context.rotate() rotates the arrow to the proper direction
- context.scale() will set the size
- context.save() and context.restore() make the transformations to start again from the original setting every time
- The arrow is drawn always with the same size and from left to right, using the Canvas methods
- context.restore() prepares the Canvas for the next iteration
SVG version
You can find the whole code here
- This version is more or less like the Canvas one. The main difference is in this section of code
- The arrow is drawn using an SVG path instead of line by line
- SVG can handle the transformations in an easier way. So those are applied to each element with the transform attribute
Barbs
Wind barbs are a common way to represent the speed and direction of the wind. Each small line or triangle attached to the line indicating direction adds speed values. Let’s see how to get them using D3js & Canvas:
You can find the whole code here
- d3.range returns an array of positions from 0 to the image size, each barbSize pixels. Very convenient in our case
- For each of these positions in the output image, an arrow will be calculated
- From the image pixel position to a lat-lon position, the projection.invert method must be used
- The GeoTransform is applied to get the pixel position in the original GeoTIFF file
- The wind direction is calculated with the atan2 function, but changing the axis order and the y-axis sign so the 0 degrees start from the north and the original wind speed goes from south to north when positive
- Check the example image to see that the result is correct
Now, the small lines indicating speed must be drawn, and the arrow rotated:
- The most important thing to note is that the context.translate() and context.rotate() are used to put the origin of the drawing on the begining of the barb
- This avoids complex calculations for the lines, since the barb can be thought always from left to right
- The system is, basically, to check if the speed is multiple of 50, 10 and 5, which are the small lines and triangle options. For each multiple, the line is drawn and a separation is added to the position so the next line is drawn properly
- Also, it covers the case of 5<spd<10, when a small separation must be added to distinguish the 5kt line from the 10kt line
SVG version
The SVG version is very similar, but using SVG transform .
You can find the whole code here
- An SVG group is added for each barb. This way, all the lines, triangles and so on will be translated and rotated at the same time
- Note that the translate will make that the origin of the arrow is always at 0,0. This makes calculations much easier.
- The rotation is made after the translation. The order matters