Monday, June 18, 2007

getting the preview pane working

I spent most of this week trying to get the basic functionality of the preview pane working. The goals were to draw a map with randomly generated pie charts and colors where the pies were draggable and zoomed appropriately. I succeeded in generating this zoomable and draggable pie chart. Try it out. The page generates a pie with random slices and colors. Try dragging the pie, zooming to new levels, and try dragging again.

These are the steps that I took to build that code:
  1. Draw a circle on a map.
  2. Draw multiple circles on a map.
  3. Make the circles draggable.
  4. Draw a pie on a map.
  5. Make the pie draggable.
  6. Make the pie zoomable.
  7. Make the pie zoomable and draggable.
I ran into various bugs along the way that made this problem really challenging. Here are some of the implementation details:
  • Drawing the circles in Google Maps (GM) is actually easier than in Google Earth because you can easily calculate the pixel coordinates of the 90 vertices that comprise the circle. GM provides functions like fromDivPixelToLatLng() and fromLatLngToDivPixel() that then make switching back and forth to latlong coordinates easier, and you don't have to do all the complicated haversine computations yourself.
  • Making the circles draggable was a little difficult because you have to wrap the created circle svg's within appropriate HTML div elements. This turned out to be somewhat complicated because it involved manipulating the DOM node tree that simultaneously updated our array of svg elements.
  • Drawing the pies instead of circles added another layer of complexity because not only does each svg of a pie slice need to be wrapped in its own div but then all the slices of the same pie need to be wrapped together in another div that was made draggable.
  • One bug I ran into was how to get the pie pieces to fit together seamlessly. The random numbers generated for the dimensions of each slice didn't correspond exactly with the 90 evenly spaced vertices (one vertex every 5 degrees), but some simple rounding and modulo type operations fixed that. That means that the pies are not exact representations of the input data, they may be off 5 degrees or so for each slice, but I'm guessing most humans won't be able to notice that.
  • So making the new pie divs draggable wasn't a problem, but making it work with the zoom function was a bear. After zooming, the pie would either become undraggable, we'd see too many copies of the pie, and/or not all of the copies would be the same or in the correct places. There were several issues to overcome. First, I had to wipe and redraw the overlays containing the pies. Second, I had to repackage the functions so that I could save and access the random data that had been generated (i.e. the slice angle data, slice colors). Third, I had to update the location information of the pie after it was dragged. The first two tasks were not bad, but the last bug took the longest to fix.
    • At first, I tried to get the new location info from calculating the center point of the encapsulating div. Several problems with that approach: I could get the info for the left top corner of the div, but the height and width were zero, and the div's size was not only just large enough to fit the pie (the width of the div was not equal to the diameter of the circle) as I had assumed, and finally I realized that what was returned by style.left and was NOT the coordinates of the top left corner but rather the offset of the coordinates in pixels.
    • I could use the offset in pixels to calculate the new lat and long for the center of the pie. However, to convert from pixels to latlng units I needed to use a different function that incorporated zoom level information (different zooms will have different latlng to pixel relationships). This involves declaring a GProjection variable to get the fromLatLngToPixel(latlng, zoomLevel) function. Whew! But finally, we have pies we can move and zoom.

No comments: