TAChart: Implement stacked area series

git-svn-id: trunk@27135 -
This commit is contained in:
ask 2010-08-18 11:59:30 +00:00
parent 5ed0ea3d8e
commit 592cd0f85b
3 changed files with 93 additions and 58 deletions

View File

@ -169,6 +169,7 @@ type
function GetXRange(AX: Double; AIndex: Integer): Double; function GetXRange(AX: Double; AIndex: Integer): Double;
procedure PrepareGraphPoints( procedure PrepareGraphPoints(
const AExtent: TDoubleRect; AFilterByExtent: Boolean); const AExtent: TDoubleRect; AFilterByExtent: Boolean);
procedure UpdateGraphPoints(AIndex: Integer);
procedure UpdateMargins(ACanvas: TCanvas; var AMargins: TRect); override; procedure UpdateMargins(ACanvas: TCanvas; var AMargins: TRect); override;
property UseReticule: Boolean property UseReticule: Boolean
read FUseReticule write SetUseReticule default false; read FUseReticule write SetUseReticule default false;
@ -728,6 +729,18 @@ begin
UpdateParentChart; UpdateParentChart;
end; end;
procedure TBasicPointSeries.UpdateGraphPoints(AIndex: Integer);
var
i: Integer;
begin
if IsRotated then
for i := FLoBound to FUpBound do
FGraphPoints[i - FLoBound].X += AxisToGraphY(Source[i]^.YList[AIndex])
else
for i := FLoBound to FUpBound do
FGraphPoints[i - FLoBound].Y += AxisToGraphY(Source[i]^.YList[AIndex]);
end;
procedure TBasicPointSeries.UpdateMargins(ACanvas: TCanvas; var AMargins: TRect); procedure TBasicPointSeries.UpdateMargins(ACanvas: TCanvas; var AMargins: TRect);
const const
LABEL_TO_BORDER = 4; LABEL_TO_BORDER = 4;

View File

