Tuesday, January 31, 2012

Trigonometry for Web Developers, Part Two

Recap of Part One
In part one of this series, we learned about degrees vs. radians, the orientation of the polar coordinate system, and how to use HTML and Javascript to draw an arc.    Continuing to build the pieces needed to display our analog meter example, this article introduces two new trig functions and demonstrates how to use them.   We'll also look at some additional drawing capabilities of the HTML canvas object as we use Javascript to draw tick marks and labels on the face of our meter.

Tick Marks
Our meter will have a small line, or "tick mark", associated with each whole value i.e. 0, 1, 2, and so on.   In order to put these lines on the outside edge of the arc we drew in the first part of this series, we'll need to determine the angle for each line and use that along with the arc's radius to determine the two end points of the line.   Once we have these points, we can easily draw them using the HTML canvas object:

The first task is to deterermine how far apart to place each tick mark.  Since our meter will display values between and including zero and 10, we will need 11 tick marks.    While it might be possible to determine an answer using only (x,y) coordinate pairs, it's actually quite simple to do using polar coordinates.    Recall that the meter extends from an angle of 210 degrees to an angle of 330 degrees.   The difference between these two values is known as the angular distance, and by dividing this value by the number of tick marks we can determine the angular distance between each tick mark.

For each tick mark, we will use a pair of trigonometric functions to determine the end points of the line.   The sine function will be used to determine the y-axis value, and the cosine function will be used to determine the x-axis value for each end of the line.    Either function by itself cannot give the complete answer - it only knows about angles and, in this case, knows nothing about the radius we need.     Additionally, these functions assume that the base (vertex) of the angle is located at  0,0 ... which is seldom the case.    To correct for these issues, we will use the following functions :
y = sine(angle) * radius + offset_y
x = cosine(angle) * radius + offset_x
The sine and cosine functions always return a value between -1.0 and +1.0, so to translate that value into something meaningful we must do two things:   multiply it by the radius of the arc, and add the offset to the center of the circle.   For any given angle, the formulas above will locate a point exactly on our arc - this is one end of the tick mark.   We still need to find the other end of the tick mark, however.   Fortunately, this is quite trivial - we simply adjust the radius slightly by subtracting the size of the tick mark.   Assume that we use "length" to signify the length of the tick mark, the slightly altered formulas then become :
y = sine(angle) * (radius-length) + offset_y
x = cosine(angle) * (radius-length) + offset_x

All of the above logic can be expressed in a relatively small amount of code:
// Tick marks
var numTicks    = 11,
    tickLength  = 10,
    step        = (endAngle - startAngle) / numTicks,
    angle       = startAngle;
ctx.beginPath();
for(var iX = 0; iX <= numTicks; ++iX) {
  ctx.moveTo( centerX + Math.cos(angle) * radius, 
              bottomY + Math.sin(angle) * radius);
  ctx.lineTo( centerX + Math.cos(angle) * (radius - tickLength), 
              bottomY + Math.sin(angle) * (radius - tickLength));
  angle += step;
}
ctx.stroke();
After specifying the number and size of tick marks to be drawn, the angular distance between each tick mark is calculated as we described earlier.    A loop is then used to draw each tick mark by using the moveTo() method to position the drawing cursor along with the lineTo() method to draw a line from the cursor position to the new position.

The complete HTML file for this example can be obtained from here.

Labels
Wouldn't it be nice if each of the tick marks had a label to go with it?   From a user experience perspective, a label facilitates faster comprehension of the data being displayed than would a tick mark alone.   Here's what we want to end up with :
The mechanism for drawing these labels is similar to those used to draw the tick mark.   We'll again make use of the sine and cosine functions to determine the location of each label, and we'll also introduce a couple of HTML canvas methods which greatly simplify drawing the labels.

As with the tick marks, the first step is to determine the angular distance between each label and is done the same way: by dividing the difference between the ending and starting angles by the number of items we wish to display.     Also, as with drawing the tick marks, the polar coordinates (the angle and the radius) and converted to an x,y coordinate pair through the use of cosine and sine functions.     Compare the code for drawing these labels with that for drawing the tick marks - you'll find many similarities:

//-------------------------------------------------
// Value labels
var   textMetrics,
      textHeight = 14,
      label;
