TAChart: Use IChartDrawer to draw axises. Add IChartDrawer.ClippingStart ans ClippingStop methods.

git-svn-id: trunk@29530 -
This commit is contained in:
ask 2011-02-13 16:52:50 +00:00
parent 6edfc21f02
commit e3c19880f0
5 changed files with 88 additions and 70 deletions

View File

@ -55,7 +55,7 @@ var
implementation
uses
SysUtils, TAChartAxis, TAChartUtils;
SysUtils, TAChartUtils;
{$R *.lfm}

View File

@ -24,7 +24,8 @@ interface
uses
Classes, Graphics, SysUtils, Types,
TAChartUtils, TACustomSource, TAStyles, TATransformations, TATypes;
TAChartUtils, TACustomSource, TADrawUtils, TAStyles, TATransformations,
TATypes;
const
DEF_TICK_LENGTH = 4;
@ -169,7 +170,8 @@ type
procedure SetZPosition(const AValue: TChartDistance);
procedure StyleChanged(ASender: TObject);
function TryApplyStripes(ACanvas: TCanvas; var AIndex: Cardinal): Boolean;
function TryApplyStripes(
ADrawer: IChartDrawer; var AIndex: Cardinal): Boolean;
protected
function GetDisplayName: string; override;
public
@ -178,13 +180,13 @@ type
public
procedure Assign(Source: TPersistent); override;
procedure Draw(
ACanvas: TCanvas; const AClipRect: TRect;
ADrawer: IChartDrawer; const AClipRect: TRect;
const ATransf: ICoordTransformer; const AZOffset: TPoint);
procedure DrawTitle(
ACanvas: TCanvas; const ACenter, AZOffset: TPoint; ASize: Integer);
ADrawer: IChartDrawer; const ACenter, AZOffset: TPoint; ASize: Integer);
function IsVertical: Boolean; inline;
procedure Measure(
ACanvas: TCanvas; const AExtent: TDoubleRect; AFirstPass: Boolean;
ADrawer: IChartDrawer; const AExtent: TDoubleRect; AFirstPass: Boolean;
var AMeasureData: TChartAxisGroup);
published
property Alignment: TChartAxisAlignment
@ -233,12 +235,12 @@ type
public
function Add: TChartAxis; inline;
procedure Draw(
ACanvas: TCanvas; const AClipRect: TRect;
ADrawer: IChartDrawer; const AClipRect: TRect;
const ATransf: ICoordTransformer; ACurrentZ, AMaxZ: Integer;
var AIndex: Integer);
function GetAxis(AIndex: Integer): TChartAxis;
procedure Measure(
ACanvas: TCanvas; const AExtent: TDoubleRect;
ADrawer: IChartDrawer; const AExtent: TDoubleRect;
AFirstPass: Boolean; var AMargins: TChartAxisMargins);
procedure Prepare(ARect: TRect);
procedure PrepareGroups;
@ -276,7 +278,7 @@ type
implementation
uses
LResources, Math, PropEdits, TADrawUtils, TASources;
LResources, Math, PropEdits, TASources;
type
TAxisDataExtent = record
@ -452,7 +454,7 @@ begin
end;
procedure TChartAxis.Draw(
ACanvas: TCanvas; const AClipRect: TRect;
ADrawer: IChartDrawer; const AClipRect: TRect;
const ATransf: ICoordTransformer; const AZOffset: TPoint);
var
@ -461,34 +463,24 @@ var
prevCoord: Integer;
procedure BarZ(AX1, AY1, AX2, AY2: Integer);
var
oldPenStyle: TPenStyle;
r: TRect;
begin
if ACanvas.Brush.Style = bsClear then exit;
with AZOffset do
r := Rect(AX1 + X + 1, AY1 + Y + 1, AX2 + X + 1, AY2 + Y + 1);
oldPenStyle := ACanvas.Pen.Style;
ACanvas.Pen.Style := psClear;
try
ACanvas.Rectangle(r);
finally
ACanvas.Pen.Style := oldPenStyle;
end;
ADrawer.FillRect(AX1 + X, AY1 + Y, AX2 + X, AY2 + Y);
end;
procedure LineZ(AP1, AP2: TPoint);
begin
ACanvas.Line(AP1 + AZOffset, AP2 + AZOffset);
ADrawer.Line(AP1 + AZOffset, AP2 + AZOffset);
end;
procedure DrawLabelAndTick(
ALabelCenter: TPoint; const ATickRect: TRect; const AText: String);
begin
PrepareSimplePen(ACanvas, TickColor);
ADrawer.PrepareSimplePen(TickColor);
LineZ(ATickRect.TopLeft, ATickRect.BottomRight);
ALabelCenter += AZOffset;
Marks.DrawLabel(ACanvas, ALabelCenter, ALabelCenter, AText, prevLabelPoly);
Marks.DrawLabel(
ADrawer.Canvas, ALabelCenter, ALabelCenter, AText, prevLabelPoly);
end;
procedure DrawXMark(AY: Integer; AMark: Double; const AText: String);
@ -498,15 +490,15 @@ var
x := ATransf.XGraphToImage(AMark);
if Grid.Visible then begin
ACanvas.Pen.Assign(Grid);
ACanvas.Brush.Style := bsClear;
TryApplyStripes(ACanvas, stripeIndex);
BarZ(prevCoord, AClipRect.Top, x, AClipRect.Bottom);
ADrawer.Pen := Grid;
ADrawer.SetBrushParams(bsClear, clTAColor);
TryApplyStripes(ADrawer, stripeIndex);
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(ACanvas, AText).cy;
d := TickLength + Marks.CenterOffset(ADrawer.Canvas, AText).cy;
if Alignment = calTop then
d := -d;
DrawLabelAndTick(
@ -520,15 +512,15 @@ var
y := ATransf.YGraphToImage(AMark);
if Grid.Visible then begin
ACanvas.Pen.Assign(Grid);
ACanvas.Brush.Style := bsClear;
TryApplyStripes(ACanvas, stripeIndex);
BarZ(AClipRect.Left, prevCoord, AClipRect.Right, y);
ADrawer.Pen := Grid;
ADrawer.SetBrushParams(bsClear, clTAColor);
TryApplyStripes(ADrawer, stripeIndex);
BarZ(AClipRect.Left + 1, prevCoord, AClipRect.Right, y);
LineZ(Point(AClipRect.Left, y), Point(AClipRect.Right, y));
prevCoord := y;
end;
d := TickLength + Marks.CenterOffset(ACanvas, AText).cx;
d := TickLength + Marks.CenterOffset(ADrawer.Canvas, AText).cx;
if Alignment = calLeft then
d := -d;
DrawLabelAndTick(
@ -540,7 +532,7 @@ var
v: Double;
begin
if not Visible then exit;
ACanvas.Font := Marks.LabelFont;
ADrawer.Font := Marks.LabelFont;
coord := TChartAxisMargins(FAxisRect)[Alignment];
prevCoord := IfThen(IsVertical, AClipRect.Bottom, AClipRect.Left);
for i := 0 to High(FMarkValues) do begin
@ -550,15 +542,15 @@ begin
else
DrawXMark(coord, v, FMarkTexts[i]);
end;
if Grid.Visible and TryApplyStripes(ACanvas, stripeIndex) then
if Grid.Visible and TryApplyStripes(ADrawer, stripeIndex) then
if IsVertical then
BarZ(AClipRect.Left, AClipRect.Top, AClipRect.Right, prevCoord)
BarZ(AClipRect.Left + 1, AClipRect.Top, AClipRect.Right, prevCoord)
else
BarZ(prevCoord, AClipRect.Top, AClipRect.Right, AClipRect.Bottom);
BarZ(prevCoord + 1, AClipRect.Top + 1, AClipRect.Right, AClipRect.Bottom);
end;
procedure TChartAxis.DrawTitle(
ACanvas: TCanvas; const ACenter, AZOffset: TPoint; ASize: Integer);
ADrawer: IChartDrawer; const ACenter, AZOffset: TPoint; ASize: Integer);
var
p: TPoint;
dummy: TPointArray = nil;
@ -574,7 +566,7 @@ begin
calBottom: p.Y := FTitleRect.Bottom + d;
end;
p += AZOffset;
Title.DrawLabel(ACanvas, p, p, Title.Caption, dummy);
Title.DrawLabel(ADrawer.Canvas, p, p, Title.Caption, dummy);
end;
function TChartAxis.GetDisplayName: string;
@ -635,7 +627,7 @@ begin
end;
procedure TChartAxis.Measure(
ACanvas: TCanvas; const AExtent: TDoubleRect;
ADrawer: IChartDrawer; const AExtent: TDoubleRect;
AFirstPass: Boolean; var AMeasureData: TChartAxisGroup);
function CalcMarksSize(AMin, AMax: Double): TSize;
@ -658,7 +650,7 @@ procedure TChartAxis.Measure(
if AFirstPass then
t += SOME_DIGIT;
d := IfThen(Marks.DistanceToCenter, 2, 1);
with Marks.MeasureLabel(ACanvas, t) do begin
with Marks.MeasureLabel(ADrawer.Canvas, t) do begin
Result.cx := Max(cx div d, Result.cx);
Result.cy := Max(cy div d, Result.cy);
end;
@ -671,7 +663,7 @@ procedure TChartAxis.Measure(
begin
if not Title.Visible or (Title.Caption = '') then
exit(0);
sz := Title.MeasureLabel(ACanvas, Title.Caption);
sz := Title.MeasureLabel(ADrawer.Canvas, Title.Caption);
Result := IfThen(IsVertical, sz.cx, sz.cy) + Title.Distance;
end;
@ -790,11 +782,11 @@ begin
end;
function TChartAxis.TryApplyStripes(
ACanvas: TCanvas; var AIndex: Cardinal): Boolean;
ADrawer: IChartDrawer; var AIndex: Cardinal): Boolean;
begin
Result := Marks.Stripes <> nil;
if not Result then exit;
Marks.Stripes.Apply(ACanvas, AIndex);
Marks.Stripes.Apply(ADrawer.Canvas, AIndex);
AIndex += 1;
end;
@ -844,7 +836,7 @@ begin
end;
procedure TChartAxisList.Draw(
ACanvas: TCanvas; const AClipRect: TRect;
ADrawer: IChartDrawer; const AClipRect: TRect;
const ATransf: ICoordTransformer; ACurrentZ, AMaxZ: Integer;
var AIndex: Integer);
var
@ -855,8 +847,8 @@ begin
if ACurrentZ < ZPosition then break;
zoffset.Y := Min(ZPosition, AMaxZ);
zoffset.X := - zoffset.Y;
Draw(ACanvas, AClipRect, ATransf, zoffset);
DrawTitle(ACanvas, FCenterPoint, zoffset, FGroups[FGroupIndex].FTitleSize);
Draw(ADrawer, AClipRect, ATransf, zoffset);
DrawTitle(ADrawer, FCenterPoint, zoffset, FGroups[FGroupIndex].FTitleSize);
AIndex += 1;
end;
end;
@ -893,7 +885,7 @@ begin
end;
procedure TChartAxisList.Measure(
ACanvas: TCanvas; const AExtent: TDoubleRect;
ADrawer: IChartDrawer; const AExtent: TDoubleRect;
AFirstPass: Boolean; var AMargins: TChartAxisMargins);
var
i, j, ai: Integer;
@ -907,7 +899,7 @@ begin
g^.FTitleSize := 0;
for j := 0 to g^.FCount - 1 do begin
axis := TChartAxis(FGroupOrder[ai]);
axis.Measure(ACanvas, AExtent, AFirstPass, g^);
axis.Measure(ADrawer, AExtent, AFirstPass, g^);
ai += 1;
end;
if AFirstPass then

View File

@ -55,9 +55,13 @@ type
{ IChartDrawer }
IChartDrawer = interface
procedure ClippingStart(const AClipRect: TRect);
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 PrepareSimplePen(AColor: TChartColor);
procedure RadialPie(
AX1, AY1, AX2, AY2: Integer;
@ -109,19 +113,22 @@ type
procedure SetFont(AFont: TFPCustomFont);
procedure SetPen(APen: TFPCustomPen);
public
procedure ClippingStart(const AClipRect: TRect);
procedure ClippingStop;
constructor Create(ACanvas: TCanvas);
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 PrepareSimplePen(AColor: TChartColor);
procedure RadialPie(
AX1, AY1, AX2, AY2: Integer;
AStartAngle16Deg, AAngleLength16Deg: Integer);
procedure Rectangle(const ARect: TRect);
procedure Rectangle(AX1, AY1, AX2, AY2: Integer);
procedure SetPenParams(AStyle: TFPPenStyle; AColor: TChartColor);
procedure SetBrushParams(AStyle: TFPBrushStyle; AColor: TChartColor);
procedure SetPenParams(AStyle: TFPPenStyle; AColor: TChartColor);
function TextExtent(const AText: String): TPoint;
function TextExtent(AText: TStrings): TPoint;
function TextOut: TChartTextOut;
@ -316,11 +323,27 @@ end;
{ TCanvasDrawer }
procedure TCanvasDrawer.ClippingStart(const AClipRect: TRect);
begin
FCanvas.ClipRect := AClipRect;
FCanvas.Clipping := true;
end;
procedure TCanvasDrawer.ClippingStop;
begin
FCanvas.Clipping := false;
end;
constructor TCanvasDrawer.Create(ACanvas: TCanvas);
begin
FCanvas := ACanvas;
end;
procedure TCanvasDrawer.FillRect(AX1, AY1, AX2, AY2: Integer);
begin
FCanvas.FillRect(AX1, AY1, AX2, AY2);
end;
function TCanvasDrawer.GetCanvas: TCanvas;
begin
Result := FCanvas;
@ -336,6 +359,11 @@ begin
FCanvas.Line(AX1, AY1, AX2, AY2);
end;
procedure TCanvasDrawer.Line(const AP1, AP2: TPoint);
begin
FCanvas.Line(AP1, AP2);
end;
procedure TCanvasDrawer.PrepareSimplePen(AColor: TChartColor);
begin
TADrawUtils.PrepareSimplePen(FCanvas, AColor);

View File

@ -182,7 +182,7 @@ type
function GetAxis(AIndex: Integer): TChartAxis;
function GetChartHeight: Integer;
function GetChartWidth: Integer;
function GetMargins(ACanvas: TCanvas): TRect;
function GetMargins(ADrawer: IChartDrawer): TRect;
function GetSeriesCount: Integer;
function GetToolset: TBasicChartToolset;
procedure HideReticule;
@ -226,7 +226,7 @@ type
{$IFDEF LCLGtk2}
procedure DoOnResize; override;
{$ENDIF}
procedure PrepareAxis(ACanvas: TCanvas);
procedure PrepareAxis(ADrawer: IChartDrawer);
procedure PrepareLegend(
ADrawer: IChartDrawer; out ALegendItems: TChartLegendItems;
var AClipRect: TRect; out ALegendRect: TRect);
@ -594,10 +594,9 @@ begin
with TBasicChartSeries(seriesInZOrder[i]) do begin
if not Active then continue;
// Interleave axises with series according to ZPosition.
AxisList.Draw(ADrawer.Canvas, FClipRect, Self, ZPosition, d, axisIndex);
AxisList.Draw(ADrawer, FClipRect, Self, ZPosition, d, axisIndex);
OffsetDrawArea(Min(ZPosition, d), Min(Depth, d));
ADrawer.Canvas.ClipRect := FClipRect;
ADrawer.Canvas.Clipping := true;
ADrawer.ClippingStart(FClipRect);
try
try
Draw(ADrawer);
@ -607,14 +606,14 @@ begin
end;
finally
OffsetDrawArea(-Min(ZPosition, d), -Min(Depth, d));
ADrawer.Canvas.Clipping := false;
ADrawer.ClippingStop;
end;
end;
finally
seriesInZOrder.Free;
end;
end;
AxisList.Draw(ADrawer.Canvas, FClipRect, Self, MaxInt, d, axisIndex);
AxisList.Draw(ADrawer, FClipRect, Self, MaxInt, d, axisIndex);
end;
{$IFDEF LCLGtk2}
@ -655,7 +654,7 @@ begin
if Legend.Visible then
PrepareLegend(ADrawer, legendItems, FClipRect, legendRect);
try
PrepareAxis(ADrawer.Canvas);
PrepareAxis(ADrawer);
DrawBackWall(ADrawer);
DisplaySeries(ADrawer);
if Legend.Visible then
@ -852,14 +851,14 @@ begin
end;
end;
function TChart.GetMargins(ACanvas: TCanvas): TRect;
function TChart.GetMargins(ADrawer: IChartDrawer): TRect;
var
i: Integer;
begin
Result := FMargins.Data;
for i := 0 to SeriesCount - 1 do
if Series[i].Active then
Series[i].UpdateMargins(ACanvas, Result);
Series[i].UpdateMargins(ADrawer.Canvas, Result);
end;
function TChart.GetSeriesCount: Integer;
@ -932,7 +931,7 @@ begin
Draw(drawer, ARect);
end;
procedure TChart.PrepareAxis(ACanvas: TCanvas);
procedure TChart.PrepareAxis(ADrawer: IChartDrawer);
var
axisMargin: TChartAxisMargins = (0, 0, 0, 0);
a: TChartAxisAlignment;
@ -944,14 +943,14 @@ begin
end;
AxisList.PrepareGroups;
AxisList.Measure(ACanvas, CurrentExtent, true, axisMargin);
AxisList.Measure(ADrawer, CurrentExtent, true, axisMargin);
axisMargin[calLeft] := Max(axisMargin[calLeft], Depth);
axisMargin[calBottom] := Max(axisMargin[calBottom], Depth);
for a := Low(a) to High(a) do
SideByAlignment(FClipRect, a, -axisMargin[a]);
CalculateTransformationCoeffs(GetMargins(ACanvas));
AxisList.Measure(ACanvas, CurrentExtent, false, axisMargin);
CalculateTransformationCoeffs(GetMargins(ADrawer));
AxisList.Measure(ADrawer, CurrentExtent, false, axisMargin);
AxisList.Prepare(FClipRect);
end;

View File

@ -357,8 +357,7 @@ begin
r := ABounds;
r.Right -= 1;
ADrawer.Canvas.ClipRect := r;
ADrawer.Canvas.Clipping := true;
ADrawer.ClippingStart(r);
itemHeight :=
(ABounds.Bottom - ABounds.Top - Spacing) div AItems.Count - Spacing;
@ -372,7 +371,7 @@ begin
OffsetRect(r, 0, itemHeight + Spacing);
end;
finally
ADrawer.Canvas.Clipping := false;
ADrawer.ClippingStop;
end;
end;