VCL for PHP チャートコンポーネント - パート6 - チャートの生成

By: Tomohiro Takahashi

Abstract: この記事では、VCL for PHP チャートコンポーネントの作成について解説します。なお、この記事はDelphi for PHPの開発者であるJose Leon氏のブログを再構成したものです。

VCL for PHP チャートコンポーネント - チャートの生成

前回の記事では、ユーザーによるSeriesプロパティのビジュアル編集を可能にするプロパティエディタの記述方法について学びました。この記事では、ダミーのデータを使わずに、Seriesプロパティの内容を使用してチャートを生成しようと思います。

シリーズを繰り返し処理する

記事の最後にgenerateChartメソッドの全ソースコードを掲載しています。以下、順を追って確認していきます。generateChart()の中にはメインループがあり、Seriesプロパティの中のシリーズについて繰り返し処理しています:

        //Iterates through all the series
        $series = $this->_series;
        reset($series);
        while(list($key, $serie) = each($series))
        {
           //This is the main loop
           //all the following code, is inside this loop
        }

$serieにはユーザーがプロパティエディタで入力した全ての値が入っています。

ユーザーによるカスタマイズを可能にする

ユーザーが実行時にあらゆる属性を変更できるように、OnCustomizeという名前のイベントをシリーズに追加しました。ですので、最初に行わなければならないのは、そのイベントを実行することです:

if(!(($this->ControlState & csDesigning) == csDesigning))
{
    if($serie[ 'OnCustomize' ] != '')
    {
        //If we are un run-time and there is an OnCustomize event
        //call it to allow the user to override the specific series
        //parameters
        $event = $serie[ 'OnCustomize' ];
        $serie = $this->owner->$event($this, $serie);
    }
}

まず、デザイナの中でコンポーネントをレンダリングしていないことを確認します。デザイン時には、どのイベントも実行されません。そして、シリーズのOnCustomize属性に値があれば、それを$eventとして取得しそのメソッドを呼び出します。このメソッドは現在のPageのメソッドでなければならず、チャート自身を$senderとして渡します。イベントの$paramsパラメータとして、全ての属性が入った$serieも渡します。イベントの戻り値として新しいシリーズを受け取ることになります。

シリーズの作成

次にOpen Flash ChartのPHP用APIを使用してseriesオブジェクトを生成します:

//Get parameters to use
$width = $serie[ 'Width' ];
$startangle = $serie[ 'StartAngle' ];
$animate = $serie[ 'Animate' ];
$color = $serie[ 'Color' ];
$alpha = $serie[ 'Alpha' ];
$keytext = $serie[ 'KeyText' ];
$hint= $serie[ 'Hint' ];
$keysize = $serie[ 'KeySize' ];
$funfactor = $serie[ 'FunFactor' ];
$dotsize = $serie[ 'DotSize' ];
$outlinecolor = $serie[ 'OutlineColor' ];
$halosize = $serie[ 'HaloSize' ];
$onclick = $serie[ 'OnClick' ];

