3D 차트

차트를 3D로도 출력할 수 있다. 에리어의 Area3DStyle 객체가 3D 출력 관련 기능을 제공하며 다음과 같은 속성을 가진다.

 

속성

설명

Enable3D

3차원 출력 기능을 사용한다. 디폴트 값이 false여서 별다른 지정이 없으면 2D로 출력된다. 이 값을 true로 바꾸어야 3D차트가 나타난다.

Inclination

수평축에서의 회전 각도를 지정한다. 디폴트는 위에서 아래로 내려보는 30도로 되어 있다.

Rotation

수직축에서의 회전 각도이다. 디폴트는 오른쪽에서 왼쪽을 바라보는 30도로 되어 있다. 음수 각도이면 벽이 오른쪽으로 이동한다.

Perspective

원근감을 지정한다. 그리드 선이 평행하지 않고 구석의 소실점을 향하는 형식이 된다.

IsRightAngleAxes

isometric projection 기법을 사용한다. 진짜 3D는 아니지만 특정 깊이에서는 가장 자연스럽다. Perspective와는 배타적이다.

WallWidth

벽의 두께를 지정한다.

PointDepth

데이터 포인트의 깊이를 폭에 대한 비율로 지정한다. 100%이면 막대 그래프 윗면이 정사각형이며 그보다 더 깊으면 안쪽으로 길쭉해진다.

PointGapDepth

데이터 포인트간의 간격을 지정한다. 두 개의 막대 그래프를 앞 뒤로 배치했을 때 이 속성에 따라 막대간의 거리가 달라진다.

IsClustered

, 컬럼 차트가 클러스터 상태인지를 지정한다. 이 값이 true이면 막대를 나란히 배치하고 false이면 앞뒤로 배치한다.

 

속성의 의미를 읽어 봐도 이 값이 차트의 어떤 면에 영향을 미치는지 직관적으로 파악하기 어렵다. 같이 지정할 수 없는 배타적인 속성도 있고 차트 타입에 따라 효과가 약간씩 달라지기도 한다.

이런 복잡한 속성은 글을 읽어 이해하는 것보다는 실제 값을 바꿔 가며 눈으로 효과를 확인해 보는 것이 이해하기 쉽다. 다음 예제는 이런 목적으로 만든 것이며 키보드로 각 속성을 실행중에 조정해 본다. 소스를 보면 각 키가 어떤 값을 조정하는지, 값의 범위는 어떤지, 디폴트는 무엇인지 알 수 있다.

 

private void Form1_Load(object sender, EventArgs e)

{

       chart1.Series.Add("");

       chart1.Series.Add("");

       Random R = new Random(100);

       double sale = 50;

       double cost = 30;

       double profit = 10;

       for (int i = 0; i < 10; i++)

       {

                  sale += R.Next(-4, 5);

                  chart1.Series[0].Points.AddY(sale);

                  cost += R.Next(-4, 5);

                  chart1.Series[1].Points.AddY(cost);

                  profit += R.Next(-4, 5);

                  chart1.Series[2].Points.AddY(profit);

       }

       chart1.Series[0].ChartType = SeriesChartType.Line;

       chart1.Series[0].Color = Color.Blue;

       chart1.Series[0].BorderWidth = 2;

       chart1.Series[1].ChartType = SeriesChartType.Column;

       chart1.Series[1].Color = Color.Red;

       chart1.Series[2].ChartType = SeriesChartType.Column;

       chart1.Series[2].Color = Color.Green;

 

       chart1.Focus();

}

 

private void chart1_KeyPress(object sender, KeyPressEventArgs e)

