mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-16 04:39:22 +02:00
TAChart: Add new property RotationCenter to TChartTextElement and publish it for axis and series marks.
git-svn-id: trunk@54258 -
This commit is contained in:
parent
f6600384c3
commit
3456985cf7
@ -427,7 +427,6 @@ begin
|
|||||||
Self.FTransformations := Transformations;
|
Self.FTransformations := Transformations;
|
||||||
Self.FZPosition := ZPosition;
|
Self.FZPosition := ZPosition;
|
||||||
Self.FMarginsForMarks := MarginsForMarks;
|
Self.FMarginsForMarks := MarginsForMarks;
|
||||||
|
|
||||||
Self.FOnMarkToText := OnMarkToText;
|
Self.FOnMarkToText := OnMarkToText;
|
||||||
end;
|
end;
|
||||||
inherited Assign(ASource);
|
inherited Assign(ASource);
|
||||||
@ -446,6 +445,7 @@ begin
|
|||||||
TickLength := DEF_TICK_LENGTH;
|
TickLength := DEF_TICK_LENGTH;
|
||||||
FTitle := TChartAxisTitle.Create(ACollection.Owner as TCustomChart);
|
FTitle := TChartAxisTitle.Create(ACollection.Owner as TCustomChart);
|
||||||
FMarginsForMarks := true;
|
FMarginsForMarks := true;
|
||||||
|
FMarks.SetInsideDir(1, 0);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TChartAxis.Destroy;
|
destructor TChartAxis.Destroy;
|
||||||
@ -604,6 +604,7 @@ begin
|
|||||||
FMaxForMarks := Max(FMaxForMarks, GetTransform.AxisToGraph(d.FMax));
|
FMaxForMarks := Max(FMaxForMarks, GetTransform.AxisToGraph(d.FMax));
|
||||||
EnsureOrder(FValueMin, FValueMax);
|
EnsureOrder(FValueMin, FValueMax);
|
||||||
EnsureOrder(FMinForMarks, FMaxForMarks);
|
EnsureOrder(FMinForMarks, FMaxForMarks);
|
||||||
|
FRotationCenter := Marks.RotationCenter;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if Assigned(FOnMarkToText) then
|
if Assigned(FOnMarkToText) then
|
||||||
@ -826,12 +827,21 @@ begin
|
|||||||
FHelper.FAtDataOnly := AtDataOnly;
|
FHelper.FAtDataOnly := AtDataOnly;
|
||||||
FHelper.FMaxForMarks := NegInfinity;
|
FHelper.FMaxForMarks := NegInfinity;
|
||||||
FHelper.FMinForMarks := SafeInfinity;
|
FHelper.FMinForMarks := SafeInfinity;
|
||||||
|
FHelper.FRotationCenter := Marks.RotationCenter;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TChartAxis.SetAlignment(AValue: TChartAxisAlignment);
|
procedure TChartAxis.SetAlignment(AValue: TChartAxisAlignment);
|
||||||
begin
|
begin
|
||||||
if FAlignment = AValue then exit;
|
if FAlignment = AValue then exit;
|
||||||
FAlignment := AValue;
|
FAlignment := AValue;
|
||||||
|
// Define the "inside" direction of an axis such that rotated labels with
|
||||||
|
// rotation center at the text start or end never reach into the chart.
|
||||||
|
case FAlignment of
|
||||||
|
calBottom: FMarks.SetInsideDir(0, +1);
|
||||||
|
calTop : FMarks.SetInsideDir(0, -1);
|
||||||
|
calLeft : FMarks.SetInsideDir(+1, 0);
|
||||||
|
calRight : FMarks.SetInsideDir(-1, 0);
|
||||||
|
end;
|
||||||
StyleChanged(Self);
|
StyleChanged(Self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -134,6 +134,7 @@ type
|
|||||||
property LabelBrush;
|
property LabelBrush;
|
||||||
property OverlapPolicy;
|
property OverlapPolicy;
|
||||||
property Range: TChartRange read FRange write SetRange;
|
property Range: TChartRange read FRange write SetRange;
|
||||||
|
property RotationCenter;
|
||||||
property Source: TCustomChartSource read FSource write SetSource;
|
property Source: TCustomChartSource read FSource write SetSource;
|
||||||
property Stripes;
|
property Stripes;
|
||||||
property Style default smsValue;
|
property Style default smsValue;
|
||||||
@ -223,6 +224,7 @@ type
|
|||||||
FValueMin: Double;
|
FValueMin: Double;
|
||||||
FMaxForMarks: Double;
|
FMaxForMarks: Double;
|
||||||
FMinForMarks: Double;
|
FMinForMarks: Double;
|
||||||
|
FRotationCenter: TChartTextRotationCenter;
|
||||||
FZOffset: TPoint;
|
FZOffset: TPoint;
|
||||||
|
|
||||||
procedure BeginDrawing; virtual;
|
procedure BeginDrawing; virtual;
|
||||||
@ -310,6 +312,7 @@ begin
|
|||||||
Result.FValueMin := FValueMin;
|
Result.FValueMin := FValueMin;
|
||||||
Result.FMinForMarks := FMinForMarks;
|
Result.FMinForMarks := FMinForMarks;
|
||||||
Result.FMaxForMarks := FMaxForMarks;
|
Result.FMaxForMarks := FMaxForMarks;
|
||||||
|
Result.FRotationCenter := FRotationCenter;
|
||||||
Result.FZOffset := FZOffset;
|
Result.FZOffset := FZOffset;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -321,8 +324,7 @@ end;
|
|||||||
procedure TAxisDrawHelper.DrawLabel(ALabelCenter: TPoint; const AText: String);
|
procedure TAxisDrawHelper.DrawLabel(ALabelCenter: TPoint; const AText: String);
|
||||||
begin
|
begin
|
||||||
ALabelCenter += FZOffset;
|
ALabelCenter += FZOffset;
|
||||||
FAxis.Marks.DrawLabel(
|
FAxis.Marks.DrawLabel(FDrawer, ALabelCenter, ALabelCenter, AText, FPrevLabelPoly);
|
||||||
FDrawer, ALabelCenter, ALabelCenter, AText, FPrevLabelPoly);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TAxisDrawHelper.DrawMark(
|
procedure TAxisDrawHelper.DrawMark(
|
||||||
@ -426,7 +428,10 @@ procedure TAxisDrawHelperX.DrawLabelAndTick(
|
|||||||
var
|
var
|
||||||
d, up, down: Integer;
|
d, up, down: Integer;
|
||||||
begin
|
begin
|
||||||
d := FScaledTickLength + FAxis.Marks.CenterOffset(FDrawer, AText).cy;
|
if FRotationCenter = rcCenter then
|
||||||
|
d := FScaledTickLength + FAxis.Marks.CenterOffset(FDrawer, AText).cy
|
||||||
|
else
|
||||||
|
d := FScaledTickLength + FAxis.Marks.CenterHeightOffset(FDrawer, AText).cy;
|
||||||
up := FScaledTickInnerLength;
|
up := FScaledTickInnerLength;
|
||||||
down := FScaledTickLength;
|
down := FScaledTickLength;
|
||||||
if FAxis.Alignment = calTop then begin
|
if FAxis.Alignment = calTop then begin
|
||||||
@ -492,7 +497,10 @@ procedure TAxisDrawHelperY.DrawLabelAndTick(
|
|||||||
var
|
var
|
||||||
d, left, right: Integer;
|
d, left, right: Integer;
|
||||||
begin
|
begin
|
||||||
d := FScaledTickLength + FAxis.Marks.CenterOffset(FDrawer, AText).cx;
|
if FRotationCenter = rcCenter then
|
||||||
|
d := FScaledTickLength + FAxis.Marks.CenterOffset(FDrawer, AText).cx
|
||||||
|
else
|
||||||
|
d := FScaledTickLength + FAxis.Marks.CenterHeightOffset(FDrawer, AText).cx;
|
||||||
left := FScaledTickInnerLength;
|
left := FScaledTickInnerLength;
|
||||||
right := FScaledTickLength;
|
right := FScaledTickLength;
|
||||||
if FAxis.Alignment = calLeft then begin
|
if FAxis.Alignment = calLeft then begin
|
||||||
|
@ -1120,7 +1120,11 @@ var
|
|||||||
center: TPoint;
|
center: TPoint;
|
||||||
begin
|
begin
|
||||||
if AText = '' then exit;
|
if AText = '' then exit;
|
||||||
center := ADataPoint + OFFSETS[ADir] * Marks.CenterOffset(ADrawer, AText);
|
|
||||||
|
if Marks.RotationCenter = rcCenter then
|
||||||
|
center := ADataPoint + OFFSETS[ADir] * Marks.CenterOffset(ADrawer, AText)
|
||||||
|
else
|
||||||
|
center := ADataPoint + OFFSETS[ADir] * Marks.CenterHeightOffset(ADrawer, AText);
|
||||||
Marks.DrawLabel(ADrawer, ADataPoint, center, AText, prevLabelPoly);
|
Marks.DrawLabel(ADrawer, ADataPoint, center, AText, prevLabelPoly);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -40,6 +40,8 @@ type
|
|||||||
TChartLabelShape = (
|
TChartLabelShape = (
|
||||||
clsRectangle, clsEllipse, clsRoundRect, clsRoundSide, clsUserDefined);
|
clsRectangle, clsEllipse, clsRoundRect, clsRoundSide, clsUserDefined);
|
||||||
|
|
||||||
|
TChartTextRotationCenter = (rcCenter, rcEdge, rcLeft, rcRight);
|
||||||
|
|
||||||
TChartTextElement = class;
|
TChartTextElement = class;
|
||||||
|
|
||||||
TChartGetShapeEvent = procedure (
|
TChartGetShapeEvent = procedure (
|
||||||
@ -60,14 +62,18 @@ type
|
|||||||
procedure SetMargins(AValue: TChartLabelMargins);
|
procedure SetMargins(AValue: TChartLabelMargins);
|
||||||
procedure SetOnGetShape(AValue: TChartGetShapeEvent);
|
procedure SetOnGetShape(AValue: TChartGetShapeEvent);
|
||||||
procedure SetOverlapPolicy(AValue: TChartMarksOverlapPolicy);
|
procedure SetOverlapPolicy(AValue: TChartMarksOverlapPolicy);
|
||||||
|
procedure SetRotationCenter(AValue: TChartTextRotationCenter);
|
||||||
procedure SetShape(AValue: TChartLabelShape);
|
procedure SetShape(AValue: TChartLabelShape);
|
||||||
strict protected
|
strict protected
|
||||||
FAlignment: TAlignment;
|
FAlignment: TAlignment;
|
||||||
|
FInsideDir: TDoublePoint;
|
||||||
|
FRotationCenter: TChartTextRotationCenter;
|
||||||
procedure ApplyLabelFont(ADrawer: IChartDrawer); virtual;
|
procedure ApplyLabelFont(ADrawer: IChartDrawer); virtual;
|
||||||
procedure DrawLink(
|
procedure DrawLink(
|
||||||
ADrawer: IChartDrawer; ADataPoint, ALabelCenter: TPoint); virtual;
|
ADrawer: IChartDrawer; ADataPoint, ALabelCenter: TPoint); virtual;
|
||||||
function GetBoundingBox(
|
function GetBoundingBox(
|
||||||
ADrawer: IChartDrawer; const ATextSize: TPoint): TRect;
|
ADrawer: IChartDrawer; const ATextSize: TPoint): TRect;
|
||||||
|
function GetTextShiftNeeded: Boolean;
|
||||||
function IsMarginRequired: Boolean;
|
function IsMarginRequired: Boolean;
|
||||||
strict protected
|
strict protected
|
||||||
function GetFrame: TChartPen; virtual; abstract;
|
function GetFrame: TChartPen; virtual; abstract;
|
||||||
@ -75,6 +81,8 @@ type
|
|||||||
function GetLabelBrush: TBrush; virtual; abstract;
|
function GetLabelBrush: TBrush; virtual; abstract;
|
||||||
function GetLabelFont: TFont; virtual; abstract;
|
function GetLabelFont: TFont; virtual; abstract;
|
||||||
function GetLinkPen: TChartPen; virtual;
|
function GetLinkPen: TChartPen; virtual;
|
||||||
|
property RotationCenter: TChartTextRotationCenter
|
||||||
|
read FRotationCenter write SetRotationCenter default rcCenter;
|
||||||
public
|
public
|
||||||
constructor Create(AOwner: TCustomChart);
|
constructor Create(AOwner: TCustomChart);
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
@ -86,6 +94,8 @@ type
|
|||||||
function GetLabelPolygon(
|
function GetLabelPolygon(
|
||||||
ADrawer: IChartDrawer; ASize: TPoint): TPointArray;
|
ADrawer: IChartDrawer; ASize: TPoint): TPointArray;
|
||||||
function MeasureLabel(ADrawer: IChartDrawer; const AText: String): TSize;
|
function MeasureLabel(ADrawer: IChartDrawer; const AText: String): TSize;
|
||||||
|
function MeasureLabelHeight(ADrawer: IChartDrawer; const AText: String): TSize;
|
||||||
|
procedure SetInsideDir(dx, dy: Double);
|
||||||
public
|
public
|
||||||
property CalloutAngle: Cardinal
|
property CalloutAngle: Cardinal
|
||||||
read FCalloutAngle write SetCalloutAngle default 0;
|
read FCalloutAngle write SetCalloutAngle default 0;
|
||||||
@ -203,6 +213,7 @@ type
|
|||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
public
|
public
|
||||||
procedure Assign(ASource: TPersistent); override;
|
procedure Assign(ASource: TPersistent); override;
|
||||||
|
function CenterHeightOffset(ADrawer: IChartDrawer; const AText: String): TSize;
|
||||||
function CenterOffset(ADrawer: IChartDrawer; const AText: String): TSize;
|
function CenterOffset(ADrawer: IChartDrawer; const AText: String): TSize;
|
||||||
function IsMarkLabelsVisible: Boolean;
|
function IsMarkLabelsVisible: Boolean;
|
||||||
procedure SetAdditionalAngle(AAngle: Double);
|
procedure SetAdditionalAngle(AAngle: Double);
|
||||||
@ -265,6 +276,7 @@ type
|
|||||||
property LinkDistance;
|
property LinkDistance;
|
||||||
property LinkPen;
|
property LinkPen;
|
||||||
property OverlapPolicy;
|
property OverlapPolicy;
|
||||||
|
property RotationCenter;
|
||||||
property Style default smsNone;
|
property Style default smsNone;
|
||||||
property YIndex;
|
property YIndex;
|
||||||
end;
|
end;
|
||||||
@ -288,6 +300,7 @@ begin
|
|||||||
Self.FMargins.Assign(FMargins);
|
Self.FMargins.Assign(FMargins);
|
||||||
Self.FOverlapPolicy := FOverlapPolicy;
|
Self.FOverlapPolicy := FOverlapPolicy;
|
||||||
Self.FShape := FShape;
|
Self.FShape := FShape;
|
||||||
|
Self.FInsideDir := FInsideDir;
|
||||||
end;
|
end;
|
||||||
inherited Assign(ASource);
|
inherited Assign(ASource);
|
||||||
end;
|
end;
|
||||||
@ -311,7 +324,7 @@ procedure TChartTextElement.DrawLabel(
|
|||||||
const AText: String; var APrevLabelPoly: TPointArray);
|
const AText: String; var APrevLabelPoly: TPointArray);
|
||||||
var
|
var
|
||||||
labelPoly: TPointArray;
|
labelPoly: TPointArray;
|
||||||
ptText: TPoint;
|
ptText, P: TPoint;
|
||||||
i, w: Integer;
|
i, w: Integer;
|
||||||
begin
|
begin
|
||||||
ApplyLabelFont(ADrawer);
|
ApplyLabelFont(ADrawer);
|
||||||
@ -324,8 +337,7 @@ begin
|
|||||||
labelPoly := MakeCallout(
|
labelPoly := MakeCallout(
|
||||||
labelPoly, ALabelCenter, ADataPoint, OrientToRad(CalloutAngle));
|
labelPoly, ALabelCenter, ADataPoint, OrientToRad(CalloutAngle));
|
||||||
|
|
||||||
if
|
if (OverlapPolicy = opHideNeighbour) and
|
||||||
(OverlapPolicy = opHideNeighbour) and
|
|
||||||
IsPolygonIntersectsPolygon(APrevLabelPoly, labelPoly)
|
IsPolygonIntersectsPolygon(APrevLabelPoly, labelPoly)
|
||||||
then
|
then
|
||||||
exit;
|
exit;
|
||||||
@ -344,7 +356,18 @@ begin
|
|||||||
ADrawer.Polygon(labelPoly, 0, Length(labelPoly));
|
ADrawer.Polygon(labelPoly, 0, Length(labelPoly));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
ptText := RotatePoint(-ptText div 2, GetLabelAngle) + ALabelCenter;
|
case FRotationCenter of
|
||||||
|
rcCenter: P := -ptText div 2;
|
||||||
|
rcEdge,
|
||||||
|
rcLeft : begin
|
||||||
|
P := Point(0, -ptText.y div 2);
|
||||||
|
if (FRotationCenter = rcEdge) and GetTextShiftNeeded then
|
||||||
|
P.x := -ptText.x;
|
||||||
|
end;
|
||||||
|
rcRight : P := Point(-ptText.x, -ptText.y div 2);
|
||||||
|
end;
|
||||||
|
ptText := RotatePoint(P, GetLabelAngle) + ALabelCenter;
|
||||||
|
|
||||||
ADrawer.TextOut.Pos(ptText).Alignment(Alignment).Width(w).Text(AText).Done;
|
ADrawer.TextOut.Pos(ptText).Alignment(Alignment).Width(w).Text(AText).Done;
|
||||||
if not Clipped then
|
if not Clipped then
|
||||||
ADrawer.ClippingStart;
|
ADrawer.ClippingStart;
|
||||||
@ -368,6 +391,18 @@ function TChartTextElement.GetBoundingBox(
|
|||||||
begin
|
begin
|
||||||
Result := ZeroRect;
|
Result := ZeroRect;
|
||||||
InflateRect(Result, ATextSize.X div 2, ATextSize.Y div 2);
|
InflateRect(Result, ATextSize.X div 2, ATextSize.Y div 2);
|
||||||
|
|
||||||
|
case FRotationCenter of
|
||||||
|
rcCenter : ;
|
||||||
|
rcLeft,
|
||||||
|
rcEdge : begin
|
||||||
|
OffsetRect(Result, ATextSize.x div 2, 0);
|
||||||
|
if (FRotationCenter = rcEdge) and GetTextShiftNeeded then
|
||||||
|
OffsetRect(Result, -ATextSize.x, 0);
|
||||||
|
end;
|
||||||
|
rcRight : OffsetRect(Result, -ATextSize.x div 2, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
if IsMarginRequired then
|
if IsMarginRequired then
|
||||||
Margins.ExpandRectScaled(ADrawer, Result);
|
Margins.ExpandRectScaled(ADrawer, Result);
|
||||||
end;
|
end;
|
||||||
@ -413,6 +448,14 @@ begin
|
|||||||
Result := nil;
|
Result := nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TChartTextElement.GetTextShiftNeeded: Boolean;
|
||||||
|
var
|
||||||
|
textdir: TDoublePoint;
|
||||||
|
begin
|
||||||
|
SinCos(-GetLabelAngle, textdir.y, textdir.x);
|
||||||
|
Result := DotProduct(textdir, FInsideDir) > 0;
|
||||||
|
end;
|
||||||
|
|
||||||
function TChartTextElement.IsMarginRequired: Boolean;
|
function TChartTextElement.IsMarginRequired: Boolean;
|
||||||
begin
|
begin
|
||||||
Result := (GetLabelBrush.Style <> bsClear) or GetFrame.EffVisible;
|
Result := (GetLabelBrush.Style <> bsClear) or GetFrame.EffVisible;
|
||||||
@ -426,6 +469,19 @@ begin
|
|||||||
Result := MeasureRotatedRect(Point(Right - Left, Bottom - Top), GetLabelAngle);
|
Result := MeasureRotatedRect(Point(Right - Left, Bottom - Top), GetLabelAngle);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TChartTextElement.MeasureLabelHeight(
|
||||||
|
ADrawer: IChartDrawer; const AText: String): TSize;
|
||||||
|
var
|
||||||
|
R: TRect;
|
||||||
|
begin
|
||||||
|
ApplyLabelFont(ADrawer);
|
||||||
|
R := Rect(0, 0, 0, ADrawer.TextExtent(AText).y);
|
||||||
|
OffsetRect(R, 0, -(R.Bottom - R.Top) div 2);
|
||||||
|
if IsMarginRequired then
|
||||||
|
Margins.ExpandRectScaled(ADrawer, R);
|
||||||
|
Result := MeasureRotatedRect(Point(R.Right - R.Left, R.Bottom - R.Top), GetLabelAngle);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TChartTextElement.SetAlignment(AValue: TAlignment);
|
procedure TChartTextElement.SetAlignment(AValue: TAlignment);
|
||||||
begin
|
begin
|
||||||
if FAlignment = AValue then exit;
|
if FAlignment = AValue then exit;
|
||||||
@ -454,6 +510,11 @@ begin
|
|||||||
StyleChanged(Self);
|
StyleChanged(Self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TChartTextElement.SetInsideDir(dx, dy: Double);
|
||||||
|
begin
|
||||||
|
FInsideDir := DoublePoint(dx, dy);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TChartTextElement.SetOnGetShape(AValue: TChartGetShapeEvent);
|
procedure TChartTextElement.SetOnGetShape(AValue: TChartGetShapeEvent);
|
||||||
begin
|
begin
|
||||||
if TMethod(FOnGetShape) = TMethod(AValue) then exit;
|
if TMethod(FOnGetShape) = TMethod(AValue) then exit;
|
||||||
@ -468,6 +529,13 @@ begin
|
|||||||
StyleChanged(Self);
|
StyleChanged(Self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TChartTextElement.SetRotationCenter(AValue: TChartTextRotationCenter);
|
||||||
|
begin
|
||||||
|
if FRotationCenter = AValue then exit;
|
||||||
|
FRotationCenter := AValue;
|
||||||
|
StyleChanged(Self);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TChartTextElement.SetShape(AValue: TChartLabelShape);
|
procedure TChartTextElement.SetShape(AValue: TChartLabelShape);
|
||||||
begin
|
begin
|
||||||
if FShape = AValue then exit;
|
if FShape = AValue then exit;
|
||||||
@ -624,6 +692,15 @@ begin
|
|||||||
inherited Assign(ASource);
|
inherited Assign(ASource);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TGenericChartMarks.CenterHeightOffset(
|
||||||
|
ADrawer: IChartDrawer; const AText: String): TSize;
|
||||||
|
var
|
||||||
|
d: Integer;
|
||||||
|
begin
|
||||||
|
d := ADrawer.Scale(Distance);
|
||||||
|
Result := Size(d, d) + MeasureLabelHeight(ADrawer, AText) div 2;
|
||||||
|
end;
|
||||||
|
|
||||||
function TGenericChartMarks.CenterOffset(
|
function TGenericChartMarks.CenterOffset(
|
||||||
ADrawer: IChartDrawer; const AText: String): TSize;
|
ADrawer: IChartDrawer; const AText: String): TSize;
|
||||||
var
|
var
|
||||||
|
Loading…
Reference in New Issue
Block a user