//Depending on the serie type
switch($serie[ 'Type' ])
{
    case 'ctLine':
        $sobject = new line();
        $sobject->set_width((int)$width);
        $sobject->set_colour($color);
        $sobject->set_key($keytext, $keysize);
        if ($onclick!='') $sobject->set_on_click($onclick);
        break;
    case 'ctLineDot':
        $sobject = new line_dot();
        $sobject->set_halo_size((int)$halosize);
        $sobject->set_width((int)$width);
        $sobject->set_dot_size((int)$dotsize);
        $sobject->set_colour($color);
        $sobject->set_key($keytext, $keysize);
        if ($onclick!='') $sobject->set_on_click($onclick);
        break;
    case 'ctLineHollow':
        $sobject = new line_hollow();
        $sobject->set_halo_size((int)$halosize);
        $sobject->set_width((int)$width);
        $sobject->set_dot_size((int)$dotsize);
        $sobject->set_colour($color);
        $sobject->set_key($keytext, $keysize);
        if ($onclick!='') $sobject->set_on_click($onclick);
        break;
    case 'ctBar':
        $sobject = new bar();
        $sobject->set_alpha($alpha);
        $sobject->set_colour($color);
        $sobject->set_key($keytext, $keysize);
        break;
    case 'ctBarFilled':
        $sobject = new bar_filled();
        $sobject->set_alpha($alpha);
        $sobject->set_colour($color);
        $sobject->set_outline_colour($outlinecolor);
        $sobject->set_key($keytext, $keysize);
        break;
    case 'ctBarGlass':
        $sobject = new bar_glass();
        $sobject->set_alpha($alpha);
        $sobject->set_colour($color);
        $sobject->set_key($keytext, $keysize);
        break;
    case 'ctBar3D':
        $sobject = new bar_3d();
        $sobject->set_alpha($alpha);
        $sobject->set_colour($color);
        $sobject->set_key($keytext, $keysize);
        break;
    case 'ctBarSketch':
        $sobject = new bar_sketch($color, $outlinecolor, $funfactor);
        $sobject->set_alpha($alpha);
        $sobject->set_colour($color);
        $sobject->set_key($keytext, $keysize);
        break;
    case 'ctBarHorizontal':
        $sobject = new hbar($color);
        $sobject->set_colour($color);
        $sobject->set_key($keytext, $keysize);
        break;
    case 'ctBarStacked':
        $sobject = new bar_stack();
        break;
    case 'ctArea':
        $sobject = new area_line();
        $sobject->set_width((int)$width);
        $sobject->set_dot_size((int)$dotsize);
        $sobject->set_halo_size((int)$halosize);
        $sobject->set_colour($outlinecolor);
        $sobject->set_fill_colour($color);
        $sobject->set_fill_alpha($alpha);
        $sobject->set_key($keytext, $keysize);
        break;
    case 'ctAreaHollow':
        $sobject = new area_hollow();
        $sobject->set_width((int)$width);
        $sobject->set_dot_size((int)$dotsize);
        $sobject->set_halo_size((int)$halosize);
        $sobject->set_colour($outlinecolor);
        $sobject->set_fill_colour($color);
        $sobject->set_fill_alpha($alpha);
        $sobject->set_key($keytext, $keysize);
        break;
    case 'ctPie':
        $sobject = new pie();
        //On the designer, set animate always to false, as that will
        //prevent the designer to draw the chart properly
        if(($this->ControlState & csDesigning) == csDesigning) $sobject->set_animate(false);
        else
        {
            if($animate == 'false') $sobject->set_animate(false);
            else $sobject->set_animate(true);
        }
        $sobject->set_start_angle((int)$startangle);
        break;
    default:
        throw new Exception('Graph type ['.$serie[ 'Type' ].'] not supported');
}

このswitchはgenerateChartメソッドの中核となる部分で、ユーザーが作成したいタイプのシリーズに応じてserieオブジェクトを生成しています。さらに、シリーズのタイプに応じて、様々な属性を設定しています。

注目すべき点がいくつかあります

if ($onclick!='') $sobject->set_on_click($onclick);

シリーズの中にはJavascriptのクリックイベントをサポートしているものがあり、もしそのイベントがプロパティエディタで生成されていたら、それをシリーズに結びつけます。これで呼び出されるようになります。

        case 'ctPie':
        $sobject = new pie();
        //On the designer, set animate always to false, as that will
        //prevent the designer to draw the chart properly
        if(($this->ControlState & csDesigning) == csDesigning) $sobject->set_animate(false);
        else
        {
            if($animate == 'false') $sobject->set_animate(false);
            else $sobject->set_animate(true);
        }
        $sobject->set_start_angle((int)$startangle);
        break;

パイチャートはアニメーションをサポートしており、パイが表示された時に小さなアニメーションを実行します。これはデザイン時にIDE上で表示された場合に問題を引き起こすので、パイチャートでは常にanimateをfalseに設定しています。

全てのコード

これでgenerateChartメソッドがSeriesプロパティをレンダリングする準備が整いました。以下がその全コードです:

