casterle
casterle

Reputation: 1047

TeeChart Series OnMouseEnter event

I am using the version of TeeChart that ships with Rad Studio XE3.

TeeChart provides a TChartSeries event which fires when the mouse pointer moves over a series line. I use this event to display the name of the series under the pointer.

The problem is, give a series line 1 pixel wide, it’s difficult to get the pointer exactly over the line. Is there some way to add ‘padding’ to the event so it fires X number of pixels to each side of the line?

Or is there some other way to accomplish this?

Upvotes: 1

Views: 1590

Answers (2)

David Berneda
David Berneda

Reputation: 500

I'm adding a new property to Line (TLineSeries) and FastLine (TFastLineSeries) classes to accomplish this.

Series1.ClickTolerance := 4;   // <-- number of pixels around mouse XY

The default value is zero (mouse XY should be exactly over the line), like the current behavior.

As a workaround, if you are using TLineSeries, pointers can be displayed at line point positions, and the internal "clicked" function will consider pointer size:

Series1.Pointer.Visible:=True;

And for more custom control, the code below is very similar to the internal code use to detect mouse clicks. The Tolerance constant specifies the number of extra pixels to consider "in the line".

procedure TForm1.Chart1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);

const
  Tolerance=4;

var Clicked,
    t : Integer;
    Position,
    P,Old : TPoint;
begin
  Clicked:= -1;

  Position.X:=X;
  Position.Y:=Y;

  for t:=Series1.FirstValueIndex to Series1.LastValueIndex do
  begin
    P.X:=Series1.CalcXPos(t);
    P.Y:=Series1.CalcYPos(t);

    if t>Series1.FirstValueIndex then
       if PointInLine(Position,P.X,P.Y,Old.X,Old.Y,Tolerance) then
       begin
         Clicked:=t;
         break;
       end;

    Old:=P;
  end;

  if Clicked = -1 then
     Caption:=''
  else
     Caption:=IntToStr(Clicked);
end;

Upvotes: 4

Yeray
Yeray

Reputation: 5039

You can use the PointInLineTolerance function to check it at OnMouseMove event. However, you have to loop the series points manually to transform the series values into pixels and pass them to this function.

uses Series;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  Chart1.View3D:=false;

  for i:=0 to 5 do
    Chart1.AddSeries(TLineSeries).FillSampleValues;
end;

procedure TForm1.Chart1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var series, valueIndex: Integer;
    P0, P1: TPoint;
begin
  Chart1.Draw;
  for series:=0 to Chart1.SeriesCount-1 do
    with Chart1[series] do
    for valueIndex:=FirstValueIndex to LastValueIndex-1 do
    begin
      P0.X:=CalcXPos(valueIndex);
      P0.Y:=CalcYPos(valueIndex);
      P1.X:=CalcXPos(valueIndex+1);
      P1.Y:=CalcYPos(valueIndex+1);
      if PointInLineTolerance(Point(X, Y), P0.X, P0.Y, P1.X, P1.Y, 5) then
      begin
        Chart1.Canvas.TextOut(X+5,Y-10,'Series ' + IntToStr(series));
        exit;
      end;
    end;
end;

Upvotes: 1

Related Questions