Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Build a Reusable Graphical Charting Engine with C# : Page 4

The .NET framework contains everything you need to build this customizable line-graphing application that supports multiple overlaid data sets, each with its own color and line style. Unless you need extremely sophisticated charts, just draw your own.


advertisement
Zooming and Browsing the Chart
At this point, you can draw a chart of sorts, but, as it stands, it isn't particularly useful unless your data is distributed uniformly and you have a pressing need to visualize the full sample set simultaneously. Think about it. Suppose most of your data lies in the range 0.1 to 0.15, with outlying elements of -1,000 and +1,000. At the default zoom (where the entire data set just fits on the chart), your data range of particular interest would occupy only fifteen thousandths of the available space on the axis. At that size, you probably wouldn't be able to see anything meaningful. Therefore, the chart component needs some kind of zoom capability so people can identify that level of detail.

In fact, it needs two things—the ability to magnify an area of interest, and the ability to browse around that area to see how it connects with the rest of the chart. Fortunately, both are fairly trivial to implement. Because m_data_rect is a data-to-view transformation, zooming in on the data by ten percent is as simple as deflating that rectangle by ten percent. Similarly, all you need to do to browse across the data is to adjust that rectangle's origin. So, to magnify or zoom the chart, you can simply write:

public void Zoom(float percent) { float dx = (percent / 200) * m_data_rect.Width; float dy = (percent / 200) * m_data_rect.Height; m_data_rect = new RectangleF( m_data_rect.Left + dx, m_data_rect.Top + dy, m_data_rect.Width - (dx*2), m_data_rect.Height - (dy*2)); }

That magnifies the chart, but you probably won't always want to zoom the data in the center of the chart, you want to "magnify an area of interest." Sure, you can manually zoom in and then move around to view the portion you're interested in, but that would soon become tedious. To eliminate this problem the companion method Snap()centers the view about a specific point. You can use Snap() by itself to move around the chart, or you can combine it with Zoom() to give the appearance of zooming into a particular location. Normally, you would achieve this effect by first translating your rectangle to the origin of your coordinate system, then applying the zoom, and finally translating the rectangle back again. But because Zoom() always transforms about the rectangle's center, you need only perform the initial translation:

public void Snap(PointF pt) { // Correct for inverted y axis pt.Y = m_screen_rect.Bottom - pt.Y + m_margin; // Transform into data coordinates PointF origin = Transform( m_screen_rect, m_data_rect, pt); // Build a new rectangle from scratch float min_x, max_x, min_y, max_y; min_x = origin.X - (m_data_rect.Width /2); max_x = origin.X + (m_data_rect.Width /2); min_y = origin.Y - (m_data_rect.Height /2); max_y = origin.Y + (m_data_rect.Height /2); m_data_rect = new RectangleF(min_x, min_y, m_data_rect.Width, m_data_rect.Height); }

Snap() takes a point in screen coordinates, because that's how you'd expect to use it. With a chart visible on the screen, users can click somewhere with the mouse. You pass the click point to Snap() and it takes care of the rest.

Supporting zoom does have a side-effect. Before adding zoom capability, you always knew just how big m_data_rect was, so you could safely use it to create an appropriate data-to-screen transformation. But now that the rectangle can change size—specifically, when it grows smaller—the chart will extend beyond its margins, meaning that the graph will overwrite parts of its axes and generally look rather messy. Fortunately, GDI can solve that problem. Just call Graphics.SetClip(), passing in a clip rectangle, and any line segments you draw will be clipped appropriately.



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap
Thanks for your registration, follow us on our social networks to keep up-to-date