angle = startAngle;
step  = (endAngle - startAngle) / numTicks;
for(var iX = 0; iX <= numTicks; ++iX) {
  label = '' + iX;      // Javascript way to force conversion to string type
  textMetrics = ctx.measureText( label );
  ctx.save();
  ctx.translate(centerX + Math.cos(angle) * radius,
                bottomY + Math.sin(angle) * radius);
  ctx.rotate( angle + Math.PI/2);
  ctx.fillText(label, -textMetrics.width/2, textHeight*2);
  ctx.restore();
  angle += step;
}

You'll also notice a few differences.    Since each label is potentially a different size (due to differing widths of the characters within the label), and since each label is rotated slightly differently, this code relies on some HTML canvas object methods to account for these concerns.   The first method, measureText(), is used to obtain the width of the label in pixels (oddly, this method does not return height as yet).      The save() and restore() methods are used to preserve the graphics context state that we alter with the translate() and rotate() methods.

The interesting things happen with the call to the translate() method.   This method is used to move the origin (point at coordinates 0,0) to a new location.   Using the formulas presented earlier, the code uses the translate() method to establish the new origin at the point where the label should be drawn.

Since we also would like the text to be at the same angle as the tick mark, we'll make use of the canvas object's rotate() method.   This method rotates the entire drawing context by the specified amount.   In this case, we'll rotate by the angle plus an additional 90 degrees, or π/2 radians.     Why the additional 90 degrees of rotation?   The additional 90 degrees of rotation is needed to account for the zero angle being on the right side of the polar coordinate circle .

Without adding the additional 90 degrees of rotation, the labels would appear to be drawn as though laying on their side.

The complete HTML file for this example can be found here, and additional background on the HTML canvas methods can be found here.

Up Next: Drawing the Needle
We're a lot closer to having a functional meter now but still have a couple of things left to do next time.   For now, we've covered several key topics:

  • Determining angular distances between a starting and ending angle
  • Converting from polar coordinates to x,y form
  • Use of HTML canvas translate() and rotate() methods

Next time, we'll add the needle to the meter and animate its movements - stay tuned!

Continue onto Part Three...

Tuesday, January 24, 2012

Trigonometry for Web Developers, Part One

Introduction
Recently my team was tasked with developing a custom UI control for an application being built with the excellent Dojo framework.    The concept makes use of a rotatable dial, which caused some head scratching as folks hadn't used trig (trigonometry) in years.    Realizing that I could better explain the concepts by providing some "real world" examples, I put together some samples using only HTML and Javascript.  

This article is the first in a series of three, with each successive article building on the previous.    Let's get started!

Degrees vs. Radians
Most people think of angles in terms of degrees, with 360 degrees comprising a full circle.   Trig functions available in most common programming languages such as Javascript, C/C++, python, etc. all think in different units, however - these units are known as radians.    Fortunately, converting between the two is relatively easy using these formulas :
radians = (π / 180.0) * degrees
degrees = radians / (180.0 / π)
Don't let radians scare you - it's just another way of expressing the same thing and you'll like find yourself starting to "think" in radians before long. Until that time, let's create some helper functions to make things easy :
function toRadians(a_degrees)
{
  return (Math.PI / 180.0) * a_degrees;
}

function toDegrees(a_radians)
{
  return a_radians / (180.0 / Math.PI);
}
Note the use of "Math.PI" - this is a constant provided by the Javascript "Math" object that is far more precise than the typical "3.14" representation.

The diagram below demonstrates the relationship of degrees to radians, using the mathematical convention of expressing radians in terms of π.    Be sure also to notice that the circle starts from the right-most point, not the top.   This means that a line extending from the center at an angle of zero degrees/zero radians will extend to the right, not to the top, edge of the circle.


Let's Draw Something
For the purposes of demonstrating how to marry trig functions with graphics, we'll construct a simple analog-style meter in Javascript. Our meter will have a scale from 0 through 10 with tick marks for each value.     A needle will point to a value on the scale and will appear to pivot about a fixed point. We'll use Javascript to draw into an HTML canvas object, but the concepts will be the same regardless of the underlying language.

The first step is to create an HTML file to contain the page along with our Javascript.   Example 1 contains a basic HTML document along with the Javascript function DrawMeter().   When you open this file in your browser, you should see a partial circle across the top left area of your browser window, similar to the image on the right.      Go ahead and right-click to get to the "View Source" option in your browser - you'll find the helper functions for converting between degrees and radians along with the DrawMeter() function.


