Visual Basic, C & C++
분류 Delphi

[펌] TChart 기본정보 및 사용팁

페이지 정보

본문

0. 들어가기

 TChart를 처음 접했을때 기초는 도움말과 예제등으로 어느정도 익혔습니다.
 그런데 제가 꼭 필요로 했던 기능들이나 팁들은 자료찾기 어렵더군요. 
 이 글이 좀 허접할지라도 한분이라도 도움이 되었으면 좋겠습니다^^

 기본 기능들은 첨부된 예제 소스를 보시면 쉽게 이해하실 수 있고, 몇가지 팁만 서술하겠습니다.
 각 요소들을 다 설명할 수준이 못되서 도움말 참고하시면 좋을 듯 합니다.

1. TChart 중요 요소

 (1) Panel(= TChart)
  – 차트 배경. 색이나 바깥 테두리와 간격등을 설정 가능.
  – TChart.Color, TChart.MarginLeft등

 (2) TChart.Title
  – 차트 제목. 기본 중앙 상단에 표시되며 위치, 글꼴등 변경 가능.

 (3) TChart.Legend
  – 범례. 기본 버전은 기능이 미약하여 거의 사용하지 않고 필요기능(보이기/감추기, 이름/색상변경등)을 추가하여 따로 만들어서 사용하는것이 좋음.

 (4) TChart.Left Axis, TChart.BottomAxis
  – 차트 축. Left(기본 Y축), Bottom(기본 X축) 외에 Right, Top등이 존재.

  – (Property) Automatic, AutomaticMinimum, AutomaticMaximum : 데이터에 따른 축 눈금 자동 조절 여부.
  – (Property) Minimum : 축의 최소 눈금. Maximum보다 크면 Error 발생.
  – (Property) Maximum : 축의 최대 눈금. Minimum보다 작으면 Error 발생.
  – (Property) MinimumOffset, MaximumOffset : 자동 축 조정시 눈금과 데이터간 조절.
   최대 데이터가 10이고 MaximumOffset이 0%면 Maximum은 자동으로 10으로 설정됨.
   최대 데이터가 10이고 MaximumOffset이 20%면 Maximum은 자동으로 12으로 설정됨.
  – (Property) AxisValuesFormat : Label의 Format을 결정.

  – (Function) AdjustMaxMin : 데이터에 따라 축 눈금 자동 조정.
  – (Function) SetMinMax : 축의 최소, 최대 눈금 설정. Property로 설정 할 경우 직접 데이터가 크거나 작은지 체크해야함.
   현재 Y축이 10~20으로 설정되어 있을때,
   1~2로 설정하려면 Minimum을 먼저 설정해야 Error가 안나고,
   100~200으로 설정하려면 Maximum을 먼저 설정해야 하는데 이 함수를 사용하면 직접 체크하지 않아도 됨.
   
 (5) TChart.Series[]
  – 차트의 그래프. Design Time에서 추가한 Series는 자동으로 Source상에 Class가 추가됨.
  TForm1 = class(TForm)
    Chart1: TChart;
    Series1: TLineSeries;

  – 동적으로 생성 가능.
  var
    s: TLineSeries;
  begin
    s := TLineSeries.Create(Chart1);
    s.ParentChart := Chart1;

  – 데이터 속성 : 그래프의 데이터 한개에는 총 4가지의 속성이 있습니다. 이거 이해못해서 한참 해맸습니다^^
  Index : 데이터배열에 필요한 Index 정보. X축 좌측기준 0부터 시작.
  Pos : 차트에 데이터가 위치하는 좌표(윈도우 화면 좌표가 아닌 차트 내부좌표). Double 형식. 스크롤이나 해당 위치에 선 그릴때 필요.
  Value : Y축 데이터 값입니다. Double 형식.
  Label : X축 Label 값입니다. Text 형식.
  
  – (Property) Color : 그래프 색상.
  – (Property) Title : 그래프 이름. 다른 그래프와 중복 가능.
  – (Property) ValueList.ValueList[0] : X축 데이터의 Pos List. 하위 Items[]로 접근 가능.
  – (Property) ValueList.ValueList[1] : X축 데이터의 Value List. 하위 Items[]로 접근 가능.
  – (Property) LabelList : 데이터의 Label List. 하위 Labels[Index]로 접근 가능. 읽기 전용.

2. Scroll 기능 만들기

 (1) 원리
  – 데이터 추가 시, X축 좌표를 직접 입력하여 X축 설정을 통해 Scroll.

 (2) 방법
  1) X축 좌표 입력하여 데이터 추가
   s.AddXY(1, 10, ’1번’, clRed);
   s.AddXY(2, 20, ’2번’, clRed);
   s.AddXY(3, 30, ’3번’, clRed);
   s.AddXY(1.5, 15, ’1.5번’, clRed);
   s.AddXY(2.5, 25, ’2.5번’, clRed);
 

  2) X축 범위 설정을 통해 Scroll 구현
   Chart1.BottomAxis.SetMinMax(1.5, 2.5);

3. Label 변경

 (1) 원리
  – 데이터가 추가되고 Label List Class가 있지만 읽기전용으로 수정 불가능.
  – GetAxisLabel Event를 통해 LabelText를 바꿀 수 있음.

 (2) GetAxisEvent
procedure TForm1.Chart1GetAxisLabel(Sender: TChartAxis;
  Series: TChartSeries; ValueIndex: Integer; var LabelText: string);
begin
end;

  – Sender : 어떠한 축에서 Event가 발생되었는지 알 수 있음.
  – Series : 어떠한 Series에서 Event가 발생되었는지 알 수 있음. 단, 데이터 등록시 Label을 입력하지 않으면 Series는 GetAxisLabel Event를 발생하지 않음.
  – ValueIndex : 현재 표시되려는 Label의 Index를 알 수 있어 데이터에 접근 가능. 단, 데이터 등록시 Label을 입력하지 않으면 ValueIndex는 -1로 전송받음.
  – LabelText : 표시 되려는 Label. 이 변수를 변경함으로써 표시되는 Label 변경 가능. 실제 내부 Label값은 변하지 않음. 이 LabelText의 Format은 해당 축의 (Property) AxisValuesFormat으로 결정됨.

 (3) 방법
procedure TForm1.Chart1GetAxisLabel(Sender: TChartAxis;
  Series: TChartSeries; ValueIndex: Integer; var LabelText: string);
begin
    // Y축 Label 변경
    if (Sender = Chart1.LeftAxis) then  // Y축인지 검사
    begin
      LabelText := Format(‘[%s]‘, [LabelText]);
    end;

    // X축 Label 변경
    if (Sender = Chart1.BottomAxis) and (Series = Series1) then  // X축인지 검사 // Series 검사를  하지 않으면 예외 Label이 발생 할 수 있음.
    begin
      try
        LabelText := FormatDateTime(‘hh:nn:ss’, StrToDateTime(LabelText));
      except
        LabelText := ‘Wrong Format’;
      end;
    end;
end;

4. 많은 데이터 처리

 (1) 원리
   – 데이터 추가시 Label을 입력하게 되면 데이터 개수가 많아질수록(약 1만개 이상) Chart Class가 전체적으로 느려짐.
   – Label의 길이가 길어지면 더 빨리 느려지고, Label을 입력하지 않으면 속도가 아주 빠름.
   – 데이터 추가시에는 Label을 입력하지 않고, GetAxisLabel을 통해 표현하는 방법이 최고 속도 구현. 이때 GetAxisLabel의 LabelText는 좌표값으로 표시됨.

 (2) 방법
  1) 데이터 추가
for i := 1 to 86400
   s.AddXY(i, i * 10, ”, clRed);
 
  2) Label 변경
procedure TForm1.Chart1GetAxisLabel(Sender: TChartAxis;
  Series: TChartSeries; ValueIndex: Integer; var LabelText: string);
begin
    // X축 Label 변경
    if (Sender = Chart1.BottomAxis) and (Chart1.SeriesCount > 0) then  // X축인지 검사
    begin
      LabelText := Format(‘%s번’, [LabelText]);
    end;
end;

5. 시간 형식 Label 사용 및 시간 기준 Scroll

 (1) 원리
  – X축 Label 시간을 표시하는 방법
  1) 데이터 추가시 Label에 시간 넣기
  2) GetAxisLabel에서 시간 표시하기
  – 빠른 속도를 위해 Label을 입력하지 않고 위치값에 TDateTime값을 입력하여 Label을 TDateTime으로 변환하여 표시
  – 위치값을 시간으로 입력하면 SetMinMax 함수를 통해 시간 기준 Scroll 가능
 
 (2) 방법
  1) 데이터 추가
dtPivot: TDateTime;

var
  i: integer;
  dtAdd: TDateTime;
begin
  Series1.Clear;

  dtPivot := Now; // 전역변수에 마지막 시간을 입력한다.
  dtAdd := dtPivot;

  for I := 1 to 86400 do // 1초마다 24시간 만큼 추가
  begin
    Series1.AddXY(dtAdd, i, ”, clRed);
    dtAdd := dtAdd – (1/24/60/60);  // 1초 감소
  end;
end;
 
  2) 시간 표시
procedure TForm1.Chart1GetAxisLabel(Sender: TChartAxis;
  Series: TChartSeries; ValueIndex: Integer; var LabelText: string);    // Label이 없게 데이터를 추가하면  ValueIndex는 항상 -1로 넘어옴.
var
  dtLabel: TDateTime;
  dDT: double;
begin
  if (Sender = Chart1.BottomAxis) and (Chart1.SeriesCount > 0) then
  begin
    try
      dDT := StrToFloat(LabelText);
      dtLabel := dDT;
      LabelText := FormatDateTime(‘hh:nn:ss’, dtLabel);
    except
      LabelText := ‘Error’;
    end;
  end;
end;

  3) Scroll
var
  dtBegin, dtEnd: TDateTime;
begin
  dtBegin := dtPivot – ((1/24/60/60) * 10); // 마지막 시간 기준 10초 전으로 설정
  dtEnd := dtPivot; // 마지막 시간으로 설정

  if Chart1.Zoomed = false then // Zoom이 안되어 있을때만 스크롤
    Chart1.BottomAxis.SetMinMax(dtBegin, dtEnd);

  4) Zoom 해제 시, Scroll 영역 설정
procedure TForm1.Chart1UndoZoom(Sender: TObject);
var
  dtBegin, dtEnd: TDateTime;
begin
  // Zoom이 풀릴때 스크롤중이라면 범위를 맞춘다.
  if IsScroll then
  begin
    dtBegin := dtPivot – ((1/24/60/60) * 9);
    dtEnd := dtPivot;
    Chart1.BottomAxis.SetMinMax(dtBegin, dtEnd);
  end;

6. 선긋기

 (1) 원리
  – CalcXPosValue, CalcYPosValue 함수를 통해 축의 위치값에 해당하는 화면 좌표를 얻을 수 있음.
  – 해당 좌표를 이용하여 가로선, 세로선, 사각형, 글자를 AfterDraw 이벤트에서 Draw.

 (2) 방법
procedure TFrameLine.Chart2AfterDraw(Sender: TObject);
var
  x, y, i, xcc, ri, j:integer;

  dtBegin, dtEnd: TDateTime;
  sChamber: String;
  sLabel, sLabel2: String;

  // 범위용
  rT: TRect;
begin
  // 가로선
  if IsHorzLine then
  begin
    // Y축 5에 해당하는 좌표얻기
    y := Chart2.LeftAxis.CalcYPosValue(5);
    if (y >= Chart2.ChartRect.Top) and (y <= Chart2.ChartRect.Bottom) then
    begin
      // 선 색상 지정
      Chart2.Canvas.Pen.Color := clPurple;
      // 폰트 색상, 글꼴, 크기 지정
      Chart2.Canvas.Font.Name := ‘Arial’;
      Chart2.Canvas.Font.Color := clPurple;
      Chart2.Canvas.Font.Size := 8;

      // Y축 왼쪽부터 오른쪽까지 선긋기
      Chart2.Canvas.MoveTo(Chart2.ChartRect.Left,y);
      Chart2.Canvas.LineTo(Chart2.ChartRect.Right,y);
      Chart2.Canvas.TextOut(Chart2.ChartRect.Right + 2, y – 6, ‘This is 5′); // +2, -6은 적절한 위치 설정은 위함
    end;
  end;

  // 세로선
  if IsVertLine then
  begin
    // X축 3초전 좌표얻기
    dtBegin := dtPivot – ((1/24/60/60) * 3);
    x := Chart2.BottomAxis.CalcXPosValue(dtBegin);
    if (x >= Chart2.ChartRect.Left) and (x <= Chart2.ChartRect.Right) then
    begin
      // 선 색상 지정
      Chart2.Canvas.Pen.Color := clBlue;
      // 폰트 색상, 글꼴, 크기 지정
      Chart2.Canvas.Font.Name := ‘Arial’;
      Chart2.Canvas.Font.Color := clBlue;
      Chart2.Canvas.Font.Size := 8;

      // X축 위부터 아래까지 선긋기
      Chart2.Canvas.MoveTo(x, Chart2.ChartRect.Bottom);
      Chart2.Canvas.LineTo(x, Chart2.ChartRect.Top);
      Chart2.Canvas.TextOut(x, 10, Format(‘This is %s’, [FormatDateTime('hh:nn:ss', dtBegin)]));
    end;
  end;

  // 범위
  if IsRange then
  begin
    // X축 6초전 좌표얻기
    dtBegin := dtPivot – ((1/24/60/60) * 6);
    // X축 3초전 좌표얻기
    dtEnd := dtPivot – ((1/24/60/60) * 3);

    // 사각 좌표 얻기
    rT.Left := Chart2.BottomAxis.CalcXPosValue(dtBegin);
    rT.Right := Chart2.BottomAxis.CalcXPosValue(dtEnd);

    rT.Top := Chart2.ChartRect.Top;
    rT.Bottom := Chart2.ChartRect.Bottom;

    // Zoom 상태를 감안하여 표시 여부 설정
    if (rT.Left <= Chart2.ChartRect.Right) and (rT.Right >= Chart2.ChartRect.Left) then
    begin
      if rT.Left <= Chart2.ChartRect.Left then rT.Left := Chart2.ChartRect.Left;    // 좌측을 넘어가는 범위 자르기
      if rT.Right >= Chart2.ChartRect.Right then rT.Right := Chart2.ChartRect.Right; // 우측을 넘어가는 범위 자르기

      // 선 색상
      Chart2.Canvas.Pen.Color := clGreen;
      // 채우기 색상, 스타일
      Chart2.Canvas.Brush.Style := bsDiagCross;
      Chart2.Canvas.Brush.Color := clGreen;
      // 상자 그리기
      Chart2.Canvas.Rectangle(rT);

      // 상단 중간에 글자 표시
      Chart2.Canvas.Font.Name := ‘Arial’;
      Chart2.Canvas.Font.Color := clGreen;
      Chart2.Canvas.Font.Size := 8;
      Chart2.Canvas.TextOut(rT.Left, 0, Format(‘This is %s ~ %s’, [FormatDateTime('hh:nn:ss', dtBegin), FormatDateTime('hh:nn:ss', dtEnd)]));
    end;
  end;
end;

관련자료

등록된 댓글이 없습니다.
프로그래밍
Today's proverb
전반전이 끝난 상황이라면 절대로 중단하지 말라. 전반전 점수는 큰 의미가 없다. 그 너머를 보라. 승리할 수 있는 길은 끝까지 인내하는 것이다.