labels for marks

TeeChart VCL for Borland/CodeGear/Embarcadero RAD Studio, Delphi and C++ Builder.
Post Reply
JimR
Newbie
Newbie
Posts: 46
Joined: Mon Oct 24, 2016 12:00 am

labels for marks

Post by JimR » Fri Oct 20, 2017 5:06 pm

What is the best way to position the labels for point marks so that the string is centered at the same height as the mark and the left end of the string is just a little to the right of the mark? I have been trying to do the computations in pixels and then convert to user units but that seems like too much work for this simple (?) task.

Yeray
Site Admin
Site Admin
Posts: 9612
Joined: Tue Dec 05, 2006 12:00 am
Location: Girona, Catalonia
Contact:

Re: labels for marks

Post by Yeray » Mon Oct 23, 2017 6:53 am

Hello,

Note there are several LabelStyles you can try. Ie smsLabelValue:

Code: Select all

uses Series;

procedure TForm1.FormCreate(Sender: TObject);
var i : Integer;
const nPoints = 5;
      myLabels : array  [0..nPoints-1] of string = ('Cars', 'Phones', 'Tables', 'Monitors', 'Lamps');
begin
  with Chart1.AddSeries(TPointSeries) as TPointSeries do
  begin
    for i:=0 to nPoints-1 do
      Add(50+random*50, myLabels[i]);

    Marks.Visible:=True;
    Marks.Style:=smsLabelValue;
  end;
end;
If they don't fit your needs and you still want to draw the label next to the mark, you can use TAnnotationTools. Ie:

Code: Select all

uses Series, TeeTools;

var annotations: array of TAnnotationTool;

procedure TForm1.FormCreate(Sender: TObject);
var i : Integer;
const nPoints = 5;
      myLabels : array  [0..nPoints-1] of string = ('Cars', 'Phones', 'Tables', 'Monitors', 'Lamps');
begin
  SetLength(annotations, nPoints);

  with Chart1.AddSeries(TPointSeries) as TPointSeries do
  begin
    for i:=0 to nPoints-1 do
    begin
      annotations[i]:=Chart1.Tools.Add(TAnnotationTool) as TAnnotationTool;
      annotations[i].Text:=myLabels[i];

      Add(50+random*50);
    end;

    Marks.Visible:=True;
    Marks.Style:=smsValue;

    OnGetMarkText:=SeriesGetMarkText;
  end;
end;

procedure TForm1.SeriesGetMarkText(Sender: TChartSeries; ValueIndex: Integer; var MarkText: string);
begin
  if (ValueIndex>=0) and (ValueIndex<Chart1[0].Count) and (Sender.Marks.Positions[ValueIndex] <> nil) then
  begin
    annotations[ValueIndex].Left:=Sender.Marks.Positions[ValueIndex].LeftTop.X+Sender.Marks.Positions[ValueIndex].Width;
    annotations[ValueIndex].Top:=Sender.Marks.Positions[ValueIndex].LeftTop.Y;
  end;
end;
Best Regards,
ImageYeray Alonso
Development & Support
Steema Software
Av. Montilivi 33, 17003 Girona, Catalonia (SP)
Image Image Image Image Image Image Please read our Bug Fixing Policy

JimR
Newbie
Newbie
Posts: 46
Joined: Mon Oct 24, 2016 12:00 am

Re: labels for marks

Post by JimR » Thu Oct 26, 2017 3:38 pm

Thanks but this does not yet give me what I want. I have attached a screenshot below.

Two problems. First, It puts the labels to the right of the values that label each mark. I need the labels to be to the right of each point not the labels for the marks.

Second, when I run the program the annotations are initially all on top of each other at the top left of the chart until I move the mouse over one of the points. They then snap to the positions shown in the screenshot. Do I need to set some options for the TChart? My form just has a TChart component dropped onto it and then set to align with the client. No other changes to the form.

My code (copied from your second example) is given below.

Code: Select all

unit testTeeu;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VclTee.TeeGDIPlus, VclTee.TeEngine,
  Vcl.ExtCtrls, VclTee.TeeProcs, VclTee.Chart, VclTee.Series, VclTee.TeeTools;

type
  TForm1 = class(TForm)
    Chart1: TChart;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  var
    annotations: array of TAnnotationTool;
    procedure SeriesGetMarkText(Sender: TChartSeries; ValueIndex: Integer;
      var MarkText: string);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  i: Integer;
const
  nPoints = 5;
  myLabels: array [0 .. nPoints - 1] of string = ('Cars', 'Phones', 'Tables',
    'Monitors', 'Lamps');
begin
  SetLength(annotations, nPoints);

  with Chart1.AddSeries(TPointSeries) as TPointSeries do
  begin
    for i := 0 to nPoints - 1 do
    begin
      annotations[i] := Chart1.Tools.Add(TAnnotationTool) as TAnnotationTool;
      annotations[i].Text := myLabels[i];

      Add(50 + random * 50);
    end;

    Marks.Visible := True;
    Marks.Style := smsValue;

    OnGetMarkText := SeriesGetMarkText;
  end;