//---------------------------------------------------------------
function DrawMeter()
{
  var       cvs         = document.getElementById('meter'),     // Canvas object 
            centerX     = cvs.width / 2,                        // Horizontal mid-point of canvas
            bottomY     = cvs.height,                           // Bottom of canvas
            radius      = Math.min(centerX, bottomY) - 5,       // Radius of dial that fits into canvas, plus a small margin
            ctx         = cvs.getContext('2d'),                 // Graphics context for drawing
            startAngle  = toRadians(210),                       // Starting angle for scale
            endAngle    = toRadians(330);                       // Ending angle for scale
          
  // Outer edge
  ctx.beginPath();
  ctx.strokeStyle = '#777';
  ctx.arc(centerX, bottomY, radius, startAngle, endAngle, false);
  ctx.stroke();
}

This function does several interesting things.   After getting the HTML canvas element, the horizontal center and vertical bottom is found.   These values are then used to determine the radius for the meter.  The arc is then drawn representing the top of the dial, going clockwise from 210 degrees to 330 degrees, using the canvas drawing functions.

Up Next: Drawing the Tick Marks and Labels
We still have a ways to go before we having a functioning meter, but we've covered some important concepts already:
  • Degrees vs. Radians and how to convert between the two
  • Orientation of the polar coordinate system
  • Drawing an arc on an HTML canvas.

Next time, we'll draw the tick marks and labels on the meter by making use of some common trig functions to convert an angle into usable x,y coordinates.

Continue onto Part Two...

Sunday, January 22, 2012

Learn to Fly, Learn to Live

I recently saw a poster entitled, "Everything I need to know I learned in Kindergarten".    I don't recall too much of my time spent in kindergarten (except that Tim Brown liked my plastic Lear Jet toy so much that he tried to take it), but I have learned a lot about life from working on and flying small aircraft.  

1.  Attitude is Important.
Whether rotating at takeoff, configuring for cruise climb, descending for an approach, or flaring to land attitude is key.   Life is like that as well - a good attitude can make a bad situation a little better and can make a good situation great.   

2. Attitude + Power = Performance
For any given aircraft, placing the aircraft in a specific attitude coupled with a specific power setting will result in a specific level of aircraft performance.    Five degrees positive pitch in a wings-level attitude with full power in a Piper Arrow, for example, will eventually yield an 800 foot-per-minute cruise climb at about 115 knots indicated airspeed.    At work and in life, it's not enough to have the correct attitude - success also requires some effort to move forward with that attitude.    To be clear, I'm not referencing political power etc. here but rather plain old hard work - there really isn't any substitute for it.   Also, understand that setting the attitude and power may not result in the desired performance immediately - it can take a bit of time to settle into that cruise climb if you are just coming out of a power dive - but it *will* happen.   

3. Have a Plan, but Be Flexible
I'm not sure that I've ever completed a cross-country flight that went exactly according to plan.   Whether it was a deviation around building weather or ATC advising me, "Arrow One-Niner-Five, Chicago Center, I  have an amended clearance for you.  Advise when ready to copy.", something always pops up.    The key is to be ready and able to accept change.   Don't go charging straight into a thunderstorm just because your plan had you draw a straight line on a map - go around it.   For me, this means living comfortably below our means and saving/investing the difference.  That enables us to take advantage of opportunities that present themselves or deal with unexpected expenses without incurring undue stress.

4. Be the Pilot In Command (PIC)
Section 91.3 of the Federal Aviation Regulations states "The pilot in command of an aircraft is directly responsible for, and is the final authority as to, the operation of that aircraft."    You, not anyone else, are the PIC for your life and are therefore responsible for it - not your parents, not your boss, not the government.   


5. Maintain Directional Control
Every pilot has a certain capacity to control his aircraft - it starts with the pilot's very first flight and continues to build as he or she gains experience.    Sometimes a situation occurs which exceeds the pilot's abilities and instead of trying to correct the situation, the pilot freezes.   At that point, the pilot is simply along for the ride, occasionally resulting in a starring role in an NTSB report.    No matter what the situation is, be proactive about improving it.   Don't just give up and passively go along for the ride - you might not like where you end up.

6. Superior Pilots
An old adage about superior pilots goes something like this: "A superior pilot is one who uses his superior judgement to avoid needing to rely on his superior skills."      Often, this means studying and thinking about a situation instead of having a knee-jerk reaction.     It also means getting both sides of a story before making a decision, or knowing when to speak and when to shut up.   The best way to win an argument is to not have the argument in the first place, instead finding a solution far enough upstream so as to avoid the conflict entirely.



