Page 1 of 1

TChart7.04 Get drawn YValue by known XValue

Posted: Tue Apr 12, 2005 9:51 am
by 9341182
I'm using TAreaSeries. How can I calculate the YValue on the drawn Line by a given XValue?

Example:

Point 1 in the Serie: X=1 Y=10
Point 2 in the Serie: X=3 Y=30
I'm geting the XValue=2 by the Cursortool(between two points). The result must be Y=20 if stairs:=false.

I've tried to calulate it myself, therefore I need the the Serie Values at the left and the right of the cursorposition.If tried it with 'GetCursorValueIndex',
but the function returns -1 sometimes.

Posted: Tue Apr 12, 2005 10:02 am
by narcis
Hi Achim,

If you're using a TCursorTool you can do something like:

Code: Select all

procedure TForm1.ChartTool1Change(Sender: TCursorTool; x, y: Integer;
  const XValue, YValue: Double; Series: TChartSeries; ValueIndex: Integer);
begin
  if (Series1.Clicked(X,Y)<>-1) then
    Chart1.Title.Text.Text:=FloatToStr(Series.YValues[Series.Clicked(X,Y)]);
end;

Posted: Tue Apr 12, 2005 1:19 pm
by 9341182
narcis wrote:Hi,

Code: Select all

procedure TForm1.ChartTool1Change(Sender: TCursorTool; x, y: Integer;
  const XValue, YValue: Double; Series: TChartSeries; ValueIndex: Integer);
begin
  if (Series1.Clicked(X,Y)<>-1) then
    Chart1.Title.Text.Text:=FloatToStr(Series.YValues[Series.Clicked(X,Y)]);
end;
Unfortunately 'Clicked' dosen't work, too.'Clicked' needs to hit the line _exactly_, but I need the point of intersection between the vertical line of the cursortool and the line of the series.

The reason is, I want to use two Charts, both with identical x-axis,
but different y-axis. Therefore I want to use two cursortools and
synchronize them by time. If the user move the cursor to a point at time X in Chart1, I want to show the YValue of the series in Chart2 at the choosen time X.

Here is sample code for the 'clicked' behavior:
Use a Form,TChart,Lineseries and cusortool.

Code: Select all

procedure TForm6.FormShow(Sender: TObject);
var
 i:integer;
begin
  ChartTool1.FollowMouse:=true;
  ChartTool1.Style:=cssVertical;
  ChartTool1.ClickTolerance:=100; // dosen't work
  for i:= 0 to 59 do
  begin
     Series1.AddXY(i,i);
  end;
end;


procedure TForm6.ChartTool1Change(Sender: TCursorTool; x, y: Integer;
  const XValue, YValue: Double; Series: TChartSeries; ValueIndex: Integer);
var
  Index:integer;
begin
  Index:=Series1.Clicked(x,y);
  Chart1.Title.Text[0]:=IntToStr(Index);
end;

Posted: Tue Apr 12, 2005 4:36 pm
by narcis
Hi Achim,

Ah, ok, now I've understood what you want to do. Replacing your ChartTool1Change implementation for the code below should do.

Code: Select all

procedure TForm1.ChartTool1Change(Sender: TCursorTool; x, y: Integer;
  const XValue, YValue: Double; Series: TChartSeries; ValueIndex: Integer);
begin
  Chart1.Title.Text.Text:=FormatFloat('#.00',YValue);
end;

Posted: Tue Apr 12, 2005 10:31 pm
by 9341182
narcis wrote:

Code: Select all

procedure TForm1.ChartTool1Change(Sender: TCursorTool; x, y: Integer;
  const XValue, YValue: Double; Series: TChartSeries; ValueIndex: Integer);
begin
  Chart1.Title.Text.Text:=FormatFloat('#.00',YValue);
end;
Hi NarcĂ­s,
Code like this, I've tried first. :-) But the YValue is the value of the mouse cursor, not the Value of the series line crossing by the vertical Cursortool line.

But I think, I have a solution. For everyone how has the same problem, here is it :

first some math:
X1,Y1 is a point on the line at the left side of XValue
X2,Y2 is a point on the line at the right side of XValue

YValue=m*XValue + b
with m=(y2-y1)/(x2-x1) and b=y1-m*x1

YValue=(XValue-x1)*(y2-y1)/(x2-x1)+y1

Code: Select all

procedure TForm6.FormShow(Sender: TObject);
var
 i:integer;
begin
  ChartTool1.FollowMouse:=true;
  ChartTool1.Style:=cssVertical;
  for i:= 0 to 59 do
  begin
     Series1.AddXY(i,i);
  end;
end;


procedure TForm6.ChartTool1Change(Sender: TCursorTool; x, y: Integer;
  const XValue, YValue: Double; Series: TChartSeries; ValueIndex: Integer);
Var
  j:integer;
  LeftIndex,RightIndex:integer;
  found:boolean;
  X1,X2:double;
  Y1,Y2:double;
  YV:double;
begin
   if Series1.FirstValueIndex > 0 then
      LeftIndex:=Series1.FirstValueIndex - 1 // FirstValueIndex is inside of the Chart
   else
      LeftIndex:=0;
   RightIndex:=Series1.LastValueIndex;       // LastValueIndex is outside of the chart

   // search x1,x2,y1,y2
   found:=false;
   for j:= LeftIndex to RightIndex -1 do
   begin
      if (XValue >= Series1.XValue[j]) and
         (XValue <= Series1.XValue[j+1])  then
      begin
         X1:=Series1.XValue[j];
         Y1:=Series1.YValue[j];
         X2:=Series1.XValue[j+1];
         Y2:=Series1.YValue[j+1];
         found:=true;
         break;
      end;
   end;

   // calculate
   if found and (X2 <> X1) then
   begin
      YV:=(XValue-X1)*(Y2-Y1)/(X2-X1)+Y1;  // YV is the result
      Chart1.Title.Text.Text:=FloatToStrF(YV,ffFixed,5,2);
   end;
end;