Chartコントロールの3Dについて

Category: visual studio general_ja

Question

しん11111111 on Wed, 15 Jun 2016 16:09:18


System.Windows.Forms.DataVisualization.ChartingのチャートコントロールでArea3DStyleを有効にすることで3D表示はできますが、以下の設定は可能でしょうか。

・Z軸方向の目盛りを表示

・Z軸方向のラベルを表示

Replies

gekka on Wed, 15 Jun 2016 18:20:10


自前で描画してみる

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        System.Windows.Forms.DataVisualization.Charting.Chart chart;

        public Form1()
        {
            //InitializeComponent();
            this.Width=600;
            this.Height=600;

            TrackBar track = new TrackBar();
            track.Dock = DockStyle.Bottom;
            track.Minimum = 0;
            track.Maximum = 180;
            this.Controls.Add(track);

            ChartArea area = new ChartArea();
           
            var style = area.Area3DStyle;
            style.Enable3D = true;
            style.IsRightAngleAxes = true;
            style.Perspective = 20;
            style.Rotation = 60;

            chart = new Chart();
            chart.ChartAreas.Add(area);
            
            Random rnd = new Random();
            for (int i = 0; i < 5; i++)
            {
                var seri = new System.Windows.Forms.DataVisualization.Charting.Series();
                seri.ChartType = SeriesChartType.Spline;
                chart.Series.Add(seri);

                for (int x = 1; x <= 5; x++)
                {
                    seri.Points.AddXY(x, rnd.Next(1000));
                }
            }

            area.Position = new ElementPosition(0f, 0f, 100f, 90f);
            chart.Dock = DockStyle.Fill;
            this.Controls.Add(chart);

            track.Value = style.Rotation;

            chart.PostPaint += chart_PostPaint;
            track.ValueChanged += (s,e)=>
            {
                this.chart.ChartAreas[0].Area3DStyle.Rotation = ((TrackBar)s).Value;
            };

        }

        private void chart_PostPaint(object sender, System.Windows.Forms.DataVisualization.Charting.ChartPaintEventArgs e)
        {
            if (e.ChartElement is ChartArea)
            {
                var area = e.Chart.ChartAreas[0];
                var boldPen= new Pen(Brushes.Black, 5);
                foreach (var seri in e.Chart.Series)
                {
                    float xMin = (float)area.AxisX.ValueToPosition(area.AxisX.Minimum);
                    float xMax = (float)area.AxisX.ValueToPosition(area.AxisX.Maximum);
                    float y = (float)area.AxisY.ValueToPosition(area.AxisY.Crossing);
                    float z = area.GetSeriesZPosition(seri);
                    Point3D[] ps = 
                    {
                        new Point3D()
                        {
                            X = xMin, //X軸の最小位置 // 0~100
                            Y = y,// 0~100
                            Z = z
                        },
                        new Point3D()
                        {
                            X = xMax, //X軸の最大位置 // 0~100
                            Y = y,// 0~100
                            Z = z
                        },
                         new Point3D()
                        {
                            X = 100,//X軸の最大の外になるように // 0~100
                            Y = y,// 0~100
                            Z = z
                        }
                    };

                    //3次元座標をプロット用座標に変換する
                    area.TransformPoints(ps);

                    //プロット用座標をグラフィック座標に
                    PointF pMin = new PointF(ps[0].PointF.X / 100f * chart.Width, ps[0].PointF.Y / 100f * chart.Height);
                    PointF pMax = new PointF(ps[1].PointF.X / 100f * chart.Width, ps[1].PointF.Y / 100f * chart.Height);
                    PointF p100 = new PointF(ps[2].PointF.X / 100f * chart.Width, ps[2].PointF.Y / 100f * chart.Height);

                    //とりあえず線を引とシリーズ名を描画してみる
                    e.ChartGraphics.Graphics.DrawLine(Pens.Green, pMin, pMax);
                    e.ChartGraphics.Graphics.DrawLine(boldPen, pMax, p100);
                    e.ChartGraphics.Graphics.DrawString(seri.Name, this.Font, Brushes.Red, p100);
                }
            }
        }
    }
}


個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

SurferOnWww on Thu, 16 Jun 2016 03:33:35


直接の回答ではないですが・・・

Chart のサンプルは持っているでしょうか?

持っているなら以下はスルーしてください。

持っていなければ MSDN のサイトからサンプルを入手できるので、ダウンロードして動くように設定することをお勧めします。

