TAChart: Allow XCount=0 for TChartSource meaning "replace X by point index". Still some issues.

git-svn-id: trunk@60995 -
This commit is contained in:
wp 2019-04-16 14:16:58 +00:00
parent eee4ab0ff1
commit ac880dd4b9
5 changed files with 101 additions and 50 deletions

View File

@ -920,12 +920,18 @@ end;
function TChartSeries.GetGraphPointX(AIndex: Integer): Double; function TChartSeries.GetGraphPointX(AIndex: Integer): Double;
begin begin
Result := AxisToGraphX(Source[AIndex]^.X); if Source.XCount = 0 then
Result := AxisToGraphX(Index)
else
Result := AxisToGraphX(Source[AIndex]^.X);
end; end;
function TChartSeries.GetGraphPointX(AIndex, AXIndex: Integer): Double; function TChartSeries.GetGraphPointX(AIndex, AXIndex: Integer): Double;
begin begin
Result := AxisToGraphX(Source[AIndex]^.GetX(AXIndex)); if Source.XCount = 0 then
Result := AxisToGraphX(AIndex)
else
Result := AxisToGraphX(Source[AIndex]^.GetX(AXIndex));
end; end;
function TChartSeries.GetGraphPointY(AIndex: Integer): Double; function TChartSeries.GetGraphPointY(AIndex: Integer): Double;
@ -988,7 +994,7 @@ end;
class procedure TChartSeries.GetXYCountNeeded(out AXCount, AYCount: Cardinal); class procedure TChartSeries.GetXYCountNeeded(out AXCount, AYCount: Cardinal);
begin begin
AXCount := 1; AXCount := 0;
AYCount := 1; AYCount := 1;
end; end;
@ -1004,15 +1010,18 @@ end;
function TChartSeries.GetXValue(AIndex: Integer): Double; function TChartSeries.GetXValue(AIndex: Integer): Double;
begin begin
Result := Source[AIndex]^.X; if Source.XCount > 0 then
Result := Source[AIndex]^.X
else
Result := AIndex;
end; end;
function TChartSeries.GetXValues(AIndex, AXIndex: Integer): Double; function TChartSeries.GetXValues(AIndex, AXIndex: Integer): Double;
begin begin
if AXIndex = 0 then if AXIndex > 0 then
Result := Source[AIndex]^.X Result := Source[AIndex]^.XList[AXIndex - 1]
else else
Result := Source[AIndex]^.XList[AXIndex - 1]; Result := Source[AIndex]^.X;
end; end;
function TChartSeries.GetYImgValue(AIndex: Integer): Integer; function TChartSeries.GetYImgValue(AIndex: Integer): Integer;
@ -1777,12 +1786,17 @@ begin
FindExtentInterval(AExtent, AFilterByExtent); FindExtentInterval(AExtent, AFilterByExtent);
SetLength(FGraphPoints, Max(FUpBound - FLoBound + 1, 0)); SetLength(FGraphPoints, Max(FUpBound - FLoBound + 1, 0));
if (AxisIndexX < 0) and (AxisIndexY < 0) then if (AxisIndexX < 0) and (AxisIndexY < 0) then begin
// Optimization: bypass transformations in the default case. // Optimization: bypass transformations in the default case.
for i := FLoBound to FUpBound do if Source.XCount > 0 then
with Source[i]^ do for i := FLoBound to FUpBound do
FGraphPoints[i - FLoBound] := DoublePoint(X, Y) with Source[i]^ do
else FGraphPoints[i - FLoBound] := DoublePoint(X, Y)
else
for i := FLoBound to FUpBound do
with Source[i]^ do
FGraphPoints[i - FLoBound] := DoublePoint(i, Y);
end else
for i := FLoBound to FUpBound do for i := FLoBound to FUpBound do
FGraphPoints[i - FLoBound] := GetGraphPoint(i); FGraphPoints[i - FLoBound] := GetGraphPoint(i);
end; end;

View File

@ -827,6 +827,9 @@ begin
end else end else
for i:=0 to Count - 1 do for i:=0 to Count - 1 do
UpdateMinMax(Item[i]^.X, FBasicExtent.a.X, FBasicExtent.b.X); UpdateMinMax(Item[i]^.X, FBasicExtent.a.X, FBasicExtent.b.X);
end else begin
UpdateMinMax(0, FBasicExtent.a.X, FBasicExtent.b.X);
UpdateMinMax(Count-1, FBasicExtent.a.X, FBasicExtent.b.X);
end; end;
if YCount > 0 then begin if YCount > 0 then begin