What about you?  What hobbies/avocations have taught you a life lesson or two?

Tuesday, January 17, 2012

Collaboration

A few years back, my wife was lamenting the state of our yard - it was clearly not one of the "super lawns" that exist in our neighborhood.    While I preferred to think of it as preserving a bit of Minnesota prairie, she did not agree with the greenish-brown color so off to the store I went to get some fertilizer.    After a nice walk around the yard with the spreader, I was sure things would go green - and they did.   Except where I spilled a bit too much.   That dead, brown spot served as a reminder about too much of a good thing for two years.

I've come to think of collaboration like fertilizer.   Without it, things become stale and don't grow nearly as fast as they could.   At the same time, too much can be harmful.   Today, it seems like many organizations have gone to extremes in encouraging collaboration and as a result have ended up with "extreme collaboration".     If a little collaboration is good, a lot of collaboration must be better, right?

Well, maybe not so much.   While collaboration is an excellent way for cross functional teams to work towards common goals at the start, it can limit productivity and progress if not applied carefully throughout the remainder of the project.    The documentation team could probably move more quickly without the marketing folks suggesting different wording for each chapter of the user guide, for example.   The entire engineering team probably doesn't need to be part of the design group's working sessions - they just need the results.      Forcing collaboration in this case leads to paralysis - everyone needs to know and be involved in everything.   Unfortunately, few individuals possess the vast array of skills to be effective in such a role - creative design, user experience, software development, product commercialization, and other such areas each are highly specialized.    Coordinating the efforts between these various areas is a perfect application of collaboration across functional teams.   Coordinating the efforts within a specific group is best left to those within that group.

Like fertilizer, collaboration is a wonderful thing that can improve growth, provide a better end result, and improve the overall conditions when applied properly.    And like fertilizer, too much can have an effect opposite of what is desired.

What do you think?  Have you ever burned a hole in your lawn?

Tuesday, January 10, 2012

Red vs Blue



Water Cooler Talk
I was talking with some co-workers today who were lamenting the current state of management at our employer.    These wise individuals have (correctly) identified two distinct management styles within our organization.   For ease of reference, I'll refer to these two groups as the "red" team and the "blue" team.

Red: Managers who know that without their help, the engineering staff would sit dumb, deaf, and mute all day long

Blue:  Managers who support and encourage the engineering rank and file by actively engaging them and giving them the leeway needed to shine

These individuals rattled off the group associations for various managers.   Unfortunately, the red team's membership was larger (non-zero)  than it should be (zero).    How did things get this way, and what can be done about it?

The Cause
My perception is that the issue stems primarily (though not completely) from a lack of trust.   All the managers have been made directly accountable for their groups success or failure and so want to do everything possible to ensure success by tackling as much as possible themselves.   Unfortunately, this is perceived as the managers not having any trust that the engineering staff has the knowledge and experience to make the correct decision.    Regrettably, this perception of distrust is magnified by the fact that with few exceptions, the managers do not possess a software engineering background and lack "street cred".    Finally, when the manager has made a bad call, rarely have they taken responsibility for it - instead, it was a "group decision".   Such actions only serve to exacerbate the issue.

The Cure
I think the solution to this problem is relatively simple, if difficult to actually do:  communication.   Open and honest communication works wonders to build relationships and therefore trust.   Comparing the styles of managers between each camp reveals several small but significant differences:

  • Formal (largely one-way) status meetings vs. Frequent, short one-on-one conversations
  • Lack of responsiveness via email, IM vs. Nearly instant responsiveness
  • Only visits your cube when something is wrong vs. Offers to discuss it in his office.
  • "I think ..." vs. "What do you think..."
  • "That's not right!" vs. "You might be right, but tell me why you think that way."
The red styles have the effect of shutting down communication from the engineering staff, which then give the managers the impression that the engineering staff doesn't want to engage - reinforcing their belief that they must be the drivers to succeed.   The blue styles, on the other hand, encourage the staff to try more, do more, and become more.      All of these are communications related.    What would happen if the red team started adopting the blue team's communications styles?   What effect would that have on the relationship between them and their subordinates?   What effect might that have on employee engagement and productivity?

The Conclusion
Just as a ship making a small change in course can have a large effect on the final destination, making a few small changes in communications can have a large effect on the relationship between  management and staff.    Good organizations recognize this, while others eventually wither away.

I am fortunate to have a manager solidly playing for the blue team.   How about you?