block by GerHobbelt 3480186

Interactive Streamgraph D3

Full Screen

A little blurb to settle the nerves …… ? 8

This demo expands on the standard streamgraph demo in several ways:

Positioning tags in the streams

And then there’s the important bit of course: one way to find the ‘proper spot’ in each stream to print the tag, as big as possible. As can be seen in the code (bottom section of index.hmtl) this was a quest; I didn’t commit all the iterations into git, but the ‘improvement #x’ comments are indicative of what came after I finally got the basic approach nailed - which only worked for a large enough data set as every ‘tag’ had to span multiple [x] data points to allow this simplistic algorithm to deliver something near usable.

The improvements now allow for small datasets as they are sliced/interpolated at a 1px step to produce (interpolated) data points to make the tag placement algorithm work as desired.

How I got here

The general idea was to scan each stream polygon from left to right and see where we might find a horizontal-enough section that could fit the tag, in its smallest form or maybe bigger. Then continue with the scan in order to find the ‘best’ location by picking the top 1 from the candidate set.

This started out as code which located the first (‘left-most’) [x] datapoint which was ‘high enough’ (.y value!) to make a chance of containing the tag text bbox. Then the code would interpolate the left-most x position for which the .y was exactly the minimum required, and from there the code went to scan to the right to find when we’d hit a right edge, either a downwards upper edge (.y0 + .y) or a upwards going lower edge (.y0). This still lacked the ‘growing’ code which is needed to find out how big we can scale the text vertically, but somewhere in there I screwed up and got eaten by bugs.

So I ditched that part of the code and went for the ‘lazy method’ as you see now, which was intended as a speed optimization for that original approach: if you’ld have enough data points, the interpolation tacics wouldn’t be required as with sufficient data points, every pixel would be covered by an explicit datapoint anyhow. After a bit of testing and headscratching due to yet another off-by-one mistake of mine I got where I am today (seek out the if(0) in the code to see the visual debugging of red point indicating text x,y and green box indicating the detected largest rectangle fitting the given stream).

Then a bit of pondering led to the decision to keep the ‘lazy method’ as the only method (so that TODO comment at the bottom is now practically bogus) and just ‘tweak’ small datasets into becomes virtually large datasets by altering the stepsize in the scan loop to a non-integer, minimal step size. And the rest is history…