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

Message ListMessage List     Post MessagePost Message

  ImageMapHandler (python)
Posted by Bernd Engelmann on Mar-27-2006 16:53
Hello,
please, can you give a short example how to bring  the ImageMapHandler utility class into the namespace for python, I do not find it in pychartdir.py, but in the documentation.
I have an imagemap string create from a chart with getHTMLImageMap and got x.y from a Mouseclick in a GUI. Now I want to get the current hot spot via ImageMapHandler.getHotSpot.
Thank you,
Bernd

  Re: ImageMapHandler (python)
Posted by Peter Kwan on Mar-28-2006 01:29
Hi Bernd,

Sorry for this problem. This is in fact due to a bug in the documentation. The CChartViewer and ImageMapHandler are only available in the C++ edition of ChartDirector.

Currently, there is no easy way to use image maps in GUI written by Python, except your GUI happens to be browser based. One work around is not to use image maps at all, but to obtain the approximate position of the mouse with your own code.

For example, for XY charts, you may compute the position of the mouse as projected on the x-axis in the mouse event handler like:

#percentage along the x-axis
percentageX = float(mouseCursorXCoor - plotAreaLeftCoor) / plotAreaWidth

#assume x-axis is configured with Axis.setLabels
xIndex = int(percentageX * len(xLabels) - 0.5)

From the above two lines, you already know which xLabels the mouse cursor is on top of. You may perform what you need immediately (in this UI design, the cursor does not need to be exactly on the data point).

If you need the cursor to be more precisely on the data point, you may use yCoor = c.getYCoor(data[xIndex]) to obtain the y-coordinate of the data point, and test if the cursor is close enough to the data point.

The above is for the label based axis. For linear axis (configured using setLinearScale or auto-scaling), the code is similar:

percentageX = float(mouseCursorXCoor - plotAreaLeftCoor) / plotAreaWidth
xValue = percentageX * (c.xAxis().getMaxValue() - c.xAxis().getMinValue()) + c.xAxis().getMinValue()

The above code obtains the x-value of the mouse cursor. You may then use binary search to obtain the xIndex from your data.

Hope this can help.

Regards
Peter Kwan

  Re: ImageMapHandler (python)
Posted by Bernd Engelmann on Mar-28-2006 02:22
Hi Peter,
thank you, this helps.
Regards,
Bernd

  Re: ImageMapHandler (python)
Posted by Christophe on Dec-06-2009 23:42
Peter Kwan wrote:


Currently, there is no easy way to use image maps in GUI written by Python, except your GUI happens to be browser based. One work around is not to use image maps at all, but to obtain the approximate position of the mouse with your own code.


Hi Peter,

As this was written in 2006, is this still valid today?

Thanks,

Christophe

  Re: ImageMapHandler (python)
Posted by Peter Kwan on Dec-08-2009 00:06
Hi Christophe,

Yes. It is still valid today.

Because in Python, there is no standard GUI framework, there is no built-in GUI features in ChartDirector that targets any particular GUI framework.

Also, there is no "ImageMapHandler" utility in any edition of ChartDirector, except ChartDirector and C++. The documentation has been updated to reflect that.

Regards
Peter Kwan

  Re: ImageMapHandler (python)
Posted by Christophe on May-17-2010 01:41
Hello Peter,

I'm trying to implement your suggestion but instead of using an XYChart, I'm using a FinanceChart. Is it possible to access the xAxis data of a Finance chart?

Thanks,

Christophe

  Re: ImageMapHandler (python)
Posted by Peter Kwan on May-17-2010 23:31
Hi Christophe,

The FinanceChart is a container for multiple XYChart objects. (A typical FinanceChart can have a main price chart, and a number of indicator charts.) As all the XYChart objects in the FinanceChart use the same x-axis scale, you can simply use the x-axis of any XYChart you like.

For example:

#Add a main price chart to the FinanceChart. Save the returned XYChart object
#so we can use it later.
myMainPriceChart = myFinanceChart.addMainChart(....)

.....

After myFinanceChart.layout or makeChart, you can use:

xMax = myMainPriceChart.xAxis().getMaxValue()
.....


Hope this can help.

Regards
Peter Kwan

  Re: ImageMapHandler (python)
Posted by Christophe Dupre on Nov-13-2010 06:51
Hi Peter,

Thanks for the last reply. I have to admit that I'm a bit confused by it all.
Just to recap, I have a FinanceChart, and I'd like to know which candlestick the mouse is over.

Peter Kwan wrote:
#percentage along the x-axis
percentageX = float(mouseCursorXCoor - plotAreaLeftCoor) / plotAreaWidth
Is mouseCursorXCoor the cursor position against the top left corner of the screen?

What is plotAreaLeftCoor? Is it the most left position of the chart or QLabel (the chart is over a QLabel in my application)?

Is plotAreaWidth the width of the FinanceChart object?
e.g.
width = 640
self.chart = FinanceChart(x )

Peter Kwan wrote:
#assume x-axis is configured with Axis.setLabels
xIndex = int(percentageX * len(xLabels) - 0.5)
Is len(xlables) the number of data points (candlestick) on my graph?


Peter Kwan wrote:
After myFinanceChart.layout or makeChart, you can use:

xMax = myMainPriceChart.xAxis().getMaxValue()
How do I make use of this?
print "max: " + str(self.mainChart.xAxis().getMaxValue()) returns 174 always, irrespective of the size of the chart.

Thanks,

Christophe

  Re: ImageMapHandler (python)
Posted by Peter Kwan on Nov-15-2010 22:46
Hi Christophe,

For the formula:

percentageX = float(mouseCursorXCoor - plotAreaLeftCoor) / plotAreaWidth

The mouseCursorXCoor is the coordinate relative to the top-left position of the chart image (possibly the QLabel in your application).

The plotAreaLeftCoor is the left side of the plot area. It can be obtained by (in ChartDirector Ver 5.x):

plotAreaLeftCoor = myMainPriceChart.getPlotArea().getLeftX()

Similarly, the plotAreaWidth is the width of the plot area. It can be obtained by:

plotAreaWidth = myMainPriceChart.getPlotArea().getWidth()

In a FinanceChart, the you should use the number of plotted trading session on the chart to compute the xIndex. This may or may not be equal to the number of "candlesticks" or "data points" in your data. It is because:

- Your code may have use the "extraPoints" parameter (passed to ChartDirector in FinanceChart.setData) to trim off some leading points from being plotted.

- Your data may contain timestamps without candlesticks (they will still be plotted as empty space on the chart). This technique is often used to introduce empty space on the right side of the chart.

So for a FinanceChart, instead of using len(xLabels), you may use the code in my previous message:

xMax = myMainPriceChart.xAxis().getMaxValue()

If xMax returns 174 always irrespective of the pixel size of the chart, that means you have 174 plotted timeStamps irrespective of the pixel size of your chart. It is normal that xMax does not depend on the pixel size of the chart.

Note that if the original formula computes "xIndex = int(percentageX * len(xLabels) - 0.5)" the index of the plotted data point. If you want to get the index of your data array, you may use:

xIndex = int(percentageX * xMax - 0.5) + extraPoints

The extraPoints is the last parameter you use in FinanceChart.setData, which is the number of leading data points that are not plotted. So the visible point with index "0" is actually the data value with index "extraPoints" in your data array.

