Gabriel Attuati
Gabriel Attuati

Reputation: 27

Draw a marker on each new point on teechart

I am developing an application on Embarcadero XE where i receive real time data from the ethernet port and display on a teechart chart on the screen.

The application works like an osciloscope, that is, there is a time window (10 seconds for example) of data that the chart displays, and each new incoming point overwrites what already is on screen.

I would like your help to make a code that puts a marker on only the newest point added, so the user can keep track of which of the points on the screen is the most recent point. I don´t want all of the points with a marker, i want only the newest.

The series being used is a fastline.

Here is the code i'm using to add data to the chart:

//Delete already existing point
if (Oscilografia.Series[0].Count>1) then
begin
Oscilografia.Series[0].Delete(cont);
end;
//Write point
Oscilografia.Series[0].addxy(cont,data, '', clblue);

Upvotes: 1

Views: 5090

Answers (2)

Yeray
Yeray

Reputation: 5039

As an alternative to J's proposal of using custom drawing techniques to draw a pointer, you could change the TFastLineSeries to use a TLineSeries and make its Pointer Visible. Then, you can use OnGetPointerStyle event to hide all the pointers except the last one:

uses Series;

var Series1: TLineSeries;

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

  Series1:=Chart1.AddSeries(TLineSeries) as TLineSeries;
  for i:=0 to 360 do
    Series1.Add(Sin(PI*i/180));

  Series1.Pointer.Visible:=true;
  Series1.OnGetPointerStyle:=SeriesGetPointerStyle;
end;

function TForm1.SeriesGetPointerStyle(Sender:TChartSeries; ValueIndex:Integer):TSeriesPointerStyle;
begin
  result:=(Sender as TLineSeries).Pointer.Style;

  if (ValueIndex<>Sender.Count-1) then
    result:=psNothing;
end;

enter image description here

And as a complement, if you want to show the Mark of the last point in the series, you can make the series' Marks Visible and use OnGetMarkText event to hide all the Marks except the last one:

uses Series;

var Series1: TLineSeries;

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

  Series1:=Chart1.AddSeries(TLineSeries) as TLineSeries;
  for i:=0 to 360 do
    Series1.Add(Sin(PI*i/180));

  Series1.Pointer.Visible:=true;
  Series1.OnGetPointerStyle:=SeriesGetPointerStyle;

  Series1.Marks.Visible:=true;
  Series1.OnGetMarkText:=SeriesGetMarkText;
end;

function TForm1.SeriesGetPointerStyle(Sender:TChartSeries; ValueIndex:Integer):TSeriesPointerStyle;
begin
  result:=(Sender as TLineSeries).Pointer.Style;

  if (ValueIndex<>Sender.Count-1) then
    result:=psNothing;
end;

procedure TForm1.SeriesGetMarkText(Sender:TChartSeries; ValueIndex:Integer; var MarkText:String);
begin
  if (ValueIndex<>Sender.Count-1) then
    MarkText:='';
end;

Note I'm using a TLineSeries here also, but if you are only interested on showing the Marks and not the Pointer, you can still use a TFastLineSeries.

enter image description here

Upvotes: 1

J...
J...

Reputation: 31403

You have several options. The simplest is to make a new TPointSeries to display the current point. If you wish to not show this series in the legend then simply set :

 Oscilografia.Series[n].ShowInLegend := false;

where n is the index of the series you wish to exclude from the legend.

Alternatively, you can custom-draw any relevant items in the OnAfterDraw handler. For example :

procedure TForm1.Chart1AfterDraw(Sender: TObject);
var
  xPos, yPos : integer;
begin
  Chart1.Canvas.Pen.Color := clRed;
  Chart1.Canvas.Pen.Style := psSolid;
  Chart1.Canvas.Pen.Width := 1;
  Chart1.Canvas.Pen.Mode := pmCopy;

  xPos := Chart1.BottomAxis.CalcPosValue(CurrentXValue);
  yPos := Chart1.LeftAxis.CalcPosValue(CurrentYValue);

  // Parameters are 
  //  X-Coord, Y-Coord, X-Radius, Y-Radius, Start Angle, End Angle, Hole%
  Chart1.Canvas.Donut(xPos, yPos, 3, 3, 0, 360, 0);
end;

This produces, for example :

enter image description here

Custom drawing lets you do other things also, like add markers, etc. For example :

procedure TForm1.Chart1AfterDraw(Sender: TObject);
var
  xPos, yPos : integer;
  yMax, yMin : integer;
begin
  Chart1.Canvas.Pen.Color := clRed;
  Chart1.Canvas.Pen.Style := psSolid;
  Chart1.Canvas.Pen.Width := 1;
  Chart1.Canvas.Pen.Mode := pmCopy;

  xPos := Chart1.BottomAxis.CalcPosValue(CurrentXValue);
  yPos := Chart1.LeftAxis.CalcPosValue(CurrentYValue);

  Chart1.Canvas.Donut(xPos, yPos, 3, 3, 0, 360, 0);

  Chart1.Canvas.Pen.Color := clGreen;
  Chart1.Canvas.Pen.Style := psDash;

  yMax := Chart1.LeftAxis.CalcPosValue(Chart1.LeftAxis.Maximum);
  yMin := Chart1.LeftAxis.CalcPosValue(Chart1.LeftAxis.Minimum);
  Chart1.Canvas.DoVertLine(xPos, yMax, yMin);
end;

Which gives a dashed vertical line that follows the current point :

enter image description here

Note that the CalcPosValue function is exposed by the chart axes and allows you to translate a point in the axis-space to an integer (screen) coordinate in the chart's canvas space.

Upvotes: 5

Related Questions