TAChart: Use IChartDrawer to draw labels

git-svn-id: trunk@29531 -
This commit is contained in:
ask 2011-02-13 17:28:51 +00:00
parent e3c19880f0
commit 829ea72a9d
5 changed files with 78 additions and 59 deletions

View File

@ -479,8 +479,7 @@ var
ADrawer.PrepareSimplePen(TickColor);
LineZ(ATickRect.TopLeft, ATickRect.BottomRight);
ALabelCenter += AZOffset;
Marks.DrawLabel(
ADrawer.Canvas, ALabelCenter, ALabelCenter, AText, prevLabelPoly);
Marks.DrawLabel(ADrawer, ALabelCenter, ALabelCenter, AText, prevLabelPoly);
end;
procedure DrawXMark(AY: Integer; AMark: Double; const AText: String);
@ -492,13 +491,13 @@ var
if Grid.Visible then begin
ADrawer.Pen := Grid;
ADrawer.SetBrushParams(bsClear, clTAColor);
TryApplyStripes(ADrawer, stripeIndex);
BarZ(prevCoord + 1, AClipRect.Top + 1, x, AClipRect.Bottom);
if TryApplyStripes(ADrawer, stripeIndex) then
BarZ(prevCoord + 1, AClipRect.Top + 1, x, AClipRect.Bottom);
LineZ(Point(x, AClipRect.Top), Point(x, AClipRect.Bottom));
prevCoord := x;
end;
d := TickLength + Marks.CenterOffset(ADrawer.Canvas, AText).cy;
d := TickLength + Marks.CenterOffset(ADrawer, AText).cy;
if Alignment = calTop then
d := -d;
DrawLabelAndTick(
@ -514,13 +513,13 @@ var
if Grid.Visible then begin
ADrawer.Pen := Grid;
ADrawer.SetBrushParams(bsClear, clTAColor);
TryApplyStripes(ADrawer, stripeIndex);
BarZ(AClipRect.Left + 1, prevCoord, AClipRect.Right, y);
if TryApplyStripes(ADrawer, stripeIndex) then
BarZ(AClipRect.Left + 1, prevCoord, AClipRect.Right, y);
LineZ(Point(AClipRect.Left, y), Point(AClipRect.Right, y));
prevCoord := y;
end;
d := TickLength + Marks.CenterOffset(ADrawer.Canvas, AText).cx;
d := TickLength + Marks.CenterOffset(ADrawer, AText).cx;
if Alignment = calLeft then
d := -d;
DrawLabelAndTick(
@ -544,7 +543,7 @@ begin
end;
if Grid.Visible and TryApplyStripes(ADrawer, stripeIndex) then
if IsVertical then
BarZ(AClipRect.Left + 1, AClipRect.Top, AClipRect.Right, prevCoord)
BarZ(AClipRect.Left + 1, AClipRect.Top + 1, AClipRect.Right, prevCoord)
else
BarZ(prevCoord + 1, AClipRect.Top + 1, AClipRect.Right, AClipRect.Bottom);
end;
@ -566,7 +565,7 @@ begin
calBottom: p.Y := FTitleRect.Bottom + d;
end;
p += AZOffset;
Title.DrawLabel(ADrawer.Canvas, p, p, Title.Caption, dummy);
Title.DrawLabel(ADrawer, p, p, Title.Caption, dummy);
end;
function TChartAxis.GetDisplayName: string;
@ -650,7 +649,7 @@ procedure TChartAxis.Measure(
if AFirstPass then
t += SOME_DIGIT;
d := IfThen(Marks.DistanceToCenter, 2, 1);
with Marks.MeasureLabel(ADrawer.Canvas, t) do begin
with Marks.MeasureLabel(ADrawer, t) do begin
Result.cx := Max(cx div d, Result.cx);
Result.cy := Max(cy div d, Result.cy);
end;
@ -663,7 +662,7 @@ procedure TChartAxis.Measure(
begin
if not Title.Visible or (Title.Caption = '') then
exit(0);
sz := Title.MeasureLabel(ADrawer.Canvas, Title.Caption);
sz := Title.MeasureLabel(ADrawer, Title.Caption);
Result := IfThen(IsVertical, sz.cx, sz.cy) + Title.Distance;
end;

View File

@ -24,8 +24,8 @@ interface
uses
Classes, Graphics, SysUtils,
TAChartAxis, TAChartUtils, TACustomSource, TAGraph, TALegend, TASources,
TAStyles, TATypes;
TAChartAxis, TAChartUtils, TACustomSource, TADrawUtils, TAGraph, TALegend,
TASources, TAStyles, TATypes;
const
DEF_AXIS_INDEX = -1;
@ -202,7 +202,7 @@ type
procedure PrepareGraphPoints(
const AExtent: TDoubleRect; AFilterByExtent: Boolean);
procedure UpdateGraphPoints(AIndex: Integer);
procedure UpdateMargins(ACanvas: TCanvas; var AMargins: TRect); override;
procedure UpdateMargins(ADrawer: IChartDrawer; var AMargins: TRect); override;
procedure UpdateMinXRange;
property UseReticule: Boolean
read FUseReticule write SetUseReticule default false;
@ -744,6 +744,7 @@ end;
procedure TBasicPointSeries.DrawLabels(ACanvas: TCanvas);
var
prevLabelPoly: TPointArray;
drawer: IChartDrawer;
procedure DrawLabel(
const AText: String; const ADataPoint: TPoint; ADir: TLabelDirection);
@ -754,14 +755,15 @@ var
center: TPoint;
begin
if AText = '' then exit;
center := ADataPoint + OFFSETS[ADir] * Marks.CenterOffset(ACanvas, AText);
Marks.DrawLabel(ACanvas, ADataPoint, center, AText, prevLabelPoly);
center := ADataPoint + OFFSETS[ADir] * Marks.CenterOffset(drawer, AText);
Marks.DrawLabel(drawer, ADataPoint, center, AText, prevLabelPoly);
end;
var
g: TDoublePoint;
i: Integer;
begin
drawer := TCanvasDrawer.Create(ACanvas);
if not Marks.IsMarkLabelsVisible then exit;
for i := 0 to Count - 1 do begin
g := GetGraphPoint(i);
@ -898,7 +900,8 @@ begin
FGraphPoints[i - FLoBound].Y += AxisToGraphY(Source[i]^.YList[AIndex]);
end;
procedure TBasicPointSeries.UpdateMargins(ACanvas: TCanvas; var AMargins: TRect);
procedure TBasicPointSeries.UpdateMargins(
ADrawer: IChartDrawer; var AMargins: TRect);
const
LABEL_TO_BORDER = 4;
var
@ -916,7 +919,7 @@ begin
dir := GetLabelDirection(i);
d := IfThen(Marks.DistanceToCenter, 2, 1);
with Marks.MeasureLabel(ACanvas, labelText) do
with Marks.MeasureLabel(ADrawer, labelText) do
dist := IfThen(dir in [ldLeft, ldRight], cx, cy) div d;
m[dir] := Max(m[dir], dist + Marks.Distance + LABEL_TO_BORDER);
end;

View File

@ -55,13 +55,16 @@ type
{ IChartDrawer }
IChartDrawer = interface
procedure AddToFontOrientation(ADelta: Integer);
procedure ClippingStart(const AClipRect: TRect);
procedure ClippingStart;
procedure ClippingStop;
procedure FillRect(AX1, AY1, AX2, AY2: Integer);
function GetCanvas: TCanvas;
function HasCanvas: Boolean;
procedure Line(AX1, AY1, AX2, AY2: Integer);
procedure Line(const AP1, AP2: TPoint);
procedure Polygon(const APoints: array of TPoint);
procedure PrepareSimplePen(AColor: TChartColor);
procedure RadialPie(
AX1, AY1, AX2, AY2: Integer;
@ -113,6 +116,8 @@ type
procedure SetFont(AFont: TFPCustomFont);
procedure SetPen(APen: TFPCustomPen);
public
procedure AddToFontOrientation(ADelta: Integer);
procedure ClippingStart;
procedure ClippingStart(const AClipRect: TRect);
procedure ClippingStop;
constructor Create(ACanvas: TCanvas);
@ -121,6 +126,7 @@ type
function HasCanvas: Boolean;
procedure Line(AX1, AY1, AX2, AY2: Integer);
procedure Line(const AP1, AP2: TPoint);
procedure Polygon(const APoints: array of TPoint);
procedure PrepareSimplePen(AColor: TChartColor);
procedure RadialPie(
AX1, AY1, AX2, AY2: Integer;
@ -323,12 +329,23 @@ end;
{ TCanvasDrawer }
procedure TCanvasDrawer.AddToFontOrientation(ADelta: Integer);
begin
with FCanvas.Font do
Orientation := Orientation + ADelta;
end;
procedure TCanvasDrawer.ClippingStart(const AClipRect: TRect);
begin
FCanvas.ClipRect := AClipRect;
FCanvas.Clipping := true;
end;
procedure TCanvasDrawer.ClippingStart;
begin
FCanvas.Clipping := true;
end;
procedure TCanvasDrawer.ClippingStop;
begin
FCanvas.Clipping := false;
@ -364,6 +381,11 @@ begin
FCanvas.Line(AP1, AP2);
end;
procedure TCanvasDrawer.Polygon(const APoints: array of TPoint);
begin
FCanvas.Polygon(APoints);
end;
procedure TCanvasDrawer.PrepareSimplePen(AColor: TChartColor);
begin
TADrawUtils.PrepareSimplePen(FCanvas, AColor);

View File

@ -63,7 +63,7 @@ type
procedure SetDepth(AValue: TChartDistance); virtual; abstract;
procedure SetTitle(const AValue: String); virtual; abstract;
procedure SetZPosition(AValue: TChartDistance); virtual; abstract;
procedure UpdateMargins(ACanvas: TCanvas; var AMargins: TRect); virtual;
procedure UpdateMargins(ADrawer: IChartDrawer; var AMargins: TRect); virtual;
procedure VisitSources(
AVisitor: TChartOnSourceVisitor; AAxis: TChartAxis; var AData); virtual;
@ -858,7 +858,7 @@ begin
Result := FMargins.Data;
for i := 0 to SeriesCount - 1 do
if Series[i].Active then
Series[i].UpdateMargins(ADrawer.Canvas, Result);
Series[i].UpdateMargins(ADrawer, Result);
end;
function TChart.GetSeriesCount: Integer;
@ -1285,9 +1285,9 @@ begin
end;
procedure TBasicChartSeries.UpdateMargins(
ACanvas: TCanvas; var AMargins: TRect);
ADrawer: IChartDrawer; var AMargins: TRect);
begin
Unused(ACanvas, AMargins);
Unused(ADrawer, AMargins);
end;
procedure TBasicChartSeries.VisitSources(

View File

@ -128,7 +128,7 @@ type
private
function GetDistanceToCenter: Boolean;
function LabelAngle: Double; inline;
procedure PutLabelFontTo(ACanvas: TCanvas);
procedure PutLabelFontTo(ADrawer: IChartDrawer);
procedure SetAttachment(AValue: TChartMarkAttachment);
procedure SetDistanceToCenter(AValue: Boolean);
protected
@ -160,14 +160,14 @@ type
destructor Destroy; override;
public
procedure Assign(Source: TPersistent); override;
function CenterOffset(ACanvas: TCanvas; const AText: String): TSize;
procedure Assign(ASource: TPersistent); override;
function CenterOffset(ADrawer: IChartDrawer; const AText: String): TSize;
procedure DrawLabel(
ACanvas: TCanvas; const ADataPoint, ALabelCenter: TPoint;
ADrawer: IChartDrawer; const ADataPoint, ALabelCenter: TPoint;
const AText: String; var APrevLabelPoly: TPointArray);
function GetLabelPolygon(ASize: TPoint): TPointArray;
function IsMarkLabelsVisible: Boolean;
function MeasureLabel(ACanvas: TCanvas; const AText: String): TSize;
function MeasureLabel(ADrawer: IChartDrawer; const AText: String): TSize;
procedure SetAdditionalAngle(AAngle: Double);
public
property DistanceToCenter: Boolean
@ -482,10 +482,10 @@ end;
{ TGenericChartMarks }
procedure TGenericChartMarks.Assign(Source: TPersistent);
procedure TGenericChartMarks.Assign(ASource: TPersistent);
begin
if Source is Self.ClassType then
with TGenericChartMarks(Source) do begin
if ASource is Self.ClassType then
with TGenericChartMarks(ASource) do begin
Self.FClipped := FClipped;
Self.FDistance := FDistance;
Self.FFormat := FFormat;
@ -498,15 +498,15 @@ begin
Self.FOverlapPolicy := FOverlapPolicy;
Self.FStyle := FStyle;
end;
inherited Assign(Source);
inherited Assign(ASource);
end;
function TGenericChartMarks.CenterOffset(
ACanvas: TCanvas; const AText: String): TSize;
ADrawer: IChartDrawer; const AText: String): TSize;
begin
Result := Point(Distance, Distance);
if not DistanceToCenter then
Result += MeasureLabel(ACanvas, AText) div 2;
Result += MeasureLabel(ADrawer, AText) div 2;
end;
constructor TGenericChartMarks.Create(AOwner: TCustomChart);
@ -532,16 +532,15 @@ begin
end;
procedure TGenericChartMarks.DrawLabel(
ACanvas: TCanvas; const ADataPoint, ALabelCenter: TPoint;
ADrawer: IChartDrawer; const ADataPoint, ALabelCenter: TPoint;
const AText: String; var APrevLabelPoly: TPointArray);
var
wasClipping: Boolean = false;
labelPoly: TPointArray;
ptText: TPoint;
i: Integer;
begin
PutLabelFontTo(ACanvas);
ptText := MultiLineTextExtent(ACanvas, AText);
PutLabelFontTo(ADrawer);
ptText := ADrawer.TextExtent(AText);
labelPoly := GetLabelPolygon(ptText);
for i := 0 to High(labelPoly) do
labelPoly[i] += ALabelCenter;
@ -553,23 +552,21 @@ begin
exit;
APrevLabelPoly := labelPoly;
if not Clipped and ACanvas.Clipping then begin
ACanvas.Clipping := false;
wasClipping := true;
end;
if not Clipped then
ADrawer.ClippingStop;
ACanvas.Pen.Assign(LinkPen);
ACanvas.Line(ADataPoint, ALabelCenter);
ACanvas.Brush.Assign(LabelBrush);
ADrawer.Pen := LinkPen;
ADrawer.Line(ADataPoint, ALabelCenter);
ADrawer.Brush := LabelBrush;
if IsMarginRequired then begin
ACanvas.Pen.Assign(Frame);
ACanvas.Polygon(labelPoly);
ADrawer.Pen := Frame;
ADrawer.Polygon(labelPoly);
end;
ptText := RotatePoint(-ptText div 2, LabelAngle) + ALabelCenter;
MultiLineTextOut(ACanvas, ptText, AText, taLeftJustify, 0);
if wasClipping then
ACanvas.Clipping := true;
ADrawer.TextOut.Pos(ptText).Text(AText).Done;
if not Clipped then
ADrawer.ClippingStart;
end;
function TGenericChartMarks.GetDistanceToCenter: Boolean;
@ -603,24 +600,22 @@ begin
end;
function TGenericChartMarks.MeasureLabel(
ACanvas: TCanvas; const AText: String): TSize;
ADrawer: IChartDrawer; const AText: String): TSize;
var
sz: TPoint;
begin
PutLabelFontTo(ACanvas);
sz := MultiLineTextExtent(ACanvas, AText);
PutLabelFontTo(ADrawer);
sz := ADrawer.TextExtent(AText);
if IsMarginRequired then
sz += Point(MARKS_MARGIN_X, MARKS_MARGIN_Y) * 2;
Result := MeasureRotatedRect(sz, LabelAngle);
end;
procedure TGenericChartMarks.PutLabelFontTo(ACanvas: TCanvas);
procedure TGenericChartMarks.PutLabelFontTo(ADrawer: IChartDrawer);
begin
with ACanvas.Font do begin
Assign(LabelFont);
if FAdditionalAngle <> 0 then
Orientation := Orientation + RadToOrient(FAdditionalAngle);
end;
ADrawer.Font := LabelFont;
if FAdditionalAngle <> 0 then
ADrawer.AddToFontOrientation(RadToOrient(FAdditionalAngle));
end;
procedure TGenericChartMarks.SetAdditionalAngle(AAngle: Double);