Page 1 of 1

Further problems with Teechart for PHP source code

Posted: Fri Mar 06, 2009 5:13 am
by 15952693
Unfortunately the Steems supplied source code still has bugs. In this case I have created a small test harness which is operative here

http://www.softwaremage.co.nz/charttest/charttest.php

and the source code is downloadable here so that you can use it to test your fixes.

http://www.softwaremage.co.nz/files/ste ... t_test.zip

It took a long time to understand why adding a second bar to a series collection failed becuase it does not, at least in Delphi for PHP, generate an exception. But the bug seems to be buried in a low level graphic routine:

Chartbrush::setColor and also Chartbrush::setForegroundColor
public function setColor($value) {
$this->color = $this->setColorProperty($this->color, $value);
}

setColorProperty is a method of the ancestor class and presumably that is what you want to call.

If you take a look at the demonstration URL I have been able to implement the multibar chart as in the Teechart demo using fillSampleValues which is all well and good.

However, assuming my code is correct it does not seem possible to programmatically add series when other methods are used to populate the chart.

The second chart involves the rendering of a single series barchart. In this case the chart renders the Series Labels even if we call the clear() method to get rid of them. Your suggestion of a couple of days ago of using setVisible(False) does not work either because that method is not implemented on Series Labels. Note too that the series label text is in fact appearing on the Axis labels. Somewhere in the many wrappers for inserting chart values these values must be getting reversed somewhere.

Also the left axis is defective in that the numbering sequence doesnt relate to any other chart artifact.

Because we want to review this product over the weekend and post it for the benefit of the Delphi for PHP community we will be relying upon the version that you supply after fixing this further bug.

But I would appreciate it if you could also use the test harness to test the chart making functionality is working or provide a revised test harness which works with your code to deliver what we want.

Cheers,
Steve Cooney.

Posted: Tue Mar 10, 2009 11:45 am
by Pep
Hi Steve,
It took a long time to understand why adding a second bar to a series collection failed becuase it does not, at least in Delphi for PHP, generate an exception. But the bug seems to be buried in a low level graphic routine:

Chartbrush::setColor and also Chartbrush::setForegroundColor
public function setColor($value) {
$this->color = $this->setColorProperty($this->color, $value);
}

setColorProperty is a method of the ancestor class and presumably that is what you want to call.

If you take a look at the demonstration URL I have been able to implement the multibar chart as in the Teechart demo using fillSampleValues which is all well and good.

However, assuming my code is correct it does not seem possible to programmatically add series when other methods are used to populate the chart.
I'm not sure what you mean here, how can I reproduce the problem here ?
The second chart involves the rendering of a single series barchart. In this case the chart renders the Series Labels even if we call the clear() method to get rid of them. Your suggestion of a couple of days ago of using setVisible(False) does not work either because that method is not implemented on Series Labels.
Maybe I misunderstood your problem. In the case you want to hide the Series Marks you should use the SerVisible method which exist into the TeeShape.php unit (which is the ancestor of SeriesMarks.php). The code to hide would be :

