TAChart: Pre-filter points outside of the current extent in TLineSeries.Draw

git-svn-id: trunk@25921 -
This commit is contained in:
ask 2010-06-05 15:06:46 +00:00
parent 1e84a4ad0a
commit 160c2dc205
2 changed files with 38 additions and 14 deletions

View File

@ -408,20 +408,20 @@ var
// For extremely long series (10000 points or more), the Canvas.Line // For extremely long series (10000 points or more), the Canvas.Line
// call becomes a bottleneck. So represent a serie as a sequence of polylines. // call becomes a bottleneck. So represent a serie as a sequence of polylines.
// This achieves approximately 3x speedup for the typical case. // This achieves approximately 3x speedup for the typical case.
SetLength(points, 2 * Count); SetLength(points, 2 * Length(gp));
SetLength(breaks, Count + 1); SetLength(breaks, Length(gp) + 1);
case LineType of case LineType of
ltFromPrevious: begin ltFromPrevious: begin
for i := 0 to Count - 2 do for i := 0 to High(gp) - 1 do
CacheLine(gp[i], gp[i + 1]); CacheLine(gp[i], gp[i + 1]);
end; end;
ltFromOrigin: begin ltFromOrigin: begin
orig := AxisToGraph(ZeroDoublePoint); orig := AxisToGraph(ZeroDoublePoint);
for i := 0 to Count - 1 do for i := 0 to High(gp) do
CacheLine(orig, gp[i]); CacheLine(orig, gp[i]);
end; end;
ltStepXY, ltStepYX: begin ltStepXY, ltStepYX: begin
for i := 0 to Count - 2 do begin for i := 0 to High(gp) - 1 do begin
if (LineType = ltStepXY) xor IsRotated then if (LineType = ltStepXY) xor IsRotated then
m := DoublePoint(gp[i + 1].X, gp[i].Y) m := DoublePoint(gp[i + 1].X, gp[i].Y)
else else
@ -451,33 +451,44 @@ var
end; end;
var var
i: Integer; i, lb, ub: Integer;
ai: TPoint; ai: TPoint;
ext: TDoubleRect; ext: TDoubleRect;
begin begin
// Do not draw anything if the series extent does not intersect CurrentExtent.
ext.a := AxisToGraph(Source.Extent.a); ext.a := AxisToGraph(Source.Extent.a);
ext.b := AxisToGraph(Source.Extent.b); ext.b := AxisToGraph(Source.Extent.b);
if LineType = ltFromOrigin then if LineType = ltFromOrigin then
ExpandRect(ext, AxisToGraph(ZeroDoublePoint)); ExpandRect(ext, AxisToGraph(ZeroDoublePoint));
if not RectIntersectsRect(ext, ParentChart.CurrentExtent) then exit; if not RectIntersectsRect(ext, ParentChart.CurrentExtent) then exit;
SetLength(gp, Count); // Find an interval of x-values intersecting the CurrentExtent.
// Requires monotonic (but not necessarily increasing) axis transformation.
lb := 0;
ub := Count - 1;
if LineType <> ltFromOrigin then begin
Source.FindBounds(GraphToAxisX(ext.a.X), GraphToAxisX(ext.b.X), lb, ub);
lb := Max(lb - 1, 0);
ub := Min(ub + 1, Count - 1);
end;
SetLength(gp, ub - lb + 1);
if (AxisIndexX < 0) and (AxisIndexY < 0) then if (AxisIndexX < 0) and (AxisIndexY < 0) then
// Optimization: bypass transformations in the default case. // Optimization: bypass transformations in the default case.
for i := 0 to Count - 1 do for i := lb to ub do
with Source[i]^ do with Source[i]^ do
gp[i] := DoublePoint(X, Y) gp[i - lb] := DoublePoint(X, Y)
else else
for i := 0 to Count - 1 do for i := lb to ub do
gp[i] := GetGraphPoint(i); gp[i - lb] := GetGraphPoint(i);
DrawLines; DrawLines;
DrawLabels(ACanvas); DrawLabels(ACanvas);
if FShowPoints then if FShowPoints then
for i := 0 to Count - 1 do begin for i := lb to ub do begin
if not ParentChart.IsPointInViewPort(gp[i]) then continue; if not ParentChart.IsPointInViewPort(gp[i - lb]) then continue;
ai := ParentChart.GraphToImage(gp[i]); ai := ParentChart.GraphToImage(gp[i - lb]);
FPointer.Draw(ACanvas, ai, GetColor(i)); FPointer.Draw(ACanvas, ai, GetColor(i));
if Assigned(FOnDrawPointer) then if Assigned(FOnDrawPointer) then
FOnDrawPointer(Self, ACanvas, i, ai); FOnDrawPointer(Self, ACanvas, i, ai);

View File

@ -61,6 +61,7 @@ type
public public
class procedure CheckFormat(const AFormat: String); class procedure CheckFormat(const AFormat: String);
function Extent: TDoubleRect; virtual; function Extent: TDoubleRect; virtual;
procedure FindBounds(AXMin, AXMax: Double; out ALB, AUB: Integer);
function FormatItem(const AFormat: String; AIndex: Integer): String; function FormatItem(const AFormat: String; AIndex: Integer): String;
function IsSorted: Boolean; virtual; function IsSorted: Boolean; virtual;
procedure ValuesInRange( procedure ValuesInRange(
@ -306,6 +307,18 @@ begin
Result := FExtent; Result := FExtent;
end; end;
procedure TCustomChartSource.FindBounds(
AXMin, AXMax: Double; out ALB, AUB: Integer);
begin
EnsureOrder(AXMin, AXMax);
ALB := 0;
while (ALB < Count) and (Item[ALB]^.X < AXMin) do
Inc(ALB);
AUB := Count - 1;
while (AUB > 0) and (Item[AUB]^.X < AXMax) do
Inc(AUB);
end;
function TCustomChartSource.FormatItem( function TCustomChartSource.FormatItem(
const AFormat: String; AIndex: Integer): String; const AFormat: String; AIndex: Integer): String;
const const