Hope this can help.

Regards
Peter Kwan

  Re: ImageMapHandler (python)
Posted by Christophe on Apr-16-2011 02:15
Thanks Peter,

That works pretty well.
Similarly, how can I find the current Y value of the mouse?

Thanks,

Christophe

  Re: ImageMapHandler (python)
Posted by Christophe Dupre on Apr-16-2011 07:32
I did a search, and found some code that I adapted for python:

yAxisMin = self.mainChart.yAxis().getMinValue();
yAxisMax = self.mainChart.yAxis().getMaxValue();
pixelAtYMin = self.mainChart.getYCoor(yAxisMin);
pixelAtYMax = self.mainChart.getYCoor(yAxisMax);

print yAxisMin, yAxisMax, pixelAtYMin, pixelAtYMax
#linear interpolation
yValue = (mouseCursorYCoor - pixelAtYMin) / float( (pixelAtYMax - pixelAtYMin))  * (yAxisMax - yAxisMin) + yAxisMin;

That works pretty well, but the yValue is slightly offset. I believe this is due to the space occupied by the O,H,L,C legend.
Can the yValue be more accurate?

Regards,

Christophe

  Re: ImageMapHandler (python)
Posted by Peter Kwan on Apr-16-2011 18:29
Hi Christophe,

The formula you are using will not be affected by the legend. It should be accurate.

Would you mind to clarify how much is the "slight offset"? May you can attach the chart image, and inform me what is the "print yAxisMin, yAxisMax, pixelAtYMin, pixelAtYMax, mouseCursorYCoor" (note: I need to mouseCursorYCoor as well), so I can verify if this is really an offset. You can also use Windows Paint or other graphics editor to check yourself if the values are correct.

There can be many reasons for a real or apparent offset. For example:

(a) The mouseCursorYCoor may be incorrect (not reflecting the actual mouse cursor position). Note that the formula to compute the mouseCursorYCoor refers to the mouse coordinate relative to the "self.mainChart". If you are using a FinanceChart, note that the coordinate relative to the "self.mainChart" may be different from the coordinate relative to the "FinanceChart" (the image), unless the "self.mainChart" happens to be at the top chart in the FinanceChart. If the "self.mainChart" is not the top chart, you would need to accurately get the offset due to all the charts above the "self.mainChart".

(b) If you are writing a web application, note that the method to get the mouse coordinates relative to an object differs for different browser brand, version and whether you are using quirk or standard mode. Please test carefully that the mouseCursorYCoor is really the mouse coordinate relative to the chart.

(c) Note that a pixel is not a point. It is a square representing a range of values. For example, y = 100 and y = 100.1 may be represented by the same pixel. You may consider the formula you use to be calculating the value at the center of the pixel. For example, if the y value at the centre of the pixel is 100.1, then the formula returns 100.1. However, it is possible to have a grid line at y = 100 at the same pixel, because y = 100 is also represented by the same pixel. So the fact that the computed value and the grid line does not agree is not an error. It just means both values are at the same pixel.

(d) Note that the code only works after the chart has been drawn or at least layout. The yAxisMin, yAxisMax, pixelAtYMin and pixelAtYMax may not be accurate if you call the API before the chart is drawn or layout.

Hope this can help.

Regards
Peter Kwan

  Re: ImageMapHandler (python)
Posted by Christophe Dupre on Apr-17-2011 04:33
Attachments:
Peter Kwan wrote:
Would you mind to clarify how much is the "slight offset"? May you can attach the chart image, and inform me what is the "print yAxisMin, yAxisMax, pixelAtYMin, pixelAtYMax, mouseCursorYCoor" (note: I need to mouseCursorYCoor as well), so I can verify if this is really an offset. You can also use Windows Paint or other graphics editor to check yourself if the values are correct.
See attached screenshot. The mouse pointer is at 3300, but the yValue is 3256.

Peter Kwan wrote:
(a) The mouseCursorYCoor may be incorrect (not reflecting the actual mouse cursor position). Note that the formula to compute the mouseCursorYCoor refers to the mouse coordinate relative to the "self.mainChart". If you are using a FinanceChart, note that the coordinate relative to the "self.mainChart" may be different from the coordinate relative to the "FinanceChart" (the image), unless the "self.mainChart" happens to be at the top chart in the FinanceChart. If the "self.mainChart" is not the top chart, you would need to accurately get the offset due to all the charts above the "self.mainChart".
This is probably the reaon. How do I know whether self.mainChart is at the top or not?

Thanks,

Christophe
Screenshot-2.png

  Re: ImageMapHandler (python)
Posted by Peter Kwan on Apr-17-2011 12:25
Hi Christophe,

From your screen shot, I suspect the error is due to the mouse coordinate "mouseCursorYCoor" not accurate.

In the screen shot, I see a FinanceChart, which seems to be using a white background color. This is a rectangle surrounding the FinanceChart. It looks like this rectangle is not created by ChartDirector, but is a QT Widget. So I assume you are putting the chart image into this QT Widget for display.

It seems your mouse y coordinate is relative to the QT Widget, not relative to the chart. (You can measure it easily using an graphics editor.) The y coordinates differ by around 10 pixels, because the chart is not at the top of the QT Widget. In the screen shot, it seems there is 10-pixel margin at the top. From the color of the margin (which is light grey), it seems the margin is not created by ChartDirector, but is created by the QT Widget.

If the above is the cause of the problem, to solve the problem, please adjust the y-coordinate by the top margin you are using, so that the y-coordinate is relative to the chart.

Hope this can help.

Regards
Peter Kwan

  Re: ImageMapHandler (python)
Posted by Christophe on Nov-04-2011 01:35
Hi Peter,

Thanks for the last reply, that worked pretty well.

I would like to do something similar with trend lines. What I'd like to do is "select" a trend line that is already drawn so that I can move it, delete, etc...
How would you go about finding out if the mouse coordinate are over a line?

Thanks,

Christophe

  Re: ImageMapHandler (python)
Posted by Peter Kwan on Nov-04-2011 19:11
Hi Christophe,

I am not exactly sure the type of "trend line" you are referring to (as the "trend line" can mean several different things). Anyway, if you know the end points of a line segment, your code can easily compute the coordinates of a thin rectangle (possibly rotated) that encloses the line segment. Then given the mouse coordinate, you can use a "point in polygon" test to determine if the mouse is over the line segment.

(The point in polygon test only requires a few lines of code. For example, see http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html.)

Hope this can help.

Regards
Peter Kwan

  Re: ImageMapHandler (python)
Posted by Christophe on Nov-04-2011 21:31
Hi Peter,

By trendline, I just mean a line between 2 points. I'm displaying financial data so I'd like to draw support and resistance lines, trend lines, etc...

Thanks for the link, that's very helpful.

Moving forward a bit, let's say that I can mouse over a line and detect it. The next thing I'll want to do is to move it left/up/down, change it's color, etc... Would I need to redraw the whole chart whenever I move a line? I suppose this would be quite CPU intensive. Just wondering if it would be possible to create 2 pictures - one for the OHLC data, and one for the lines - and overlay them?

Regards,

Christophe

  Re: ImageMapHandler (python)
Posted by Peter Kwan on Nov-05-2011 00:21
Hi Christophe,

