TAChart: Add Marks.YIndex property, implement labels for stacked series

git-svn-id: trunk@30588 -
This commit is contained in:
ask 2011-05-06 15:27:27 +00:00
parent 88a88c1b2b
commit 553a073919
4 changed files with 58 additions and 19 deletions

View File

@ -165,7 +165,7 @@ type
function Count: Integer; inline; function Count: Integer; inline;
procedure Delete(AIndex: Integer); virtual; procedure Delete(AIndex: Integer); virtual;
function Extent: TDoubleRect; virtual; function Extent: TDoubleRect; virtual;
function FormattedMark(AIndex: Integer): String; function FormattedMark(AIndex: Integer; AYIndex: Integer = 0): String;
function IsEmpty: Boolean; override; function IsEmpty: Boolean; override;
function ListSource: TListChartSource; function ListSource: TListChartSource;
property Source: TCustomChartSource property Source: TCustomChartSource
@ -192,7 +192,6 @@ type
function GetLabelDirection(AIndex: Integer): TLabelDirection; function GetLabelDirection(AIndex: Integer): TLabelDirection;
procedure SetMarkPositions(AValue: TLinearMarkPositions); procedure SetMarkPositions(AValue: TLinearMarkPositions);
procedure SetUseReticule(AValue: Boolean); procedure SetUseReticule(AValue: Boolean);
protected protected
FGraphPoints: array of TDoublePoint; FGraphPoints: array of TDoublePoint;
FLoBound: Integer; FLoBound: Integer;
@ -555,12 +554,12 @@ begin
Result := Source.ExtentCumulative; Result := Source.ExtentCumulative;
end; end;
function TChartSeries.FormattedMark(AIndex: integer): String; function TChartSeries.FormattedMark(AIndex, AYIndex: Integer): String;
begin begin
if Assigned(FOnGetMark) then if Assigned(FOnGetMark) then
FOnGetMark(Result, AIndex) FOnGetMark(Result, AIndex)
else else
Result := Source.FormatItem(Marks.Format, AIndex); Result := Source.FormatItem(Marks.Format, AIndex, AYIndex);
end; end;
procedure TChartSeries.GetBounds(var ABounds: TDoubleRect); procedure TChartSeries.GetBounds(var ABounds: TDoubleRect);
@ -767,14 +766,26 @@ var
var var
g: TDoublePoint; g: TDoublePoint;
i: Integer; i, si: Integer;
ld: TLabelDirection;
begin begin
if not Marks.IsMarkLabelsVisible then exit; if not Marks.IsMarkLabelsVisible then exit;
for i := 0 to Count - 1 do begin for i := 0 to Count - 1 do begin
g := GetGraphPoint(i); g := GetGraphPoint(i);
ld := GetLabelDirection(i);
for si := 0 to Source.YCount - 1 do begin
if si > 0 then
if IsRotated then
g.X += AxisToGraphY(Source[i]^.YList[si - 1])
else
g.Y += AxisToGraphY(Source[i]^.YList[si - 1]);
with ParentChart do with ParentChart do
if IsPointInViewPort(g) then if
DrawLabel(FormattedMark(i), GraphToImage(g), GetLabelDirection(i)); (Marks.YIndex = MARKS_YINDEX_ALL) or (Marks.YIndex = si) and
IsPointInViewPort(g)
then
DrawLabel(FormattedMark(i, si), GraphToImage(g), ld);
end;
end; end;
end; end;

View File

