From 51fe94a1a88b30c630bdff4b064a2af0d26f9884 Mon Sep 17 00:00:00 2001 From: vincents Date: Tue, 28 Aug 2007 15:59:34 +0000 Subject: [PATCH] TAChart: patch from Luis Rodrigues and Helio Rocha-Pinto (bug #9507) + implemented property Inverted * bug fixes git-svn-id: trunk@11873 - --- components/tachart/tagraph.pas | 949 +++++++++++++++++++-------------- 1 file changed, 559 insertions(+), 390 deletions(-) diff --git a/components/tachart/tagraph.pas b/components/tachart/tagraph.pas index 2646391257..4d7f465bef 100644 --- a/components/tachart/tagraph.pas +++ b/components/tachart/tagraph.pas @@ -61,8 +61,10 @@ const type - TDrawVertReticule=procedure(Sender:TComponent;IndexSerie,Index,Xi,Yi:Integer;Xg,Yg:Double) of object; - TDrawReticule=procedure(Sender:TComponent;IndexSerie,Index,Xi,Yi:Integer;Xg,Yg:Double) of object; + TDrawVertReticule=procedure(Sender:TComponent;IndexSerie,Index,Xi,Yi:Integer; + Xg,Yg:Double) of object; + TDrawReticule=procedure(Sender:TComponent;IndexSerie,Index,Xi,Yi:Integer; + Xg,Yg:Double) of object; TCustomChart = class(TGraphicControl); @@ -70,13 +72,11 @@ type TChartPen = class(TPen) private FVisible: boolean; - FChanged: TNotifyEvent; procedure SetVisible(value: boolean); protected procedure Assign(Source:TPersistent); override; published property Visible: boolean read FVisible write SetVisible; - property OnChange: TNotifyEvent read FChanged write FChanged; end; TLegendAlignment=(laLeft,laRight,laTop,laBottom); @@ -85,7 +85,6 @@ type FVisible: boolean; FAlignment: TLegendAlignment; FOwner: TCustomChart; - FChanged: TNotifyEvent; FFont: TFont; FFrame: TChartPen; @@ -104,14 +103,12 @@ type property Alignment: TLegendAlignment read FAlignment write SetAlignment; property Font: TFont read FFont write SetFont; property Frame: TChartPen read FFrame write SetFrame; - property OnChange: TNotifyEvent read FChanged write FChanged; end; TChartTitle = class(TPersistent) private FVisible: boolean; FOwner: TCustomChart; - FChanged: TNotifyEvent; FFont: TFont; FFrame: TChartPen; FBrush: TBrush; @@ -137,14 +134,12 @@ type property Frame: TChartPen read FFrame write SetFrame; property Alignment: TAlignment read FAlignment write SetAlignment; property Text: TStrings read FText write SetText; - property OnChange: TNotifyEvent read FChanged write FChanged; end; TChartAxisTitle = class(TPersistent) private FVisible: boolean; FOwner: TCustomChart; - FChanged: TNotifyEvent; FAngle: Integer; FCaption: String; FFont: TFont; @@ -162,20 +157,21 @@ type property Caption: String read FCaption write SetCaption; property Angle: Integer read FAngle write SetAngle; property Font: TFont read FFont write SetFont; - property OnChange: TNotifyEvent read FChanged write FChanged; end; + TAxisScale=(asIncreasing,asDecreasing,asLogIncreasing,asLogDecreasing); TChartAxis = class(TPersistent) private FVisible: boolean; FOwner: TCustomChart; - FChanged: TNotifyEvent; FTitle: TChartAxisTitle; FGrid: TChartPen; + FInverted: boolean; procedure SetVisible(value: boolean); procedure SetTitle(value: TChartAxisTitle); procedure SetGrid(value: TChartPen); + procedure SetInverted(value: boolean); procedure StyleChanged(Sender: TObject); protected procedure Assign(Source:TPersistent); override; @@ -184,9 +180,10 @@ type Destructor Destroy; override; published property Visible: boolean read FVisible write SetVisible; + property Inverted: boolean read FInverted write SetInverted; property Title: TChartAxisTitle read FTitle write SetTitle; property Grid: TChartPen read FGrid write SetGrid; - property OnChange: TNotifyEvent read FChanged write FChanged; + end; TChart = class(TCustomChart) @@ -298,7 +295,6 @@ type procedure DrawLegend; procedure AddSerie(Serie:TComponent); -// procedure DeleteSerie(Serie:TSerie); procedure DeleteSerie(Serie:TComponent); function GetSerie(i:Integer):TComponent; procedure SetAutoXMin(Auto:Boolean); @@ -410,7 +406,7 @@ end; procedure TChartPen.SetVisible(Value: Boolean); begin FVisible := Value; - if assigned( FChanged ) then FChanged(Self); + if assigned( OnChange ) then OnChange(Self); end; procedure TChartPen.Assign(Source: TPersistent); @@ -430,9 +426,9 @@ end; Constructor TChartAxis.Create(AOwner: TCustomChart); begin inherited Create; + FOwner := AOwner; FVisible := True; FTitle := TChartAxisTitle.Create(AOwner); - FTitle.OnChange := StyleChanged; FGrid := TChartPen.Create; FGrid.Width:=1; FGrid.Color:=clGray; @@ -451,19 +447,26 @@ end; procedure TChartAxis.SetVisible(value: boolean); begin FVisible := value; - if assigned( FChanged ) then FChanged(Self); + StyleChanged(Self); end; procedure TChartAxis.SetTitle(value: TChartAxisTitle); begin FTitle.Assign(Value); - if assigned( FChanged ) then FChanged(Self); + StyleChanged(Self); end; procedure TChartAxis.SetGrid(value: TChartPen); begin FGrid.Assign(Value); - if assigned( FChanged ) then FChanged(Self); + StyleChanged(Self); +end; + +procedure TChartAxis.SetInverted(value: boolean); +//Inverts the axis scale from increasing to decreasing +begin + FInverted := value; + StyleChanged(Self); end; procedure TChartAxis.Assign(Source:TPersistent); @@ -478,7 +481,7 @@ end; procedure TChartAxis.StyleChanged(Sender: TObject); begin - if assigned( FChanged ) then FChanged(Self); + FOwner.invalidate; end; /////////////////////////////////////////////////////////////////////////////// @@ -488,7 +491,9 @@ end; Constructor TChartAxisTitle.Create(AOwner: TCustomChart); begin inherited Create; + FOwner := AOwner; FFont := TFont.Create; + FFont.OnChange := StyleChanged; end; Destructor TChartAxisTitle.Destroy; @@ -500,24 +505,24 @@ end; procedure TChartAxisTitle.SetCaption(value: String); begin FCaption := Value; - if assigned( FChanged ) then FChanged(Self); + StyleChanged(Self); end; procedure TChartAxisTitle.SetAngle(value: Integer); begin FAngle := Value; - if assigned( FChanged ) then FChanged(Self); + StyleChanged(Self); end; procedure TChartAxisTitle.SetFont(value: TFont); begin FFont.Assign( Value ); - if assigned( FChanged ) then FChanged(Self); + StyleChanged(Self); end; procedure TChartAxisTitle.StyleChanged(Sender: TObject); begin - if assigned( FChanged ) then FChanged(Self); + FOwner.Invalidate; end; procedure TChartAxisTitle.Assign(Source:TPersistent); @@ -571,30 +576,30 @@ end; procedure TChartLegend.SetVisible(value: boolean); begin FVisible := value; - if assigned( FChanged ) then FChanged(Self); + StyleChanged(Self); end; procedure TChartLegend.SetAlignment(value: TLegendAlignment); begin FAlignment := value; - if assigned( FChanged ) then FChanged(Self); + StyleChanged(Self); end; procedure TChartLegend.SetFont(value: TFont); begin FFont.Assign( value ); - if assigned( FChanged ) then FChanged(Self); + StyleChanged(Self); end; procedure TChartLegend.SetFrame(value: TChartPen); begin FFrame.Assign( value ); - if assigned( FChanged ) then FChanged(Self); + StyleChanged(Self); end; procedure TChartLegend.StyleChanged(Sender: TObject); begin - if assigned( FChanged ) then FChanged(Self);; + FOwner.Invalidate; end; //////////////////////////////////////////////////////////////////////////////// @@ -616,7 +621,6 @@ begin FBrush.Color := FOwner.Color; FBrush.OnChange := StyleChanged; FText := TStringList.Create; - FText.Add('TAChart'); end; Destructor TChartTitle.Destroy; @@ -632,14 +636,13 @@ end; Procedure TChartTitle.Assign(Source:TPersistent); begin if Source is TChartTitle then - With TChartLegend(Source) do - Begin - Self.FVisible := FVisible; - Self.FFont.Assign( Font ); - Self.FBrush.Assign( Brush ); - Self.FFrame.Assign( Frame ); - Self.FText.Assign( Text ); - end; + With TChartLegend(Source) do Begin + Self.FVisible := FVisible; + Self.FFont.Assign( Font ); + Self.FBrush.Assign( Brush ); + Self.FFrame.Assign( Frame ); + Self.FText.Assign( Text ); + end; inherited Assign(Source); end; @@ -647,50 +650,49 @@ end; procedure TChartTitle.SetVisible(value: boolean); begin FVisible := value; - if assigned( FChanged ) then FChanged(Self); + StyleChanged( Self ); end; procedure TChartTitle.SetFont(value: TFont); begin FFont.Assign( value ); - if assigned( FChanged ) then FChanged(Self); + StyleChanged( Self ); end; procedure TChartTitle.SetFrame(value: TChartPen); begin FFrame.Assign( value ); - if assigned( FChanged ) then FChanged(Self); + StyleChanged( Self ); end; procedure TChartTitle.SetBrush(value: TBrush); begin FBrush.Assign( value ); - if assigned( FChanged ) then FChanged(Self); + StyleChanged( Self ); end; procedure TChartTitle.SetText(value: TStrings); begin FText.Assign( value ); - if assigned( FChanged ) then FChanged(Self); -end; - -procedure TChartTitle.StyleChanged(Sender: TObject); -begin - if assigned( FChanged ) then FChanged(Self);; + StyleChanged( Self ); end; procedure TChartTitle.SetAlignment(value: TAlignment); begin FAlignment := Value; - if assigned( FChanged ) then FChanged(Self);; + StyleChanged( Self ); end; +procedure TChartTitle.StyleChanged(Sender: TObject); +begin + FOwner.Invalidate; +end; - -procedure CalculateIntervals(Mini,Maxi:Double;var Debut,Pas:Double); +procedure CalculateIntervals(Mini,Maxi:Double; AxisScale: TAxisScale; + var Debut,Pas:Double); var Etendue,EtendueTmp:Double; NbPas,Mult:array[1..3] of Double; @@ -701,129 +703,180 @@ var BTmp:Byte; i,j:Integer; begin -if Maxi>59 then - Sleep(1); -Etendue:=Maxi-Mini; -if Etendue=0 then begin Debut:=Mini; Pas:=1; Exit; end; - -Mult[1]:=1; -EtendueTmp:=Etendue; -NbPas[1]:=EtendueTmp; -if NbPas[1]>=10 then - begin - while NbPas[1]>10 do + if Maxi>59 then Sleep(1); + Etendue:=Maxi-Mini; + if Etendue=0 then begin Debut:=Mini; Pas:=1; Exit; end; + Mult[1]:=1; + EtendueTmp:=Etendue; + NbPas[1]:=EtendueTmp; + if NbPas[1]>=10 then begin - EtendueTmp:=EtendueTmp/10; - Mult[1]:=Mult[1]/10; - NbPas[1]:=EtendueTmp; - end; - end -else - begin - while EtendueTmp*10<=10 do + while NbPas[1]>10 do + begin + EtendueTmp:=EtendueTmp/10; + Mult[1]:=Mult[1]/10; + NbPas[1]:=EtendueTmp; + end; + end + else begin - EtendueTmp:=EtendueTmp*10; - Mult[1]:=Mult[1]*10; - NbPas[1]:=EtendueTmp; + while EtendueTmp*10<=10 do + begin + EtendueTmp:=EtendueTmp*10; + Mult[1]:=Mult[1]*10; + NbPas[1]:=EtendueTmp; + end; end; - end; - -Mult[2]:=1; -EtendueTmp:=Etendue; -NbPas[2]:=EtendueTmp/0.5; -if NbPas[2]>=10 then - begin - while NbPas[2]>10 do + Mult[2]:=1; + EtendueTmp:=Etendue; + NbPas[2]:=EtendueTmp/0.5; + if NbPas[2]>=10 then begin - EtendueTmp:=EtendueTmp/10; - Mult[2]:=Mult[2]/10; - NbPas[2]:=EtendueTmp/0.5; - end; - end -else - begin - while EtendueTmp*10/0.5<=10 do + while NbPas[2]>10 do + begin + EtendueTmp:=EtendueTmp/10; + Mult[2]:=Mult[2]/10; + NbPas[2]:=EtendueTmp/0.5; + end; + end + else begin - EtendueTmp:=EtendueTmp*10; - Mult[2]:=Mult[2]*10; - NbPas[2]:=EtendueTmp/0.5; + while EtendueTmp*10/0.5<=10 do + begin + EtendueTmp:=EtendueTmp*10; + Mult[2]:=Mult[2]*10; + NbPas[2]:=EtendueTmp/0.5; + end; end; - end; - -Mult[3]:=1; -EtendueTmp:=Etendue; -NbPas[3]:=EtendueTmp/0.2; -if NbPas[3]>=10 then - begin - while NbPas[3]>10 do + Mult[3]:=1; + EtendueTmp:=Etendue; + NbPas[3]:=EtendueTmp/0.2; + if NbPas[3]>=10 then begin - EtendueTmp:=EtendueTmp/10; - Mult[3]:=Mult[3]/10; - NbPas[3]:=EtendueTmp/0.2; - end; - end -else - begin - while EtendueTmp*10/0.2<=10 do + while NbPas[3]>10 do + begin + EtendueTmp:=EtendueTmp/10; + Mult[3]:=Mult[3]/10; + NbPas[3]:=EtendueTmp/0.2; + end; + end + else begin - EtendueTmp:=EtendueTmp*10; - Mult[3]:=Mult[3]*10; - NbPas[3]:=EtendueTmp/0.2; + while EtendueTmp*10/0.2<=10 do + begin + EtendueTmp:=EtendueTmp*10; + Mult[3]:=Mult[3]*10; + NbPas[3]:=EtendueTmp/0.2; + end; end; - end; - -for i:=1 to 3 do Index[i]:=i; - -Trouve:=True; -while Trouve do - begin - Trouve:=False; - for i:=1 to 2 do - if NbPas[i]>NbPas[i+1] then + for i:=1 to 3 do Index[i]:=i; + Trouve:=True; + while Trouve do begin - Trouve:=True; - DTmp:=NbPas[i]; - NbPas[i]:=NbPas[i+1]; - NbPas[i+1]:=DTmp; - BTmp:=Index[i]; - Index[i]:=Index[i+1]; - Index[i+1]:=BTmp; + Trouve:=False; + for i:=1 to 2 do + if NbPas[i]>NbPas[i+1] then + begin + Trouve:=True; + DTmp:=NbPas[i]; + NbPas[i]:=NbPas[i+1]; + NbPas[i+1]:=DTmp; + BTmp:=Index[i]; + Index[i]:=Index[i+1]; + Index[i+1]:=BTmp; + end; end; - end; - -if NbPas[3]<=10 then j:=3 -else if NbPas[2]<=10 then j:=2 -else if NbPas[1]<=10 then j:=1 -else - begin -// ShowMessage(lang('Erreur')); - Exit; - end; - -if Index[j]=1 then Pas:=1; -if Index[j]=2 then Pas:=0.5; -if Index[j]=3 then Pas:=0.2; -Pas:=Pas/Mult[Index[j]]; -// If 0 is in the interval, it is cool to have it as a mark ! -if (Mini<0) and (Maxi>0) then - begin - Debut:=0; - while Debut>Mini do Debut:=Debut-Pas; - end -else - begin - // Don''t work if mini is negative and > 1 -// if Abs(Mini)<1 then - Debut:=Round((Mini-Pas)*Mult[Index[j]])/Mult[Index[j]] -// else -// Debut:=System.Int(Mini)-Pas; //null - end; + if NbPas[3]<=10 then j:=3 + else if NbPas[2]<=10 then j:=2 + else if NbPas[1]<=10 then j:=1 + else + begin + // ShowMessage(lang('Erreur')); + Exit; + end; + if Index[j]=1 then Pas:=1; + if Index[j]=2 then Pas:=0.5; + if Index[j]=3 then Pas:=0.2; + Pas:=Pas/Mult[Index[j]]; + case AxisScale of + asIncreasing: + begin + // Sets 0 as a mark, in case it is in the interval + if (Mini<0) and (Maxi>0) then + begin + Debut:=0; + while (Debut > Mini) do Debut := Debut-Pas; + end + else + begin + // Don''t work if mini is negative and > 1 + // if Abs(Mini)<1 then + Debut:=Round((Mini-Pas)*Mult[Index[j]])/Mult[Index[j]] + // else + // Debut:=System.Int(Mini)-Pas; //null + end; + end; + asDecreasing: + begin + // Sets 0 as a mark, in case it is in the interval + if (Mini<0) and (Maxi>0) then + begin + Debut:=0; + while (Debut < Maxi) do Debut := Debut+Pas; + end + else + begin + // Don''t work if mini is negative and > 1 + // if Abs(Mini)<1 then + Debut:=Round((Maxi+Pas)*Mult[Index[j]])/Mult[Index[j]] + // else + // Debut:=System.Int(Mini)-Pas; //null + end; + end; + asLogIncreasing: + begin + // FIXME: asLogIncreasing is still not implemented. The following is the + // same code for asIncreasing; + // Sets 0 as a mark, in case it is in the interval + if (Mini<0) and (Maxi>0) then + begin + Debut:=0; + while (Debut > Mini) do Debut := Debut-Pas; + end + else + begin + // Don''t work if mini is negative and > 1 + // if Abs(Mini)<1 then + Debut:=Round((Mini-Pas)*Mult[Index[j]])/Mult[Index[j]] + // else + // Debut:=System.Int(Mini)-Pas; //null + end; + end; + asLogDecreasing: + begin + // FIXME: asLogDecreasing is still not implemented. The following is the + // same code for asIncreasing; + // Sets 0 as a mark, in case it is in the interval + if (Mini<0) and (Maxi>0) then + begin + Debut:=0; + while (Debut > Mini) do Debut := Debut-Pas; + end + else + begin + // Don''t work if mini is negative and > 1 + // if Abs(Mini)<1 then + Debut:=Round((Mini-Pas)*Mult[Index[j]])/Mult[Index[j]] + // else + // Debut:=System.Int(Mini)-Pas; //null + end; + end; + end; {case AxisScale} end; constructor TChart.Create(AOwner:TComponent); begin -inherited Create(AOwner); - + inherited Create(AOwner); TmpBrush := TBrush.Create; TmpPen := TPen.Create; TmpFont := TFont.Create; @@ -831,64 +884,56 @@ inherited Create(AOwner); FAllowZoom := True; FAxisVisible := true; + Width := 400; + Height := 300; -Width := 400; -Height := 300; + XMarkOld:=-1; + YMarkOld:=-1; -XMarkOld:=-1; -YMarkOld:=-1; + Series:=TSeriesList.Create; -Series:=TSeriesList.Create; + YMarkWidth:=10; -YMarkWidth:=10; + FAutoUpdateXMin:=True; + FAutoUpdateXMax:=True; + FAutoUpdateYMin:=True; + FAutoUpdateYMax:=True; -FAutoUpdateXMin:=True; -FAutoUpdateXMax:=True; -FAutoUpdateYMin:=True; -FAutoUpdateYMax:=True; + Color:=clBtnFace; + AxisColor:=clBlack; -Color:=clBtnFace; -AxisColor:=clBlack; + FXGraphMax:=0; + FXGraphMin:=0; + FYGraphMax:=0; + FYGraphMin:=0; -FXGraphMax:=0; -FXGraphMin:=0; -FYGraphMax:=0; -FYGraphMin:=0; + MirrorX:=False; + Fixed:=False; + Zoom:=False; + FShowReticule:=False; + FShowVerticalReticule:=False; + FBackColor := Color; -MirrorX:=False; -Fixed:=False; -Zoom:=False; -FShowReticule:=False; -FShowVerticalReticule:=False; -FBackColor := Color; + FGraphBrush:=TBrush.Create; + FGraphBrush.OnChange:=StyleChanged; -FGraphBrush:=TBrush.Create; -FGraphBrush.OnChange:=StyleChanged; + FLegend := TChartLegend.Create(Self); + FTitle := TChartTitle.Create(Self); + FTitle.Alignment := taCenter; + FTitle.Text.Add('TAChart'); + FTitle.Visible := true; + FFoot := TChartTitle.Create(Self); -//luis -FLegend := TChartLegend.Create(Self); -FLegend.OnChange := StyleChanged; -FTitle := TChartTitle.Create(Self); -FTitle.Alignment := taCenter; -FTitle.Visible := true; -FTitle.OnChange := StyleChanged; -FFoot := TChartTitle.Create(Self); -FFoot.Text.Clear; -FFoot.Alignment := taCenter; -FFoot.OnChange := StyleChanged; - - -FLeftAxis := TChartAxis.Create(Self); -FLeftAxis.Title.Angle := 90; -FLeftAxis.OnChange := StyleChanged; -FBottomAxis := TChartAxis.Create(Self); -FBottomAxis.Title.Angle := 0; -FBottomAxis.OnChange := StyleChanged; - -FFrame := TChartPen.Create; -FFrame.Visible := true; -FFrame.OnChange := StyleChanged; + FLeftAxis := TChartAxis.Create(Self); + FLeftAxis.Title.Angle := 90; + FLeftAxis.Inverted := false; + FBottomAxis := TChartAxis.Create(Self); + FBottomAxis.Title.Angle := 0; + FBottomAxis.Inverted := false; + FFrame := TChartPen.Create; + FFrame.Visible := true; + FFrame.OnChange := StyleChanged; end; destructor TChart.Destroy; @@ -949,36 +994,31 @@ begin Canvas.Font.Assign(TmpFont); end; - - if FBottomAxis.Visible and FAxisVisible then begin //FIXME: fix to rotate other than 0/90/180 degres + if FBottomAxis.Visible and FAxisVisible then begin + //FIXME: fix to rotate other than 0/90/180 degres YImageMin:=YImageMin-Canvas.TextHeight(FBottomAxis.Title.Caption); end; - - - -if FMirrorX then begin - XImageMin:=Width-YMarkWidth-GetLegendWidth; - XImageMax:=10; -end else begin - if FLeftAxis.Visible and FAxisVisible then - XImageMin:=YMarkWidth+Canvas.TextHeight(FLeftAxis.Title.Caption) - else - XImageMin:=YMarkWidth; - - XImageMax:=Width-10-GetLegendWidth; -end; - -Refresh; + if FMirrorX then begin + XImageMin:=Width-YMarkWidth-GetLegendWidth; + XImageMax:=10; + end else begin + if FLeftAxis.Visible and FAxisVisible then + XImageMin:=YMarkWidth+Canvas.TextHeight(FLeftAxis.Title.Caption) + else + XImageMin:=YMarkWidth; + XImageMax:=Width-10-GetLegendWidth; + end; + Refresh; end; procedure TChart.Clean; begin -Canvas.Pen.Mode:=pmCopy; -Canvas.Pen.Style:=psSolid; -Canvas.Pen.Color:=Color; -Canvas.Brush.Color:=Color; -Canvas.Brush.Style:=bsSolid; -Canvas.Rectangle(0,0,Width,Height); + Canvas.Pen.Mode:=pmCopy; + Canvas.Pen.Style:=psSolid; + Canvas.Pen.Color:=Color; + Canvas.Brush.Color:=Color; + Canvas.Brush.Style:=bsSolid; + Canvas.Rectangle(0,0,Width,Height); end; procedure TChart.DrawTitleFoot; @@ -998,19 +1038,15 @@ begin taCenter: xpos := (Width-Canvas.TextWidth(FTitle.Text[i])) div 2; taRightJustify: xpos := XImageMax - Canvas.TextWidth(FTitle.Text[i]); end; - Canvas.TextOut( xpos ,t,FTitle.Text[i]); t := t + Canvas.TextHeight(FTitle.Text[i]); end; - Canvas.Brush.Assign( TmpBrush ); Canvas.Font.Assign( TmpFont ); - end; - - if FFoot.Visible and (FFoot.Text.Count > 0) then begin + end; + if FFoot.Visible and (FFoot.Text.Count > 0) then begin TmpBrush.Assign( Canvas.Brush ); TmpFont.Assign( Canvas.Font ); - Canvas.Brush.Assign( FFoot.Brush ); Canvas.Font.Assign( FFoot.Font ); t := Height-5-Canvas.TextHeight(FFoot.Text[0]); @@ -1020,14 +1056,12 @@ begin taCenter: xpos := (Width-Canvas.TextWidth(FFoot.Text[i])) div 2; taRightJustify: xpos := XImageMax - Canvas.TextWidth(FFoot.Text[i]); end; - Canvas.TextOut( xpos ,t,FFoot.Text[i]); t := t - Canvas.TextHeight(FFoot.Text[i]); end; - Canvas.Brush.Assign( TmpBrush ); Canvas.Font.Assign( TmpFont ); - end; + end; end; procedure TChart.DrawAxis; @@ -1038,23 +1072,50 @@ var Marque,Debut,Pas:Double; T: Integer; LeftAxisWidth: Integer; + LeftAxisScale, BottomAxisScale : TAxisScale; begin + // Check AxisScale for both axes + Case LeftAxis.Inverted of + true : LeftAxisScale := asDecreasing; + false: LeftAxisScale := asIncreasing; + end; + Case BottomAxis.Inverted of + true : BottomAxisScale := asDecreasing; + false: BottomAxisScale := asIncreasing; + end; // Find max mark width MaxLargTexte:=0; Debut:=FYGraphMax; Pas:=1; - CalculateIntervals(FYGraphMin,FYGraphMax,Debut,Pas); + CalculateIntervals(FYGraphMin,FYGraphMax,LeftAxisScale,Debut,Pas); if FYGraphMin<>FYGraphMax then begin Marque:=Debut; - while Marque<=FYGraphMax+Pas*10e-10 do begin - if (Marque>=FYGraphMin) then begin - YGraphToImage(Marque,YTemp); - MyText:=Trim(FloatToStr(Marque)); - LargTexte:=Canvas.TextWidth(MyText); - if LargTexte>MaxLargTexte then MaxLargTexte:=LargTexte; - end; - Marque:=Marque+Pas; - end; + case LeftAxisScale of + asIncreasing: + begin + while Marque<=FYGraphMax+Pas*10e-10 do begin + if (Marque>=FYGraphMin) then begin + YGraphToImage(Marque,YTemp); + MyText:=Trim(FloatToStr(Marque)); + LargTexte:=Canvas.TextWidth(MyText); + if LargTexte>MaxLargTexte then MaxLargTexte:=LargTexte; + end; + Marque:=Marque+Pas; + end; + end; + asDecreasing: + begin + while Marque>=FYGraphMin-Pas*10e-10 do begin + if (Marque<=FYGraphMax) then begin + YGraphToImage(Marque,YTemp); + MyText:=Trim(FloatToStr(Marque)); + LargTexte:=Canvas.TextWidth(MyText); + if LargTexte>MaxLargTexte then MaxLargTexte:=LargTexte; + end; + Marque:=Marque-Pas; + end; + end; + end; {case LeftAxisScale} end; YMarkWidth:=10; @@ -1070,16 +1131,36 @@ begin XImageMax:=10; end else begin - XImageMin:=YMarkWidth; - XImageMax:=Width-10-GetLegendWidth; + XImageMin:=YMarkWidth; + XImageMax:=Width-10-GetLegendWidth; end; // Update coefs if (FXGraphMax-FXGraphMin <>0) and (FYGraphMax-FYGraphMin <> 0) then begin - ax:=(XImageMax-XImageMin)/(FXGraphMax-FXGraphMin); - bx:=XImageMax-ax*FXGraphMax; - ay:=(YImageMax-YImageMin)/(FYGraphMax-FYGraphMin); - by:=YImageMax-ay*FYGraphMax; + case BottomAxisScale of + asIncreasing: + begin + ax:=(XImageMax-XImageMin)/(FXGraphMax-FXGraphMin); + bx:=XImageMax-ax*FXGraphMax; + end; + asDecreasing: + begin + ax:=(XImageMax-XImageMin)/(FXGraphMin-FXGraphMax); + bx:=XImageMin-ax*FXGraphMax; + end; + end; + case LeftAxisScale of + asIncreasing: + begin + ay:=(YImageMax-YImageMin)/(FYGraphMax-FYGraphMin); + by:=YImageMax-ay*FYGraphMax; + end; + asDecreasing: + begin + ay:=(YImageMax-YImageMin)/(FYGraphMin-FYGraphMax); + by:=YImageMin-ay*FYGraphMax; + end; + end; end; end; @@ -1110,51 +1191,91 @@ begin if FMirrorX then T := Width-Canvas.TextWidth(FLeftAxis.Title.Caption)+5 else T := 5; if FTitle.Visible then - RotateLabel(Canvas, T, YImageMin+((YImageMax-YImageMin) div 2)+(Canvas.TextWidth(FLeftAxis.Title.Caption) div 2), - FLeftAxis.Title.Caption, FLeftAxis.Title.Angle) + RotateLabel(Canvas, T, YImageMin+((YImageMax-YImageMin) div 2) + +(Canvas.TextWidth(FLeftAxis.Title.Caption) div 2), + FLeftAxis.Title.Caption, FLeftAxis.Title.Angle) else - RotateLabel(Canvas, T, YImageMin+((YImageMax-YImageMin) div 2)+(Canvas.TextWidth(FLeftAxis.Title.Caption) div 2), - FLeftAxis.Title.Caption, FLeftAxis.Title.Angle); + RotateLabel(Canvas, T, YImageMin+((YImageMax-YImageMin) div 2) + +(Canvas.TextWidth(FLeftAxis.Title.Caption) div 2), + FLeftAxis.Title.Caption, FLeftAxis.Title.Angle); end; if FBottomAxis.Visible and FAxisVisible then begin - RotateLabel(Canvas, XImageMin+((XImageMax-XImageMin) div 2)-(Canvas.TextWidth(FBottomAxis.Title.Caption) div 2) , - YImageMin+5+Canvas.TextHeight(FBottomAxis.Title.Caption), FBottomAxis.Title.Caption, FBottomAxis.Title.Angle); + RotateLabel(Canvas, XImageMin+((XImageMax-XImageMin) div 2) + -(Canvas.TextWidth(FBottomAxis.Title.Caption) div 2), + YImageMin+5+Canvas.TextHeight(FBottomAxis.Title.Caption), + FBottomAxis.Title.Caption, FBottomAxis.Title.Angle); end; // X graduations if FBottomAxis.Visible and FAxisVisible then begin Debut:=FXGraphMax; Pas:=1; - CalculateIntervals(FXGraphMin,FXGraphMax,Debut,Pas); + CalculateIntervals(FXGraphMin,FXGraphMax,BottomAxisScale,Debut,Pas); if FXGraphMin<>FXGraphMax then begin Marque:=Debut; - while Marque<=FXGraphMax+Pas*10e-10 do begin - if (Marque>=FXGraphMin) then begin - XGraphToImage(Marque,XTemp); - Canvas.Brush.Assign(FGraphBrush); - if FBottomAxis.Grid.Visible then begin - Canvas.Pen.Assign(FBottomAxis.Grid); - if (XTemp<>XImageMax) and (XTemp<>XImageMin) then begin - Canvas.MoveTo(XTemp,YImageMin); - Canvas.LineTo(XTemp,YImageMax); + case BottomAxisScale of + asIncreasing: + begin + while Marque<=FXGraphMax+Pas*10e-10 do begin + if (Marque>=FXGraphMin) then begin + XGraphToImage(Marque,XTemp); + Canvas.Brush.Assign(FGraphBrush); + if FBottomAxis.Grid.Visible then begin + Canvas.Pen.Assign(FBottomAxis.Grid); + if (XTemp<>XImageMax) and (XTemp<>XImageMin) then + begin + Canvas.MoveTo(XTemp,YImageMin); + Canvas.LineTo(XTemp,YImageMax); + end; + end; + Canvas.Pen.Color:=AxisColor; + Canvas.Pen.Style:=psSolid; + Canvas.Pen.Mode:=pmCopy; + Canvas.MoveTo(XTemp,YImageMin-4); + Canvas.LineTo(XTemp,YImageMin+4); + Canvas.Brush.Color:=Color; + MyText:=Trim(FloatToStr(Marque)); + LargTexte:=Canvas.TextWidth(MyText) div 2; + XPos:=XTemp-LargTexte; + if XPos<1 then Xpos:=1; + if XPos+LargTexte*2>Width then Xpos:=Width-LargTexte*2-1; + Canvas.TextOut(Xpos,YImageMin+4,MyText); + end; + Marque:=Marque+Pas; end; end; - Canvas.Pen.Color:=AxisColor; - Canvas.Pen.Style:=psSolid; - Canvas.Pen.Mode:=pmCopy; - Canvas.MoveTo(XTemp,YImageMin-4); - Canvas.LineTo(XTemp,YImageMin+4); - Canvas.Brush.Color:=Color; - MyText:=Trim(FloatToStr(Marque)); - LargTexte:=Canvas.TextWidth(MyText) div 2; - XPos:=XTemp-LargTexte; - if XPos<1 then Xpos:=1; - if XPos+LargTexte*2>Width then Xpos:=Width-LargTexte*2-1; - Canvas.TextOut(Xpos,YImageMin+4,MyText); - end; - Marque:=Marque+Pas; - end; + asDecreasing: + begin + while Marque>=FXGraphMin-Pas*10e-10 do begin + if (Marque<=FXGraphMax) then begin + XGraphToImage(Marque,XTemp); + Canvas.Brush.Assign(FGraphBrush); + if FBottomAxis.Grid.Visible then begin + Canvas.Pen.Assign(FBottomAxis.Grid); + if (XTemp<>XImageMax) and (XTemp<>XImageMin) then + begin + Canvas.MoveTo(XTemp,YImageMin); + Canvas.LineTo(XTemp,YImageMax); + end; + end; + Canvas.Pen.Color:=AxisColor; + Canvas.Pen.Style:=psSolid; + Canvas.Pen.Mode:=pmCopy; + Canvas.MoveTo(XTemp,YImageMin-4); + Canvas.LineTo(XTemp,YImageMin+4); + Canvas.Brush.Color:=Color; + MyText:=Trim(FloatToStr(Marque)); + LargTexte:=Canvas.TextWidth(MyText) div 2; + XPos:=XTemp-LargTexte; + if XPos<1 then Xpos:=1; + if XPos+LargTexte*2>Width then Xpos:=Width-LargTexte*2-1; + Canvas.TextOut(Xpos,YImageMin+4,MyText); + end; + Marque:=Marque-Pas; + end; + end; + end; {case BottomAxisScale} end; end; @@ -1163,38 +1284,77 @@ begin MaxLargTexte:=0; Debut:=FYGraphMax; Pas:=1; - CalculateIntervals(FYGraphMin,FYGraphMax,Debut,Pas); + CalculateIntervals(FYGraphMin,FYGraphMax,LeftAxisScale,Debut,Pas); if FYGraphMin<>FYGraphMax then begin Marque:=Debut; - while Marque<=FYGraphMax+Pas*10e-10 do begin - if (Marque>=FYGraphMin) then begin - YGraphToImage(Marque,YTemp); - Canvas.Brush.Assign(FGraphBrush); - //draw grid - if FBottomAxis.Grid.Visible then begin - Canvas.Pen.Assign(FBottomAxis.Grid); - if (YTemp<>YImageMax) and (YTemp<>YImageMin) then begin - Canvas.MoveTo(XImageMin,YTemp); - Canvas.LineTo(XImageMax,YTemp); + case LeftAxisScale of + asIncreasing: + begin + while Marque<=FYGraphMax+Pas*10e-10 do begin + if (Marque>=FYGraphMin) then begin + YGraphToImage(Marque,YTemp); + Canvas.Brush.Assign(FGraphBrush); + //draw grid + if FBottomAxis.Grid.Visible then begin + Canvas.Pen.Assign(FBottomAxis.Grid); + if (YTemp<>YImageMax) and (YTemp<>YImageMin) then + begin + Canvas.MoveTo(XImageMin,YTemp); + Canvas.LineTo(XImageMax,YTemp); + end; + end; + Canvas.Pen.Color:=AxisColor; + Canvas.Pen.Style:=psSolid; + Canvas.Pen.Mode:=pmCopy; + Canvas.MoveTo(XImageMin-4,YTemp); + Canvas.LineTo(XImageMin+4,YTemp); + Canvas.Brush.Color:=Color; + MyText:=Trim(FloatToStr(Marque)); + LargTexte:=Canvas.TextWidth(MyText); + if LargTexte>MaxLargTexte then MaxLargTexte:=LargTexte; + HautTexte:=Canvas.TextHeight(MyText) div 2; + if FMirrorX then + Canvas.TextOut(XImageMin+6,YTemp-HautTexte,MyText) + else + Canvas.TextOut(XImageMin-7-LargTexte,YTemp-HautTexte,MyText); + end; + Marque:=Marque+Pas; end; end; - Canvas.Pen.Color:=AxisColor; - Canvas.Pen.Style:=psSolid; - Canvas.Pen.Mode:=pmCopy; - Canvas.MoveTo(XImageMin-4,YTemp); - Canvas.LineTo(XImageMin+4,YTemp); - Canvas.Brush.Color:=Color; - MyText:=Trim(FloatToStr(Marque)); - LargTexte:=Canvas.TextWidth(MyText); - if LargTexte>MaxLargTexte then MaxLargTexte:=LargTexte; - HautTexte:=Canvas.TextHeight(MyText) div 2; - if FMirrorX then - Canvas.TextOut(XImageMin+6,YTemp-HautTexte,MyText) - else - Canvas.TextOut(XImageMin-7-LargTexte,YTemp-HautTexte,MyText); - end; - Marque:=Marque+Pas; - end; + asDecreasing: + begin + while Marque>=FYGraphMin-Pas*10e-10 do begin + if (Marque<=FYGraphMax) then begin + YGraphToImage(Marque,YTemp); + Canvas.Brush.Assign(FGraphBrush); + //draw grid + if FBottomAxis.Grid.Visible then begin + Canvas.Pen.Assign(FBottomAxis.Grid); + if (YTemp<>YImageMax) and (YTemp<>YImageMin) then + begin + Canvas.MoveTo(XImageMin,YTemp); + Canvas.LineTo(XImageMax,YTemp); + end; + end; + Canvas.Pen.Color:=AxisColor; + Canvas.Pen.Style:=psSolid; + Canvas.Pen.Mode:=pmCopy; + Canvas.MoveTo(XImageMin-4,YTemp); + Canvas.LineTo(XImageMin+4,YTemp); + Canvas.Brush.Color:=Color; + MyText:=Trim(FloatToStr(Marque)); + LargTexte:=Canvas.TextWidth(MyText); + if LargTexte>MaxLargTexte then MaxLargTexte:=LargTexte; + HautTexte:=Canvas.TextHeight(MyText) div 2; + if FMirrorX then + Canvas.TextOut(XImageMin+6,YTemp-HautTexte,MyText) + else + Canvas.TextOut(XImageMin-7-LargTexte,YTemp-HautTexte,MyText); + end; + Marque:=Marque-Pas; + end; + end; + end; {case LeftAxisScale} end; end; end; @@ -1250,8 +1410,6 @@ begin end; end; end; - - Canvas.Brush.Assign(TmpBrush); Canvas.Pen.Assign(TmpPen); Canvas.Font.Assign(TmpFont); @@ -1344,8 +1502,9 @@ if (not FLegend.Visible) or (SeriesInLegendCount = 0) then begin Result:=0; Exit if only_pie then begin//if only one pie show diferent legend MySerie := get_pie; j := 0; - for i := 0 to MySerie.Count - 1 do begin //clean this coord shoould not be published - k := Canvas.TextWidth( format('%1.2g',[PChartCoord(MySerie.Coord.items[i])^.y])+' '+PChartCoord(MySerie.Coord.items[i])^.Text) ; + for i := 0 to MySerie.Count - 1 do begin //clean this coord should not be published + k := Canvas.TextWidth( format('%1.2g',[PChartCoord(MySerie.Coord.items[i])^.y]) + +' '+PChartCoord(MySerie.Coord.items[i])^.Text) ; if k>j then j:=k; end; Result:=j+20+10; @@ -1364,30 +1523,23 @@ end; procedure TChart.SetGraphBrush(Value:TBrush); begin -showmessage('ad'); -FGraphBrush.Assign(Value); + Showmessage('ad'); + FGraphBrush.Assign(Value); end; procedure TChart.AddSerie(Serie:TComponent); begin -if FShowVerticalReticule then - DrawVerticalReticule(XMarkOld); -if FShowReticule then - DrawReticule(XMarkOld,YMarkOld); - -//disable axis when we ave tpie series -if Serie is TPieSeries then begin - LeftAxis.Visible := False; - BottomAxis.Visible := False; + if FShowVerticalReticule then DrawVerticalReticule(XMarkOld); + if FShowReticule then DrawReticule(XMarkOld,YMarkOld); + //disable axis when we have TPie series + if Serie is TPieSeries then begin + LeftAxis.Visible := False; + BottomAxis.Visible := False; + end; + Series.Add(Serie); + TChartSeries(Serie).ParentChart := Self; end; - - -Series.Add(Serie); -TChartSeries(Serie).ParentChart := Self; -end; - -//procedure TChart.DeleteSerie(Serie:TSerie); procedure TChart.DeleteSerie(Serie:TComponent); var i:Integer; @@ -1408,31 +1560,31 @@ end; function TChart.GetSerie(i:Integer):TComponent; begin -Result:=Series[i]; + Result:=Series[i]; end; procedure TChart.SetAutoXMin(Auto:Boolean); begin -FAutoUpdateXMin:=Auto; -Refresh; + FAutoUpdateXMin:=Auto; + Refresh; end; procedure TChart.SetAutoXMax(Auto:Boolean); begin -FAutoUpdateXMax:=Auto; -Refresh; + FAutoUpdateXMax:=Auto; + Refresh; end; procedure TChart.SetAutoYMin(Auto:Boolean); begin -FAutoUpdateYMin:=Auto; -Refresh; + FAutoUpdateYMin:=Auto; + Refresh; end; procedure TChart.SetAutoYMax(Auto:Boolean); begin -FAutoUpdateYMax:=Auto; -Refresh; + FAutoUpdateYMax:=Auto; + Refresh; end; procedure TChart.Refresh; @@ -1442,12 +1594,19 @@ var NBPointsMax:Integer; Serie:TChartSeries; XMinSeries,XMaxSeries,YMinSeries,YMaxSeries:Double; + LeftAxisScale, BottomAxisScale : TAxisScale; begin - if FShowVerticalReticule then - DrawVerticalReticule(XMarkOld); - if FShowReticule then - DrawReticule(XMarkOld,YMarkOld); - + if FShowVerticalReticule then DrawVerticalReticule(XMarkOld); + if FShowReticule then DrawReticule(XMarkOld,YMarkOld); + // Check AxisScale for both axes + Case LeftAxis.Inverted of + true : LeftAxisScale := asDecreasing; + false: LeftAxisScale := asIncreasing; + end; + Case BottomAxis.Inverted of + true : BottomAxisScale := asDecreasing; + false: BottomAxisScale := asIncreasing; + end; // Search # of points, min and max of all series if Zoom then begin Zoom:=False; @@ -1529,66 +1688,80 @@ begin FYGraphMax:=0; end; end; - -// Image <-> Graph coeff calculation -if FXGraphMax<>FXGraphMin then + // Image <-> Graph coeff calculation + if FXGraphMax<>FXGraphMin then begin - ax:=(XImageMax-XImageMin)/(FXGraphMax-FXGraphMin); - bx:=XImageMax-ax*FXGraphMax; + case BottomAxisScale of + asIncreasing: + begin + ax:=(XImageMax-XImageMin)/(FXGraphMax-FXGraphMin); + bx:=XImageMax-ax*FXGraphMax; + end; + asDecreasing: + begin + ax:=(XImageMax-XImageMin)/(FXGraphMin-FXGraphMax); + bx:=XImageMin-ax*FXGraphMax; + end; + end; end -else + else begin - ax:=1; - bx:=0; + ax:=1; + bx:=0; end; -if FYGraphMax<>FYGraphMin then + if FYGraphMax<>FYGraphMin then begin - ay:=(YImageMax-YImageMin)/(FYGraphMax-FYGraphMin); - by:=YImageMax-ay*FYGraphMax; + case LeftAxisScale of + asIncreasing: + begin + ay:=(YImageMax-YImageMin)/(FYGraphMax-FYGraphMin); + by:=YImageMax-ay*FYGraphMax; + end; + asDecreasing: + begin + ay:=(YImageMax-YImageMin)/(FYGraphMin-FYGraphMax); + by:=YImageMin-ay*FYGraphMax; + end; + end; end -else + else begin - ay:=1; - by:=0; + ay:=1; + by:=0; end; - -Clean; -DrawAxis; -DisplaySeries; -DrawTitleFoot; - -if FLegend.Visible then DrawLegend; - -if FShowVerticalReticule then - DrawVerticalReticule(XMarkOld); -if FShowReticule then - DrawReticule(XMarkOld,YMarkOld); + Clean; + DrawAxis; + DisplaySeries; + DrawTitleFoot; + if FLegend.Visible then DrawLegend; + if FShowVerticalReticule then DrawVerticalReticule(XMarkOld); + if FShowReticule then DrawReticule(XMarkOld,YMarkOld); end; procedure TChart.XGraphToImage(Xin:Double;var XOut:Integer); begin -XOut:=Round(ax*XIn+bx); + XOut:=Round(ax*XIn+bx); end; procedure TChart.YGraphToImage(Yin:Double;var YOut:Integer); begin -YOut:=Round(ay*YIn+by); + YOut:=Round(ay*YIn+by); end; procedure TChart.GraphToImage(Xin,Yin:Double;var XOut,YOut:Integer); begin -XGraphToImage(Xin,XOut); -YGraphToImage(Yin,YOut); + XGraphToImage(Xin,XOut); + YGraphToImage(Yin,YOut); end; procedure TChart.XImageToGraph(XIn:Integer;var XOut:Double); begin -XOut:=(XIn-bx)/ax; + XOut:=(XIn-bx)/ax; end; procedure TChart.YImageToGraph(YIn:Integer;var YOut:Double); begin -YOut:=(YIn-by)/ay; + YOut:=(YIn-by)/ay; end; procedure TChart.ImageToGraph(XIn,YIn:Integer;var XOut,YOut:Double); @@ -1602,16 +1775,9 @@ var i:Integer; Serie:TChartSeries; Rgn : HRGN; - p: array[0..1] of TPoint; begin - //set cliping region - p[0].x := XImageMin; - p[0].y := YImageMax; - p[1].x := XImageMax; - p[1].y := YImageMin; -// LPtoDP(Canvas.Handle, p, 2); - - Rgn := CreateRectRgn(p[0].x, p[0].y, p[1].x, p[1].y); + //set cliping region so we don't draw outsite + Rgn := CreateRectRgn(XImageMin, YImageMax, XImageMax, YImageMin); SelectClipRgn (Canvas.Handle, Rgn); // Update all series @@ -1619,6 +1785,9 @@ begin Serie:= TChartSeries( Series[i] ); if Serie.Active then Serie.Draw; end; + + //now disable clipping + SelectClipRgn(Canvas.Handle, 0); end; procedure TChart.SetShowVerticalReticule(Value:Boolean);