There are many approproaches to moving a line. The followings are some examples:

(a) You may note that as you move the mouse over the chart, you do not need to redraw the chart. It is because the mouse cursor is not part of the chart. It just stays on top of the chart.

You may use the same method for the line. You do not need to treat it as part of the chart, but as a separate object and put it on top of the chart. The methods to do this depend on your GUI framework. In some GUI frameworks, you may create a "line control" and put it on top of the "chart control". In some GUI frameworks, there may be a GUI "onPaint" event (or a message loop or message pump or something similar), and you can insert additional graphics code there to repaint the display with the additional line.

(b) If the line you want to draw cannot be achieved easily by your GUI framework (eg. it uses some special line styles with fancy symbols and labels, etc), you may consider the line as part of the chart. Even that, you may not need to update the chart as the mouse is dragging. Many common user interface does not redraw the "real thing" when the mouse is dragging. Instead, sometimes just a "outline box" is drawn to allow the user know where to "drop" the object. The "outline box" itself, being very simple, can usually be achieved easily with common GUI framework (that is, it does not need to be considered as part of the chart). The chart only needs to be updated when the user "drops" the object.

Hope this can help.

Regards
Peter Kwan

  Re: ImageMapHandler (python)
Posted by quanghx on Oct-16-2012 02:11
Attachments:
Hi,

I've got a nearly the same question to this guy, but a bit different.

Please have a look on my Chart, How can I detect the closest points to my mouse line
(vertical line I mean) when mouse move.

Regards,
quanghx
attach1.png

  Re: ImageMapHandler (python)
Posted by Peter Kwan on Oct-17-2012 00:33
Hi quanghx,

Is it a web application or a desktop application?

For a web application, ChartDirector 5.1 includes a Javascript library that can determine the points closest to the mouse. See the "Programming Track Cursor" sample code:

http://www.advsofteng.com/doc/cdpython.htm#trackcursor.htm

For a desktop application in Python, you may use the following method:

- From the "mouse move" event of your GUI framework, you should be able to obtain the mouse x-coordinate relative to the chart. You can then use the ChartDirector XYChart.getNearestXValue API to translate the x data value closest to the mouse x-coordinate.

- You may then search your data using linear or binary search to locate the points that are at the x data value. You may also use Layer.getXIndexOf followed by DataSet.getPosition to obtain the value of the data points at the x data value.

(The logic of the above steps are similar to the Javascript sample code in the web examples.)

Hope this can help.

Regards
Peter Kwan

  Re: ImageMapHandler (python)
Posted by quanghx on Oct-18-2012 00:38
This is web application, and this is my code to create the Chart,

on javascript code, I've got Chart empty.

so...what happen to my Chart?

/******** Javascript *********/
    if (!viewer.getChart())
        return;
/******** End Javascript *********/


