ASE Home Page Products Download Purchase Support About ASE
ChartDirector Support
Forum HomeForum Home   SearchSearch

Message ListMessage List     Post MessagePost Message

  AJAX partial update fro multiple charts
Posted by Hong on Aug-24-2009 14:05
Hi, there,

I'd like to use AJAX partial update fro multiple charts in one web page, how many JsChartViewer and WebChartViewer do I need to define?
Thanks,
- Hong

  Re: AJAX partial update fro multiple charts
Posted by Peter Kwan on Aug-24-2009 22:25
Attachments:
Hi Hong,

For each AJAX chart in a web page, you need a JsChartViewer on the web page, and a corresponding WebChartViewer on the server side. So for multiple AJAX charts in a web page, you need multiple JsChartViewer and WebChartViewer objects.

There is an example of multiple independent zooming and scrolling at the following forum thread (the code in that thread is in Perl):

http://www.chartdir.com/forum/download_thread.php?bn=chartdir_support&thread=1196812637#N1196905148

I have also attached an ASP.NET example for multiple synchronous zooming and scrolling (which means if you scroll one chart, both charts will update):

Hope this can help.

Regards
Peter Kwan
multiple_sync_zoomscrolldemo.aspx
<%@ Page Language="C#" Debug="true" %>
<%@ Import Namespace="ChartDirector" %>
<%@ Register TagPrefix="chart" Namespace="ChartDirector" Assembly="netchartdir" %>
<script runat="server">

//
// We need to handle 3 types of request: - initial request for the full web page - partial update
// (AJAX chart update) to update the chart without reloading the page - full page update for old
// browsers that does not support partial updates
//

// The total date range of all data.
DateTime startDate;
DateTime endDate;

// The date range of the data that we zoomed into (visible on the chart).
DateTime viewPortStartDate;
DateTime viewPortEndDate;

//
// Handles the initial request
//
private void createFirstChart(WebChartViewer viewer)
{
    // Initialize the Javascript ChartViewer
    viewer.MouseUsage = WebChartMouseUsage.Scroll;

    // In this demo, we allow scrolling the chart for the last 5 years
    startDate = DateTime.Now.Date.AddYears(-5);
    endDate = DateTime.Now.Date;

    // The initial selected date range is last 1 year
    viewPortStartDate = endDate.AddYears(-1);
    viewPortEndDate = endDate;

    // We store the scroll range as custom Javascript ChartViewer attributes, so the range can be
    // retrieved later in postback or partial update requests
    viewer.SetCustomAttr("startDate", startDate.Ticks);
    viewer.SetCustomAttr("endDate", endDate.Ticks);

    // In this demo, we set the maximum zoom-in to 10 days
    viewer.ZoomInWidthLimit = 10.0 / endDate.Subtract(startDate).Days;

    // Draw the chart
    drawChart(viewer);
}

//
// Handles partial update (AJAX chart update)
//
private void processPartialUpdate(WebChartViewer viewer)
{
    // Retrieve the overall date range from custom Javascript ChartViewer attributes.
    startDate = new DateTime(Int64.Parse(viewer.GetCustomAttr("startDate")));
    endDate = new DateTime(Int64.Parse(viewer.GetCustomAttr("endDate")));

    // Now we need to determine the visible date range selected by the user. There are two
    // possibilities. The user may use the zoom/scroll features of the Javascript ChartViewer to
    // select the range, or s/he may use the start date / end date select boxes to select the date
    // range.

    if (viewer.IsViewPortChangedEvent) {
        // Is a view port change event from the Javascript ChartViewer, so we should get the
        // selected date range from the ChartViewer view port settings.
        double duration = endDate.Subtract(startDate).TotalSeconds;
        viewPortStartDate = startDate.AddSeconds((int)(Math.Round(viewer.ViewPortLeft * duration)));
        viewPortEndDate = viewPortStartDate.AddSeconds((int)(Math.Round(viewer.ViewPortWidth *
            duration)));
    } else {
        // The user has changed the selected range by using the start date / end date select boxes.
        // We need to retrieve the selected dates from those boxes. For partial updates, the select
        // box values are sent in as Javascript ChartViewer custom attributes.
        int sYear = int.Parse(viewer.GetCustomAttr(StartYear.ClientID));
        int sMonth = int.Parse(viewer.GetCustomAttr(StartMonth.ClientID));
        int sDay = int.Parse(viewer.GetCustomAttr(StartDay.ClientID));
        int eYear = int.Parse(viewer.GetCustomAttr(EndYear.ClientID));
        int eMonth = int.Parse(viewer.GetCustomAttr(EndMonth.ClientID));
        int eDay = int.Parse(viewer.GetCustomAttr(EndDay.ClientID));

        // Note that for browsers that do not support Javascript, there is no validation on the
        // client side. So it is possible for the day to exceed the valid range for a month (eg. Nov
        // 31, but Nov only has 30 days). So we set the date by adding the days difference to the 1
        // day of a month. For example, Nov 31 will be treated as Nov 1 + 30 days = Dec 1.
        viewPortStartDate = new DateTime(sYear, sMonth, 1).AddDays(sDay - 1);
        viewPortEndDate = new DateTime(eYear, eMonth, 1).AddDays(eDay - 1);
    }

    // Draw the chart
    drawChart(viewer);

    //
    // We need to communicate the new start date / end date back to the select boxes on the browser
    // side.
    //

    // Send year, month, day components to the start date / end date select boxes through Javascript
    // ChartViewer custom attributes.
    viewer.SetCustomAttr(StartYear.ClientID, viewPortStartDate.Year);
    viewer.SetCustomAttr(StartMonth.ClientID, viewPortStartDate.Month);
    viewer.SetCustomAttr(StartDay.ClientID, viewPortStartDate.Day);
    viewer.SetCustomAttr(EndYear.ClientID, viewPortEndDate.Year);
    viewer.SetCustomAttr(EndMonth.ClientID, viewPortEndDate.Month);
    viewer.SetCustomAttr(EndDay.ClientID, viewPortEndDate.Day);
}