end;

procedure TForm1.SeriesGetMarkText(Sender: TChartSeries; ValueIndex: Integer;
  var MarkText: string);
begin
  if (ValueIndex >= 0) and (ValueIndex < Chart1[0].Count) and
    (Sender.Marks.Positions[ValueIndex] <> nil) then
  begin
    annotations[ValueIndex].Left := Sender.Marks.Positions[ValueIndex].LeftTop.X
      + Sender.Marks.Positions[ValueIndex].Width;
    annotations[ValueIndex].Top := Sender.Marks.Positions[ValueIndex].LeftTop.Y;
  end;
end;

end.
Thanks for your help.
Attachments
Screen Shot 10-26-17 at 11.26 AM.PNG
Screen Shot 10-26-17 at 11.26 AM.PNG (18.23 KiB) Viewed 13261 times

Yeray
Site Admin
Site Admin
Posts: 9612
Joined: Tue Dec 05, 2006 12:00 am
Location: Girona, Catalonia
Contact:

Re: labels for marks

Post by Yeray » Fri Oct 27, 2017 7:26 am

Hello,
JimR wrote:First, It puts the labels to the right of the values that label each mark. I need the labels to be to the right of each point not the labels for the marks.
I'm not sure to understand if you want to also show the default marks or not. If you don't want to show the default marks, you can just modify their text and position without needing to use TAnnotationTools.
An image could help to clarify the goal.
JimR wrote:Second, when I run the program the annotations are initially all on top of each other at the top left of the chart until I move the mouse over one of the points. They then snap to the positions shown in the screenshot. Do I need to set some options for the TChart? My form just has a TChart component dropped onto it and then set to align with the client. No other changes to the form.
It also fails to correctly reposition the annotations when you zoom and unzoom. this happens because the TAnnotationTools are drawn earlier than the series in the drawing center; so the annotation positions that are calculated in the SeriesGetMarkText will apply at the next repaint. To solve it, you can force a chart repaint when these events happen. Ie:

Code: Select all

procedure TForm1.Chart1UndoZoom(Sender: TObject);
begin
  Chart1.Draw;
end;

procedure TForm1.Chart1Zoom(Sender: TObject);
begin
  Chart1.Draw;
end;

procedure TForm1.FormCreate(Sender: TObject);
//...

  Chart1.Draw;
end;
Best Regards,
ImageYeray Alonso
Development & Support
Steema Software
Av. Montilivi 33, 17003 Girona, Catalonia (SP)
Image Image Image Image Image Image Please read our Bug Fixing Policy

JimR
Newbie
Newbie
Posts: 46
Joined: Mon Oct 24, 2016 12:00 am

Re: labels for marks

Post by JimR » Wed Nov 01, 2017 4:53 pm

Right, I don't want to display the marks - I just want to show their labels at the ends of some arrow series.

The default seems to be to plot them centered above where the mark would be. I need them centered vertically but plotted to the right of where the mark would be (though for some plots I would like them to the left and right justified up to where the mark would be). For example: Xaaaaaa or aaaaaX (where X is the mark and aaaaa is some text for the label).

I could not find position constants for left, right, center, etc. for the labels.

The annotation option seems more complicated as I believe I would need to calculate positions in pixels and redraw after any zoom etc. (Is that correct?)

Thanks

Yeray
Site Admin
Site Admin
Posts: 9612
Joined: Tue Dec 05, 2006 12:00 am
Location: Girona, Catalonia
Contact:

Re: labels for marks

Post by Yeray » Thu Nov 02, 2017 11:11 am

Hello,
JimR wrote:Right, I don't want to display the marks - I just want to show their labels at the ends of some arrow series.

The default seems to be to plot them centered above where the mark would be. I need them centered vertically but plotted to the right of where the mark would be (though for some plots I would like them to the left and right justified up to where the mark would be). For example: Xaaaaaa or aaaaaX (where X is the mark and aaaaa is some text for the label).

I could not find position constants for left, right, center, etc. for the labels.

The annotation option seems more complicated as I believe I would need to calculate positions in pixels and redraw after any zoom etc. (Is that correct?)
You can modify the Marks positions by accessing the Marks.Positions array. You can find an example of how to modify these positions here.
Note you have to recalculate the positions after every zoom/scroll, exactly the same issue as with the TAnnotationTools option.

If you still find problems with it, please try to show a screenshot/mockup showing the expected result.
Best Regards,
ImageYeray Alonso
Development & Support
Steema Software
Av. Montilivi 33, 17003 Girona, Catalonia (SP)
Image Image Image Image Image Image Please read our Bug Fixing Policy

Post Reply