From 2acf57df8dd6211d4bcbef74289d35a2bc16851c Mon Sep 17 00:00:00 2001 From: ask Date: Sun, 13 Feb 2011 12:45:10 +0000 Subject: [PATCH] TAChart: Start implementation of IChartDrawer interface git-svn-id: trunk@29519 - --- components/tachart/tadrawutils.pas | 75 ++++++++++++++++- components/tachart/tagraph.pas | 130 +++++++++++++++++------------ 2 files changed, 149 insertions(+), 56 deletions(-) diff --git a/components/tachart/tadrawutils.pas b/components/tachart/tadrawutils.pas index 20e0e4d432..88874713da 100644 --- a/components/tachart/tadrawutils.pas +++ b/components/tachart/tadrawutils.pas @@ -21,7 +21,10 @@ unit TADrawUtils; interface uses - Classes, Graphics, SysUtils, Types; + Classes, Graphics, FPCanvas, SysUtils, Types; + +type + TChartColor = -$7FFFFFFF-1..$7FFFFFFF; const Colors: array [1..15] of TColor = ( @@ -29,6 +32,8 @@ const clTeal, clNavy, clMaroon, clLime, clOlive, clPurple, clSilver, clAqua); type + //TCanvas = TFPCustomCanvas; + TPenBrushFont = set of (pbfPen, pbfBrush, pbfFont); { TPenBrushFontRecall } @@ -45,6 +50,35 @@ type procedure Recall; end; + IChartDrawer = interface + function GetCanvas: TCanvas; + procedure PrepareSimplePen(AColor: TChartColor); + procedure Rectangle(const ARect: TRect); + procedure SetBrush(APen: TFPCustomBrush); + procedure SetBrushParams(AStyle: TBrushStyle; AColor: TChartColor); + procedure SetPen(APen: TFPCustomPen); + + property Brush: TFPCustomBrush write SetBrush; + property Canvas: TCanvas read GetCanvas; + property Pen: TFPCustomPen write SetPen; + end; + + { TCanvasDrawer } + + TCanvasDrawer = class(TInterfacedObject, IChartDrawer) + private + FCanvas: TCanvas; + procedure SetBrush(ABrush: TFPCustomBrush); + procedure SetPen(APen: TFPCustomPen); + public + constructor Create(ACanvas: TCanvas); + function GetCanvas: TCanvas; + + procedure PrepareSimplePen(AColor: TChartColor); + procedure Rectangle(const ARect: TRect); + procedure SetBrushParams(AStyle: TBrushStyle; AColor: TChartColor); + end; + procedure DrawLineDepth(ACanvas: TCanvas; AX1, AY1, AX2, AY2, ADepth: Integer); procedure DrawLineDepth(ACanvas: TCanvas; const AP1, AP2: TPoint; ADepth: Integer); @@ -175,6 +209,45 @@ begin Result := ACanvas.TextHeight(TYPICAL_TEXT); end; +{ TCanvasDrawer } + +constructor TCanvasDrawer.Create(ACanvas: TCanvas); +begin + FCanvas := ACanvas; +end; + +function TCanvasDrawer.GetCanvas: TCanvas; +begin + Result := FCanvas; +end; + +procedure TCanvasDrawer.PrepareSimplePen(AColor: TChartColor); +begin + TADrawUtils.PrepareSimplePen(FCanvas, AColor); +end; + +procedure TCanvasDrawer.Rectangle(const ARect: TRect); +begin + FCanvas.Rectangle(ARect); +end; + +procedure TCanvasDrawer.SetBrush(ABrush: TFPCustomBrush); +begin + FCanvas.Brush.Assign(ABrush); +end; + +procedure TCanvasDrawer.SetBrushParams( + AStyle: TBrushStyle; AColor: TChartColor); +begin + FCanvas.Brush.Style := AStyle; + FCanvas.Brush.Color := AColor; +end; + +procedure TCanvasDrawer.SetPen(APen: TFPCustomPen); +begin + FCanvas.Pen.Assign(APen); +end; + { TPenBrushFontRecall } constructor TPenBrushFontRecall.Create(ACanvas: TCanvas; AParams: TPenBrushFont); diff --git a/components/tachart/tagraph.pas b/components/tachart/tagraph.pas index 770d0dbea5..03e699fabb 100644 --- a/components/tachart/tagraph.pas +++ b/components/tachart/tagraph.pas @@ -29,7 +29,7 @@ interface uses Graphics, Classes, Controls, LCLType, SysUtils, - TAChartAxis, TAChartUtils, TALegend, TATypes; + TAChartAxis, TAChartUtils, TADrawUtils, TALegend, TATypes; type TChart = class; @@ -78,7 +78,8 @@ type destructor Destroy; override; public - procedure Draw(ACanvas: TCanvas); virtual; abstract; + procedure Draw(ADrawer: IChartDrawer); virtual; + procedure Draw(ACanvas: TCanvas); virtual; function IsEmpty: Boolean; virtual; abstract; procedure MovePoint(var AIndex: Integer; const ANewPos: TPoint); virtual; @@ -214,8 +215,8 @@ type procedure VisitSources( AVisitor: TChartOnSourceVisitor; AAxis: TChartAxis; var AData); protected - procedure Clear(ACanvas: TCanvas; const ARect: TRect); - procedure DisplaySeries(ACanvas: TCanvas); + procedure Clear(ADrawer: IChartDrawer; const ARect: TRect); + procedure DisplaySeries(ADrawer: IChartDrawer); procedure DrawBackWall(ACanvas: TCanvas); procedure DrawTitleFoot(ACanvas: TCanvas); procedure MouseDown( @@ -251,6 +252,7 @@ type function Clone: TChart; procedure CopyToClipboardBitmap; procedure DeleteSeries(ASeries: TBasicChartSeries); + procedure Draw(ADrawer: IChartDrawer; const ARect: TRect); procedure DrawLegendOn(ACanvas: TCanvas; var ARect: TRect); function GetFullExtent: TDoubleRect; procedure PaintOnCanvas(ACanvas: TCanvas; ARect: TRect); @@ -354,7 +356,7 @@ var implementation uses - Clipbrd, Dialogs, GraphMath, LCLProc, LResources, Math, TADrawUtils, Types; + Clipbrd, Dialogs, GraphMath, LCLProc, LResources, Math, Types; function CompareZPosition(AItem1, AItem2: Pointer): Integer; begin @@ -539,41 +541,10 @@ end; procedure TChart.PaintOnCanvas(ACanvas: TCanvas; ARect: TRect); var - i: Integer; - legendItems: TChartLegendItems = nil; - legendRect: TRect; + drawer: IChartDrawer; begin - Clear(ACanvas, ARect); - - FClipRect := ARect; - InflateRect(FClipRect, -2, -2); - - for i := 0 to AxisList.Count - 1 do - with AxisList[i] do - if Transformations <> nil then - Transformations.SetChart(Self); - for i := 0 to SeriesCount - 1 do - Series[i].BeforeDraw; - - if not FIsZoomed then - FLogicalExtent := GetFullExtent; - FCurrentExtent := FLogicalExtent; - DrawTitleFoot(ACanvas); - if Legend.Visible then - PrepareLegend(ACanvas, legendItems, FClipRect, legendRect); - try - PrepareAxis(ACanvas); - DrawBackWall(ACanvas); - DisplaySeries(ACanvas); - if Legend.Visible then - Legend.Draw(ACanvas, legendItems, legendRect); - finally - legendItems.Free; - end; - DrawReticule(ACanvas); - - for i := 0 to SeriesCount - 1 do - Series[i].AfterDraw; + drawer := TCanvasDrawer.Create(ACanvas); + Draw(drawer, ARect); end; procedure TChart.PrepareLegend( @@ -652,19 +623,18 @@ begin rY.UpdateMinMax(@YImageToGraph); end; -procedure TChart.Clear(ACanvas: TCanvas; const ARect: TRect); +procedure TChart.Clear(ADrawer: IChartDrawer; const ARect: TRect); var defaultDrawing: Boolean = true; begin - PrepareSimplePen(ACanvas, Color); - ACanvas.Brush.Color := Color; - ACanvas.Brush.Style := bsSolid; - if Assigned(OnBeforeDrawBackground) then - OnBeforeDrawBackground(Self, ACanvas, ARect, defaultDrawing); + ADrawer.PrepareSimplePen(Color); + ADrawer.SetBrushParams(bsSolid, Color); + if (ADrawer.Canvas <> nil) and Assigned(OnBeforeDrawBackground) then + OnBeforeDrawBackground(Self, ADrawer.Canvas, ARect, defaultDrawing); if defaultDrawing then - ACanvas.Rectangle(ARect); - if Assigned(OnAfterDrawBackground) then - OnAfterDrawBackground(Self, ACanvas, ARect); + ADrawer.Rectangle(ARect); + if (ADrawer.Canvas <> nil) and Assigned(OnAfterDrawBackground) then + OnAfterDrawBackground(Self, ADrawer.Canvas, ARect); end; procedure TChart.ClearSeries; @@ -901,7 +871,7 @@ begin PaintOnCanvas(ACanvas, Rect); end; -procedure TChart.DisplaySeries(ACanvas: TCanvas); +procedure TChart.DisplaySeries(ADrawer: IChartDrawer); procedure OffsetDrawArea(AZPos, ADepth: Integer); begin @@ -928,27 +898,66 @@ begin with TBasicChartSeries(seriesInZOrder[i]) do begin if not Active then continue; // Interleave axises with series according to ZPosition. - AxisList.Draw(ACanvas, FClipRect, Self, ZPosition, d, axisIndex); + AxisList.Draw(ADrawer.Canvas, FClipRect, Self, ZPosition, d, axisIndex); OffsetDrawArea(Min(ZPosition, d), Min(Depth, d)); - ACanvas.ClipRect := FClipRect; - ACanvas.Clipping := true; + ADrawer.Canvas.ClipRect := FClipRect; + ADrawer.Canvas.Clipping := true; try try - Draw(ACanvas); + Draw(ADrawer); except Active := false; raise; end; finally OffsetDrawArea(-Min(ZPosition, d), -Min(Depth, d)); - ACanvas.Clipping := false; + ADrawer.Canvas.Clipping := false; end; end; finally seriesInZOrder.Free; end; end; - AxisList.Draw(ACanvas, FClipRect, Self, MaxInt, d, axisIndex); + AxisList.Draw(ADrawer.Canvas, FClipRect, Self, MaxInt, d, axisIndex); +end; + +procedure TChart.Draw(ADrawer: IChartDrawer; const ARect: TRect); +var + i: Integer; + legendItems: TChartLegendItems = nil; + legendRect: TRect; +begin + Clear(ADrawer, ARect); + + FClipRect := ARect; + InflateRect(FClipRect, -2, -2); + + for i := 0 to AxisList.Count - 1 do + with AxisList[i] do + if Transformations <> nil then + Transformations.SetChart(Self); + for i := 0 to SeriesCount - 1 do + Series[i].BeforeDraw; + + if not FIsZoomed then + FLogicalExtent := GetFullExtent; + FCurrentExtent := FLogicalExtent; + DrawTitleFoot(ADrawer.Canvas); + if Legend.Visible then + PrepareLegend(ADrawer.Canvas, legendItems, FClipRect, legendRect); + try + PrepareAxis(ADrawer.Canvas); + DrawBackWall(ADrawer.Canvas); + DisplaySeries(ADrawer); + if Legend.Visible then + Legend.Draw(ADrawer.Canvas, legendItems, legendRect); + finally + legendItems.Free; + end; + DrawReticule(ADrawer.Canvas); + + for i := 0 to SeriesCount - 1 do + Series[i].AfterDraw; end; procedure TChart.DrawReticule(ACanvas: TCanvas); @@ -1260,6 +1269,17 @@ begin inherited; end; +procedure TBasicChartSeries.Draw(ADrawer: IChartDrawer); +begin + Draw(ADrawer.Canvas); +end; + +procedure TBasicChartSeries.Draw(ACanvas: TCanvas); +begin + Unused(ACanvas); + raise EChartError(ClassName + '.Draw not implemented'); +end; + function TBasicChartSeries.GraphToAxisX(AX: Double): Double; begin Result := AX;