//
// Handles full update
//
private void processFullUpdate(WebChartViewer viewer)
{
    // A full chart update is essentially the same as a partial chart update. The main difference is
    // that in a full chart update, the start date / end date select boxes are in Form Post
    // variables, while in partial chart update, they are in Javascript ChartViewer custom
    // attributes.
    //
    // So a simple implementation of the full chart update is to copy the Form Post values to the
    // Javascript ChartViewer custom attributes, and then call the partial chart update.

    // Controls to copy
    DropDownList[] ctrls = {StartYear, StartMonth, StartDay, EndYear, EndMonth, EndDay};

    // Copy control values to Javascript ChartViewer custom attributes
    for(int i = 0; i < ctrls.Length; ++i) {
        viewer.SetCustomAttr(ctrls[i].ClientID, ctrls[i].SelectedItem.Value);
    }

    // Now can use partial chart update
    processPartialUpdate(viewer);
}

//
// Draw the chart
//
private void drawChart(WebChartViewer viewer)
{
    //
    // Validate and adjust the view port dates.
    //

    // Verify if the view port dates are within limits
    double totalDuration = endDate.Subtract(startDate).TotalSeconds;
    double minDuration = viewer.ZoomInWidthLimit * totalDuration;
    if (viewPortStartDate < startDate) {
        viewPortStartDate = startDate;
    }
    if (endDate.Subtract(viewPortStartDate).TotalSeconds < minDuration) {
        viewPortStartDate = endDate.AddSeconds(-minDuration);
    }
    if (viewPortEndDate > endDate) {
        viewPortEndDate = endDate;
    }
    if (viewPortEndDate.Subtract(viewPortStartDate).TotalSeconds < minDuration) {
        viewPortEndDate = viewPortStartDate.AddSeconds(minDuration);
    }

    // Adjust the view port to reflect the actual date range
    viewer.ViewPortLeft = viewPortStartDate.Subtract(startDate).TotalSeconds / totalDuration;
    viewer.ViewPortWidth = viewPortEndDate.Subtract(viewPortStartDate).TotalSeconds / totalDuration;

    //
    // Now we have the date range, we can get the necessary data. In this demo, we just use a random
    // number generator. In practice, you may get the data from a database or XML or by other means.
    // (See "Using Data Sources with ChartDirector" in the ChartDirector documentation if you need
    // some sample code on how to read data from database to array variables.)
    //

    // Just a random number generator to generate the data - emulates a table of numbers from
    // startDate to endDate
    RanTable r = new RanTable((viewer == WebChartViewer1) ? 127 : 111, 4, (int)(0.5 + totalDuration / 86400) + 1);
    r.setDateCol(0, startDate, 86400);
    r.setCol(1, 150, -10, 10);
    r.setCol(2, 200, -10, 10);
    r.setCol(3, 250, -10, 10);

    // Emulate selecting the date range viewPortStartDate to viewPortEndDate. Note that we add one
    // day margin on both ends. It is because we are using daily data, but the view port can cover
    // partial days. For example, the view port end date can be at 3:00am Feb 1, 2006. In this case,
    // we need the data point at Feb 2, 2006.
    r.selectDate(0, viewPortStartDate.AddDays(-1), viewPortEndDate.AddDays(1));

    // Emulate getting the random data from the table
    DateTime[] timeStamps = Chart.NTime(r.getCol(0));
    double[] dataSeriesA = r.getCol(1);
    double[] dataSeriesB = r.getCol(2);
    double[] dataSeriesC = r.getCol(3);

    if (timeStamps.Length >= 520) {
        //
        // Zoomable chart with high zooming ratios often need to plot many thousands of points when
        // fully zoomed out. However, it is usually not needed to plot more data points than the
        // pixel resolution of the chart. Plotting too many points may cause the points and the
        // lines to overlap on the same pixel. So rather than increasing resolution, this reduces
        // the clarity of the chart. It is better to aggregate the data first if there are too many
        // points.
        //
        // In our current example, the chart plot area only has 520 pixels in width and is using a 2
        // pixel line width. So if there are more than 520 data points, we aggregate the data using
        // the ChartDirector aggregation utility method.
        //
        // If in your real application, you do not have too many data points, you may remove the
        // following code altogether.
        //

        // Set up an aggregator to aggregate the data based on regular sized slots
        ArrayMath m = new ArrayMath(timeStamps);
        m.selectRegularSpacing((timeStamps.Length) / 260);

        // For the timestamps, take the first timestamp on each slot
        timeStamps = m.aggregate(timeStamps, Chart.AggregateFirst);

        // For the data values, take the averages
        dataSeriesA = m.aggregate(dataSeriesA, Chart.AggregateAvg);
        dataSeriesB = m.aggregate(dataSeriesB, Chart.AggregateAvg);
        dataSeriesC = m.aggregate(dataSeriesC, Chart.AggregateAvg);
    }

    //
    // Now we have obtained the data, we can plot the chart.
    //

    //================================================================================
    // Step 1 - Configure overall chart appearance.
    //================================================================================

    // Create an XYChart object 600 x 300 pixels in size, with pale blue (0xf0f0ff) background,
    // black (000000) rounded border, 1 pixel raised effect.
    XYChart c = new XYChart(600, 300, 0xf0f0ff, 0x000000);
    c.setRoundedFrame();

    // Set the plotarea at (52, 60) and of size 520 x 192 pixels. Use white (ffffff) background.
    // Enable both horizontal and vertical grids by setting their colors to grey (cccccc). Set
    // clipping mode to clip the data lines to the plot area.
    c.setPlotArea(55, 60, 520, 192, 0xffffff, -1, -1, 0xcccccc, 0xcccccc);
    c.setClipping();

    // Add a top title to the chart using 15 pts Times New Roman Bold Italic font, with a light blue
    // (ccccff) background, black (000000) border, and a glass like raised effect.
    c.addTitle("Zooming and Scrolling >>> " + viewer.ClientID, "Times New Roman Bold Italic", 15
        ).setBackground(0xccccff, 0x000000, Chart.glassEffect());

    // Add a bottom title to the chart to show the date range of the axis, with a light blue
    // (ccccff) background.
    c.addTitle2(Chart.Bottom, "From <*font=Arial Bold Italic*>" + c.formatValue(viewPortStartDate,
        "{value|mmm dd, yyyy}") + "<*/font*> to <*font=Arial Bold Italic*>" + c.formatValue(
        viewPortEndDate, "{value|mmm dd, yyyy}") + "<*/font*> (Duration <*font=Arial Bold Italic*>"
         + (int)(Math.Round(viewPortEndDate.Subtract(viewPortStartDate).TotalSeconds / 86400.0)) +
        "<*/font*> days)", "Arial Italic", 10).setBackground(0xccccff);

    // Add a legend box at the top of the plot area with 9pts Arial Bold font with flow layout.
    c.addLegend(50, 33, false, "Arial Bold", 9).setBackground(Chart.Transparent, Chart.Transparent);

    // Set axes width to 2 pixels
    c.xAxis().setWidth(2);
    c.yAxis().setWidth(2);

    // Add a title to the y-axis
    c.yAxis().setTitle("Price (USD)", "Arial Bold", 10);

    //================================================================================
    // Step 2 - Add data to chart
    //================================================================================

    //
    // In this example, we represent the data by lines. You may modify the code below if you want to
    // use other representations (areas, scatter plot, etc).
    //

    // Add a line layer for the lines, using a line width of 2 pixels
    LineLayer layer = c.addLineLayer2();
    layer.setLineWidth(2);

    // Now we add the 3 data series to a line layer, using the color red (ff0000), green (00cc00)
    // and blue (0000ff)
    layer.setXData(timeStamps);
    layer.addDataSet(dataSeriesA, 0xff0000, "Product Alpha");
    layer.addDataSet(dataSeriesB, 0x00cc00, "Product Beta");
    layer.addDataSet(dataSeriesC, 0x0000ff, "Product Gamma");

    //================================================================================
    // Step 3 - Set up x-axis scale
    //================================================================================

    // Set x-axis date scale to the view port date range. ChartDirector auto-scaling will
    // automatically determine the ticks on the axis.
    c.xAxis().setDateScale(viewPortStartDate, viewPortEndDate);

    //
    // In the current demo, the x-axis range can be from a few years to a few days. We can let
    // ChartDirector auto-determine the date/time format. However, for more beautiful formatting, we
    // set up several label formats to be applied at different conditions.
    //

    // If all ticks are yearly aligned, then we use "yyyy" as the label format.
    c.xAxis().setFormatCondition("align", 31104000);
    c.xAxis().setLabelFormat("{value|yyyy}");

    // If all ticks are monthly aligned, then we use "mmm yyyy" in bold font as the first label of a
    // year, and "mmm" for other labels.
    c.xAxis().setFormatCondition("align", 2592000);
    c.xAxis().setMultiFormat(Chart.StartOfYearFilter(), "<*font=bold*>{value|mmm yyyy}",
        Chart.AllPassFilter(), "{value|mmm}");

    // If all ticks are daily algined, then we use "mmm dd<*br*>yyyy" in bold font as the first
    // label of a year, and "mmm dd" in bold font as the first label of a month, and "dd" for other
    // labels.
    c.xAxis().setFormatCondition("align", 86400);
    c.xAxis().setMultiFormat(Chart.StartOfYearFilter(),
        "<*block,halign=left*><*font=bold*>{value|mmm dd<*br*>yyyy}", Chart.StartOfMonthFilter(),
        "<*font=bold*>{value|mmm dd}");
    c.xAxis().setMultiFormat2(Chart.AllPassFilter(), "{value|dd}");

    // For all other cases (sub-daily ticks), use "hh:nn<*br*>mmm dd" for the first label of a day,
    // and "hh:nn" for other labels.
    c.xAxis().setFormatCondition("else");
    c.xAxis().setMultiFormat(Chart.StartOfDayFilter(), "<*font=bold*>{value|hh:nn<*br*>mmm dd}",
        Chart.AllPassFilter(), "{value|hh:nn}");

    //================================================================================
    // Step 4 - Set up y-axis scale
    //================================================================================

    if (viewer.ZoomDirection == WebChartDirection.Horizontal) {
        // y-axis is auto-scaled - so vertically, the view port always cover the entire y data
        // range. We save the y-axis scale for supporting xy-zoom mode if needed in the future.
        c.layout();
        viewer.SetCustomAttr("minValue", c.yAxis().getMinValue());
        viewer.SetCustomAttr("maxValue", c.yAxis().getMaxValue());
        viewer.ViewPortTop = 0;
        viewer.ViewPortHeight = 1;
    } else {
        // xy-zoom mode - retrieve the auto-scaled axis range, which contains the entire y data
        // range.
        double minValue = double.Parse(viewer.GetCustomAttr("minValue"));
        double maxValue = double.Parse(viewer.GetCustomAttr("maxValue"));

        // Compute the view port axis range
        double axisLowerLimit = maxValue - (maxValue - minValue) * (viewer.ViewPortTop +
            viewer.ViewPortHeight);
        double axisUpperLimit = maxValue - (maxValue - minValue) * viewer.ViewPortTop;

        // Set the axis scale to the view port axis range
        c.yAxis().setLinearScale(axisLowerLimit, axisUpperLimit);

        // By default, ChartDirector will round the axis scale to the tick position. For zooming, we
        // want to use the exact computed axis scale and so we disable rounding.
        c.yAxis().setRounding(false, false);
    }

    //================================================================================
    // Step 5 - Output the chart
    //================================================================================

    // Output the chart
    viewer.Image = c.makeWebImage(Chart.PNG);

    // Include tool tip for the chart
    viewer.ImageMap = viewer.MakeDelayedMap(c.getHTMLImageMap("", "",
        "title='[{dataSetName}] {x|mmm dd, yyyy}: USD {value|2}'"), true);
}