@ -128,6 +128,7 @@ type
destructor Destroy; override; destructor Destroy; override;
procedure Draw(ACanvas: TCanvas); override; procedure Draw(ACanvas: TCanvas); override;
function Extent: TDoubleRect; override;
published published
property AxisIndexX; property AxisIndexX;
property AxisIndexY; property AxisIndexY;
@ -366,7 +367,7 @@ end;
procedure TLineSeries.Draw(ACanvas: TCanvas); procedure TLineSeries.Draw(ACanvas: TCanvas);
var var
ext: TDoubleRect; ext: TDoubleRect;
i, j: Integer; i: Integer;
begin begin
with Extent do begin with Extent do begin
ext.a := AxisToGraph(a); ext.a := AxisToGraph(a);
@ -380,12 +381,7 @@ begin
PrepareGraphPoints(ext, LineType <> ltFromOrigin); PrepareGraphPoints(ext, LineType <> ltFromOrigin);
DrawSingleLineInStack(ACanvas); DrawSingleLineInStack(ACanvas);
for i := 0 to Source.YCount - 2 do begin for i := 0 to Source.YCount - 2 do begin
if IsRotated then UpdateGraphPoints(i);
for j := FLoBound to FUpBound do
FGraphPoints[j - FLoBound].X += AxisToGraphY(Source[j]^.YList[i])
else
for j := FLoBound to FUpBound do
FGraphPoints[j - FLoBound].Y += AxisToGraphY(Source[j]^.YList[i]);
DrawSingleLineInStack(ACanvas); DrawSingleLineInStack(ACanvas);
end; end;
end; end;
@ -975,16 +971,18 @@ var
pts: TPointArray; pts: TPointArray;
numPts: Integer; numPts: Integer;
procedure PushPoint(const A: TDoublePoint); procedure PushPoint(const AP: TPoint); overload;
var
p: TPoint;
begin begin
p := ParentChart.GraphToImage(A); if (numPts > 0) and (AP = pts[numPts - 1]) then exit;
if (numPts > 0) and (p = pts[numPts - 1]) then exit; pts[numPts] := AP;
pts[numPts] := p;
numPts += 1; numPts += 1;
end; end;
procedure PushPoint(const AP: TDoublePoint); overload;
begin
PushPoint(ParentChart.GraphToImage(AP));
end;
function ProjToLine(const APt: TDoublePoint; ACoord: Double): TDoublePoint; function ProjToLine(const APt: TDoublePoint; ACoord: Double): TDoublePoint;
begin begin
Result := APt; Result := APt;
@ -993,14 +991,14 @@ var
else else
Result.Y := ACoord; Result.Y := ACoord;
end; end;
var var
i: Integer; i, j, n2, numPrevPts: Integer;
a, b: TDoublePoint; a, b: TDoublePoint;
ext, ext2: TDoubleRect; ext, ext2: TDoubleRect;
z: Double; z, z1, z2: Double;
prevPts: TPointArray;
begin begin
if Count = 0 then exit; if IsEmpty then exit;
ext := ParentChart.CurrentExtent; ext := ParentChart.CurrentExtent;
ext2 := ext; ext2 := ext;
@ -1010,52 +1008,70 @@ begin
PrepareGraphPoints(ext, true); PrepareGraphPoints(ext, true);
if Length(FGraphPoints) = 0 then exit; if Length(FGraphPoints) = 0 then exit;
SetLength(pts, Length(FGraphPoints) * 2 + 2); SetLength(pts, Length(FGraphPoints) * 4 + 4);
numPts := 0; SetLength(prevPts, Length(pts));
numPrevPts := 0;
if UseZeroLevel then if UseZeroLevel then
z := AxisToGraphY(ZeroLevel) z := AxisToGraphY(ZeroLevel)
else if IsRotated then
z := ext2.a.X
else else
z := ext2.a.Y; z := IfThen(IsRotated, ext2.a.X, ext2.a.Y);
z1 := z;
z2 := z;
a := ProjToRect(FGraphPoints[0], ext2); for j := 0 to Source.YCount - 1 do begin
PushPoint(ProjToLine(a, z)); if j > 0 then
PushPoint(a); UpdateGraphPoints(j - 1);
for i := 0 to High(FGraphPoints) - 1 do begin numPts := 0;
a := FGraphPoints[i]; a := ProjToRect(FGraphPoints[0], ext2);
b := FGraphPoints[i + 1]; PushPoint(ProjToLine(a, z1));
case ConnectType of z1 := IfThen(IsRotated, a.X, a.Y);
ctLine: ; for i := 0 to High(FGraphPoints) - 1 do begin
ctStepXY: a := FGraphPoints[i];
if IsRotated then b := FGraphPoints[i + 1];
b.X := a.X case ConnectType of
else ctLine: ;
b.Y := a.Y; ctStepXY:
ctStepYX: if IsRotated then
if IsRotated then b.X := a.X
a.X := b.X else
else b.Y := a.Y;
a.Y := b.Y; ctStepYX:
end; if IsRotated then
// Avoid integer overflow at extreme zoom levels. a.X := b.X
if LineIntersectsRect(a, b, ext2) then begin else
PushPoint(a); a.Y := b.Y;
PushPoint(b); 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; 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;
ACanvas.Brush.Assign(AreaBrush);
ACanvas.Pen.Assign(AreaContourPen);
if Depth > 0 then
// Rendering is incorrect when values cross zero level.
for i := 1 to n2 - 2 do
DrawLineDepth(ACanvas, pts[i], pts[i + 1], Depth);
ACanvas.Polygon(pts, false, 0, numPts);
DrawLabels(ACanvas);
end; end;
a := ProjToRect(FGraphPoints[High(FGraphPoints)], ext2);
PushPoint(a);
PushPoint(ProjToLine(a, z));
ACanvas.Brush.Assign(AreaBrush);
ACanvas.Pen.Assign(AreaContourPen);
if Depth > 0 then
// Rendering is incorrect when values cross zero level.
for i := 0 to numPts - 2 do
DrawLineDepth(ACanvas, pts[i], pts[i + 1], Depth);
ACanvas.Polygon(pts, false, 0, numPts);
if AreaLinesPen.Style <> psClear then begin if AreaLinesPen.Style <> psClear then begin
ACanvas.Pen.Assign(AreaLinesPen); ACanvas.Pen.Assign(AreaLinesPen);
for i := 1 to High(FGraphPoints) - 1 do begin for i := 1 to High(FGraphPoints) - 1 do begin
@ -1064,7 +1080,13 @@ begin
ACanvas.Line(ParentChart.GraphToImage(a), ParentChart.GraphToImage(b)); ACanvas.Line(ParentChart.GraphToImage(a), ParentChart.GraphToImage(b));
end; end;
end; end;
DrawLabels(ACanvas); end;
function TAreaSeries.Extent: TDoubleRect;
begin
Result := inherited Extent;
if not IsEmpty and UseZeroLevel then
UpdateMinMax(ZeroLevel, Result.a.Y, Result.b.Y);
end; end;
function TAreaSeries.GetLabelDirection(AIndex: Integer): TLabelDirection; function TAreaSeries.GetLabelDirection(AIndex: Integer): TLabelDirection;

View File

@ -17,7 +17,7 @@
unit TASources; unit TASources;
{$mode objfpc}{$H+} {$H+}
interface interface