diff --git a/components/tachart/demo/nan/Main.lfm b/components/tachart/demo/nan/Main.lfm index e5049c3143..d22859dc95 100644 --- a/components/tachart/demo/nan/Main.lfm +++ b/components/tachart/demo/nan/Main.lfm @@ -41,6 +41,10 @@ object Form1: TForm1 BarBrush.Color = clRed Source = lcs1 end + object Chart1AreaSeries1: TAreaSeries + Active = False + Source = lcs1 + end object Chart1PieSeries1: TPieSeries Active = False Source = lcs1 @@ -79,6 +83,7 @@ object Form1: TForm1 Items.Strings = ( 'Line' 'Bar' + 'Area' 'Pie' ) OnClick = rgSeriesTypeClick diff --git a/components/tachart/demo/nan/Main.pas b/components/tachart/demo/nan/Main.pas index e39b034e05..d064327cc4 100644 --- a/components/tachart/demo/nan/Main.pas +++ b/components/tachart/demo/nan/Main.pas @@ -11,6 +11,7 @@ uses type TForm1 = class(TForm) Chart1: TChart; + Chart1AreaSeries1: TAreaSeries; Chart1BarSeries1: TBarSeries; Chart1LineSeries1: TLineSeries; Chart1PieSeries1: TPieSeries; diff --git a/components/tachart/demo/nan/nandemo.lpi b/components/tachart/demo/nan/nandemo.lpi index 86503ef1ea..eb95f4a510 100644 --- a/components/tachart/demo/nan/nandemo.lpi +++ b/components/tachart/demo/nan/nandemo.lpi @@ -64,6 +64,8 @@ + + diff --git a/components/tachart/tacustomseries.pas b/components/tachart/tacustomseries.pas index 33231b6539..40341fd6a2 100644 --- a/components/tachart/tacustomseries.pas +++ b/components/tachart/tacustomseries.pas @@ -212,6 +212,9 @@ type FUpBound: Integer; FUseReticule: Boolean; + strict protected + procedure UpdateGraphPoints(AIndex: Integer); overload; inline; + procedure UpdateGraphPoints(AIndex, ALo, AUp: Integer); overload; protected procedure AfterAdd; override; procedure AfterDrawPointer( @@ -224,7 +227,6 @@ type function GetZeroLevel: Double; virtual; procedure PrepareGraphPoints( const AExtent: TDoubleRect; AFilterByExtent: Boolean); - procedure UpdateGraphPoints(AIndex: Integer); procedure UpdateMargins(ADrawer: IChartDrawer; var AMargins: TRect); override; procedure UpdateMinXRange; @@ -1025,16 +1027,21 @@ begin UpdateParentChart; end; -procedure TBasicPointSeries.UpdateGraphPoints(AIndex: Integer); +procedure TBasicPointSeries.UpdateGraphPoints(AIndex, ALo, AUp: Integer); var i: Integer; begin if IsRotated then - for i := FLoBound to FUpBound do - FGraphPoints[i - FLoBound].X += AxisToGraphY(Source[i]^.YList[AIndex]) + for i := ALo to AUp do + FGraphPoints[i - ALo].X += AxisToGraphY(Source[i]^.YList[AIndex]) else - for i := FLoBound to FUpBound do - FGraphPoints[i - FLoBound].Y += AxisToGraphY(Source[i]^.YList[AIndex]); + for i := ALo to AUp do + FGraphPoints[i - ALo].Y += AxisToGraphY(Source[i]^.YList[AIndex]); +end; + +procedure TBasicPointSeries.UpdateGraphPoints(AIndex: Integer); +begin + UpdateGraphPoints(AIndex, FLoBound, FUpBound); end; procedure TBasicPointSeries.UpdateMargins( diff --git a/components/tachart/taseries.pas b/components/tachart/taseries.pas index a5df13dcf7..fbe3a994f5 100644 --- a/components/tachart/taseries.pas +++ b/components/tachart/taseries.pas @@ -1068,11 +1068,91 @@ var end; var - i, j, n2, numPrevPts: Integer; - a, b: TDoublePoint; ext, ext2: TDoubleRect; - z, z1, z2: Double; prevPts: TPointArray; + + procedure DrawSegment(AStart, AEnd: Integer); + var + i, j, n2, numPrevPts: Integer; + a, b: TDoublePoint; + z, z1, z2: Double; + begin + numPts := 0; + numPrevPts := 0; + + if UseZeroLevel then + z := AxisToGraphY(ZeroLevel) + else + z := IfThen(IsRotated, ext2.a.X, ext2.a.Y); + z1 := z; + z2 := z; + + for j := 0 to Source.YCount - 1 do begin + if j > 0 then + UpdateGraphPoints(j - 1, AStart, AEnd); + numPts := 0; + a := ProjToRect(FGraphPoints[AStart], ext2); + PushPoint(ProjToLine(a, z1)); + z1 := IfThen(IsRotated, a.X, a.Y); + for i := AStart to AEnd - 1 do begin + a := FGraphPoints[i]; + b := FGraphPoints[i + 1]; + case ConnectType of + ctLine: ; + ctStepXY: + if IsRotated then + b.X := a.X + else + b.Y := a.Y; + ctStepYX: + if IsRotated then + a.X := b.X + else + a.Y := b.Y; + end; + // Avoid integer overflow at extreme zoom levels. + if LineIntersectsRect(a, b, ext2) then begin + PushPoint(a); + PushPoint(b); + end + else begin + PushPoint(ProjToRect(a, ext2)); + PushPoint(ProjToRect(b, ext2)); + end; + end; + a := ProjToRect(FGraphPoints[AEnd], ext2); + PushPoint(ProjToLine(a, z2)); + z2 := IfThen(IsRotated, a.X, a.Y); + n2 := numPts; + + for i := 0 to numPrevPts - 1 do + PushPoint(prevPts[numPrevPts - i - 1]); + for i := 0 to n2 - 1 do + prevPts[i] := pts[i]; + numPrevPts := n2; + + ADrawer.Brush := AreaBrush; + ADrawer.Pen := AreaContourPen; + if Styles <> nil then + Styles.Apply(ADrawer, j); + if Depth > 0 then + // Rendering is incorrect when values cross zero level. + for i := 1 to n2 - 2 do + ADrawer.DrawLineDepth(pts[i], pts[i + 1], Depth); + ADrawer.Polygon(pts, 0, numPts); + end; + if AreaLinesPen.Style <> psClear then begin + ADrawer.Pen := AreaLinesPen; + for i := AStart + 1 to AEnd - 1 do begin + a := ProjToRect(FGraphPoints[i], ext2); + b := ProjToLine(a, z); + ADrawer.Line(ParentChart.GraphToImage(a), ParentChart.GraphToImage(b)); + end; + end; + end; + +var + i, j: Integer; begin if IsEmpty then exit; @@ -1086,77 +1166,17 @@ begin SetLength(pts, Length(FGraphPoints) * 4 + 4); SetLength(prevPts, Length(pts)); - numPrevPts := 0; - - if UseZeroLevel then - z := AxisToGraphY(ZeroLevel) - else - z := IfThen(IsRotated, ext2.a.X, ext2.a.Y); - z1 := z; - z2 := z; - - for j := 0 to Source.YCount - 1 do begin - if j > 0 then - UpdateGraphPoints(j - 1); - numPts := 0; - a := ProjToRect(FGraphPoints[0], ext2); - PushPoint(ProjToLine(a, z1)); - z1 := IfThen(IsRotated, a.X, a.Y); - for i := 0 to High(FGraphPoints) - 1 do begin - a := FGraphPoints[i]; - b := FGraphPoints[i + 1]; - case ConnectType of - ctLine: ; - ctStepXY: - if IsRotated then - b.X := a.X - else - b.Y := a.Y; - ctStepYX: - if IsRotated then - a.X := b.X - else - a.Y := b.Y; - end; - // Avoid integer overflow at extreme zoom levels. - if LineIntersectsRect(a, b, ext2) then begin - PushPoint(a); - PushPoint(b); + j := -1; + for i := 0 to High(FGraphPoints) do + if IsNan(FGraphPoints[i]) = (j >= 0) then + if j >= 0 then begin + DrawSegment(j, i - 1); + j := -1; end - else begin - PushPoint(ProjToRect(a, ext2)); - PushPoint(ProjToRect(b, ext2)); - end; - end; - a := ProjToRect(FGraphPoints[High(FGraphPoints)], ext2); - PushPoint(ProjToLine(a, z2)); - z2 := IfThen(IsRotated, a.X, a.Y); - n2 := numPts; - - for i := 0 to numPrevPts - 1 do - PushPoint(prevPts[numPrevPts - i - 1]); - for i := 0 to n2 - 1 do - prevPts[i] := pts[i]; - numPrevPts := n2; - - ADrawer.Brush := AreaBrush; - ADrawer.Pen := AreaContourPen; - if Styles <> nil then - Styles.Apply(ADrawer, j); - if Depth > 0 then - // Rendering is incorrect when values cross zero level. - for i := 1 to n2 - 2 do - ADrawer.DrawLineDepth(pts[i], pts[i + 1], Depth); - ADrawer.Polygon(pts, 0, numPts); - end; - if AreaLinesPen.Style <> psClear then begin - ADrawer.Pen := AreaLinesPen; - for i := 1 to High(FGraphPoints) - 1 do begin - a := ProjToRect(FGraphPoints[i], ext2); - b := ProjToLine(a, z); - ADrawer.Line(ParentChart.GraphToImage(a), ParentChart.GraphToImage(b)); - end; - end; + else + j := i; + if j >= 0 then + DrawSegment(j, High(FGraphPoints)); DrawLabels(ADrawer); end;