//
// A simple utility to set up year-month-day selection drop down list boxes.
//
// Parameters: yearList: The DropDownList control for selecting the year. monthList: The
// DropDownList control for selecting the month. dayList: The DropDownList control for selecting the
// day. startTime: The starting datefor the selectable date range. endTime: The ending date for the
// selectable date range. currentTime: The initially date shown in the controls.
//
private void SetYMDControls(DropDownList yearList, DropDownList monthList, DropDownList dayList,
    DateTime startTime, DateTime endTime, DateTime currentTime)
{
    // Set the yearList to contain all possible years
    yearList.Items.Clear();
    for(int i = startTime.Year; i < endTime.Year + 1; ++i) {
        yearList.Items.Add(new ListItem(i.ToString()));
    }

    // Set the yearList to contain all possible months
    monthList.Items.Clear();
    for(int i = 1; i < 13; ++i) {
        monthList.Items.Add(new ListItem(i.ToString()));
    }

    // Set the dayList to contain all possible days
    dayList.Items.Clear();
    for(int i = 1; i < 32; ++i) {
        dayList.Items.Add(new ListItem(i.ToString()));
    }

    // Set the controls to the initial date
    yearList.SelectedIndex = currentTime.Year - startTime.Year;
    monthList.SelectedIndex = currentTime.Month - 1;
    dayList.SelectedIndex = currentTime.Day - 1;
}

