Source for file Functions.php
Documentation is available at Functions.php
* Description: Basic abstract function class.
* Examples of derived functions are: Add, Subtract, High, Low, Average and
* @copyright (c) 1995-2010 by Steema Software SL. All Rights Reserved. <info@steema.com>
* @link http://www.steema.com
function __get( $property ) {
$method = "get{$property}";
function __set ( $property,$value ) {
$method = "set{$property}";
return $this->$method($value);
private function initFields() {
$this->periodAlign = PeriodAlign::$CENTER;
public function newInstance($f) /* tODO throw IllegalAccessException,
InstantiationException*/ {
return $f->newInstance();
* Controls how many points or X range will trigger a new point
* Zero means all source points.<br>
* For example, Average function uses the Period property to calculate a
* new average point each time the "Period" number of points or X range is
* <b>NOTE:</b> You may switch between number of points or X range by using
* the Function PeriodStyle property. <br>
/** @todo ELIMINATE EXCEPTION HERE ! */
// throw new TeeChartException(Language.getString("FunctionPeriod"));
* Returns the Series parent of Function.<br>
* Run-time and read only. <br>
* The Series property returns the Series parent of this Function.<br>
* TChart uses Series to do the actual drawing.
if ($this->series != $value) {
$this->series->setFunction(null);
$value->setFunction($this);
* Controls how the Period property is interpreted.<br>
* Either as number of points or as range.<br>
* Range means Period property is specified in a range of values. <br>
* Being able to define Period as a range can be very useful when using
* Date-Time series and when you want to express the Period of the
* function in a date-time step like OneMonth or OneDay.<br>
* So, for example you can now plot the monthly average of sales function
* just using a normal Average function on a date-time source series and
* setting the function period to one month :<br>
* { Place a series1 and fill it with datetime data values at runtime
* (or from a database) } <br>
* series2.setFunction( new Average() ); <br>
* series2.getFunction().setPeriodStyle( Range); series2.getFunction().setPeriod(
* DateTimeStep[ dtOneMonth ]); series2.setDataSource(series1);<br><br>
* This will result in several points, each one showing the average of
* each month of data in Series1. <br>
* It's mandatory that points in the source Series1 should be sorted by
* date when calculating functions on datetime periods. <br><br>
* The range can also be used for non-datetime series: <br><br>
* series2.setFunction( new Average() ) ; <br>
* series2.getFunction().setPeriodStyle(Range); <br>
* series2.getFunction().setPeriod(100); <br>
* series2.setDataSource(series1) ; <br>>br>
* This will calculate an average for each group of points inside every
* (Points with X >=0, X<100 will be used to calculate the first average,
* points with X >=100, X<200 will be used to calculate the second average
* Notice this is different than calculating an average for every 100
* Default value: PeriodStyle.NumPoints
return $this->periodStyle;
if ($this->periodStyle != $value) {
$this->periodStyle = $value;
* Controls where to place function calculations inside the full period
* The position of calculation output points within range.<br>
* When the function Period is greater than zero (so it calculates by
* groups of points), the function results are added to the series by
* default at the center position of the Function Period. You can change
* this by setting PeriodAlign to <br><br>
* - First (function result will be added to series at start of each
* - Center (function result will be added to series at center of each
* - Last (function result will be added to series at end of each period)
* <code>function1.setPeriodAlign(Center);
* // <-- by default is centered</code> <br>
* The First and Last constants will plot calculations at the start and
* end X coordinates of each Period .<br>
* Default value: PeriodAlign.Centre
return $this->periodAlign;
if ($this->periodAlign != $value) {
$this->periodAlign = $value;
protected function addFunctionXY($yMandatorySource, $tmpX, $tmpY) {
$this->series->addXY($tmpX, $tmpY);
$this->series->addXY($tmpY, $tmpX);
// MS : added to allow overrides in curve fitting functions
protected function calculatePeriod($source, $tmpX, $firstIndex, $lastIndex) {
$this->calculate($source, $firstIndex, $lastIndex));
* Performs function operation on SourceSeries series.<br>
* First and Last parameters are ValueIndex of first and last point used
* You can override Calculate function to perform customized calculation
public function calculate($source, $first, $last) {
* Performs function operation on list of series (SourceSeriesList).<br>
* The ValueIndex parameter defines ValueIndex of point in each Series in
* You can override CalculateMany function to perform customized
* calculation on list of SourceSeries.
* @param sourceSeries ArrayList
// MS : added to allow overrides in curve fitting functions
if (!$this->series->getAllowSinglePoint()) {
$tmpX = $notMandatorySource->getMinimum();
$tmpX = $notMandatorySource->getMaximum();
if ((!$source->getYMandatory()) && $this->series->getYMandatory()) {
$tmpX = $notMandatorySource->getMinimum() +
0.5 * $notMandatorySource->getRange();
$this->series->addXY($tmpX, $tmpY);
$tmpX = $notMandatorySource->getMinimum() +
0.5 * $notMandatorySource->getRange();
if ($this->series->getYMandatory()) {
$this->series->addXY($tmpY, $tmpX);
$tmpCount = $source->getCount();
$tmpBreakPeriod = $notMandatorySource->value[$tmpFirst];
$tmpLast = $tmpFirst + MathUtils::round($this->dPeriod) - 1;
$posFirst = $notMandatorySource->value[$tmpFirst];
if ($tmpLast < $tmpCount) {
$posLast = $notMandatorySource->value[$tmpLast];
$posFirst = $tmpBreakPeriod;
// tmpBreakPeriod = series.horizAxis().IncDecDateTime(true,
// tmpBreakPeriod, dPeriod, tmpStep);
$posLast = $tmpBreakPeriod - ($this->dPeriod * 0.001);
while ($tmpLast < $tmpCount - 1) {
if ($notMandatorySource->value[$tmpLast + 1] < $tmpBreakPeriod) {
if ($tmpLast < $tmpCount) {
$tmpX = ($posFirst + $posLast) * 0.5;
if (($this->periodStyle == PeriodStyle::$RANGE) &&
($this->notMandatorySource->value[$tmpFirst] < $tmpBreakPeriod)) {
if (($this->periodStyle == PeriodStyle::$NUMPOINTS) || $tmpCalc) {
if (($this->periodStyle == PeriodStyle::$NUMPOINTS) || $tmpCalc) {
$tmpFirst = $tmpLast + 1;
} while ($tmpFirst <= $tmpCount - 1);
return Language::getString("GalleryFunctions");
$tmp = ($this->series != null) ? $this->series->getMandatory()->getDataMember() : "";
return $s->getMandatory();
return $s->getValueList($tmp);
private function calculateFunctionMany($source) {
$xList = $s->getNotMandatory();
// Find datasource with bigger number of points... 5.02
for ( $t = 0; $t < sizeof($source); $t++ ) {
if (($o != null) && ($o->getCount() > $s->getCount())) {
$xList = $s->getNotMandatory();
// use source to calculate points...
for ( $tt = 0; $tt < sizeof($source); $tt++ ) {
for ( $tt = 0; $tt < $s->getCount(); $tt++ ) {
$tmpX = $xList->value[$tt];
if (!$s->getYMandatory()) { // $this->swap
$this->series->addXYText($tmpX, $tmpY, $s->getLabels($tt));
* Gets all points from Source series, performs a function operation and
* stores results in ParentSeries.<br>
* @param source ArrayList
$this->calculateFunctionMany($source);
if ($s->getCount() > 0) {
private function beginUpdate() {
private function endUpdate() {
* Performs a checkDataSource method call on parent Series.<br>
* Basically, all points in parent Series are recalculated.<br>
* The recalculating is performed only if internal updating flag is set to
* To make sure updating is set to false, you can call Function
* endUpdate() method prior to calling Function recalculate.
$this->series->checkDataSource();
/** Does nothing, used only by Bollinger and Stochastic **/
|