Hi,
I'm trying to use the TColorLineTool to draw horizontal lines at the bottom and top of the left axes.
It works, except in the case of a bar chart with visible marks. Bar charts with marks automatically rescale in order to fit the marks on the chart. I don't know why only bar charts do this. Other chart series types don't, though it might be nice if they did.
In any case, when the marks are visible, the color line with a style of clMaximum, isn't positioned at the top of the axis, but at the top of the bar.
I have included a simple unit that shows this. I would appreciate help in getting the line to always be positioned at the top of the axis, regardless of the series type, or marks visibility. Maybe there is some other way to do it.
Regards,
Bill
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, TeEngine, Series, ExtCtrls, TeeProcs, Chart, StdCtrls;
type
TForm1 = class(TForm)
Chart1: TChart;
Series1: TBarSeries;
CheckBox1: TCheckBox;
procedure FormCreate(Sender: TObject);
procedure CheckBox1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses
TeeTools;
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
Series1.Marks.Visible := CheckBox1.Checked;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
I: Integer;
ColorLineTool: TColorLineTool;
begin
for I := 0 to 10 do
Series1.Add(I, IntToStr(I));
Series1.Marks.Visible := CheckBox1.Checked;
{ Maximum line }
ColorLineTool := Chart1.Tools.Add(TColorLineTool.Create(Self)) as TColorLineTool;
ColorLineTool.Axis := Chart1.LeftAxis;
ColorLineTool.Style := clMaximum;
end;
end.
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 407
ClientWidth = 617
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object Chart1: TChart
Left = 49
Top = 43
Width = 400
Height = 250
Title.Text.Strings = (
'TChart')
TabOrder = 0
object Series1: TBarSeries
Marks.Callout.Brush.Color = clBlack
Marks.Visible = True
Gradient.Direction = gdTopBottom
XValues.Name = 'X'
XValues.Order = loAscending
YValues.Name = 'Bar'
YValues.Order = loNone
end
end
object CheckBox1: TCheckBox
Left = 23
Top = 10
Width = 97
Height = 17
Caption = 'CheckBox1'
TabOrder = 1
OnClick = CheckBox1Click
end
end
TColorLineTool glitch
Hi Bill,
The problem is that when you have your axis maximum set to auto (Chart1.Axes.Left.AutomaticMaximum is true) the ChartRect is recalculated to fit the marks (if they're visible) but Chart1.Axes.Left.Maximum is not changed. So to draw your line at the top of the ChartRect you should replace this line:
for this anotherone:
The problem is that when you have your axis maximum set to auto (Chart1.Axes.Left.AutomaticMaximum is true) the ChartRect is recalculated to fit the marks (if they're visible) but Chart1.Axes.Left.Maximum is not changed. So to draw your line at the top of the ChartRect you should replace this line:
Code: Select all
ColorLineTool.Style := clMaximum;
Code: Select all
ColorLineTool.Value := Chart1.Axes.Left.CalcPosPoint(Chart1.Axes.Left.IStartPos);
Best Regards,
Yeray Alonso Development & Support Steema Software Av. Montilivi 33, 17003 Girona, Catalonia (SP) | |
Please read our Bug Fixing Policy |
I tried what you suggested but got the same result. I included my modified code below. Note: I moved the creation of the lines into the AfterDraw event. I also gave the top and bottom lines different colors to make it easier to see what is happening. With this code, the lines aren't right when I zoom either.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, TeEngine, Series, ExtCtrls, TeeProcs, Chart, StdCtrls;
type
TForm1 = class(TForm)
Chart1: TChart;
Series1: TBarSeries;
CheckBox1: TCheckBox;
Series2: TPointSeries;
procedure FormCreate(Sender: TObject);
procedure CheckBox1Click(Sender: TObject);
procedure Chart1AfterDraw(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses
TeeTools;
procedure TForm1.Chart1AfterDraw(Sender: TObject);
var
AAxes: Integer;
ColorLineTool: TColorLineTool;
begin
Chart1.Tools.Clear;
for AAxes := 0 to Pred(Chart1.AxesList.Count) do
if (Chart1.AxesList.Items[AAxes].Title.Caption = 'Left 1') or
(Chart1.AxesList.Items[AAxes].Title.Caption = 'Custom 1') then
begin
{ Minimum line }
ColorLineTool := Chart1.Tools.Add(TColorLineTool.Create(Self)) as TColorLineTool;
ColorLineTool.Axis := Chart1.AxesList.Items[AAxes];
ColorLineTool.Style := clMinimum;
ColorLineTool.Pen.Color := clGreen;
ColorLineTool.Pen.Width := 2;
{ Maximum line }
ColorLineTool := Chart1.Tools.Add(TColorLineTool.Create(Self)) as TColorLineTool;
ColorLineTool.Axis := Chart1.AxesList.Items[AAxes];
ColorLineTool.Value := ColorLineTool.Axis.CalcPosPoint(ColorLineTool.Axis.IStartPos);
ColorLineTool.Pen.Color := clRed;
ColorLineTool.Pen.Width := 2;
end;
end;
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
Series1.Marks.Visible := CheckBox1.Checked;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
I: Integer;
begin
for I := 0 to 10 do
begin
Series1.Add(I, IntToStr(I));
Series2.Add(I, IntToStr(I));
end;
Series1.Marks.Visible := CheckBox1.Checked;
Chart1.Draw;
end;
end.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, TeEngine, Series, ExtCtrls, TeeProcs, Chart, StdCtrls;
type
TForm1 = class(TForm)
Chart1: TChart;
Series1: TBarSeries;
CheckBox1: TCheckBox;
Series2: TPointSeries;
procedure FormCreate(Sender: TObject);
procedure CheckBox1Click(Sender: TObject);
procedure Chart1AfterDraw(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses
TeeTools;
procedure TForm1.Chart1AfterDraw(Sender: TObject);
var
AAxes: Integer;
ColorLineTool: TColorLineTool;
begin
Chart1.Tools.Clear;
for AAxes := 0 to Pred(Chart1.AxesList.Count) do
if (Chart1.AxesList.Items[AAxes].Title.Caption = 'Left 1') or
(Chart1.AxesList.Items[AAxes].Title.Caption = 'Custom 1') then
begin
{ Minimum line }
ColorLineTool := Chart1.Tools.Add(TColorLineTool.Create(Self)) as TColorLineTool;
ColorLineTool.Axis := Chart1.AxesList.Items[AAxes];
ColorLineTool.Style := clMinimum;
ColorLineTool.Pen.Color := clGreen;
ColorLineTool.Pen.Width := 2;
{ Maximum line }
ColorLineTool := Chart1.Tools.Add(TColorLineTool.Create(Self)) as TColorLineTool;
ColorLineTool.Axis := Chart1.AxesList.Items[AAxes];
ColorLineTool.Value := ColorLineTool.Axis.CalcPosPoint(ColorLineTool.Axis.IStartPos);
ColorLineTool.Pen.Color := clRed;
ColorLineTool.Pen.Width := 2;
end;
end;
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
Series1.Marks.Visible := CheckBox1.Checked;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
I: Integer;
begin
for I := 0 to 10 do
begin
Series1.Add(I, IntToStr(I));
Series2.Add(I, IntToStr(I));
end;
Series1.Marks.Visible := CheckBox1.Checked;
Chart1.Draw;
end;
end.
Hi Bill,
I'm sorry but I'm not sure to understand what exactly you need. Why have you moved the Lines creation to OnAfterDraw event? You want to have always a line at the top of the chart and anotherone at the bottom?
I've modified your new OnAfterDraw event to achieve it and it remains:
And the form:
I'm sorry but I'm not sure to understand what exactly you need. Why have you moved the Lines creation to OnAfterDraw event? You want to have always a line at the top of the chart and anotherone at the bottom?
I've modified your new OnAfterDraw event to achieve it and it remains:
Code: Select all
procedure TForm1.Chart1AfterDraw(Sender: TObject);
var
AAxes: Integer;
ColorLineTool: TColorLineTool;
begin
Chart1.Tools.Clear;
for AAxes := 0 to Pred(Chart1.AxesList.Count) do
if (Chart1.AxesList.Items[AAxes].Title.Caption = 'Custom 1') then
begin
{ Minimum line }
ColorLineTool := Chart1.Tools.Add(TColorLineTool.Create(Self)) as TColorLineTool;
ColorLineTool.Axis := Chart1.AxesList.Items[AAxes];
ColorLineTool.Style := clMinimum;
ColorLineTool.Pen.Color := clGreen;
ColorLineTool.Pen.Width := 2;
end
else if (Chart1.AxesList.Items[AAxes].Title.Caption = 'Left 1') then
begin
{ Maximum line }
ColorLineTool := Chart1.Tools.Add(TColorLineTool.Create(Self)) as TColorLineTool;
ColorLineTool.Axis := Chart1.AxesList.Items[AAxes];
ColorLineTool.Value := Chart1.AxesList.Items[AAxes].IEndPos;
ColorLineTool.Pen.Color := clRed;
ColorLineTool.Pen.Width := 2;
end;
end;
Code: Select all
object Form1: TForm1
Left = 189
Top = 86
Width = 641
Height = 434
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object Chart1: TChart
Left = 49
Top = 43
Width = 512
Height = 310
Title.Text.Strings = (
'TChart')
BottomAxis.Axis.Width = 1
CustomAxes = <
item
Horizontal = False
OtherSide = True
Title.Caption = 'Custom 1'
end>
LeftAxis.Axis.Width = 1
LeftAxis.Title.Caption = 'Left 1'
View3D = False
OnAfterDraw = Chart1AfterDraw
TabOrder = 0
object Series1: TBarSeries
Marks.Arrow.Visible = True
Marks.Callout.Brush.Color = clBlack
Marks.Callout.Arrow.Visible = True
Marks.Visible = True
VertAxis = aCustomVertAxis
Gradient.Direction = gdTopBottom
XValues.Name = 'X'
XValues.Order = loAscending
YValues.Name = 'Bar'
YValues.Order = loNone
CustomVertAxis = 0
end
object Series2: TPointSeries
Marks.Arrow.Visible = True
Marks.Callout.Brush.Color = clBlack
Marks.Callout.Arrow.Visible = True
Marks.Visible = False
ClickableLine = False
Pointer.InflateMargins = True
Pointer.Style = psRectangle
Pointer.Visible = True
XValues.Name = 'X'
XValues.Order = loAscending
YValues.Name = 'Y'
YValues.Order = loNone
end
end
object CheckBox1: TCheckBox
Left = 23
Top = 10
Width = 97
Height = 17
Caption = 'CheckBox1'
TabOrder = 1
OnClick = CheckBox1Click
end
end
Best Regards,
Yeray Alonso Development & Support Steema Software Av. Montilivi 33, 17003 Girona, Catalonia (SP) | |
Please read our Bug Fixing Policy |
When you have multiple axes, one above the other, and in my application I allow up to four, it looks better when there is something to clearly mark where one axis ends and the next starts. I am trying to draw a thick line at the bottom and the top of each axis to achieve this effect. It should look as if I have multiple charts stacked one above the other.
It would look even better if I could place a shape (filled rectangle) between the axes, but I'm not sure how to do that.
Bill
It would look even better if I could place a shape (filled rectangle) between the axes, but I'm not sure how to do that.
Bill
Hi Bill,
I achieved what you requested working with:
-StartPosition and EndPosition percents from Custom axes.
-Chart1.CustomAxes.Items.CalcPosPoint(Chart1.CustomAxes.Items.IEndPos) and IStartPos pixels from Custom Axes.
-Value pixels from Color Line Tools.
-Left, Width, Top, Height pixels from Rectangle Tools.
The following code shows you a complete example. I only added a chart, a combobox and a checkbox in designtime to show everything by code:
I achieved what you requested working with:
-StartPosition and EndPosition percents from Custom axes.
-Chart1.CustomAxes.Items.CalcPosPoint(Chart1.CustomAxes.Items.IEndPos) and IStartPos pixels from Custom Axes.
-Value pixels from Color Line Tools.
-Left, Width, Top, Height pixels from Rectangle Tools.
The following code shows you a complete example. I only added a chart, a combobox and a checkbox in designtime to show everything by code:
Code: Select all
procedure TForm1.FormCreate(Sender: TObject);
const nSeries = 4;
var i: Integer;
begin
Chart1.View3D := false;
Chart1.Title.Visible := false;
Chart1.Legend.Visible := false;
Chart1.MarginLeft := 5;
Chart1.Axes.Bottom.Axis.Width := 1;
for i:=0 to nSeries-1 do
begin
Chart1.AddSeries(TLineSeries);
ComboBox1.Items.Add('Series' + inttostr(i+1));
With Chart1.CustomAxes do
begin
Add;
Chart1.Tools.Add(TColorLineTool);
(Chart1.Tools.Items[i*2] as TColorLineTool).Axis := Items[i];
Chart1.Tools.Add(TColorLineTool);
(Chart1.Tools.Items[(i*2)+1] as TColorLineTool).Axis := Items[i];
Chart1[i].CustomVertAxis := Items[i];
Items[i].PositionUnits := muPixels;
Items[i].Axis.Width := 1;
Items[i].Axis.Color := Chart1[i].Color;
end;
Chart1[i].FillSampleValues();
end;
for i:=0 to Chart1.SeriesCount-2 do
begin
Chart1.Tools.Add(TRectangleTool);
(Chart1.Tools.Items[i+Chart1.SeriesCount*2] as TRectangleTool).PositionUnits := muPixels;
end;
ComboBox1.ItemIndex := 0;
Chart1.Draw;
CalcPositions;
for i:=0 to (Chart1.SeriesCount*2)-1 do
begin
((Chart1.Tools.Items[i]) as TColorLineTool).AllowDrag := false;
end;
end;
procedure TForm1.ComboBox1Change(Sender: TObject);
begin
CheckBox1.Checked := Chart1[ComboBox1.ItemIndex].Marks.Visible;
end;
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
Chart1[ComboBox1.ItemIndex].Marks.Visible := CheckBox1.Checked;
Chart1.Draw;
CalcPositions;
end;
procedure TForm1.CalcPositions;
var percent, i: Integer;
begin
percent := 100 div Chart1.SeriesCount;
for i := 0 to Chart1.CustomAxes.Count-1 do
begin
With Chart1.CustomAxes do
begin
Items[i].StartPosition := (percent * i) + percent/5;
Items[i].EndPosition := (percent * (i+1)) - percent/5;
((Chart1.Tools.Items[(i*2)+1]) as TColorLineTool).Value := Items[i].CalcPosPoint(Items[i].IEndPos);
((Chart1.Tools.Items[i*2]) as TColorLineTool).Value := Items[i].CalcPosPoint(Items[i].IStartPos);
end;
end;
Chart1.Draw;
for i := (Chart1.SeriesCount*2) to (Chart1.SeriesCount*2 + Chart1.SeriesCount-2) do
begin
With (Chart1.Tools.Items[i] as TRectangleTool), Chart1.CustomAxes do
begin
Left := Chart1.ChartRect.Left;
Width := Chart1.ChartRect.Right-Chart1.ChartRect.Left+2;
Top := Items[i-(Chart1.SeriesCount*2)].IEndPos;
Height := Items[i-(Chart1.SeriesCount*2)+1].IStartPos - Items[i-(Chart1.SeriesCount*2)].IEndPos + 2;
AllowDrag := false;
AllowResize := false;
end;
end;
end;
Best Regards,
Yeray Alonso Development & Support Steema Software Av. Montilivi 33, 17003 Girona, Catalonia (SP) | |
Please read our Bug Fixing Policy |