2013-09-28

tan function visualization

Intro

Remy Sharp organized a competition to celebrate JS Bin's 5th birthday. All of the details can be found under this link. A lot was going on in my life at the time when the competition was opened so I didn't think I'll even catch an opportunity to solve some of the assignments that were posted. By the time I started trying to figure out the examples most of the stuff was already solved by these wonderful, incredible and very smart people:

Tan function

I started looking at the posted assignments and crosschecking if some of them were already solved. I found that this one still wasn't solved. Since it looked solvable to me I gave it a go. I've spent most of the evening analyzing the movement, drawing triangles, calculating the angles, making canvas experiments. At one point I came to a conclusion that the moving dot is nothing more than a representation of a tan function and felt a bit stupid because it should have been obvious!

Implementation

After I figured out it was a tan function the hard way, everything was pretty easy. All of the code is essentially here:

   // spin the circle around
   angle = (angle + dangle) % ( 2 * Math.PI);  

   // calculate the green dot position
   anglex = Math.cos(angle) * circlehalf;
   angley = Math.sin(angle) * circlehalf;
   drawdotx = circlex + anglex;
   drawdoty = circley + angley;
   
   // calculate the connecting points on the graph
   linex = circlehalf / Math.tan(angle);
   linex2 = circlehalf / Math.tan(angle + Math.PI);

The trick

The only tricky part was with drawing the graph. Because connecting the graph algorithmically caused the unexpected line to appear every time the dot switched from positive to negative infinity. But it turned out it could all be solved with a simple if statement:

     for (var i = cheight; i > 0; i-- ) {
      ctx.beginPath();

      ctx.moveTo(circlex - linex, cheight - hsplit - i - 1);

      linex = circlehalf / Math.tan(angle - i * dangle);

      ctx.lineTo(circlex - linex, cheight - hsplit - i);

      // avoids drawing a connection between +/- infinity
      if ((circlex - linex) < cwidth) {
        ctx.stroke();
      }

    }
 

And here's my example on:
JS Bin
Codepen

No comments: