Page 1 of 1

How to clip drawn points in a chart ?

Posted: Tue May 20, 2008 7:54 am
by 8573088
Teechart 6.01 (with source), Delphi 7

I'm showing data in a TChart using TPointSeries. I'm showing it in a grid (I use TChartShape for each rectangle in that grid).

Now, when the user resizes a data point (Pointer.HorizSize, Pointer.VeriSize) those points will eventually draw outside a grid's rectangle.

(Also, depending on the order the points are added, it "seems" like points are being shifted.)

Is there functionality within tchart to clip the drawing of each point?

See below:

Left shows with point size 2

Middle shows with point size 8

Right shows what I want

Image

Posted: Tue May 20, 2008 10:32 am
by yeray
Hi Marck,

Firs of all I'd like to say that this should be easier with teechart v8 since there is the SubChart tool and with it you could work as with 4 different charts in the same chart. So these separations should work by default as each chart would perform its own clipping.

In the following example I use 4 Shape series as in your picture but if you are using more, I think you wont' have too much troubles adapting it.
Also note that I use a UpDownButton associated to an Edit text box to control the increment of the pointers size.

Code: Select all

type
  TForm1 = class(TForm)
    Chart1: TChart;
    Series1: TChartShape;
    Series2: TChartShape;
    Series3: TChartShape;
    Series4: TChartShape;
    Series5: TPointSeries;
    Edit1: TEdit;
    UpDown1: TUpDown;
    procedure FormCreate(Sender: TObject);
    procedure UpDown1Click(Sender: TObject; Button: TUDBtnType);
    function Series5GetPointerStyle(Sender: TChartSeries;
      ValueIndex: Integer): TSeriesPointerStyle;

...


var
  Form1: TForm1;
  ClipRect: array [0..3] of TRect;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var i: integer;
begin
  //some chart config
  with Chart1 do
  begin
    View3D := false;

    with Axes.Left do
    begin
      Automatic := false;
      Minimum := 0;
      Maximum := 100;
    end;

    with Axes.Bottom do
    begin
      Automatic := false;
      Minimum := 0;
      Maximum := 100;
    end;

    Legend.Visible := false;
  end;

  UpDown1.Position := Series5.Pointer.HorizSize;

  //drawing four rectangles to divide the chart in 4 zones
  for i := 0 to 3 do
    (Chart1[i] as TChartShape).Style := chasRectangle;

  with Series1 do //rectangle down-left
  begin
    X0 := 0;
    X1 := 30;
    Y0 := 0;
    Y1 := 70;
  end;

  with Series2 do //rectangle down-right
  begin
    X0 := 30;
    X1 := 100;
    Y0 := 0;
    Y1 := 70;
  end;

  with Series3 do //rectangle up-left
  begin
    X0 := 0;
    X1 := 30;
    Y0 := 70;
    Y1 := 100;
  end;

  with Series4 do //rectangle up-right
  begin
    X0 := 30;
    X1 := 100;
    Y0 := 70;
    Y1 := 100;
  end;

  //drawing the point series
  with Series5 do
  begin
    Color := clYellow;
    Pointer.Pen.Hide;

    //poits at down-left
    AddXY(5,50,'',clGray);
    AddXY(5,65,'',clGray);
    AddXY(25,50,'',clGray);
    AddXY(25,65,'',clGray);

    //points at down-right
    AddXY(35,50,'',clYellow);
    AddXY(35,65,'',clYellow);
    AddXY(55,50,'',clYellow);
    AddXY(55,65,'',clYellow);

    //points at up-left
    AddXY(5,75,'',clYellow);
    AddXY(5,95,'',clYellow);
    AddXY(25,75,'',clYellow);
    AddXY(25,95,'',clYellow);

    //points at up-right
    AddXY(35,75,'',clYellow);
    AddXY(35,95,'',clYellow);
    AddXY(55,75,'',clYellow);
    AddXY(55,95,'',clYellow);
  end;

  //we need the 4 coordinates of teh 4 rectangles in pixels, we store them in global array of rectangles
  Chart1.Draw;

  for i := 0 to 3 do
  begin
    with (Chart1[i] as TChartShape) do
    begin
      ClipRect[i].Left := CalcXPosValue(X0)+1;
      ClipRect[i].Right := CalcXPosValue(X1);
      ClipRect[i].Top := CalcYPosValue(Y0);
      ClipRect[i].Bottom := CalcYPosValue(Y1)+1;
    end;
  end;
end;

procedure TForm1.UpDown1Click(Sender: TObject; Button: TUDBtnType);
begin
  Series5.Pointer.HorizSize := UpDown1.Position;
  Series5.Pointer.VertSize := UpDown1.Position;
end;

function TForm1.Series5GetPointerStyle(Sender: TChartSeries;
  ValueIndex: Integer): TSeriesPointerStyle;
begin
  with Chart1.Canvas do
  begin
    UnClipRectangle;
    if (Series5.XValue[ValueIndex] < Series1.X1) then   //in left half
    begin
      if (Series5.YValue[ValueIndex] < Series1.Y1) then //in first rectangle
        ClipRectangle(ClipRect[0])
      else                                              //in 3rd rectangle
        ClipRectangle(ClipRect[2]);
    end
    else                                                //in right half
    begin
      if (Series5.YValue[ValueIndex] < Series1.Y1) then //in second rectangle
        ClipRectangle(ClipRect[1])
      else                                              //in 4thrd rectangle
        ClipRectangle(ClipRect[3]);
    end;
  end;

  Result := psRectangle;
end;

Posted: Tue May 20, 2008 10:43 am
by 8573088
Thank you very much for your rapid and clear reply :!:

I'm sure your example will solve the problem for me :)

Have a nice day,

Marck