Turning the Graph Function Into an Object in JavaScript, Part 2

In drawing a graph I’ve created variables for all sorts of coordinates (where do the axes begin and end?) and characteristics (how many tickmarks per interval, how long are they, and what color?). However, rather than define the locations directly they should be calculated indirectly based on the presence and size of other items associated with the graph.

Let’s begin with the top of the graph with respect to the canvas upon which it’s drawn. We have to leave a certain amount of buffer space to make it look nice, we may have to leave space for half the text of half the label at the top of the y-axis (in the left margin as shown), and we may have to leave room for the title of the graph, if one is specified. Given that the origin of the coordinate system is defined to be the upper left corner of the canvas and positive values increase going right and down, we need to allow pixels as follows:

  • margin between top of graph area and top of next feature up, either the title or the top of the canvas
  • height of the title text, if it is present
  • margin between the top of the title text and the top of the canvas
  • height of any y-axis label text that extends beyond the top of the y-axis itself
  • margin between top of topmost y-axis label and top of canvas, if the top of the label text represents the topmost element to be drawn

We might decide to package up the specification, location, and drawing of axes but the same values will have to be considered. Also, the top label on the y-axis may not be drawn at the top of the axis itself; there may be offsets. It may also be possible for label text to be drawn at an angle.

If there are any other elements added to the upper margin of the graph they would have to be taken into account as well. Similarly, if text for a title is present but is not located in the upper margin (as opposed to being located in the graph area itself), then that would also have to be considered.

Even more interestingly it may be possible to define an axis aligned to the top of the graph, in which case we’d have to account for the length of the longest tick marks, the height of tick labels and an additional axis title, and additional margins as needed. Secondary y-axes are commonly drawn on the the right side of graphs (and more than one can be placed on either the right or left side), but it is uncommon to encounter even one, much less more than one, placed along the top of the graphing area. Nonetheless in order to be completely flexible we’ll go ahead and plan for such an occurrence. (It’s also possible to draw axes in the middle of a graph, as in cases where an origin would be in the middle of the graph area.)

However we ultimately decide to structure things, we’ll need to know the height of the label text we plan to draw before we formally draw it. There are two aspects to this. The first is the height and width of the text itself and the second has to do with the angle at which the text is drawn. The width is easily calculated as shown:

The fillText function itself can take an optional fourth parameter, that specifies the maximum width in pixels. This doesn’t define where line or word wraps take place, it defines the width the text will take (in pixels) after the text is stretched or compressed to the desired width. If the maximum width in pixels is defined, that value overrides the textWidth value calculated above.

Now it gets trickier. There is no function to calculate the height of the text you plan to draw so there are a few ways to approach it.

  • Do some outside experimentation with a particular font and size so you know how it will behave–and then stick to using that font and that size. Pay attention to the number of vertical pixels in capital letters and descenders. Note that numerical digits have the same height as capital letters and also have no descenders. This method has the virtues of being completely accurate and completely automated once you’ve done the work up front.
  • Perform the experiments described above on numerous fonts and numerous sizes and build a table of height values you can reference.
  • Make the height a default or even a user-supplied parameter. This method can generate undesired or unexpected results or can place some of the burden on the user to adjust things, and in a way that may not always be understandable.
  • Use one of the other automated or semi-automated methods described at links like this.

You can see from the third option, which actually subsumes the first two, that this is a tricky problem that I’ll discuss in detail tomorrow. I also have a discussion of determining the effective width and height of rotated text in the queue. The two concepts work together, as you’ll see, so I’ll address them both at the same time.

This entry was posted in Software and tagged , , . Bookmark the permalink.

Leave a Reply