ChartDirector Ver 4.1 (PHP Edition Edition)
Zooming and Scrolling Framework
Introduction
When talking about "zooming", it is common to think about zooming like a digital photograph, in which everything is magnified, but is otherwise exactly the same. The zoom ratio is usually a few times and the same data (the photograph) are used at all zoom levels.
There is a much more powerful type of zooming, like zooming in a map. For example, one may start with a world map, and zoom all the way down to seeing the streets and buildings within a city. The zoom ratio can be in the order of 500000 - 1000000 times. Different presentation method may be used at different scales. For example, the world map may show only terrain information, while at highest zoom ratio the map may show the names of individual streets.
The ChartDirector Zooming and Scrolling Framework is designed based on the second model or zooming. The key features are:
- Virtually unlimited zoom ratio.
For example, one can zoom from 10 years down to 1 second (a zoom ratio of 315 million times).
- Allows different chart types and data grouping methods at different scales.
For example, to plot temperature for 1 day, one may be interested hourly temperature. On the other hand, to plot the temperature for 1 year, one may be interested in the daily high-low range (eg. using two lines for high and low daily temperatures and fill the region in between) rather than the hourly temperatures.
- Click and drag to control zooming and scrolling.
The browser side Javascript chart viewer control (JsChartViewer) implements zoom/scroll controls via mouse actions. One may use the mouse to drag to scroll, drag to select a region to zoom into, click to zoom in, and click to zoom out depending on the mouse usage mode (set using JsChartViewer.setMouseUsage).
- Allows external controls for zooming and scrolling.
In many applications, it may be desirable to have several controls to control zooming and scrolling. For example, for a time based chart, in addition to use "drag to scroll" and "drag to zoom", one may want to allow users to select the start and end dates on the axis using drop down list boxes or other controls.
The View Port
The ChartDirector Zooming and Scrolling framework is based on the concept of a view port.
A view port can be imagined as a rectangular window of an underlying rectangular surface. For example, a chart that has 10 years of data can be imagined as a very long chart. If one only displays one of the year, we can say the view port covers only 10% of the underlying chart.
With the view port concept, scrolling can be handled as moving the view port, while zooming in and out can be handled as changing the view port size.
WebChartViewer and JsChartViewer
The ChartDirector Zooming and Scrolling Framework for web applications is based on two controls:
- JsChartViewer : This is a browser side Javascript control that manages the view port. It allows the view port coordinates to be modified by mouse actions, such as drag to scroll, drag to select a region to zoom into, click to zoom in, and click to zoom out.
- WebChartViewer : This is the server side counterpart of JsChartViewer. It acts as a "proxy" to JsChartViewer. Properties of the browser side JsChartViewer will be accessible as properties of the WebChartViewer, and vice versa.
In a typical web page with a zoomable and scrollable chart, the operation is like:
- The browser sends a request to the server for the web page.
- On the server side, the chart is created and set into the WebChartViewer. The WebChartViewer may also be configured with the initial state of the JsChartViewer. The WebChartViewer may then generated the HTML tags for the chart image and the JsChartViewer state. These tags may be inserted into the web page to be sent to the browser.
- On the browser side, the user can then see the chart, and can use the mouse actions to zoom or scroll the chart.
- When a zooming or scrolling action occurs, the JsChartViewer will update its view port coordinates and send the updated state to the server.
- On the server side, the WebChartViewer can be used to retrieve the updated view port coordinates. An updated chart can then be created and set it into the WebChartViewer, which will then be sent back to the browser side JsChartViewer for display.
The last three steps may then repeat many times.
Partial Chart Update and Full Page Update
ChartDirector supports using AJAX (Asynchronous Javascript And XML) methods for the communication between the JsChartViewer and WebChartViewer. So the chart can be updated without refreshing the web page. In ChartDirector terminology, this is called a partial chart update.
The vast majority of the browsers nowadays support AJAX. However, it is still possible a user may be using a non-AJAX supporting browser. To handle these cases, ChartDirector also supports using traditional full page update method. In this method, the JsChartViewer updates the WebChartViewer by using HTTP POST or GET, and the WebChartViewer updates the browser display by updating the entire page.
JsChartViewer.canSupportPartialUpdate can be used to dynamically detect if a browser supports AJAX or not, so the JsChartViewer can determine which method to use to communicate with the WebChartViewer.
Integration with External Controls
It is not uncommon for a web page to be designed with multiple ways to control the axis range of the chart. For example, in a time based chart, in addition to using "drag to scroll" and "drag to select region" to select the time range of the chart, there may be text fields or drop down list boxes to allow the user to select the start time and end time directly.
Although the text fields or drop down list boxes are not part of the JsChartViewer, it would be ideal if these external controls can also use partial chart updates (AJAX requests), so the chart can be updated without the web page refreshing.
Also, if a user drags to scroll the chart using JsChartViewer, in addition to updating the chart, the text fields or drop down list boxes may also need to be updated to show the new time range.
To support external controls, JsChartViewer and WebChartViewer support custom attributes. Like other properties of JsChartViewer and WebChartViewer, custom attributes set on the browser side JsChartViewer will be accessible from the server side WebChartViewer, and vice versa.
For example, in the above case with external text fields for entering the start and end dates, the operation may be like:
- Suppose the user enters the start and end dates directly using text fields and then press the "OK button". In the onClick event handler of the button, JsChartViewer.setCustomAttr may be used to copy the text fields into the JsChartViewer as custom attributes. Then JsChartViewer.partialUpdate may be used to sent a partial chart update request to the server.
- On the server side, WebChartViewer.getCustomAttr may be used to get back the text field data. The server side script may then validate the user input, create an updated chart, and set it into the WebChartViewer. If the text fields are updated (eg., after user input validation, the text fields may have changed), they may be modified using WebChartViewer.setCustomAttr. The updated chart and text field data will then be sent back to the browser.
- On the browser side, upon receiving the response, JsChartViewer will display the updated chart. To update the text fields, a JsChartViewer.PostUpdate event handler may be used to copy the custom attributes (get using JsChartViewer.getCustomAttr) to the text fields.
Persistent State Storage
Apart from supporting external controls, another usage of custom attributes is to provide a persistent state storage across multiple chart update requests.
In a zoomable and scrollable, whenever the view port is updated, there will be a request sent to the server for an updated chart. It is often useful to have a storage that is persistent across multiple chart update requests. In other words, data set in a chart update request can be retrieved in subsequent chart update requests.
Custom attributes can serve this role because attributes set on the server side WebChartViewer will be transported to the browser side JsChartViewer. During chart update requests, these attributes will be transported back to the server side. So these custom attributes are preserved across chart update requests from both the server side and browser side point of view.
Typical Server Side Code Structure
The server side code may need to handle the following types of requests from the browser:
- Initial page request: This occurs when the page is accessed for the first time by a browser. The server side script should set the initial state of the JsChartViewer (through the WebChartViewer), and generate the entire web page including the chart.
- Partial chart update (AJAX request): This occurs when the JsChartViewer sends a partial chart update requests to the server. The WebChartViewer may be used to access the JsChartViewer state, and an updated chart and updated state be sent as a response.
WebChartViewer.isPartialUpdateRequest may be used to detect if the current HTTP request is a partial update request.
- Full page update: This occurs when the browser sends a traditional HTTP POST or GET request to the server. The request may be due to the zoom or scroll mouse actions, or it can be submitted by external controls.
WebChartViewer.isFullUpdateRequest may be used to detect if the current HTTP request is a full update request due to zoom or scroll mouse actions.
Note that one may always design a web page that only uses partial chart update or full page update, in which case only the corresponding request type needs to be implemented.
If a page only supports partial chart update, then very old browsers that do not support AJAX may be unable to zoom or scroll the chart, but they can still see the initial chart.
If a page only supports full page update, then it will work with all browsers, but each zooming or scrolling requests will result in updating the entire web page.
The typical code structure will be like:
- For the initial page request, initialize the overall range and visible range of the chart. For example, for a time based chart, one may set the overall range to be 5 years, and the initial visible range to be 1 year.
If the initial chart is designed to display all available data, one may use the auto-scaled axis range (obtain using Axis.getMaxValue and Axis.getMinValue after creating the chart) as the overall range.
The overall range and visible range may then be used to compute the initial view port position and size.
The overall range is needed in subsequent chart update requests. It may be stored as custom attributes using WebChartViewer.setCustomAttr, so it can be retrieved in subsequent chart update requests.
- In subsequent chart update requests, use the view port settings and the overall range to determine the visible range.
- Retrieve the necessary data based on the visible range.
If the number of data points are small, you may also retrieve all data without regarding the visible range. ChartDirector will automatically clip the data to the view port. On the other hand, if there are many data points (which is typical of charts that need to zoom and scroll), it is recommended you retrieve only the necessary data to improve charting performance.
For charts that need to zoom or scroll, it is not uncommon to have data series with thousands or even millions of points. However, considering a typical plot area is less than a thousand pixels in width, for most chart types, it is not necessary to plot that many points.
Plotting too many data points will reduce the effective resolution of the chart rather than increasing it. It is like drawing a world map on the screen by drawing each street in each city in detail. Instead of getting a very detail map, one probably get a not too useful map.
In general, for most chart types, the best chart is obtained when the number of data points is about the same as the number of pixels in width. As a rule of thumb, one may try to aggregate the data points together so that the number of points is 50% to 100% of the number of pixels in width.
Aggregation means to group multiple data points together into one point. Common aggregation methods include using averaging, resampling, peak value, summation, etc. The exact method to use depends on your chart type and the nature of the data. For example, in a line chart, one may use averaging as the aggregation method, while for an area chart, one may use the peak value as the aggregation method.
Sometimes, it may be meaningful to aggregate one data series into multiple data series. For example, suppose we have a data series representing the hourly temperature, and we need to plot it for a year (365 x 24 = 8760 points). Instead of plotting the data directly, we may aggregate the data into 3 daily series, representing the maximum, minimum and average temperature of a day. We may even use a color to fill the region between the maximum and minimum lines. The resulting chart will be much for elegant and useful than using the raw data directly.
If the data come from a SQL database, one can often aggregate the data by using the GROUP BY clause in SQL statements. This may make the database query much faster, as the query result set will have much less records.
ChartDirector includes a utility method ArrayMath.aggregate that can be used to conveniently aggregate data. This is useful for non-SQL data sources that do not support aggregate statements.
- Draw the chart with the given data.
There are plenty of sample code elsewhere in this documentation on how to draw various charts with ChartDirector. A special point to note is that the charting code may need to configure the axis scale as according to the view port, except for the initial chart which may use auto-scaling.
The created chart may be stored in a session variable using BaseChart.makeSession. The URL to retrieve the chart should be set to the WebChartViewer using WebChartViewer.setImageUrl. If an image map is available for the chart, it should be set to the WebChartViewer using WebChartViewer.setImageMap.
- Return the output to the the browser.
For partial chart update request, WebChartViewer.partialUpdateChart should be use to return the response to the browser.
For the initial page request or full page updates, WebChartViewer.renderHTML should be used to create the HTML tags that represent the chart. These tags may then be inserted in the HTML web page to be sent to the browser.
Typical Browser Side Code Structure
On the browser side, the typical code structure will be like:
Library Files Required for Zoomable/Scrollable Charts
A zoomable/scrollable chart requires the following files. Please ensure you copy the necessary files to the proper directories (typically the same directory as the script) and reference them using the proper paths.
File | Description
|
---|
getchart.php | The standard utility script used in the image url for retrieving the chart image from a session variable (see BaseChart.makeSession).
|
cdjcv.js zoomin.cur zoomout.cur nozoom.cur wait.gif | The script file for JsChartViewer, and the supporting cursor and image files. These files must be in the same directory.
|
© 2006 Advanced Software Engineering Limited. All rights reserved.