//
// Page Load event handler
//
protected void Page_Load(object sender, EventArgs e)
{
    //
    // We need to handle the first chart request, partial update request (AJAX chart update) and
    // full page update
    //
    if (WebChartViewer.IsPartialUpdateRequest(Page)) {
        // *** Is a parial update request ***

        if (WebChartViewer.GetSenderClientId(Page) == WebChartViewer1.ClientID)
        {
	        // The .NET platform will not restore the states of the controls before or during Page_Load,
	        // so we need to restore the state ourselves
	        WebChartViewer1.LoadViewerState();

	        // Draw the chart in partial update mode
	        processPartialUpdate(WebChartViewer1);

	        // Output the chart immediately and then terminate the page life cycle.
	        WebChartViewer1.PartialUpdateChart();
	    }
        if (WebChartViewer.GetSenderClientId(Page) == WebChartViewer2.ClientID)
        {
			WebChartViewer2.LoadViewerState();
			processPartialUpdate(WebChartViewer2);
			WebChartViewer2.PartialUpdateChart();
		}
    } else if (IsPostBack) {
        // *** Is a full update request ***
        processFullUpdate(WebChartViewer1);
        processFullUpdate(WebChartViewer2);
   } else {
        // *** Page is first accessed ***
        createFirstChart(WebChartViewer1);
        createFirstChart(WebChartViewer2);
    }

    // Initialize the date controls to show the selected data
    SetYMDControls(StartYear, StartMonth, StartDay, startDate, endDate, viewPortStartDate);
    SetYMDControls(EndYear, EndMonth, EndDay, startDate, endDate, viewPortEndDate);
}