@ -32,11 +32,15 @@ type
// Like TColor, but avoiding dependency on Graphics. // Like TColor, but avoiding dependency on Graphics.
TChartColor = -$7FFFFFFF-1..$7FFFFFFF; TChartColor = -$7FFFFFFF-1..$7FFFFFFF;
TChartDataItem = record { TChartDataItem }
TChartDataItem = object
public
X, Y: Double; X, Y: Double;
Color: TChartColor; Color: TChartColor;
Text: String; Text: String;
YList: TDoubleDynArray; YList: TDoubleDynArray;
function GetY(AIndex: Integer): Double;
end; end;
PChartDataItem = ^TChartDataItem; PChartDataItem = ^TChartDataItem;
@ -73,7 +77,8 @@ type
function ExtentCumulative: TDoubleRect; function ExtentCumulative: TDoubleRect;
function ExtentList: TDoubleRect; function ExtentList: TDoubleRect;
procedure FindBounds(AXMin, AXMax: Double; out ALB, AUB: Integer); procedure FindBounds(AXMin, AXMax: Double; out ALB, AUB: Integer);
function FormatItem(const AFormat: String; AIndex: Integer): String; function FormatItem(
const AFormat: String; AIndex, AYIndex: Integer): String;
function IsSorted: Boolean; virtual; function IsSorted: Boolean; virtual;
procedure ValuesInRange( procedure ValuesInRange(
AMin, AMax: Double; const AFormat: String; AUseY: Boolean; AMin, AMax: Double; const AFormat: String; AUseY: Boolean;
@ -130,6 +135,17 @@ begin
AItem.YList[i] := 0; AItem.YList[i] := 0;
end; end;
{ TChartDataItem }
function TChartDataItem.GetY(AIndex: Integer): Double;
begin
AIndex := EnsureRange(AIndex, 0, Length(YList));
if AIndex = 0 then
Result := Y
else
Result := YList[AIndex - 1];
end;
{ TChartSourceBuffer } { TChartSourceBuffer }
procedure TChartSourceBuffer.AddFirst(const AItem: TChartDataItem); procedure TChartSourceBuffer.AddFirst(const AItem: TChartDataItem);
@ -357,19 +373,20 @@ begin
end; end;
function TCustomChartSource.FormatItem( function TCustomChartSource.FormatItem(
const AFormat: String; AIndex: Integer): String; const AFormat: String; AIndex, AYIndex: Integer): String;
const const
TO_PERCENT = 100; TO_PERCENT = 100;
var var
total, percent: Double; total, percent, vy: Double;
begin begin
total := ValuesTotal; total := ValuesTotal;
with Item[AIndex]^ do begin
if total = 0 then if total = 0 then
percent := 0 percent := 0
else else
percent := Y / total * TO_PERCENT; percent := TO_PERCENT / total;
Result := Format(AFormat, [y, percent, Text, total, X]); with Item[AIndex]^ do begin
vy := GetY(AYIndex);
Result := Format(AFormat, [vy, vy * percent, Text, total, X]);
end; end;
end; end;
@ -409,7 +426,7 @@ begin
v := IfThen(AUseY, Item[i]^.Y, Item[i]^.X); v := IfThen(AUseY, Item[i]^.Y, Item[i]^.X);
if not InRange(v, AMin, AMax) then continue; if not InRange(v, AMin, AMax) then continue;
AValues[cnt] := v; AValues[cnt] := v;
ATexts[cnt] := FormatItem(AFormat, i); ATexts[cnt] := FormatItem(AFormat, i, 0);
cnt += 1; cnt += 1;
end; end;
SetLength(AValues, cnt); SetLength(AValues, cnt);

View File

@ -1089,7 +1089,6 @@ begin
for i := 1 to n2 - 2 do for i := 1 to n2 - 2 do
ADrawer.DrawLineDepth(pts[i], pts[i + 1], Depth); ADrawer.DrawLineDepth(pts[i], pts[i + 1], Depth);
ADrawer.Polygon(pts, 0, numPts); ADrawer.Polygon(pts, 0, numPts);
DrawLabels(ADrawer);
end; end;
if AreaLinesPen.Style <> psClear then begin if AreaLinesPen.Style <> psClear then begin
ADrawer.Pen := AreaLinesPen; ADrawer.Pen := AreaLinesPen;
@ -1099,6 +1098,7 @@ begin
ADrawer.Line(ParentChart.GraphToImage(a), ParentChart.GraphToImage(b)); ADrawer.Line(ParentChart.GraphToImage(a), ParentChart.GraphToImage(b));
end; end;
end; end;
DrawLabels(ADrawer);
end; end;
function TAreaSeries.Extent: TDoubleRect; function TAreaSeries.Extent: TDoubleRect;

View File

@ -37,6 +37,7 @@ const
DEF_MARGIN = 4; DEF_MARGIN = 4;
DEF_MARKS_DISTANCE = 20; DEF_MARKS_DISTANCE = 20;
DEF_POINTER_SIZE = 4; DEF_POINTER_SIZE = 4;
MARKS_YINDEX_ALL = -1;
type type
TCustomChart = class(TCustomControl) TCustomChart = class(TCustomControl)
@ -130,12 +131,14 @@ type
TGenericChartMarks = class(TChartElement) TGenericChartMarks = class(TChartElement)
{$ENDIF} {$ENDIF}
private private
FYIndex: Integer;
procedure AddMargins(ADrawer: IChartDrawer; var ASize: TPoint); procedure AddMargins(ADrawer: IChartDrawer; var ASize: TPoint);
function GetDistanceToCenter: Boolean; function GetDistanceToCenter: Boolean;
function LabelAngle: Double; inline; function LabelAngle: Double; inline;
procedure PutLabelFontTo(ADrawer: IChartDrawer); procedure PutLabelFontTo(ADrawer: IChartDrawer);
procedure SetAttachment(AValue: TChartMarkAttachment); procedure SetAttachment(AValue: TChartMarkAttachment);
procedure SetDistanceToCenter(AValue: Boolean); procedure SetDistanceToCenter(AValue: Boolean);
procedure SetYIndex(AValue: Integer);
protected protected
FAdditionalAngle: Double; FAdditionalAngle: Double;
FAttachment: TChartMarkAttachment; FAttachment: TChartMarkAttachment;
@ -194,6 +197,7 @@ type
property Distance: TChartDistance read FDistance write SetDistance; property Distance: TChartDistance read FDistance write SetDistance;
property LabelFont: TFont read FLabelFont write SetLabelFont; property LabelFont: TFont read FLabelFont write SetLabelFont;
property Visible default true; property Visible default true;
property YIndex: Integer read FYIndex write SetYIndex default 0;
end; end;
TChartLinkPen = class(TChartPen) TChartLinkPen = class(TChartPen)
@ -728,6 +732,13 @@ begin
StyleChanged(Self); StyleChanged(Self);
end; end;
procedure TGenericChartMarks.SetYIndex(AValue: Integer);
begin
if FYIndex = AValue then exit;
FYIndex := AValue;
StyleChanged(Self);
end;
{ TChartMarks } { TChartMarks }
procedure TChartMarks.Assign(Source: TPersistent); procedure TChartMarks.Assign(Source: TPersistent);