View File

@ -1280,21 +1280,32 @@ var
n, ok: Integer; n, ok: Integer;
begin begin
FIsUnorderedX := false; FIsUnorderedX := false;
while (ASourceIndex < ASource.Count) and IsNan(ASource[ASourceIndex]^.Point) do if ASource.XCount > 0 then
ASourceIndex += 1; while (ASourceIndex < ASource.Count) and IsNan(ASource[ASourceIndex]^.Point) do
ASourceIndex += 1;
FSourceStartIndex := ASourceIndex; FSourceStartIndex := ASourceIndex;
FFirstCacheIndex := ACacheIndex; FFirstCacheIndex := ACacheIndex;
while (ASourceIndex < ASource.Count) and not IsNan(ASource[ASourceIndex]^.Point) do begin if ASource.XCount > 0 then
with ASource[ASourceIndex]^ do while (ASourceIndex < ASource.Count) and not IsNan(ASource[ASourceIndex]^.Point) do begin
if (ACacheIndex > FFirstCacheIndex) and (FOwner.FX[ACacheIndex - 1] >= X) then with ASource[ASourceIndex]^ do
FIsUnorderedX := true if (ACacheIndex > FFirstCacheIndex) and (FOwner.FX[ACacheIndex - 1] >= X) then
else begin FIsUnorderedX := true
FOwner.FX[ACacheIndex] := X; else begin
FOwner.FX[ACacheIndex] := X;
FOwner.FY[ACacheIndex] := Y;
ACacheIndex += 1;
end;
ASourceIndex += 1;
end
else
while ASourceIndex < ASource.Count do begin
with ASource[ASourceIndex]^ do begin
FOwner.FX[ACacheIndex] := ASourceIndex;
FOwner.FY[ACacheIndex] := Y; FOwner.FY[ACacheIndex] := Y;
ACacheIndex += 1; ACacheIndex += 1;
end; end;
ASourceIndex += 1; ASourceIndex += 1;
end; end;
FLastCacheIndex := ACacheIndex - 1; FLastCacheIndex := ACacheIndex - 1;
if FLastCacheIndex < FFirstCacheIndex then exit(false); // No points if FLastCacheIndex < FFirstCacheIndex then exit(false); // No points
if IsFewPoints then exit(true); if IsFewPoints then exit(true);
@ -1654,20 +1665,25 @@ procedure TFitSeries.CalcXRange(out AXMin, AXMax: Double);
var var
ext: TDoubleRect; ext: TDoubleRect;
begin begin
with Source.BasicExtent do begin if Source.XCount > 0 then begin
ext.a := AxisToGraph(a); with Source.BasicExtent do begin
ext.b := AxisToGraph(b); ext.a := AxisToGraph(a);
end; ext.b := AxisToGraph(b);
NormalizeRect(ext); end;
if IsRotated then begin NormalizeRect(ext);
AXMin := GraphToAxisY(ext.a.Y); if IsRotated then begin
AXMax := GraphToAxisY(ext.b.Y); AXMin := GraphToAxisY(ext.a.Y);
AXMax := GraphToAxisY(ext.b.Y);
end else begin
AXMin := GraphToAxisX(ext.a.X);
AXMax := GraphToAxisX(ext.b.X);
end;
EnsureOrder(AXMin, AXMax);
FFitRange.Intersect(AXMin, AXMax);
end else begin end else begin
AXMin := GraphToAxisX(ext.a.X); AXMin := 0;
AXMax := GraphToAxisX(ext.b.X); AXMax := Source.Count - 1;
end; end;
EnsureOrder(AXMin, AXMax);
FFitRange.Intersect(AXMin, AXMax);
end; end;
procedure TFitSeries.Assign(ASource: TPersistent); procedure TFitSeries.Assign(ASource: TPersistent);
@ -1786,7 +1802,10 @@ var
function IsValidPoint(AX, AY: Double): Boolean; inline; function IsValidPoint(AX, AY: Double): Boolean; inline;
begin begin
Result := not IsNaN(AX) and not IsNaN(AY) and InRange(AX, xmin, xmax); if Source.XCount > 0 then
Result := not IsNaN(AX) and not IsNaN(AY) and InRange(AX, xmin, xmax)
else
Result := not IsNaN(AY);
end; end;
procedure TryFit; procedure TryFit;
@ -1816,7 +1835,10 @@ var
for i := 0 to ns - 1 do for i := 0 to ns - 1 do
with Source.Item[i]^ do with Source.Item[i]^ do
if IsValidPoint(X, Y) then begin if IsValidPoint(X, Y) then begin
xv[j] := TransformX(X); if Source.XCount > 0 then
xv[j] := TransformX(X)
else
xv[j] := TransformX(i);
yv[j] := TransformY(Y); yv[j] := TransformY(Y);
if hasErrorBars and Source.GetYErrorBarLimits(i, yp, yn) then if hasErrorBars and Source.GetYErrorBarLimits(i, yp, yn) then
dy[j] := abs(TransformY(yp) - TransformY(yn)) / 2; dy[j] := abs(TransformY(yp) - TransformY(yn)) / 2;

