TAChart: Add wordwrapping feature to axis title.

git-svn-id: trunk@64799 -
This commit is contained in:
wp 2021-03-14 00:27:35 +00:00
parent 970b6b43d6
commit 2d5c00038e
4 changed files with 133 additions and 15 deletions

View File

@ -116,11 +116,14 @@ type
FRange: TChartRange;
FTitle: TChartAxisTitle;
FTransformations: TChartAxisTransformations;
FWrappedTitle: String;
FZPosition: TChartDistance;
function GetMarks: TChartAxisMarks; inline;
function GetRealTitle: String;
function GetValue(AIndex: Integer): TChartValueText; inline;
function GetValueCount: Integer; inline;
function IsWordwrappedTitle: Boolean;
function PositionIsStored: Boolean;
procedure SetAtDataOnly(AValue: Boolean);
procedure SetAxisPen(AValue: TChartAxisPen);
@ -139,6 +142,7 @@ type
procedure SetTitle(AValue: TChartAxisTitle);
procedure SetTransformations(AValue: TChartAxisTransformations);
procedure SetZPosition(AValue: TChartDistance);
procedure WordwrapTitle(ADrawer: IChartDrawer; AClipRect: TRect);
protected
function GetDisplayName: String; override;
@ -160,8 +164,8 @@ type
function IsFlipped: Boolean; override;
function IsPointInside(const APoint: TPoint): Boolean;
function IsVertical: Boolean; inline;
procedure Measure(
const AExtent: TDoubleRect; var AMeasureData: TChartAxisGroup);
procedure Measure(const AExtent: TDoubleRect; const AClipRect: TRect;
var AMeasureData: TChartAxisGroup);
function MeasureLabelSize(ADrawer: IChartDrawer): Integer;
function PositionToCoord(const ARect: TRect): Integer;
procedure PrepareHelper(
@ -235,8 +239,8 @@ type
procedure Draw(ACurrentZ: Integer; var AIndex: Integer);
function GetAxisByAlign(AAlign: TChartAxisAlignment): TChartAxis;
function GetEnumerator: TChartAxisEnumerator;
function Measure(
const AExtent: TDoubleRect; ADepth: Integer): TChartAxisMargins;
function Measure(const AExtent: TDoubleRect; const AClipRect: TRect;
ADepth: Integer): TChartAxisMargins;
procedure Prepare(ARect: TRect);
procedure PrepareGroups;
procedure SetAxisByAlign(AAlign: TChartAxisAlignment; AValue: TChartAxis);
@ -276,7 +280,8 @@ type
implementation
uses
LResources, Math, PropEdits, TAChartStrConsts, TAGeometry, TAMath;
LResources, Math, PropEdits,
TAChartStrConsts, TAGeometry, TAMath;
var
VIdentityTransform: TChartAxisTransformations;
@ -636,7 +641,7 @@ begin
end;
TPointBoolArr(p)[IsVertical] := FTitlePos;
p += FHelper.FZOffset;
Title.DrawLabel(FHelper.FDrawer, p, p, Title.Caption, FTitlePolygon);
Title.DrawLabel(FHelper.FDrawer, p, p, GetRealTitle, FTitlePolygon);
end;
function TChartAxis.GetAlignment: TChartAxisAlignment;
@ -665,6 +670,14 @@ begin
Result := TChartAxisMarks(inherited Marks);
end{%H-}; // to silence the compiler warning of impossible inherited inside inline proc
function TChartAxis.GetRealTitle: String;
begin
if Title.Visible and IsWordwrappedTitle then
Result := FWrappedTitle
else
Result := Title.Caption;
end;
procedure TChartAxis.GetMarkValues;
var
i: Integer;
@ -763,6 +776,13 @@ begin
Result := Alignment in [calLeft, calRight];
end;
function TChartAxis.IsWordwrappedTitle: Boolean;
begin
Result := Title.Wordwrap and (
((FAlignment in [calLeft, calRight]) and (abs(Title.LabelFont.Orientation) = 900)) or
((FAlignment in [calTop, calBottom]) and (Title.LabelFont.Orientation = 0)) );
end;
function TChartAxis.MakeValuesInRangeParams(
AMin, AMax: Double): TValuesInRangeParams;
begin
@ -779,7 +799,7 @@ begin
end;
procedure TChartAxis.Measure(
const AExtent: TDoubleRect; var AMeasureData: TChartAxisGroup);
const AExtent: TDoubleRect; const AClipRect: TRect; var AMeasureData: TChartAxisGroup);
var
v: Boolean;
d: IChartDrawer;
@ -788,7 +808,7 @@ var
begin
if not Title.Visible or (Title.Caption = '') then exit(0);
// Workaround for issue #19780, fix after upgrade to FPC 2.6.
with Title.MeasureLabel(d, Title.Caption) do
with Title.MeasureLabel(d, GetRealTitle) do
Result := IfThen(v, cx, cy);
if Title.DistanceToCenter then
Result := Result div 2;
@ -856,11 +876,16 @@ begin
maxi := i;
end;
end;
if Title.Visible and IsWordwrappedTitle then
WordwrapTitle(d, AClipRect);
with AMeasureData do begin
FSize := Max(sz, FSize);
FTitleSize := Max(TitleSize, FTitleSize);
FMargin := Max(Margin, FMargin);
end;
if minc < MaxInt then begin
UpdateFirstLast(minc, mini, rmin, rmax);
UpdateFirstLast(maxc, maxi, rmin, rmax);
@ -1139,6 +1164,24 @@ begin
end;
}
procedure TChartAxis.WordwrapTitle(ADrawer: IChartDrawer; AClipRect: TRect);
var
w: Integer;
begin
if Alignment in [calLeft, calRight] then
w := AClipRect.Height
else if Alignment in [calBottom, calTop] then
w := AClipRect.Width
else
begin
FWrappedTitle := Title.Caption;
exit;
end;
ADrawer.Font := Title.LabelFont;
FWrappedTitle := TADrawUtils.WordWrap(Title.Caption, ADrawer, w, Title.TextFormat);
end;
{ TChartAxisList }
function TChartAxisList.Add: TChartAxis; inline;
@ -1210,8 +1253,8 @@ begin
AList.Sort(ACompare);
end;
function TChartAxisList.Measure(
const AExtent: TDoubleRect; ADepth: Integer): TChartAxisMargins;
function TChartAxisList.Measure(const AExtent: TDoubleRect;
const AClipRect: TRect; ADepth: Integer): TChartAxisMargins;
var
g: ^TChartAxisGroup;
@ -1239,14 +1282,14 @@ begin
for j := 0 to g^.FCount - 1 do begin
axis := TChartAxis(FGroupOrder[ai]);
try
axis.Measure(AExtent, g^);
axis.Measure(AExtent, AClipRect, g^);
except
axis.Visible := false;
raise;
end;
ai += 1;
end;
// Axises of the same group should have the same Alignment, Position and ZPosition.
// Axes of the same group should have the same Alignment, Position and ZPosition.
if axis.IsDefaultPosition then
Result[axis.Alignment] += Max(0,
g^.FSize + g^.FTitleSize + g^.FMargin +

View File

@ -41,11 +41,13 @@ type
strict private
FCaption: String;
FPositionOnMarks: Boolean;
FWordwrap: Boolean;
function GetFont: TFont;
procedure SetCaption(AValue: String);
procedure SetFont(AValue: TFont);
procedure SetPositionOnMarks(AValue: Boolean);
procedure SetWordwrap(AValue: Boolean);
public
constructor Create(AOwner: TCustomChart);
@ -60,6 +62,7 @@ type
read FPositionOnMarks write SetPositionOnMarks default false;
property TextFormat;
property Visible default false;
property Wordwrap: Boolean read FWordwrap write SetWordwrap default false;
end;
ICoordTransformer = interface
@ -603,6 +606,14 @@ begin
StyleChanged(Self);
end;
procedure TChartAxisTitle.SetWordwrap(AValue: Boolean);
begin
if FWordwrap = AValue then exit;
FWordwrap := AValue;
StyleChanged(Self);
end;
{ TCustomChartAxisMarks }
constructor TCustomChartAxisMarks.Create(AOwner: TCustomChart);

View File

@ -15,7 +15,7 @@ unit TADrawUtils;
interface
uses
Classes, FPCanvas, FPImage, Types, TAChartUtils;
SysUtils, Classes, FPCanvas, FPImage, Types, TAChartUtils;
type
// Same types as in Graphics unit, but without dependency.
@ -191,10 +191,14 @@ type
function FPColorToChartColor(AFPColor: TFPColor): TChartColor;
function ColorDef(AColor, ADefaultColor: TChartColor): TChartColor; inline;
function Wordwrap(const AText: String; ADrawer: IChartDrawer;
AMaxWidth: Integer; ATextFormat: TChartTextFormat): String;
implementation
uses
Math, fasthtmlparser, htmlutil, TAGeometry, TAHtml;
StrUtils, Math, fasthtmlparser, htmlutil, TAGeometry, TAHtml;
const
LINE_INTERVAL = 2;
@ -798,5 +802,65 @@ begin
Result := TChartTextOut.Create(Self);
end;
// Inserts LineEndings into the provided string AText such that its width
// does not exceed the given width.
function WordWrap(const AText: String; ADrawer: IChartDrawer;
AMaxWidth: Integer; ATextFormat: TChartTextFormat): string;
var
L: TStrings;
sa: TStringArray;
line, testline: String;
s: String;
w, ws, wspace: Integer;
i: Integer;
begin
Result := '';
if ATextFormat = tfNormal then
begin
wspace := ADrawer.TextExtent(' ').X;
L := TStringList.Create;
try
L.Text := AText;
for i := 0 to L.Count-1 do
begin
sa := SplitString(L[i], ' ');
line := '';
w := 0;
for s in sa do
begin
ws := ADrawer.TextExtent(s).X;
if w + wspace + ws <= AMaxWidth then
begin
line := IfThen(line='', s, line + ' ' + s);
w := w + wspace + ws;
end else
begin
if line = '' then
begin
Result := IfThen(Result='', s, Result + LineEnding + s);
line := '';
w := 0;
end else
begin
Result := IfThen(Result='', line, Result + LineEnding + line);
line := s;
w := ws;
end;
end;
end;
if line <> '' then
Result := IfThen(Result='', line, Result + LineEnding + line);
if i <> L.Count-1 then
Result := Result + LineEnding;
end;
finally
L.Free;
end;
end else
// ToDo: Implement wordwrap for html format
Result := AText;
end;
end.

View File

@ -1521,7 +1521,7 @@ begin
CalculateTransformationCoeffs(scSeriesMargins, scChartMargins, scMinDataSpace);
cr := FClipRect;
for tries := 1 to 10 do begin
axisMargin := AxisList.Measure(CurrentExtent, scDepth);
axisMargin := AxisList.Measure(CurrentExtent, FClipRect, scDepth);
axisMargin[calLeft] := Max(axisMargin[calLeft], scDepth);
axisMargin[calBottom] := Max(axisMargin[calBottom], scDepth);
FClipRect := cr;