インフラジスティックス・ジャパン株式会社のBlog

インフラジスティックス・ジャパン株式会社のチームメンバーが技術トレンド、製品Tips、サポート情報からライセンス、日々の業務から感じることなど、さまざまなトピックについてお伝えするBlogです。

UltraChart: FillSceneGraphを使いこなそう!

UltraChartでは、単純な配列やDataTable、独自に定義したクラスなど様々な形のデータをバインドすることができ、バインドしたデータを様々なチャートタイプで表現することができます。

基本的には、データバインド、チャートタイプの選択、選択されたチャートタイプ毎の細かい設定(マーカーの種類やツールチップの表示やメモリのインターバルなど)を行う事で要件を満たすことができると思いますが、これらの基本機能では実現できない表示を行いたい場合に FillSceneGraph イベントを活用して独自にUIエレメントを描画します。FillSceneGraphイベントはグラフを描画する際に起こるイベントで、描画するUI Elementを追加したり変更したりすることができます。

今回は以下の図に、FillSceneGraph を使用して上限値と下限値を示すボーダーラインを描画します。

image

ボーダーラインの描画

上の図は、数値型の一次元配列をバインドしたとてもシンプルなラインチャートです。今回は、Y軸の150のラインに上限値の目安となるラインを、-150のラインに下限値の目安となるラインを描画します。

まず、以下のように、FillSceneGraph のイベントハンダラを追加します。

// FillSceneGraphイベントの定義
this.ultraChart1.FillSceneGraph += new Infragistics.UltraChart.Shared.Events.FillSceneGraphEventHandler(ultraChart1_FillSceneGraph);

続いて、以下のように FillSceneGraph イベント内で、追加したいUI Elementをインスタンス化し、SceneGraphオブジェクトに追加します。

// FillSceneGraphイベント(ここで範囲のラインを描画します。)
private void ultraChart1_FillSceneGraph(object sender, Infragistics.UltraChart.Shared.Events.FillSceneGraphEventArgs e)
{
    // 最大値と最小値の範囲設定
    double maxValue = 150.0;
    double minValue = -150.0;
    IAdvanceAxis axisY = e.Grid["Y"] as IAdvanceAxis;
    IAdvanceAxis axisX = e.Grid["X"] as IAdvanceAxis;

    // 最大値のライン設定
    int maxYCoord = (int)axisY.Map(maxValue);
    int xStart = (int)axisX.MapMinimum;
    int xEnd = (int)axisX.MapMaximum;
    Line maxLine = new Line(new Point(xStart, maxYCoord), new Point(xEnd, maxYCoord));
    maxLine.PE.Stroke = Color.Orange;
    maxLine.PE.StrokeWidth = 1;
    e.SceneGraph.Add(maxLine);

    // 最大値のラベル設定
    Text maxLabel = new Text();
    maxLabel.SetTextString("Max: " + maxValue.ToString());
    Size targetLabelSize = Size.Ceiling(Platform.GetLabelSizePixels(maxLabel.GetTextString(), maxLabel.labelStyle));
    maxLabel.bounds = new Rectangle(xStart, maxYCoord - targetLabelSize.Height, targetLabelSize.Width, targetLabelSize.Height);
    e.SceneGraph.Add(maxLabel);

    // 最小値のライン設定
    int minYCoord = (int)axisY.Map(minValue);
    Line minLine = new Line(new Point(xStart, minYCoord), new Point(xEnd, minYCoord));
    minLine.PE.Stroke = Color.Orange;
    minLine.PE.StrokeWidth = 1;
    e.SceneGraph.Add(minLine);

    // 最小値のラベル設定
    Text minLabel = new Text();
    minLabel.SetTextString("Min: " + minValue.ToString());
    targetLabelSize = Size.Ceiling(Platform.GetLabelSizePixels(minLabel.GetTextString(), minLabel.labelStyle));
    minLabel.bounds = new Rectangle(xStart, minYCoord - targetLabelSize.Height, targetLabelSize.Width, targetLabelSize.Height);
    e.SceneGraph.Add(minLabel);

}

上記コード内では、Y軸上で150及び-150にあたる座標と、X軸の始点や終点を計算した後、描画するラインエレメントを上限値用(MaxLine)と下限値用(MinLine)の2つ生成し、SceneGraphオブジェクトに追加しています。また、上限値及び下限値を示すラベルも併せて追加しています。

実行結果

image

FillSceneGraphイベント内で追加したエレメントが描画され、上限値とか下限値のラインを引くことができました。

凡例の追加

折角なので、上記と同じ要領で凡例の中に、オレンジ色のラインが上限値と下限値を示すラインであることがわかるように、凡例のアイテムを(擬似的に)描画してみましょう。

以下のコードをFillSceneGraphイベント内に追加します。

            // 凡例アイテムの最後に独自の凡例アイテムを追加する。 
            List<Primitive> legentP = e.SceneGraph.OfType<Primitive>()
                .Where(pr => pr is Box && pr.Path != null && pr.Path.ToLower().Contains("legend")).ToList<Primitive>();
            if (legentP.Count > 0)
            {
                Box lastLegedBox = (Box)legentP[legentP.Count - 1];
                Rectangle MaxMinRect = lastLegedBox.rect;
                Point loc = lastLegedBox.rect.Location;

                loc.Offset(0, lastLegedBox.rect.Height + 5);
                MaxMinRect.Location = loc;
                Box MaxMin = new Box(MaxMinRect);
                MaxMin.PE = lastLegedBox.PE.Clone();
                MaxMin.PE.Fill = maxLine.PE.Stroke;
                MaxMin.PE.FillStopColor = ChangeColorBrightness(maxLine.PE.Stroke, -0.3f);
                e.SceneGraph.Add(MaxMin);

                Text MaxMinLabel = new Text();
                MaxMinLabel.SetTextString("Max and Min");
                Size MaxMinLabellSize = Size.Ceiling(Platform.GetLabelSizePixels(MaxMinLabel.GetTextString(), MaxMinLabel.labelStyle));
                loc.Offset(MaxMin.rect.Width + 2, 0);
                MaxMinLabel.bounds = new Rectangle(loc, MaxMinLabellSize);
                e.SceneGraph.Add(MaxMinLabel);
            }

コード内でやっていることは、凡例アイテムをどこに追加するかの座標計算とアイテムの追加(BoxエレメントとTextエレメントで構成)です。

実行結果

image

凡例にアイテムが追加されました。シリーズに応じて自動的に追加されるものと比較しても違いがわからないですね。

FillSceneGraphを使用すれば、UI Elementとして表現できるものはなんでも描画できるのです!(座標計算は大変ですが…)

今回のサンプルはこちらから

サンプル

今回ご紹介したUltraChart を含む NetAdvantage は無料でトライアル版が利用できます。

NetAdvantage トライアル版

Windows Formsコントロール - Infragistics Ultimate UI for Windows Forms