{

       ChartArea3DStyle a = chart1.ChartAreas[0].Area3DStyle;

       switch (e.KeyChar)

       {

                  case 'q':a.Inclination = Math.Min(a.Inclination + 5, 90); break;

                  case 'a':a.Inclination = Math.Max(a.Inclination -5, -90); break;

                  case 'w':a.Rotation = Math.Min(a.Rotation + 5, 180); break;

                  case 's':a.Rotation = Math.Max(a.Rotation - 5, -180);break;

                  case 'e': a.Perspective = Math.Min(a.Perspective + 5, 100); break;

                  case 'd': a.Perspective = Math.Max(a.Perspective - 5, 0); break;

                  case 'r': a.WallWidth = Math.Min(a.WallWidth + 2, 30); break;

                  case 'f': a.WallWidth = Math.Max(a.WallWidth - 2, 0); break;

                  case 't': a.PointDepth = Math.Min(a.PointDepth + 25, 1000); break;

                  case 'g': a.PointDepth = Math.Max(a.PointDepth - 25, 0); break;

                  case 'y': a.PointGapDepth = Math.Min(a.PointGapDepth + 25, 1000); break;

                  case 'h': a.PointGapDepth = Math.Max(a.PointGapDepth - 25, 0); break;

                  case 'z': a.Enable3D = !a.Enable3D;break;

                  case 'x':

                            a.Inclination = 30;

                            a.Rotation = 30;

                             a.Perspective = 0;

                            a.WallWidth = 7;

                            a.PointDepth = 100;

                            a.PointGapDepth = 100;

                            a.IsClustered = false;

                            a.IsRightAngleAxes = true;

                            break;

                  case 'c':a.IsClustered = !a.IsClustered;break;

                  case 'v':a.IsRightAngleAxes = !a.IsRightAngleAxes;break;

       }

 

       Text = String.Format("inc={0},rot={1},per={2},wall={3},dep={4},gap={5}",

                  a.Inclination, a.Rotation,a.Perspective, a.WallWidth,

                  a.PointDepth, a.PointGapDepth);

}

 

두 개의 컬럼 시리즈와 한개의 라인 시리즈를 차트에 표시했다. 키보드 입력을 받으려면 차트에게 포커스를 주어야 하며 KeyPress 이벤트에서 눌러진 키에 따라 속성값을 조정한다. 3D 옵션을 지정하지 않아 처음 실행하면 2D로 출력된다.

이 상태에서 키를 눌러 속성을 조정하며 각 키의 기능은 소스를 보면 알 수 있다. z키가 3D 옵션을 토글하며 x키는 모든 속성을 디폴트로 되돌린다. Z키를 누르면 3D 차트가 나타난다.

하늘에 파란 구름이 떠 있고 땅에 아파트 2동이 줄 지어 서 있다. 이 상태에서 qa, ws키를 눌러 수평, 수직 각도를 틀면 다른 각도에서 바라볼 수 있다. x키를 누르면 언제든지 디폴트 옵션으로 돌아간다.

ed, rf키는 원근감과 벽 두께를 조정한다.

tg는 막대의 두께를 조정하고 yh는 막대간의 거리를 변경한다. 거리를 충분히 띄우면 두 차트가 각각 따로 배치된다.

c키를 눌러 클러스터 상태로 배치하면 두 막대가 앞뒤가 아닌 좌우로 나란히 배열된다. 2D에서는 당연히 나란히 배치할 수밖에 없지만 3D에서는 앞뒤로도 배치할 수 있다.

v키를 눌러 IsRightAngleAxes 옵션을 토글하면 각도가 차트에 영향을 미치는 방식이 달라진다. 각도를 바꿔 가며 차트를 회전시킬 때는 이 옵션을 끄는 것이 더 자연스럽다.

이 예제를 통해 3D 차트의 각 속성이 어떤 영향을 미치는지 연구해 보고 목적에 딱 맞는 옵션을 찾아 적용하면 된다. 말로 설명하는 것보다는 훨씬 더 직관적으로 이해할 수 있고 옵션간의 조합 효과를 테스트하기도 쉽다.

 

이상으로 차트 컨트롤에 대한 강좌를 마친다. 개발툴에 기본 포함된 컨트롤이라기에는 기능이 다채롭고 안정성이나 성능도 충분히 만족할만한 컨트롤이다. 양이 좀 많지만 충분한 시간을 투자하여 잘 연구해 두워 두면 실무에 유용하게 사용할 수 있다.