View File

@ -1418,7 +1418,10 @@ begin
if Length(FAngleCache) = Count then exit; if Length(FAngleCache) = Count then exit;
SetLength(FAngleCache, Count); SetLength(FAngleCache, Count);
for i := 0 to Count - 1 do begin for i := 0 to Count - 1 do begin
SinCos(Source[i]^.X, s, c); if Source.XCount > 0 then
SinCos(Source[i]^.X, s, c)
else
SinCos(i, s, c);
FAngleCache[i].FSin := s; FAngleCache[i].FSin := s;
FAngleCache[i].FCos := c; FAngleCache[i].FCos := c;
end; end;

View File

@ -1243,6 +1243,7 @@ begin
SetLength(heights, Source.YCount + 1); SetLength(heights, Source.YCount + 1);
for pointIndex := FLoBound to FUpBound do begin for pointIndex := FLoBound to FUpBound do begin
p := Source[pointIndex]^.Point; p := Source[pointIndex]^.Point;
if Source.XCount = 0 then p.X := pointIndex + FLoBound;
if SkipMissingValues(pointIndex) then if SkipMissingValues(pointIndex) then
continue; continue;
p.X := AxisToGraphX(p.X); p.X := AxisToGraphX(p.X);
@ -1518,19 +1519,25 @@ begin
UpdateMinMax(GraphToAxisY(ZeroLevel), Result.a.Y, Result.b.Y); UpdateMinMax(GraphToAxisY(ZeroLevel), Result.a.Y, Result.b.Y);
// Show first and last bars fully. // Show first and last bars fully.
i := 0; if Source.XCount = 0 then begin
x := NearestXNumber(i, +1); // --> x is in graph units BarOffsetWidth(x, 0, ofs, w);
if not IsNan(x) then begin Result.a.X -= (ofs + w);
BarOffsetWidth(x, i, ofs, w); Result.b.X += (ofs + w);
x := GraphToAxisX(x + ofs - w); // x is in graph units, Extent in axis units! end else begin
Result.a.X := Min(Result.a.X, x); i := 0;
end; x := NearestXNumber(i, +1); // --> x is in graph units
i := Count - 1; if not IsNan(x) then begin
x := NearestXNumber(i, -1); BarOffsetWidth(x, i, ofs, w);
if not IsNan(x) then begin x := GraphToAxisX(x + ofs - w); // x is in graph units, Extent in axis units!
BarOffsetWidth(x, i, ofs, w); Result.a.X := Min(Result.a.X, x);
x := GraphToAxisX(x + ofs + w); end;
Result.b.X := Max(Result.b.X, x); i := Count - 1;
x := NearestXNumber(i, -1);
if not IsNan(x) then begin
BarOffsetWidth(x, i, ofs, w);
x := GraphToAxisX(x + ofs + w);
Result.b.X := Max(Result.b.X, x);
end;
end; end;
end; end;
@ -1600,6 +1607,8 @@ begin
// Iterate through all points of the series // Iterate through all points of the series
for pointIndex := 0 to Count - 1 do begin for pointIndex := 0 to Count - 1 do begin
sp := Source[pointindex]^.Point; sp := Source[pointindex]^.Point;
if Source.XCount = 0 then
sp.X := pointIndex;
if IsNan(sp) then if IsNan(sp) then
continue; continue;
sp.X := AxisToGraphX(sp.X); sp.X := AxisToGraphX(sp.X);