/******** PHP *********/
#
# Draw the chart
#
function drawChart(&$viewer,&$data,&$key,&$axis,&$tags) {

    global $startDate, $endDate, $viewPortStartDate, $viewPortEndDate;

    #
    # Validate and adjust the view port dates.
    #
    # Verify if the view port dates are within limits
    $totalDuration = $endDate - $startDate;

    $minDuration = $viewer->getZoomInWidthLimit() * $totalDuration;
    if ($viewPortStartDate < $startDate) {
        $viewPortStartDate = $startDate;
    }
    if ($endDate - $viewPortStartDate < $minDuration) {
        $viewPortStartDate = $endDate - $minDuration;
    }
    if ($viewPortEndDate > $endDate) {
        $viewPortEndDate = $endDate;
    }
    if ($viewPortEndDate - $viewPortStartDate < $minDuration) {
        $viewPortEndDate = $viewPortStartDate + $minDuration;
    }

    # Adjust the view port to reflect the selected date range
    $viewer->setViewPortWidth(($viewPortEndDate - $viewPortStartDate) /
$totalDuration);
    $viewer->setViewPortLeft(($viewPortStartDate - $startDate) / $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


$size=sizeof($key);
$data1=array();
$data2=array();
# Add the data sets to the line layer

//if I get 30 days day from the last day
// 30 - (today - lastday)-$i  1...90; 20...60;

$days=90*4;

$size=sizeof($key);

$offset=$days-sizeof($data[0])-7-4;

for($i=0;$i<$size;$i++){
    for($j=0;$j<$offset;$j++)
{
        $data1[$i][$j]=NoValue;
        $data2[$i][$j]=NoValue;

}
for(;$j<90*4+$offset-1;$j++)
{
    if($data[$i][$j-$offset]>20000 ||$data[$i][$j-$offset]<-20000){
        $data1[$i][$j]=NoValue;
        $data2[$i][$j]=NoValue;
    }
        else {

            $data1[$i][$j]=$data[$i][$j-$offset];
            $data2[$i][$j]=$tags[$i][$j-$offset];

    }
}

//$layer->addDataSet($data1[$i], -1, $key[$i]);
}


$r = new RanTable(127, 4, (int)($totalDuration / 86400*4) + 1);
    $r->setDateCol(0, $startDate, 86400/4);
   // $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 - 86400, $viewPortEndDate + 86400);

    # Emulate getting the random data from the table
    $timeStamps = $r->getCol(0);

    for($i=0;$i<sizeof($key);$i++)
  {
//   $dataSeriesA = $r->getCol(1);
   // $dataSeriesB = $r->getCol(2);
    $dataSeries[$i] = $data1[$i];

}



    if (count($timeStamps) >= 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
        $m = new ArrayMath($timeStamps);
        $m->selectRegularSpacing(count($timeStamps) / 260);

        # For the timestamps, take the first timestamp on each slot
        $timeStamps = $m->aggregate($timeStamps, AggregateFirst);

        # For the data values, take the averages
        $dataSeriesA = $m->aggregate($dataSeriesA, AggregateAvg);
        $dataSeriesB = $m->aggregate($dataSeriesB, AggregateAvg);
        $dataSeriesC = $m->aggregate($dataSeriesC, 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.
    //$c = new XYChart(600, 450, 0xf0f0ff, 0x000000);
    //$c = new XYChart(600, 450, 0xEFF8FF, 0x000000);
   // $c = new XYChart(600, 450, 0x86B7DF, 0x000000);
    $c = new XYChart(600, 483, 0xFFFFFF, 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, 85, 520, 332, 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.
    $textBoxObj = $c->addTitle(" ", "timesbi.ttf", 21);
    //$textBoxObj->setBackground(0xccccff, 0x000000, glassEffect());
    //$textBoxObj->setBackground(0x86B7DF, 0x000000, glassEffect());
//$textBoxObj->setBackground(0xff3333, 0xFFFFFF, glassEffect());
$textBoxObj->setBackground($c-
>patternColor(dirname(__FILE__)."/../../../img/rate_fee_header_bg.png"), 0x000000, 1);

    # Add a bottom title to the chart to show the date range of the axis, with a light blue
(ccccff)
    # background.
    $textBoxObj = $c->addTitle2(Bottom, sprintf(
        "From <*font=arialbi.ttf*>%s<*/font*> to <*font=arialbi.ttf*>%s<*/font*>
(Duration ".
        "<*font=arialbi.ttf*>%s<*/font*> days)", $c->formatValue($viewPortStartDate,
        "{value|mmm dd, yyyy}"), $c->formatValue($viewPortEndDate, "{value|mmm dd,
yyyy}"), (int)(
        0.5 + ($viewPortEndDate - $viewPortStartDate) / 86400)), "ariali.ttf", 10);
    //$textBoxObj->setBackground(0xccccff);
   //$textBoxObj->setBackground(0x86B7DF);
    $textBoxObj->setBackground(0xFFFFFF);
   // $textBoxObj->setBackground(0xFFFFFF);

    # Add a legend box at the top of the plot area with 9pts Arial Bold font with flow
layout.
    $legendObj = $c->addLegend(50, 43, false, "arialbd.ttf", 9);
    $legendObj->setBackground(Transparent, 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("Out of pocket fees*($) ", "arialbd.ttf", 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
    $layer = $c->addLineLayer2();
    $layer->setLineWidth(1);

//$layer->setGapColor($c->dashLineColor(0x030303));
//$layer->setGapColor(SameAsMainColor);

    # 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");
*/
/*
$size=sizeof($key);
$data1=array();
# Add the data sets to the line layer

//if I get 30 days day from the last day
// 30 - (today - lastday)-$i  1...90; 20...60;


*/
$color[0]=0xff3333;
$color[1]=0x33ff33;
$color[2]=0x6666ff    ;

for($i=0;$i<$size;$i++){
    /*for($j=0;$j<$days-sizeof($data[$i]);$j++)
{
        $data1[$i][$j]=NoValue;

}
for(;$j<90;$j++)
{
    if($data[$i][$j-($days-sizeof($data[$i]))]>10000 ||$data[$i][$j-($days-
sizeof($data[$i]))]<-10000)
        $data1[$i][$j]=NoValue;
        else $data1[$i][$j]=$data[$i][$j-($days-sizeof($data[$i]))];
}
*/
//$layer->addDataSet($dataSeries[$i], -1, $key[$i]);
//$layer->setGapColor($c->dashLineColor(0x00ff00));
$dataSetObj=$layer->addDataSet($dataSeries[$i], 0x000000, $key[$i]);
$layer->addExtraField($data2[$i]);

$layer->setGapColor(SameAsMainColor);

//$dataSetObj->setDataSymbol(Cross2Shape(), 5);
$dataSetObj->setDataSymbol(CircleShape, 8, $color[$i]);
//$dataSetObj->setDataSymbol(DiamondShape, 10,-1,Transparent);

}



#=================================================================
===============
    # 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", 360 * 86400);
    $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", 30 * 86400);
    $c->xAxis->setMultiFormat(StartOfYearFilter(), "<*font=bold*>{value|mmm yyyy}",
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(StartOfYearFilter(),
        "<*block,halign=left*><*font=bold*>{value|mmm dd<*br*>yyyy}",
StartOfMonthFilter(),
        "<*font=bold*>{value|mmm dd}");
    $c->xAxis->setMultiFormat2(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(StartOfDayFilter(), "<*font=bold*>
{value|hh:nn<*br*>mmm dd}",
        AllPassFilter(), "{value|hh:nn}");


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

#=================================================================
===============

    if ($viewer->getZoomDirection() == DirectionHorizontal) {
        # 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->setViewPortTop(0);
        $viewer->setViewPortHeight(1);
    } else {
        # xy-zoom mode - retrieve the auto-scaled axis range, which contains the entire y
data
        # range.
        $minValue = $viewer->getCustomAttr("minValue");
        $maxValue = $viewer->getCustomAttr("maxValue");

        # Compute the view port axis range
        $axisLowerLimit = $maxValue - ($maxValue - $minValue) * ($viewer-
>getViewPortTop() +
            $viewer->getViewPortHeight());
        $axisUpperLimit = $maxValue - ($maxValue - $minValue) * $viewer-
>getViewPortTop();

        # 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

#=================================================================
===============

    # Create the image and save it in a temporary location
    $chartQuery = $c->makeSession($viewer->getId());

    # Include tool tip for the chart
    /*$imageMap = $c->getHTMLImageMap("", "",
        "title='[{dataSetName}] {x|mmm dd, yyyy}: USD {value|2}'");*/
$imageMap = $c->getHTMLImageMap("", "",      "title='{dataSetName}, Lender fees*
{value|2}, {x|mmm dd, yyyy}{dsdiField0} '");

    # Set the chart URL, image map, and chart metrics to the viewer. For the image map,
we use
    # delayed delivery and with compression, so the chart image will show up quicker.
   // print(base_url()."ChartDirector/getchart.php?".$chartQuery);die;

    $viewer->setImageUrl(base_url()."ChartDirector/getchart.php?".$chartQuery);
    $viewer->setImageMap(base_url()."ChartDirector/getchart.php?".$viewer-
>makeDelayedMap($imageMap, true));
    $viewer->setChartMetrics($c->getChartMetrics());

}

  Re: ImageMapHandler (python)
Posted by Peter Kwan on Oct-18-2012 23:51
Hi guanghx,

To use the Programmable Track Cursor feature of ChartDirector 5.1, the code on the server side must use setChartModel/getJsChartModel to export the necessary information to the browser, so that the browser Javascript code knows how to draw the track cursor.

So in "# Step 5 - Output the chart", please remove all your existing code and replace them with:

    # Output the chart
    $chartQuery = $c->makeSession($viewer->getId());

    # Set the chart URL to the viewer
    $viewer->setImageUrl("getchart.php?".$chartQuery);

    # Output Javascript chart model to the browser to support tracking cursor
    $viewer->setChartModel($c->getJsChartModel());


In your case, your charting code seems to come from ChartDirector 5.0.x or 4.1. If you are using ChartDirector 5.1, you can always modify them to add track cursors. However, we have not tested if you can directly copy some of the code fragments from the ChartDirector 5.1 sample code to the ChartDirector 5.0.x or 4.1 sample code. Some modifications may be necessary. For example, in ChartDirector 5.0.x or 4.1 sample code, the Javascript code is initialized by directly calling the initialization function in the onload attribute of the <body> tag. In ChartDirector 5.1 sample code, Javascript code is initialized by using the addEventListener utility.

You may consider to port your code to base on the ChartDirector 5.1 sample code.

Regards
Peter Kwan

  Re: ImageMapHandler (python)
Posted by quanghx on Oct-19-2012 01:25
Attachments:
I'm using ChartDirector 5.1, but when I do as what you told, I've got a error message that
"Fatal error: Call to undefined method WebChartViewer::setChartModel()"

I'm using: $viewer = new WebChartViewer("chart1");
and I'm not sure that's the right one or not.

Attach with this message is full of my code to draw the Chart. Please take a look and give
me the best help.

Thank you,
quanghx
chartbasic.php
<script type="text/javascript" src="/ChartDirector/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>
<?php

#
# 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.
$startDate = null;
$endDate = null;

# The date range of the data that we zoomed into (visible on the chart).
$viewPortStartDate = null;
$viewPortEndDate = null;



#
# Handles the initial request
#
function createFirstChart(&$viewer,&$data,&$key,&$x_axis,&$tags) {

    global $startDate, $endDate, $viewPortStartDate, $viewPortEndDate;

    # Initialize the Javascript ChartViewer
    $viewer->setMouseUsage(MouseUsageScroll);

    # In this demo, we allow scrolling the chart for the last 5 years
    list($unused, $unused, $hour, $d, $m, $y, $unused, $unused, $unused) = localtime();

    # The localtime month format is from 0 - 11, while the year is offsetted by 1900. We adjust them
    # to human used format.
    $m = $m + 1;
    $y = $y + 1900;
	$d=$d+1; 
    $endDate = chartTime($y, $m, $d);

    # We roll back 5 years for the start date. Note that if the end date is Feb 29 (leap year only
    # date), we need to change it to Feb 28 in the start year
    if (($m == 2) && ($d == 29)) {
        $d = 28;
    }
    //$startDate = chartTime($y, $m, $d-90);
	$weekends= 90/7 *2;
//$startDate = chartTime($y, $m, $d-90-$weekends-9);
if($hour>=18 && $hour <24)
{
$startDate = chartTime($y, $m, $d-90+1+3);
    # The initial selected date range is last 1 year
    $viewPortStartDate = chartTime($y, $m, $d-90+1+3);
 }
 else
 {
$startDate = chartTime($y, $m, $d-90+1+2);
    # The initial selected date range is last 1 year
    $viewPortStartDate = chartTime($y, $m, $d-90+1+2);
}
 
 
    $viewPortEndDate = $endDate;

    # We store the scroll range as custom Javascript ChartViewer attributes, so the range can be
    # retrieved later in partial or full update requests
    $viewer->setCustomAttr("startDate", $startDate);
    $viewer->setCustomAttr("endDate", $endDate);

    # In this demo, we set the maximum zoom-in to 10 days
    $viewer->setZoomInWidthLimit(1 * 86400 / ($endDate - $startDate));

    # Draw the chart
    drawChart($viewer,$data,$key,$x_axis,$tags);
}

#
# Handles partial update (AJAX chart update)
#
function processPartialUpdate(&$viewer,&$data,&$key,&$x_axis,&$tags) {

    global $startDate, $endDate, $viewPortStartDate, $viewPortEndDate;

    # Retrieve the overall date range from custom Javascript ChartViewer attributes.
    $startDate = $viewer->getCustomAttr("startDate");
    $endDate = $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.
        $duration = $endDate - $startDate;
        $viewPortStartDate = $startDate + (int)(0.5 + $viewer->getViewPortLeft() * $duration);
        $viewPortEndDate = $viewPortStartDate + (int)(0.5 + $viewer->getViewPortWidth() * $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.
        $startYear = (int)($viewer->getCustomAttr("StartYear"));
        $startMonth = (int)($viewer->getCustomAttr("StartMonth"));
        $startDay = (int)($viewer->getCustomAttr("StartDay"));
        $endYear = (int)($viewer->getCustomAttr("EndYear"));
        $endMonth = (int)($viewer->getCustomAttr("EndMonth"));
        $endDay = (int)($viewer->getCustomAttr("EndDay"));

        # 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 = chartTime($startYear, $startMonth, 1) + ($startDay - 1) * 86400;
        $viewPortEndDate = chartTime($endYear, $endMonth, 1) + ($endDay - 1) * 86400;
    }

    # Draw the chart
    drawChart($viewer,$data,$key,$axis,$tags);

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

    # The getChartYMD function retrives the date as an 8 digit decimal number yyyymmdd.
    $startYMD = getChartYMD($viewPortStartDate);
    $endYMD = getChartYMD($viewPortEndDate);

    # Send year, month, day components to the start date / end date select boxes through Javascript
    # ChartViewer custom attributes.
    $viewer->setCustomAttr("StartYear", (int)($startYMD / 10000));
    $viewer->setCustomAttr("StartMonth", (int)($startYMD / 100) % 100);
    $viewer->setCustomAttr("StartDay", $startYMD % 100);
    $viewer->setCustomAttr("EndYear", (int)($endYMD / 10000));
    $viewer->setCustomAttr("EndMonth", (int)($endYMD / 100) % 100);
    $viewer->setCustomAttr("EndDay", $endYMD % 100);
}

#
# Handles full update
#
function processFullUpdate(&$viewer,&$data,&$key,&$x_axis,&$tags) {
    # 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
    $ctrls = array("StartYear", "StartMonth", "StartDay", "EndYear", "EndMonth", "EndDay");

    # Copy control values to Javascript ChartViewer custom attributes
    for($i = 0; $i < count($ctrls); ++$i) {
        $viewer->setCustomAttr($ctrls[$i], $_REQUEST[$ctrls[$i]]);
    }

    # Now can use partial chart update
    processPartialUpdate($viewer,$data,$key,$x_axis,$tags);
}

#
# Draw the chart
#
function drawChart(&$viewer,&$data,&$key,&$axis,&$tags) {

    global $startDate, $endDate, $viewPortStartDate, $viewPortEndDate;

    #
    # Validate and adjust the view port dates.
    #
    # Verify if the view port dates are within limits
    $totalDuration = $endDate - $startDate;
 
    $minDuration = $viewer->getZoomInWidthLimit() * $totalDuration;
    if ($viewPortStartDate < $startDate) {
        $viewPortStartDate = $startDate;
    }
    if ($endDate - $viewPortStartDate < $minDuration) {
        $viewPortStartDate = $endDate - $minDuration;
    }
    if ($viewPortEndDate > $endDate) {
        $viewPortEndDate = $endDate;
    }
    if ($viewPortEndDate - $viewPortStartDate < $minDuration) {
        $viewPortEndDate = $viewPortStartDate + $minDuration;
    }

    # Adjust the view port to reflect the selected date range
    $viewer->setViewPortWidth(($viewPortEndDate - $viewPortStartDate) / $totalDuration);
    $viewer->setViewPortLeft(($viewPortStartDate - $startDate) / $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


$size=sizeof($key);
$data1=array();
$data2=array();
# Add the data sets to the line layer

//if I get 30 days day from the last day
// 30 - (today - lastday)-$i  1...90; 20...60;

$days=90*4;

$size=sizeof($key);

$offset=$days-sizeof($data[0])-7-4;

for($i=0;$i<$size;$i++){
	for($j=0;$j<$offset;$j++)
{
		$data1[$i][$j]=NoValue;
		$data2[$i][$j]=NoValue;
		
}
for(;$j<90*4+$offset-1;$j++)
{
	if($data[$i][$j-$offset]>20000 ||$data[$i][$j-$offset]<-20000){
		$data1[$i][$j]=NoValue;
		$data2[$i][$j]=NoValue;
	}
		else {
		
			$data1[$i][$j]=$data[$i][$j-$offset];
			$data2[$i][$j]=$tags[$i][$j-$offset];
			
	}
}

//$layer->addDataSet($data1[$i], -1, $key[$i]);
}


 $r = new RanTable(127, 4, (int)($totalDuration / 86400*4) + 1);
    $r->setDateCol(0, $startDate, 86400/4);
   // $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 - 86400, $viewPortEndDate + 86400);

    # Emulate getting the random data from the table
    $timeStamps = $r->getCol(0);
  
    for($i=0;$i<sizeof($key);$i++)
  {
 //   $dataSeriesA = $r->getCol(1);
   // $dataSeriesB = $r->getCol(2);
    $dataSeries[$i] = $data1[$i];
   
}



    if (count($timeStamps) >= 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
        $m = new ArrayMath($timeStamps);
        $m->selectRegularSpacing(count($timeStamps) / 260);

        # For the timestamps, take the first timestamp on each slot
        $timeStamps = $m->aggregate($timeStamps, AggregateFirst);

        # For the data values, take the averages
        $dataSeriesA = $m->aggregate($dataSeriesA, AggregateAvg);
        $dataSeriesB = $m->aggregate($dataSeriesB, AggregateAvg);
        $dataSeriesC = $m->aggregate($dataSeriesC, 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.
    //$c = new XYChart(600, 450, 0xf0f0ff, 0x000000);
    //$c = new XYChart(600, 450, 0xEFF8FF, 0x000000);
   // $c = new XYChart(600, 450, 0x86B7DF, 0x000000);
    $c = new XYChart(600, 483, 0xFFFFFF, 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, 85, 520, 332, 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.
    $textBoxObj = $c->addTitle(" ", "timesbi.ttf", 21);
    //$textBoxObj->setBackground(0xccccff, 0x000000, glassEffect());
    //$textBoxObj->setBackground(0x86B7DF, 0x000000, glassEffect());
//$textBoxObj->setBackground(0xff3333, 0xFFFFFF, glassEffect());
$textBoxObj->setBackground($c->patternColor(dirname(__FILE__)."/../../../img/rate_fee_header_bg.png"), 0x000000, 1);

    # Add a bottom title to the chart to show the date range of the axis, with a light blue (ccccff)
    # background.
    $textBoxObj = $c->addTitle2(Bottom, sprintf(
        "From <*font=arialbi.ttf*>%s<*/font*> to <*font=arialbi.ttf*>%s<*/font*> (Duration ".
        "<*font=arialbi.ttf*>%s<*/font*> days)", $c->formatValue($viewPortStartDate,
        "{value|mmm dd, yyyy}"), $c->formatValue($viewPortEndDate, "{value|mmm dd, yyyy}"), (int)(
        0.5 + ($viewPortEndDate - $viewPortStartDate) / 86400)), "ariali.ttf", 10);
    //$textBoxObj->setBackground(0xccccff);
   //$textBoxObj->setBackground(0x86B7DF);
    $textBoxObj->setBackground(0xFFFFFF);
   // $textBoxObj->setBackground(0xFFFFFF);

    # Add a legend box at the top of the plot area with 9pts Arial Bold font with flow layout.
    $legendObj = $c->addLegend(50, 43, false, "arialbd.ttf", 9);
    $legendObj->setBackground(Transparent, 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("Out of pocket fees*($) ", "arialbd.ttf", 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
    $layer = $c->addLineLayer2();
    $layer->setLineWidth(1);
  
//$layer->setGapColor($c->dashLineColor(0x030303));
//$layer->setGapColor(SameAsMainColor);

    # 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");
*/
/*
$size=sizeof($key);
$data1=array();
# Add the data sets to the line layer

//if I get 30 days day from the last day
// 30 - (today - lastday)-$i  1...90; 20...60;


*/
$color[0]=0xff3333;
$color[1]=0x33ff33;
$color[2]=0x6666ff	;

for($i=0;$i<$size;$i++){
	/*for($j=0;$j<$days-sizeof($data[$i]);$j++)
{
		$data1[$i][$j]=NoValue;
	
}
for(;$j<90;$j++)
{
	if($data[$i][$j-($days-sizeof($data[$i]))]>10000 ||$data[$i][$j-($days-sizeof($data[$i]))]<-10000)
		$data1[$i][$j]=NoValue;
		else $data1[$i][$j]=$data[$i][$j-($days-sizeof($data[$i]))];
}
*/
//$layer->addDataSet($dataSeries[$i], -1, $key[$i]);
//$layer->setGapColor($c->dashLineColor(0x00ff00));
$dataSetObj=$layer->addDataSet($dataSeries[$i], 0x000000, $key[$i]);
$layer->addExtraField($data2[$i]);

$layer->setGapColor(SameAsMainColor);

//$dataSetObj->setDataSymbol(Cross2Shape(), 5);
$dataSetObj->setDataSymbol(CircleShape, 8, $color[$i]);
//$dataSetObj->setDataSymbol(DiamondShape, 10,-1,Transparent);

}


    #================================================================================
    # 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", 360 * 86400);
    $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", 30 * 86400);
    $c->xAxis->setMultiFormat(StartOfYearFilter(), "<*font=bold*>{value|mmm yyyy}", 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(StartOfYearFilter(),
        "<*block,halign=left*><*font=bold*>{value|mmm dd<*br*>yyyy}", StartOfMonthFilter(),
        "<*font=bold*>{value|mmm dd}");
    $c->xAxis->setMultiFormat2(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(StartOfDayFilter(), "<*font=bold*>{value|hh:nn<*br*>mmm dd}",
        AllPassFilter(), "{value|hh:nn}");

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

    if ($viewer->getZoomDirection() == DirectionHorizontal) {
        # 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->setViewPortTop(0);
        $viewer->setViewPortHeight(1);
    } else {
        # xy-zoom mode - retrieve the auto-scaled axis range, which contains the entire y data
        # range.
        $minValue = $viewer->getCustomAttr("minValue");
        $maxValue = $viewer->getCustomAttr("maxValue");

        # Compute the view port axis range
        $axisLowerLimit = $maxValue - ($maxValue - $minValue) * ($viewer->getViewPortTop() +
            $viewer->getViewPortHeight());
        $axisUpperLimit = $maxValue - ($maxValue - $minValue) * $viewer->getViewPortTop();

        # 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
    #================================================================================

    # Create the image and save it in a temporary location
    $chartQuery = $c->makeSession($viewer->getId());

    # Include tool tip for the chart
    /*$imageMap = $c->getHTMLImageMap("", "",
    "title='[{dataSetName}] {x|mmm dd, yyyy}: USD {value|2}'");*/
    $imageMap = $c->getHTMLImageMap("", "",      "title='{dataSetName}, Lender fees* {value|2}, {x|mmm dd, yyyy}{dsdiField0} '");

    # Set the chart URL, image map, and chart metrics to the viewer. For the image map, we use
    # delayed delivery and with compression, so the chart image will show up quicker.
   // print(base_url()."ChartDirector/getchart.php?".$chartQuery);die;

    $viewer->setImageUrl(base_url()."ChartDirector/getchart.php?".$chartQuery);
    $viewer->setImageMap(base_url()."ChartDirector/getchart.php?".$viewer->makeDelayedMap($imageMap, true));
    $viewer->setChartMetrics($c->getChartMetrics());
    
    # Output Javascript chart model to the browser to support tracking cursor
    $viewer->setChartModel($c->getJsChartModel());

    
}

#
# A utility to create the <option> tags for the date range <select> boxes
#
# Parameters: startValue: The minimum selectable value. endValue: The maximum selectable value.
# selectedValue: The currently selected value.
#
function createSelectOptions($startValue, $endValue, $selectedValue) {
    $ret = array_pad(array(), ($endValue - $startValue + 1), null);
    for($i = $startValue; $i < $endValue + 1; ++$i) {
        if ($i == $selectedValue) {
            # Use a "selected" <option> tag if it is the selected value
            $ret[$i - $startValue] = "<option value='$i' selected>$i</option>";
        } else {
            # Use a normal <option> tag
            $ret[$i - $startValue] = "<option value='$i'>$i</option>";
        }
    }
    return join("", $ret);
}

# Create the WebChartViewer object
$viewer = new WebChartViewer("chart1");

if ($viewer->isPartialUpdateRequest()) {
    # Is a partial update request (AJAX chart update)
  
    processPartialUpdate($viewer,$data,$key,$x_axis,$tags);
    # Since it is a partial update, there is no need to output the entire web page. We stream the
    # chart and then terminate the script immediately.
    print($viewer->partialUpdateChart());
    exit();
} else if ($viewer->isFullUpdateRequest()) {
    # Is a full update request
    processFullUpdate($viewer,$data,$key,$x_axis,$tags);
} else {
    # Is a initial request
    createFirstChart($viewer,$data,$key,$x_axis,$tags);
}

# Create the <option> tags for the start date / end date select boxes to reflect the currently
# selected data range
/*$startYearSelectOptions = createSelectOptions((int)(getChartYMD($startDate) / 10000), (int)(
    getChartYMD($endDate) / 10000), (int)(getChartYMD($viewPortStartDate) / 10000));*/
    $startYearSelectOptions = createSelectOptions(2012,2012, 1);
$startMonthSelectOptions = createSelectOptions(1, 12, (int)(getChartYMD($viewPortStartDate) / 100) %
    100);
$startDaySelectOptions = createSelectOptions(1, 31, (int)(getChartYMD($viewPortStartDate) % 100));

/*$endYearSelectOptions = createSelectOptions((int)(getChartYMD($startDate) / 10000), (int)(
    getChartYMD($endDate) / 10000), (int)(getChartYMD($viewPortEndDate) / 10000));
  */ 
  $endYearSelectOptions = createSelectOptions(2012,2012, 1);
$endMonthSelectOptions = createSelectOptions(1, 12, (int)(getChartYMD($viewPortEndDate) / 100) % 100
    );
$endDaySelectOptions = createSelectOptions(1, 31, (int)(getChartYMD($viewPortEndDate) % 100));
?>

<script type="text/javascript">
	
window.onload = function(e)
{
initJsChartViewer();
}
</script>
<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('<?php echo $viewer->getId()?>');

/*quanghx    mouse_move_on_chart(viewer);*/

    // Draw track cursor when mouse is moving over plotarea
    viewer.attachHandler("MouseMovePlotArea", function(e) {
        traceFinance(viewer, viewer.getPlotAreaMouseX());
    });

    // Initialize the track line with legend to show the latest data point
    if (viewer.getChart())
        traceFinance(viewer, viewer.getChart().getPlotArea().getRightX());
        
    // Connect the mouse usage buttons to the Javascript ChartViewer object
    connectViewerMouseUsage('ViewerMouseUsage1', viewer);
    // Connect the xy zoom mode buttons to the Javascript ChartViewer object
    connectViewerZoomControl('ViewerZoomControl1', viewer);

    // 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);
        document.getElementById('SubmitButton').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', 'StartMonth', 'StartDay', 'EndYear', 'EndMonth', 'EndDay'];
        viewer.attachHandler("PreUpdate", function() { copyToViewer(viewer, controlsToSync); });
        viewer.attachHandler("PostUpdate", function() { copyFromViewer(viewer, controlsToSync); });
    }
    else
        // Browser cannot support partial update - so use full page update
        viewer.attachHandler("ViewPortChanged", function() { document.forms[0].submit(); });
}
// 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();
            }
        }
    }
}


function connectViewerMouseUsage(controlId, viewer)
{
    // 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); syncButtons(); }
    getObj(controlId + "_ZoomIn").onclick = function() { viewer.setMouseUsage(JsChartViewer.ZoomIn); syncButtons(); }
    getObj(controlId + "_ZoomOut").onclick = function() {  viewer.setMouseUsage(JsChartViewer.ZoomOut); syncButtons(); }
}

// Connect the zoom/scroll direction buttons to the Javascript ChartViewer
function connectViewerZoomControl(controlId, viewer)
{
    // 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);
        syncButtons();
    }
    getObj(controlId + "_Xmode").onclick = function() { setViewerDirection(JsChartViewer.Horizontal); }
    getObj(controlId + "_XYmode").onclick = function() { setViewerDirection(JsChartViewer.HorizontalVertical); }
}
// 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();
}
      

/* quanghx      
function mouse_move_on_chart(viewer){
    function get_mouse_position(){
        $("#rate_and_fee_content").mousemove(function(e){
            $('#line_x').css('left', e.pageX+2);
            //$('#line_x').css('top', e.pageY);
        }); 
        
        $("#rate_and_fee_content").hover(
            function (e) {
                $('#line_x').show();
            }, 
            function () {
                $('#line_x').hide();
            }
        );
        
        //$("#map_chart1 area").mouseover(
        var text = "";
        $("#rate_and_fee_content area").hover(
            function (e) {
                text = $(this).attr("title");
                $(this).attr("title", "");
                display_tooltip(true, e.pageX, e.pageY, text);
            }, 
            function () {
                display_tooltip(false, 0,0,0);
                $(this).attr("title", text);
            }
        );
    }
    
    function display_tooltip(display, x, y, text){
        if(display == true){
            $("#dot_info").css('left', x-230);
            $("#dot_info").css('top', y-15);
            $("#dot_info").html(text);
            $("#dot_info").show();
        }
        else{
            $("#dot_info").hide();
            $("#dot_info").html("");
        }
    }
    
    get_mouse_position();

    //viewer.attachHandler("MouseMoveChart", get_mouse_position);
    viewer.attachHandler("MouseMovePlotArea", get_mouse_position);
}
*/

function traceFinance(viewer, mouseX)
{
    // Remove all previously drawn tracking object
    viewer.hideObj("all");

    // It is possible for a FinanceChart to be empty, so we need to check for it.
    if (!viewer.getChart())
        return;

    // Get the data x-value that is nearest to the mouse
    var xValue = viewer.getChart().getNearestXValue(mouseX);

    // Iterate the XY charts (main price chart and indicator charts) in the FinanceChart
    var c = null;
    for (var i = 0; i < viewer.getChartCount(); ++i)
    {
        c = viewer.getChart(i);

        // Variables to hold the legend entries
        var ohlcLegend = "";
        var legendEntries = [];

        // Iterate through all layers to build the legend array
        for (var j = 0; j < c.getLayerCount(); ++j)
        {
            var layer = c.getLayerByZ(j);
            var xIndex = layer.getXIndexOf(xValue);
            var dataSetCount = layer.getDataSetCount();

            // In a FinanceChart, only layers showing OHLC data can have 4 data sets
            if (dataSetCount == 4)
            {
                var highValue = layer.getDataSet(0).getValue(xIndex);
                var lowValue = layer.getDataSet(1).getValue(xIndex);
                var openValue = layer.getDataSet(2).getValue(xIndex);
                var closeValue = layer.getDataSet(3).getValue(xIndex);

                if (closeValue == null)
                    continue;

                // Build the OHLC legend
                ohlcLegend =
                    "Open: " + openValue.toPrecision(4) + ", High: " + highValue.toPrecision(4) +
                    ", Low: " + lowValue.toPrecision(4) + ", Close: " + closeValue.toPrecision(4);

                // We also draw an upward or downward triangle for up and down days and the %% change
                var lastCloseValue = layer.getDataSet(3).getValue(xIndex - 1);
                if (lastCloseValue != null)
                {
                    var change = closeValue - lastCloseValue;
                    var percent = change * 100 / closeValue;
                    if (change >= 0)
                        ohlcLegend += "&nbsp;&nbsp;<span style='color:#008800;'>&#9650; ";
                    else
                        ohlcLegend += "&nbsp;&nbsp;<span style='color:#CC0000;'>&#9660; ";
                    ohlcLegend += change.toPrecision(4) + " (" + percent.toFixed(2) + "%%)</span>";
                }

                // Add a spacer box, and make sure the line does not wrap within the legend entry
                ohlcLegend = "<nobr>" + ohlcLegend + viewer.htmlRect(20, 0) + "</nobr> ";
            }
            else
            {
                // Iterate through all the data sets in the layer
                for (var k = 0; k < dataSetCount; ++k)
                {
                    var dataSet = layer.getDataSetByZ(k);
                    var name = dataSet.getDataName();
                    var value = dataSet.getValue(xIndex);
                    if ((!name) || (value == null))
                        continue;

                    // In a FinanceChart, the data set name consists of the indicator name and its latest value. It is
                    // like "Vol: 123M" or "RSI (14): 55.34". As we are generating the values dynamically, we need to
                    // extract the indictor name out, and also the volume unit (if any).

                    // The unit character, if any, is the last character and must not be a digit.
                    var unitChar = name.charAt(name.length - 1);
                    if ((unitChar >= '0') && (unitChar <= '9'))
                        unitChar = '';

                    // The indicator name is the part of the name up to the colon character.
                    var delimiterPosition = name.indexOf(':');
                    if (delimiterPosition != -1)
                        name = name.substring(0, delimiterPosition);

                    // In a FinanceChart, if there are two data sets, it must be representing a range.
                    if (dataSetCount == 2)
                    {
                        // We show both values in the range
                        var value2 = layer.getDataSetByZ(1 - k).getValue(xIndex);
                        name = name + ": " + Math.min(value, value2).toPrecision(4) + " - "
                            + Math.max(value, value2).toPrecision(4);
                    }
                    else
                    {
                        // In a FinanceChart, only the layer for volume bars has 3 data sets for up/down/flat days
                        if (dataSetCount == 3)
                        {
                            // The actual volume is the sum of the 3 data sets.
                            value = layer.getDataSet(0).getValue(xIndex) + layer.getDataSet(1).getValue(xIndex) +
                                layer.getDataSet(2).getValue(xIndex);
                        }

                        // Create the legend entry
                        name = name + ": " + value.toPrecision(4) + unitChar;
                    }

                    // Build the legend entry, consist of a colored square box and the name (with the data value in it).
                    legendEntries.push("<nobr>" + viewer.htmlRect(5, 5, dataSet.getDataColor(),
                        "solid 1px black") + " " + name + viewer.htmlRect(20, 0) + "</nobr>");
                }
            }
        }

        // The legend is formed by concatenating the legend entries.
        var legend = legendEntries.reverse().join(" ");

        // Add the date and the ohlcLegend (if any) at the beginning of the legend
        legend = "<nobr>[" + c.xAxis().getFormattedLabel(xValue, "mmm dd, yyyy") + "]" + viewer.htmlRect(20, 0) +
            "</nobr> " + ohlcLegend + legend;

        // Get the plot area position relative to the entire FinanceChart
        var plotArea = c.getPlotArea();
        var plotAreaLeftX = plotArea.getLeftX() + c.getAbsOffsetX();
        var plotAreaTopY = plotArea.getTopY() + c.getAbsOffsetY();

        // Draw a vertical track line at the x-position
        viewer.drawVLine("trackLine" + i, c.getXCoor(xValue) + c.getAbsOffsetX(), plotAreaTopY,
            plotAreaTopY + plotArea.getHeight(), "black 1px dotted");

        // Display the legend on the top of the plot area
        viewer.showTextBox("legend" + i, plotAreaLeftX + 1, plotAreaTopY + 1, JsChartViewer.TopLeft, legend,
            "padding-left:5px;width:" + (plotArea.getWidth() - 1) + "px;font:11px Arial;");
    }
}
</script>

  Re: ImageMapHandler (python)
Posted by Peter Kwan on Oct-20-2012 00:30
Hi quanghx,

If you cannot use setChartModel, is it possible your "phpchartdir.php" is from ChartDirector 5.0 (or 4.1)?

As your code seems to be based on ChartDirector 5.0.x or 4.1.x, I assume you are upgrading from earlier versions of ChartDirector to 5.1.

ChartDirector for PHP includes all files in the "ChartDirector/lib" subdirectory, which are DLLs and/or shared objects, and also the "phpchartdir.php" PHP include library. To upgrade ChartDirector, you would need to replace the old ChartDirector files with the files from the new ChartDirector version.

In many ChartDirector installations, people may copy the ChartDirector files to different directories. For example, the DLLs and shared objects may be copied to the PHP extension directory, and the "phpchartdir.php" may be copied to the same directory as the script or to some other directories. When the ChartDirector is upgraded, it is easy to forget to upgrade all the files which are copied to various places in the machine. So it is possible the DLLs or shared object are of ChartDirector 5.1, but the PHP script is still loading an older version of "phpchartdir.php". In this case, any new methods (such as setChartModel) will be unavailable.

Would you mind to werify which "phpchartdir.php" your script is using, and check if it is the new "phpchartdir.php" that comes with ChartDirector 5.1?

Regards
Peter Kwan

  Re: ImageMapHandler (python)
Posted by quanghx on Oct-20-2012 03:29
Thank you very much indeed Peter, my problem is resolved. Really appreciate your help

  Re: ImageMapHandler (python)
Posted by quanghx on Oct-20-2012 17:57
I'm sorry that I still have a small question that:

In the tooltip I added more additional information "{dsdiField0}" like following:

{PHP}
$imageMap = $c->getHTMLImageMap("", "",      "title='{dataSetName}, Lender fees*
{value|2}, {x|mmm dd, yyyy}{dsdiField0} '");

Now I want to get in the javascript also, I know the command to get the value of a dataset
is:

{javascript}
value = layer.getDataSet(k).getValue(xIndex)

So...Please tell me how to get {dsdiField0} in javascript also.

  Re: ImageMapHandler (python)
Posted by Peter Kwan on Oct-23-2012 02:39
Hi quanghx,

ChartDirector will not automatically export all possible data to Javascript. This is to reduce the amount of data passed to the browser, so as to improve network performance. In particular, ChartDirector will not export the extra fields (as ChartDirector cannot know if you are using them in Javascript). If you have some additional data you need to access from Javascript, please export them to Javascript with your own code.

For example, support you have an array $abcd that you want to be accessible from Javascript. Please use the following code in Javascript:

var abcd = <?php echo json_encode($abcd) ?>;

Now the Javascript variable abcd will contain the same contents as your PHP $abcd array.

(Note: json_encode requires PHP 5.2.)

Hope this can help.

Regards
Peter Kwan