function generateChart()
{
    //Includes the open flash chart library
    use_unit('openchart/php-ofc-library/open-flash-chart.php');

    //Creates the title
    $title = new title($this->Title);

    //Creates the chart
    $chart = new open_flash_chart();
    $chart->set_title($title);

    //Iterates through all the series
    $series = $this->_series;
    reset($series);
    while(list($key, $serie) = each($series))
    {
        if(!(($this->ControlState & csDesigning) == csDesigning))
        {
            if($serie[ 'OnCustomize' ] != '')
            {
                //If we are un run-time and there is an OnCustomize event
                //call it to allow the user to override the specific series
                //parameters
                $event = $serie[ 'OnCustomize' ];
                $serie = $this->owner->$event($this, $serie);
            }
        }

        //Get parameters to use
        $width = $serie[ 'Width' ];
        $startangle = $serie[ 'StartAngle' ];
        $animate = $serie[ 'Animate' ];
        $color = $serie[ 'Color' ];
        $alpha = $serie[ 'Alpha' ];
        $keytext = $serie[ 'KeyText' ];
        $hint= $serie[ 'Hint' ];
        $keysize = $serie[ 'KeySize' ];
        $funfactor = $serie[ 'FunFactor' ];
        $dotsize = $serie[ 'DotSize' ];
        $outlinecolor = $serie[ 'OutlineColor' ];
        $halosize = $serie[ 'HaloSize' ];
        $onclick = $serie[ 'OnClick' ];

        //Depending on the serie type
        switch($serie[ 'Type' ])
        {
            case 'ctLine':
                $sobject = new line();
                $sobject->set_width((int)$width);
                $sobject->set_colour($color);
                $sobject->set_key($keytext, $keysize);
                if ($onclick!='') $sobject->set_on_click($onclick);
                break;
            case 'ctLineDot':
                $sobject = new line_dot();
                $sobject->set_halo_size((int)$halosize);
                $sobject->set_width((int)$width);
                $sobject->set_dot_size((int)$dotsize);
                $sobject->set_colour($color);
                $sobject->set_key($keytext, $keysize);
                if ($onclick!='') $sobject->set_on_click($onclick);
                break;
            case 'ctLineHollow':
                $sobject = new line_hollow();
                $sobject->set_halo_size((int)$halosize);
                $sobject->set_width((int)$width);
                $sobject->set_dot_size((int)$dotsize);
                $sobject->set_colour($color);
                $sobject->set_key($keytext, $keysize);
                if ($onclick!='') $sobject->set_on_click($onclick);
                break;
            case 'ctBar':
                $sobject = new bar();
                $sobject->set_alpha($alpha);
                $sobject->set_colour($color);
                $sobject->set_key($keytext, $keysize);
                break;
            case 'ctBarFilled':
                $sobject = new bar_filled();
                $sobject->set_alpha($alpha);
                $sobject->set_colour($color);
                $sobject->set_outline_colour($outlinecolor);
                $sobject->set_key($keytext, $keysize);
                break;
            case 'ctBarGlass':
                $sobject = new bar_glass();
                $sobject->set_alpha($alpha);
                $sobject->set_colour($color);
                $sobject->set_key($keytext, $keysize);
                break;
            case 'ctBar3D':
                $sobject = new bar_3d();
                $sobject->set_alpha($alpha);
                $sobject->set_colour($color);
                $sobject->set_key($keytext, $keysize);
                break;
            case 'ctBarSketch':
                $sobject = new bar_sketch($color, $outlinecolor, $funfactor);
                $sobject->set_alpha($alpha);
                $sobject->set_colour($color);
                $sobject->set_key($keytext, $keysize);
                break;
            case 'ctBarHorizontal':
                $sobject = new hbar($color);
                $sobject->set_colour($color);
                $sobject->set_key($keytext, $keysize);
                break;
            case 'ctBarStacked':
                $sobject = new bar_stack();
                break;
            case 'ctArea':
                $sobject = new area_line();
                $sobject->set_width((int)$width);
                $sobject->set_dot_size((int)$dotsize);
                $sobject->set_halo_size((int)$halosize);
                $sobject->set_colour($outlinecolor);
                $sobject->set_fill_colour($color);
                $sobject->set_fill_alpha($alpha);
                $sobject->set_key($keytext, $keysize);
                break;
            case 'ctAreaHollow':
                $sobject = new area_hollow();
                $sobject->set_width((int)$width);
                $sobject->set_dot_size((int)$dotsize);
                $sobject->set_halo_size((int)$halosize);
                $sobject->set_colour($outlinecolor);
                $sobject->set_fill_colour($color);
                $sobject->set_fill_alpha($alpha);
                $sobject->set_key($keytext, $keysize);
                break;
            case 'ctPie':
                $sobject = new pie();
                //On the designer, set animate always to false, as that will
                //prevent the designer to draw the chart properly
                if(($this->ControlState & csDesigning) == csDesigning) $sobject->set_animate(false);
                else
                {
                    if($animate == 'false') $sobject->set_animate(false);
                    else $sobject->set_animate(true);
                }
                $sobject->set_start_angle((int)$startangle);
                break;
            default:
                throw new Exception('Graph type ['.$serie[ 'Type' ].'] not supported');
        }

        $min = 0;
        $max = 10;
        $values = array();
        for($i = 1; $i <= 10; $i++) $values[ ] = rand($min, $max);
        $sobject->set_values($values);
        //Add the serie to the chart
        $chart->add_element($sobject);
    }

    if($this->_backgroundcolor != "") $chart->set_bg_colour($this->_backgroundcolor);

    //Get the json code
    $chartoutput = $chart->toPrettyString();

    if(($this->ControlState & csDesigning) == csDesigning)
    {
        //In design time, we need to store that information on a file
        //and feed the chart with that file
        $url = getScriptFilename();
        $dir = dirname($url);
        $tempfile = $dir.'\chart.json';
        file_put_contents($tempfile, $chartoutput);
    }
    else
    {
        //On run time, just dump it to the output
        echo $chartoutput;
    }
}

Server Response from: ETNASC04