</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>ChartDirector Zoom and Scroll Demonstration</title>
    <script type="text/javascript" src="cdjcv.js"></script>
    <style type="text/css">
        div.chartPushButtonSelected { padding:5px; background:#ccffcc; cursor:hand; }
        div.chartPushButton { padding:5px; cursor:hand; }
        td.chartPushButton { font-family:Verdana; font-size:9pt; cursor:pointer; border-bottom:#000000 1px solid; }
    </style>
</head>
<body style="margin:0px" onload="initJsChartViewer()">
<script type="text/javascript">
// Initialize browser side Javascript controls
function initJsChartViewer()
{
    // Check if the Javascript ChartViewer library is loaded
    if (!window.JsChartViewer)
        return;

    // Get the Javascript ChartViewer object
    var viewer = JsChartViewer.get('<%=WebChartViewer1.ClientID%>');
    var viewer2 = JsChartViewer.get('<%=WebChartViewer2.ClientID%>');
	
    // Connect the mouse usage buttons to the Javascript ChartViewer object
    connectViewerMouseUsage('ViewerMouseUsage1', viewer, viewer2);
    // Connect the xy zoom mode buttons to the Javascript ChartViewer object
    connectViewerZoomControl('ViewerZoomControl1', viewer, viewer2);

    // Detect if browser is capable of support partial update (AJAX chart update)
    if (JsChartViewer.canSupportPartialUpdate())
    {
        // Browser can support partial update, so connect the view port change event and
        // the submit button to trigger a partial update
        viewer.attachHandler("ViewPortChanged", viewer.partialUpdate);
        viewer2.attachHandler("ViewPortChanged", viewer2.partialUpdate);
        document.getElementById('<%=SubmitButton.ClientID%>').onclick = function() { viewer.partialUpdate(); return false; };

        // For partial updates, we need to pass the start date / end date select boxes values to/from
        // the server via Javascript ChartViewer custom attributes
        var controlsToSync = ['<%=StartYear.ClientID%>', '<%=StartMonth.ClientID%>', '<%=StartDay.ClientID%>',
            '<%=EndYear.ClientID%>', '<%=EndMonth.ClientID%>', '<%=EndDay.ClientID%>'];
        
        viewer.attachHandler("PreUpdate", function() { copyToViewer(viewer, controlsToSync); });
        viewer.attachHandler("PostUpdate", function() { copyFromViewer(viewer, controlsToSync); if (!isSync(viewer, viewer2)) viewer2.partialUpdate(); });
        viewer2.attachHandler("PreUpdate", function() { copyToViewer(viewer2, controlsToSync); });
        viewer2.attachHandler("PostUpdate", function() { copyFromViewer(viewer2, controlsToSync); if (!isSync(viewer, viewer2)) viewer.partialUpdate(); });
    }
}
// Is the two viewers synchronized?
function isSync(viewer1, viewer2)
{
	return Math.abs(viewer1.getViewPortLeft() - viewer2.getViewPortLeft()) + Math.abs(viewer1.getViewPortWidth() - viewer2.getViewPortWidth()) < 0.001;
}
// A utility to copy HTML control values to Javascript ChartViewer custom attributes
function copyToViewer(viewer, controlsToSync)
{
    for (var i = 0; i < controlsToSync.length; ++i)
    {
        var obj = document.getElementById(controlsToSync[i]);
        if (obj && !{"button":1, "file":1, "image":1, "reset":1, "submit":1}[obj.type])
        {
            if ((obj.type == "checkbox") || (obj.type == "radio"))
                viewer.setCustomAttr(obj.id, obj.checked ? 1 : 0);
            else
                viewer.setCustomAttr(obj.id, obj.value);
        }
    }
}
// A utility to copy Javascipt ChartViewer custom attributes to HTML controls
function copyFromViewer(viewer, controlsToSync)
{
    for (var i = 0; i < controlsToSync.length; ++i)
    {
        var obj = document.getElementById(controlsToSync[i]);
        if (obj)
        {
            var value = viewer.getCustomAttr(obj.id);
            if (typeof value != "undefined")
            {
                if ((obj.type == "checkbox") || (obj.type == "radio"))
                    obj.checked = parseInt(value);
                else
                    obj.value = value;

                if (obj.validate)
                    obj.validate();
            }
        }
    }
}
</script>
<form method="post" id="ZoomScrollDemo" runat="server">
<table cellspacing="0" cellpadding="0" border="0">
    <tr>
        <td align="right" colspan="2" style="background:#000088">
            <div style="padding-bottom:2px; padding-right:3px; font-weight:bold; font-size:10pt; font-style:italic; font-family:Arial;">
                <a style="color:#FFFF00; text-decoration:none" href="http://www.advsofteng.com/">Advanced Software Engineering</a>
            </div>
        </td>
    </tr>
    <tr valign="top">
        <td style="width:150px; background:#c0c0ff; border-left:black 1px solid; border-right:black 1px solid; border-bottom:black 1px solid;">
            <!-- The following table is to create 3 cells for 3 buttons. The buttons are used to control
                 the mouse usage mode of the Javascript ChartViewer. -->
            <table id="ViewerMouseUsage1" cellspacing="0" cellpadding="0" width="100%" border="0">
                <tr>
                    <td class="chartPushButton">
                        <div class="chartPushButton" id="ViewerMouseUsage1_Scroll" title="Pointer">
                            <img src="pointer.gif" style="vertical-align:middle" width="16" height="16" alt="Pointer" />&nbsp;&nbsp;Pointer
                        </div>
                    </td>
                </tr>
                <tr>
                    <td class="chartPushButton">
                        <div class="chartPushButton" id="ViewerMouseUsage1_ZoomIn" title="Zoom In">
                            <img src="zoomInIcon.gif" style="vertical-align:middle" width="16" height="16" alt="Zoom In" />&nbsp;&nbsp;Zoom In
                        </div>
                    </td>
                </tr>
                <tr>
                    <td class="chartPushButton">
                        <div class="chartPushButton" id="ViewerMouseUsage1_ZoomOut" title="Zoom Out">
                            <img src="zoomOutIcon.gif" style="vertical-align:middle" width="16" height="16" alt="Zoom Out" />&nbsp;&nbsp;Zoom Out
                        </div>
                    </td>
                </tr>
            </table>
            <script type="text/javascript">
            // Connect the mouse usage buttons to the Javascript ChartViewer
            function connectViewerMouseUsage(controlId, viewer, viewer2)
            {
                // A cross browser utility to get the object by id.
                function getObj(id) { return document.getElementById ? document.getElementById(id) : document.all[id]; }

                // Set the button styles (colors) based on the current mouse usage mode of the Javascript ChartViewer
                function syncButtons()
                {
                    getObj(controlId + "_Scroll").className = (viewer.getMouseUsage() == JsChartViewer.Scroll) ?
                        "chartPushButtonSelected" : "chartPushButton";
                    getObj(controlId + "_ZoomIn").className = (viewer.getMouseUsage() == JsChartViewer.ZoomIn) ?
                        "chartPushButtonSelected" : "chartPushButton";
                    getObj(controlId + "_ZoomOut").className = (viewer.getMouseUsage() == JsChartViewer.ZoomOut) ?
                        "chartPushButtonSelected" : "chartPushButton";
                }
                syncButtons();

                // Run syncButtons whenever the Javascript ChartViewer is updated
                viewer.attachHandler("PostUpdate", syncButtons);

                // Set the Javascript ChartViewer mouse usage mode if a button is clicked.
                getObj(controlId + "_Scroll").onclick = function() { viewer.setMouseUsage(JsChartViewer.Scroll); viewer2.setMouseUsage(JsChartViewer.Scroll); syncButtons(); }
                getObj(controlId + "_ZoomIn").onclick = function() { viewer.setMouseUsage(JsChartViewer.ZoomIn); viewer2.setMouseUsage(JsChartViewer.ZoomIn); syncButtons(); }
                getObj(controlId + "_ZoomOut").onclick = function() { viewer.setMouseUsage(JsChartViewer.ZoomOut); viewer2.setMouseUsage(JsChartViewer.ZoomOut); syncButtons(); }
            }
            </script>
            <div style="font-size:9pt; margin:15px 5px 0px; font-family:verdana"><b>Zoom Mode</b></div>
            <!-- The following table is to create 2 cells for 2 buttons. The buttons are used to control
                 the zoom/scroll directions of the Javascript ChartViewer. -->
            <table id="ViewerZoomControl1" cellspacing="0" cellpadding="0" width="100%" border="0">
                <tr>
                    <td class="chartPushButton" style="border-bottom: #000000 1px solid; border-top: #000000 1px solid;">
                        <div class="chartPushButton" id="ViewerZoomControl1_Xmode" title="X-Axis zoomable / Y-Axis auto-scaled">
                            <img src="xrange.gif" style="vertical-align:middle" width="16" height="16" alt="X Zoom/Y Auto" />&nbsp;&nbsp;X Zoom / Y Auto
                        </div>
                    </td>
                </tr>
                <tr>
                    <td class="chartPushButton" style="border-bottom: #000000 1px solid;">
                        <div class="chartPushButton" id="ViewerZoomControl1_XYmode" title="X-Axis and Y-Axis zoomable">
                            <img src="xyrange.gif" style="vertical-align:middle" width="16" height="16" alt="XY Zoom" />&nbsp;&nbsp;XY Zoom
                        </div>
                    </td>
                </tr>
            </table>
            <script type="text/javascript">
            // Connect the zoom/scroll direction buttons to the Javascript ChartViewer
            function connectViewerZoomControl(controlId, viewer, viewer2)
            {
                // A cross browser utility to get the object by id.
                function getObj(id) { return document.getElementById ? document.getElementById(id) : document.all[id]; }

                // Set the button styles (colors) based on current zoom/scroll direction settings of the Javascript ChartViewer
                function syncButtons()
                {
                    getObj(controlId + "_Xmode").className = (viewer.getZoomDirection() == JsChartViewer.Horizontal) ?
                        "chartPushButtonSelected" : "chartPushButton";
                    getObj(controlId + "_XYmode").className = (viewer.getZoomDirection() == JsChartViewer.HorizontalVertical) ?
                        "chartPushButtonSelected" : "chartPushButton";
                }
                syncButtons();

                // Run syncButtons whenever the Javascript ChartViewer is updated
                viewer.attachHandler("PostUpdate", syncButtons);

                // Set the Javascript ChartViewer zoom/scroll direction if a button is clicked.
                function setViewerDirection(d)
                {
                   viewer.setScrollDirection(d);
                   viewer.setZoomDirection(d);
                   viewer2.setScrollDirection(d);
                   viewer2.setZoomDirection(d);
                   syncButtons();
                }
                getObj(controlId + "_Xmode").onclick = function() { setViewerDirection(JsChartViewer.Horizontal); }
                getObj(controlId + "_XYmode").onclick = function() { setViewerDirection(JsChartViewer.HorizontalVertical); }
            }
            </script>
            <div style="font-size:9pt; margin:15px 5px 0px; font-family:Verdana">
                <b>Start Time</b><br />
                <table cellspacing="0" cellpadding="0" border="0">
                    <tr>
                        <td style="font-size:8pt; font-family:Arial">Year</td>
                        <td style="font-size:8pt; font-family:Arial">Mon</td>
                        <td style="font-size:8pt; font-family:Arial">Day</td>
                    </tr>
                    <tr>
                        <td><asp:dropdownlist id="StartYear" runat="server" Width="60">
                            <asp:ListItem Value="2001">2001</asp:ListItem>
                        </asp:dropdownlist></td>
                        <td><asp:dropdownlist id="StartMonth" runat="server" Width="40">
                            <asp:ListItem Value="1">12</asp:ListItem>
                        </asp:dropdownlist></td>
                        <td><asp:dropdownlist id="StartDay" runat="server" Width="40">
                            <asp:ListItem Value="1">31</asp:ListItem>
                        </asp:dropdownlist></td>
                    </tr>
                </table>
            </div>
            <div style="font-size:9pt; margin:15px 5px 0px; font-family:Verdana">
                <b>End Time</b><br />
                <table cellspacing="0" cellpadding="0" border="0">
                    <tr>
                        <td style="font-size:8pt; font-family:Arial">Year</td>
                        <td style="font-size:8pt; font-family:Arial">Mon</td>
                        <td style="font-size:8pt; font-family:Arial">Day</td>
                    </tr>
                    <tr>
                        <td><asp:dropdownlist id="EndYear" runat="server" Width="60">
                            <asp:ListItem Value="2006">2006</asp:ListItem>
                        </asp:dropdownlist></td>
                        <td><asp:dropdownlist id="EndMonth" runat="server" Width="40">
                            <asp:ListItem Value="1">12</asp:ListItem>
                        </asp:dropdownlist></td>
                        <td><asp:dropdownlist id="EndDay" runat="server" Width="40">
                            <asp:ListItem Value="1">31</asp:ListItem>
                        </asp:dropdownlist></td>
                    </tr>
                </table>
            </div>
            <script type="text/javascript">
            // A utility to validate the day of month for the start date / end date HTML controls.
            // It sets the day of month select so that it only shows the legal range.
            function validateYMDControls(yearObj, monthObj, dayObj)
            {
                // Get the number of days in a month
                var noOfDays = [31, (parseInt(yearObj.value) % 4 == 0) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
                    [monthObj.selectedIndex];

                // Ensure the selected day of month is not bigger than the days in month
                dayObj.selectedIndex = Math.min(noOfDays - 1, dayObj.selectedIndex);

                // Extend/Shrink the day of month select box to ensure it covers the legal day range
                for (var i = dayObj.options.length; i < noOfDays; ++i)
                    dayObj.options[i] = new Option(i + 1, i + 1);
                for (var j = dayObj.options.length; j > noOfDays; --j)
                    dayObj.remove(j - 1);
            }
            // Initialize the HTML select controls for selecting dates
            function initYMDControls(yearId, monthId, dayId)
            {
                // A cross browser utility to get the object by id.
                var getObj = function(id) { return document.getElementById ? document.getElementById(id) : document.all[id]; }

                // Connect the onchange event to validateYMDControls
                getObj(yearId).onchange = getObj(yearId).validate = getObj(monthId).onchange = getObj(monthId).validate =
                    function() { validateYMDControls(getObj(yearId), getObj(monthId), getObj(dayId)); };

                // Validate once immediately
                getObj(yearId).validate();
            }
            // Connnect the start date / end date HTML select controls
            initYMDControls('<%=StartYear.ClientID%>', '<%=StartMonth.ClientID%>', '<%=StartDay.ClientID%>');
            initYMDControls('<%=EndYear.ClientID%>', '<%=EndMonth.ClientID%>', '<%=EndDay.ClientID%>');
            </script>
            <div style="margin-top:20px; font-family:Verdana; font-size:9pt; text-align:center">
                <asp:button id="SubmitButton" runat="server" Text="Update Chart"></asp:button>
            </div>
        </td>
        <td>
            <div style="font-weight:bold; font-size:20pt; margin:5px 0px 0px 5px; font-family:Arial">
                ChartDirector Zoom and Scroll Demonstration
            </div>
            <hr style="border:solid 1px #000080" />
            <div style="padding:0px 5px 0px 10px">
                <chart:WebChartViewer id="WebChartViewer1" runat="server" width="600px" height="300px" />
                <br />
                <chart:WebChartViewer id="WebChartViewer2" runat="server" width="600px" height="300px" />
            </div>
        </td>
    </tr>
</table>
</form>
</body>
</html>

  Re: AJAX partial update for multiple charts
Posted by Hong on Aug-25-2009 14:32
Thanks Peter for the answer.
-- Hong

  Re: AJAX partial update for multiple charts
Posted by Hong on Aug-26-2009 16:29
Hi, Peter,

I tried to apply your solution to my JSP environment, but I have some questions:
1. I can not use WebChartViewer.getSenderClientId() since it is not a static method, how can I compare the sender is from JSviewer1 or not?



2. Ther is not ClientId or getClientId method for WebChartViewer, the only thing that I can find is getId(), but it return ID of Webviewer, not JS view. Can I assume ID for Webviewer and JSViewer are the same?


Can I use:
if (webviewer1.getSenderClientId() == webviewer1.getId()) {
...
}
if (webviewer2.getSenderClientId() == webviewer2.getId()) {
...
}

Thanks,
- Hong

  Re: AJAX partial update for multiple charts
Posted by Peter Kwan on Aug-27-2009 00:23
Hi Hong,

Sorry for the inaccurate documentation. The getSenderClientId method actually is available as both a non-static method, and static methods. The three variety available are:

public static String getSenderClientId(ServletRequest r)
public static String getSenderClientId(PageContext context)
public String getSenderClientId()

So in your case, you can use:

if (WebChartViewer.getSenderClientId(request) == ....)

Hope this can help.

Regards
Peter Kwan

  Re: AJAX partial update for multiple charts
Posted by Hong on Aug-27-2009 13:25
Hi, Peter,

It works after I change the comparison to:
if (WebChartViewer.getSenderClientId(request).equals(webviewer1.getId())) {...}

Thanks Peter you for great help.
- Hong