Code: Select all

           // Clear out any Marks
           $barseries->getMarks()->setVisible(false);[/
Note too that the series label text is in fact appearing on the Axis labels. Somewhere in the many wrappers for inserting chart values these values must be getting reversed somewhere.
Yes, by default, if Series Marks are assigned into the Add method these are used for the labels of the mandatory Axis.

To change the axis label style the following code could be used :

Code: Select all

  // by default AxisLabelStyle::$AUTO            
$teechart->getAxes()->getBottom()->getLabels()->setStyle(AxisLabelStyle::$VALUE); 
The same way should be used to change the Legend Text style.

The Clear() method can be used for axis labels items, in the case you want to use custom axis labels instead of automatic, or just to add extra labels, similar code to the following will do it :

Code: Select all

       // To draw custom labels on the axis :
        $teechart->getChart()->getAxes()->getBottom()->getLabels()->setStyle(AxisLabelStyle::$TEXT);
        $teechart->getChart()->getAxes()->getBottom()->getLabels()->getItems()->clear();
        $teechart->getChart()->getAxes()->getBottom()->getLabels()->getItems()->add(0,"mylabel");
Also the left axis is defective in that the numbering sequence doesnt relate to any other chart artifact.
Yes, the problem was that decimal numbers was not well displayed, now it has been fixed.
Axis minimum increment can be also modified to desired value by using :

Code: Select all

$teechart->getAxes()->getLeft()->setIncrement(0.2);
But I would appreciate it if you could also use the test harness to test the chart making functionality is working or provide a revised test harness which works with your code to deliver what we want.
Sure. I've been doing some tests with your demo and the latest sources I've just posted on our web site and all seems to work fine. Could you please check if it works fine for you?
I've also added the support for bold font (a default bold font is used if bold is set to true), but you can always set a specific font (bold or not) by using :

Code: Select all

$teechart->getFont()->setName($baseDir . "fonts/DejaVuSansCondensed.ttf");
I've sent directly to your mail the sample you sent to me with few modifications.

Posted: Wed Mar 11, 2009 7:38 pm
by 15952693
Thanks for your reply and the files sent separately. Unfortunately the latest version of the source code is still unable to create multi series charts. Indeed in the sample charts you sent there was no actual example of a successfully generated chart using multiple bar charts so we wonder if you were able to succeed yourself.

However I have persevered debugging your source code and now have it working for the simple charts I currently require. In order to get to this point I have had to make further changes to the source code.

In the Series collection there is a bug which appears to create a case of infinite recursion, which was manifested by an an inability to add multiple series and execution timeouts irrespective of how long the code ran for.

In the series collection class there is a method which gets called repeatedly when a series is added.

public function clear($dispose=true) {

while (sizeof($this) > 0) {
$tmp = $this->getSeries(0);
$this->remove($tmp);

// $tmp->onDisposing();
// if ($dispose) {
// $tmp->dispose();
// }
}

I have had to moddify this so that it iterates through all members of the series collection rather than the zeroth member.

public function clear($dispose=true) {

$seriescount = sizeof($this);

for ($i=0;$i<$seriescount;$i++)
{

$tmp = $this->getSeries($i);
$this->remove($tmp);
}
}

This now allows the method to proceed.

In AxisDraw we had to add a check for a variable being set

private function calcFirstLastAllSeries($rect) {
$tmp = new IntRange(intval('1000000000000'), -1); // MAX_VALUE

for ( $t = 0; $t < sizeof($this->axis->iSeriesList); $t++) {
$s = $this->axis->iSeriesList->getSeries($t);

$s->calcFirstLastVisibleIndex();

if (($s->getFirstVisible() < $tmp->first) &&
($s->getFirstVisible() != -1)) {
$tmp->first = $s->getFirstVisible();
}

if ($s->getLastVisible() > $tmp->last) {
$tmp->last = $s->getLastVisible();
}
}


return $tmp;
}


i.e

private function calcFirstLastAllSeries($rect) {
$tmp = new IntRange(intval('1000000000000'), -1); // MAX_VALUE

for ( $t = 0; $t < sizeof($this->axis->iSeriesList); $t++) {
$s = $this->axis->iSeriesList->getSeries($t);
//
if (isset($s))
{
$s->calcFirstLastVisibleIndex();

if (($s->getFirstVisible() < $tmp->first) &&
($s->getFirstVisible() != -1)) {
$tmp->first = $s->getFirstVisible();
}

if ($s->getLastVisible() > $tmp->last) {
$tmp->last = $s->getLastVisible();
}
}
}

return $tmp;
}

Otherwise PHP raises an error

php[5772]
PHP Fatal error: Call to a member function calcFirstLastVisibleIndex() on a non-object in C:\Program Files\CodeGear\Delphi for PHP\2.0\vcl\teechart\axis\AxisDraw.php on line 387

Then we had to modify AxisLabelsItems:;repaint and apply a similar check:

public function repaint()
{
if (isset($this->iAxisLabelsItems->iAxis->chart))
{
$this->iAxisLabelsItems->iAxis->chart->invalidate();
}
}

to deal with another PHP error:

php[7508]
PHP Fatal error: Call to a member function invalidate() on a non-object in C:\Program Files\CodeGear\Delphi for PHP\2.0\vcl\teechart\axis\AxisLabelItem.php on line 47

Finally I had to modify AxisLabelItems::clear

public function clear() {
// TODO remove parent::clear();
unset($this);
$this->iAxis->chart->invalidate();
}

to remove the call to invalidate after $this has been destroyed in the prior line of code. Otherwise again PHP complains and obviously aborts processing.

That removed we have been able to, finally, make the test harness work.

Posted: Fri Mar 13, 2009 2:48 pm
by Pep
Hi Steve,

first of all, thanks for all of your suggestions and advises.
In the Series collection there is a bug which appears to create a case of infinite recursion, which was manifested by an an inability to add multiple series and execution timeouts irrespective of how long the code ran for.

In the series collection class there is a method which gets called repeatedly when a series is added.
Yes, you're correct. Finally I've modified the code you sent to me due to other problems. Here the latest version :

Code: Select all

    public function remove($s) {
        $i = $this->indexOf($s);

        if ($i > -1) {
            parent::offsetUnset($i);

            $tmpArray=Array();
            foreach($this as $item)
            {
                $tmpArray[]=$item;
            }

            $this->clear();
            for ($i=0;$i<sizeof($tmpArray);$i++)
            {
               $this[$i]=$tmpArray[$i];
            }
        }
    }

    public function clear($dispose=true) {
        foreach($this as $key=>$item)
        {
            parent::offsetUnset($key);
        }
    }
In AxisDraw we had to add a check for a variable being set

i.e
private function calcFirstLastAllSeries($rect) {
$tmp = new IntRange(intval('1000000000000'), -1); // MAX_VALUE

for ( $t = 0; $t < sizeof($this->axis->iSeriesList); $t++) {
$s = $this->axis->iSeriesList->getSeries($t);
//
if (isset($s))
{
$s->calcFirstLastVisibleIndex();

if (($s->getFirstVisible() < $tmp->first) &&
($s->getFirstVisible() != -1)) {
$tmp->first = $s->getFirstVisible();
}

if ($s->getLastVisible() > $tmp->last) {
$tmp->last = $s->getLastVisible();
}
}
}

return $tmp;
}
Ok, I've added this check into the sources.
php[5772]
PHP Fatal error: Call to a member function calcFirstLastVisibleIndex() on a non-object in C:\Program Files\CodeGear\Delphi for PHP\2.0\vcl\teechart\axis\AxisDraw.php on line 387

Then we had to modify AxisLabelsItems:;repaint and apply a similar check:

public function repaint()
{
if (isset($this->iAxisLabelsItems->iAxis->chart))
{
$this->iAxisLabelsItems->iAxis->chart->invalidate();
}
}
I've added this check into the sources.
php[7508]
PHP Fatal error: Call to a member function invalidate() on a non-object in C:\Program Files\CodeGear\Delphi for PHP\2.0\vcl\teechart\axis\AxisLabelItem.php on line 47
Finally I had to modify AxisLabelItems::clear

public function clear() {
unset($this);
$this->iAxis->chart->invalidate();
}

to remove the call to invalidate after $this has been destroyed in the prior line of code. Otherwise again PHP complains and obviously aborts processing.

That removed we have been able to, finally, make the test harness work.
I've tried using the following code :

Code: Select all

$chart->getChart()->getAxes()->getBottom()->getLabels()->getItems()->clear();
$chart->getChart()->getAxes()->getBottom()->getLabels()->setStyle(AxisLabelStyle::$TEXT);
$chart->getChart()->getAxes()->getBottom()->getLabels()->getItems()->add(0,"mylabel");
and worked fine leaving the method as is :

Code: Select all

public function clear() {
unset($this);
$this->iAxis->chart->invalidate();
}
I've updated the sources on our web site, in case you want to download the latest version.