解説が英語であるのを厭わなければこのサンプルは今後の開発に非常に有益なものになると思います。

このスレッドの質問者さんの問題がサンプルを見ると解決するかどうかは分かりませんが、解決のためのヒントはあるかもしれません。

解決できなくとも、今後の開発に役立つはずですので、ダウンロードして設定する手間をかけても損はないと思います。

サンプルの入手先や設定手順は以下の記事にありますので、興味があれば見てください。

Chart Samples
http://surferonwww.info/BlogEngine/post/2016/02/14/chart-samples.aspx

しん11111111 on Thu, 16 Jun 2016 14:14:39


ご回答ありがとうございます。

上記のサンプルで描画できることがわかりました。

Z軸方向の目盛りについて、X軸側には描画できておりますがY軸方向にも可能でしょうか?

また、Area3DStyle.Rotation、Area3DStyle.Inclinationを変更した場合、Z軸の目盛りがはみ出してしましたが、再計算などが必要なのでしょうか。

サンプルに対するご質問で恐縮ですが、よろしくお願いいたします。

しん11111111 on Thu, 16 Jun 2016 14:17:18


Webの情報などを頼りに作成しておりましたが、サンプルは持っておりませんでした。

上記のサンプルを活用させて頂きます。

gekka on Thu, 16 Jun 2016 15:09:18


3次元座標を2次元に投影して、投影された点間に直線を引いているだけという事を理解してみましょう

float xMin = (float)area.AxisX.ValueToPosition(area.AxisX.ScaleView.ViewMinimum);
float xMax = (float)area.AxisX.ValueToPosition(area.AxisX.ScaleView.ViewMaximum);
float y = (float)area.AxisY.ValueToPosition(area.AxisY.Crossing);

float z = area.GetSeriesZPosition(seri);

float yMin = (float)area.AxisY.ValueToPosition(area.AxisY.ScaleView.ViewMinimum);
float yMax = (float)area.AxisY.ValueToPosition(area.AxisY.ScaleView.ViewMaximum);
float x = (float)area.AxisX.ValueToPosition(area.AxisX.Crossing);

Point3D[][] pss =
{ 
    new Point3D[]
    {
        new Point3D()
        {
            X = x, //X軸の最小位置 // 0~100
            Y = yMin,// 0~100
            Z = z
        },
        new Point3D()
        {
            X = x, //X軸の最大位置 // 0~100
            Y = yMax,// 0~100
            Z = z
        },
            new Point3D()
        {
            X = x,//X軸の最大の外になるように // 0~100
            Y = 0,// 0~100
            Z = z
        }
    },


    new Point3D[]
    {
        new Point3D()
        {
            X = xMin, //X軸の最小位置 // 0~100
            Y = y,// 0~100
            Z = z
        },
        new Point3D()
        {
            X = xMax, //X軸の最大位置 // 0~100
            Y = y,// 0~100
            Z = z
        },
            new Point3D()
        {
            X = xMax,//X軸の最大の外になるように // 0~100
            Y = y,// 0~100
            Z = z
        }
    }
};

for (int i = 0; i < 2; i++)
{
    //3次元座標をプロット用座標に変換する
    area.TransformPoints(pss[i]);

    //プロット用座標をグラフィック座標に
    PointF pMin = new PointF(pss[i][0].PointF.X / 100f * chart.Width, pss[i][0].PointF.Y / 100f * chart.Height);
    PointF pMax = new PointF(pss[i][1].PointF.X / 100f * chart.Width, pss[i][1].PointF.Y / 100f * chart.Height);
    PointF p100 = new PointF(pss[i][2].PointF.X / 100f * chart.Width, pss[i][2].PointF.Y / 100f * chart.Height);

    //とりあえず線を引とシリーズ名を描画してみる
    e.ChartGraphics.Graphics.DrawLine(Pens.Green, pMin, pMax);
    //e.ChartGraphics.Graphics.DrawLine(boldPen, pMax, p100);
    e.ChartGraphics.Graphics.DrawString(seri.Name, this.Font, Brushes.Red, p100);
}

はみ出したがどのような意味でおっしゃっているのか判らないのですがが、見切れてしまうという意味なのであればarea.Position = new ElementPosition(0f, 0f, 80f, 80f);のようにChartAreaの配置を調整すればいいです。

しん11111111 on Sat, 18 Jun 2016 15:56:59


求めていた結果が得られました。

ご回答ありがとうございます。