mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-13 12:49:21 +02:00
TAChart: Fix severe speed issue when switching to logarithmic axis. Improved label positioning for logarithmic bar series. Fix drawing of logarithmic bar series.
git-svn-id: trunk@60065 -
This commit is contained in:
parent
6831ce0d0b
commit
a9b6333383
@ -287,11 +287,7 @@ type
|
|||||||
UseDataColors: Boolean = false);
|
UseDataColors: Boolean = false);
|
||||||
procedure FindExtentInterval(
|
procedure FindExtentInterval(
|
||||||
const AExtent: TDoubleRect; AFilterByExtent: Boolean);
|
const AExtent: TDoubleRect; AFilterByExtent: Boolean);
|
||||||
{
|
function GetLabelDataPoint(AIndex, AYIndex: Integer): TDoublePoint; virtual;
|
||||||
function GetErrorBars(APointIndex: Integer; IsXError: Boolean;
|
|
||||||
out AGraphPointPos, AGraphPointNeg: Double): Boolean;
|
|
||||||
}
|
|
||||||
function GetLabelDataPoint(AIndex: Integer): TDoublePoint; virtual;
|
|
||||||
procedure GetLegendItemsRect(AItems: TChartLegendItems; ABrush: TBrush);
|
procedure GetLegendItemsRect(AItems: TChartLegendItems; ABrush: TBrush);
|
||||||
function GetXRange(AX: Double; AIndex: Integer): Double;
|
function GetXRange(AX: Double; AIndex: Integer): Double;
|
||||||
function GetZeroLevel: Double; virtual;
|
function GetZeroLevel: Double; virtual;
|
||||||
@ -1242,12 +1238,13 @@ var
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
y: Double;
|
y, ysum: Double;
|
||||||
g, gl: TDoublePoint;
|
g, gl: TDoublePoint;
|
||||||
i, si: Integer;
|
i, si: Integer;
|
||||||
ld: TLabelDirection;
|
ld: TLabelDirection;
|
||||||
style: TChartStyle;
|
style: TChartStyle;
|
||||||
lfont: TFont;
|
lfont: TFont;
|
||||||
|
curr, prev: Double;
|
||||||
begin
|
begin
|
||||||
if not Marks.IsMarkLabelsVisible then exit;
|
if not Marks.IsMarkLabelsVisible then exit;
|
||||||
|
|
||||||
@ -1257,8 +1254,10 @@ begin
|
|||||||
ParentChart.DisableRedrawing;
|
ParentChart.DisableRedrawing;
|
||||||
|
|
||||||
for i := FLoBound to FUpBound do begin
|
for i := FLoBound to FUpBound do begin
|
||||||
if IsNan(Source[i]^.Point) then continue;
|
if IsNaN(Source[i]^.Point) then continue;
|
||||||
g := GetLabelDataPoint(i);
|
y := Source[i]^.Y;
|
||||||
|
ysum := y;
|
||||||
|
prev := GetZeroLevel;
|
||||||
for si := 0 to Source.YCount - 1 do begin
|
for si := 0 to Source.YCount - 1 do begin
|
||||||
if Styles <> nil then begin
|
if Styles <> nil then begin
|
||||||
style := Styles.StyleByIndex(si);
|
style := Styles.StyleByIndex(si);
|
||||||
@ -1267,26 +1266,31 @@ begin
|
|||||||
else
|
else
|
||||||
Marks.LabelFont.Assign(lfont);
|
Marks.LabelFont.Assign(lfont);
|
||||||
end;
|
end;
|
||||||
if not Stacked then begin
|
g := GetLabelDataPoint(i, si);
|
||||||
g := GetGraphPoint(i, 0, si);
|
if si > 0 then begin
|
||||||
y := Source[i]^.y;
|
|
||||||
end else
|
|
||||||
if si = 0 then
|
|
||||||
y := Source[i]^.y - GetZeroLevel // wp: does this survive nonlinear transformations?
|
|
||||||
else begin
|
|
||||||
y := Source[i]^.YList[si-1];
|
y := Source[i]^.YList[si-1];
|
||||||
if IsRotated then
|
if Stacked then begin
|
||||||
g.X += AxisToGraphY(y)
|
ysum := ysum + y;
|
||||||
else
|
y := ysum;
|
||||||
g.Y += AxisToGraphY(y);
|
end;
|
||||||
end;
|
end;
|
||||||
gl := g;
|
if not IsNaN(y) then begin
|
||||||
if FMarkPositions = lmpInsideCenter then begin
|
|
||||||
if IsRotated then
|
if IsRotated then
|
||||||
gl.X -= AxisToGraphX(y)/2
|
g.X := AxisToGraphX(y)
|
||||||
else
|
else
|
||||||
gl.Y -= AxisToGraphY(y)/2;
|
g.Y := AxisToGraphY(y);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
curr := TDoublePointBoolArr(g)[not IsRotated];
|
||||||
|
if MarkPositions = lmpInsideCenter then begin
|
||||||
|
if IsRotated then
|
||||||
|
gl := DoublePoint((curr + prev) * 0.5, g.y)
|
||||||
|
else
|
||||||
|
gl := DoublePoint(g.X, (curr + prev) * 0.5);
|
||||||
|
end else
|
||||||
|
gl := g;
|
||||||
|
prev := curr;
|
||||||
|
|
||||||
ld := GetLabelDirection(TDoublePointBoolArr(gl)[not IsRotated]);
|
ld := GetLabelDirection(TDoublePointBoolArr(gl)[not IsRotated]);
|
||||||
with ParentChart do
|
with ParentChart do
|
||||||
if
|
if
|
||||||
@ -1383,7 +1387,7 @@ begin
|
|||||||
Result := FErrorBars[AIndex];
|
Result := FErrorBars[AIndex];
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TBasicPointSeries.GetLabelDataPoint(AIndex: Integer): TDoublePoint;
|
function TBasicPointSeries.GetLabelDataPoint(AIndex, AYIndex: Integer): TDoublePoint;
|
||||||
begin
|
begin
|
||||||
Result := GetGraphPoint(AIndex);
|
Result := GetGraphPoint(AIndex);
|
||||||
end;
|
end;
|
||||||
@ -1736,15 +1740,16 @@ end;
|
|||||||
procedure TBasicPointSeries.UpdateMargins(
|
procedure TBasicPointSeries.UpdateMargins(
|
||||||
ADrawer: IChartDrawer; var AMargins: TRect);
|
ADrawer: IChartDrawer; var AMargins: TRect);
|
||||||
var
|
var
|
||||||
i, j: Integer; //, distX, distY: Integer;
|
i, j: Integer;
|
||||||
labelText: String;
|
labelText: String;
|
||||||
dir: TLabelDirection;
|
dir: TLabelDirection;
|
||||||
|
ap: TDoublePoint;
|
||||||
gp: TDoublePoint;
|
gp: TDoublePoint;
|
||||||
p: TPoint;
|
p: TPoint;
|
||||||
dist: TPoint;
|
dist: TPoint;
|
||||||
prev, curr, zero: Integer;
|
prev, curr, zero: Integer;
|
||||||
r, rExtent: TRect;
|
r, rExtent: TRect;
|
||||||
y: Double;
|
y, ysum: Double;
|
||||||
begin
|
begin
|
||||||
if not Marks.IsMarkLabelsVisible or not Marks.AutoMargins then exit;
|
if not Marks.IsMarkLabelsVisible or not Marks.AutoMargins then exit;
|
||||||
|
|
||||||
@ -1753,6 +1758,7 @@ begin
|
|||||||
rExtent.BottomRight := FChart.GraphToImage(DoublePoint(b.x, a.y));
|
rExtent.BottomRight := FChart.GraphToImage(DoublePoint(b.x, a.y));
|
||||||
end;
|
end;
|
||||||
r := rExtent;
|
r := rExtent;
|
||||||
|
|
||||||
with FChart do
|
with FChart do
|
||||||
zero := IfThen(IsRotated, XGraphToImage(GetZeroLevel), YGraphToImage(GetZeroLevel));
|
zero := IfThen(IsRotated, XGraphToImage(GetZeroLevel), YGraphToImage(GetZeroLevel));
|
||||||
|
|
||||||
@ -1760,6 +1766,10 @@ begin
|
|||||||
labelText := FormattedMark(i);
|
labelText := FormattedMark(i);
|
||||||
if labelText = '' then Continue;
|
if labelText = '' then Continue;
|
||||||
|
|
||||||
|
ap := Source[i]^.Point;
|
||||||
|
if IsNaN(ap.X) then
|
||||||
|
Continue;
|
||||||
|
|
||||||
with Marks.MeasureLabel(ADrawer, labelText) do
|
with Marks.MeasureLabel(ADrawer, labelText) do
|
||||||
if IsRotated then
|
if IsRotated then
|
||||||
dist := Point(cx + Marks.Distance - IfThen(Marks.DistanceToCenter, cx div 2), cy div 2)
|
dist := Point(cx + Marks.Distance - IfThen(Marks.DistanceToCenter, cx div 2), cy div 2)
|
||||||
@ -1767,15 +1777,21 @@ begin
|
|||||||
dist := Point(cx div 2, cy + Marks.Distance - IfThen(Marks.DistanceToCenter, cy div 2));
|
dist := Point(cx div 2, cy + Marks.Distance - IfThen(Marks.DistanceToCenter, cy div 2));
|
||||||
|
|
||||||
prev := zero;
|
prev := zero;
|
||||||
gp := GetLabelDataPoint(i);
|
y := ap.Y;
|
||||||
|
ysum := y;
|
||||||
for j := 0 to Source.YCount - 1 do begin
|
for j := 0 to Source.YCount - 1 do begin
|
||||||
if Stacked and (j > 0) then begin
|
gp := GetLabelDataPoint(i, j);
|
||||||
|
if (j > 0) then begin
|
||||||
y := Source[i]^.YList[j-1];
|
y := Source[i]^.YList[j-1];
|
||||||
if IsRotated then
|
if Stacked and not IsNaN(y) then begin
|
||||||
gp.x += AxisToGraphX(y)
|
if IsNaN(ysum) then ysum := y else ysum := ysum + y;
|
||||||
else
|
y := ysum;
|
||||||
gp.Y += AxisToGraphY(y);
|
end;
|
||||||
end;
|
end;
|
||||||
|
if IsRotated then
|
||||||
|
gp.x := AxisToGraphX(y)
|
||||||
|
else
|
||||||
|
gp.y := AxisToGraphY(y);
|
||||||
p := FChart.GraphToImage(gp);
|
p := FChart.GraphToImage(gp);
|
||||||
curr := TPointBoolArr(p)[not IsRotated];
|
curr := TPointBoolArr(p)[not IsRotated];
|
||||||
if MarkPositions = lmpInsideCenter then begin
|
if MarkPositions = lmpInsideCenter then begin
|
||||||
@ -1785,33 +1801,17 @@ begin
|
|||||||
p.y := (curr + prev) div 2;
|
p.y := (curr + prev) div 2;
|
||||||
end;
|
end;
|
||||||
gp := FChart.ImageToGraph(p);
|
gp := FChart.ImageToGraph(p);
|
||||||
dir := GetlabelDirection(TDoublePointBoolArr(gp)[not IsRotated]);
|
if FChart.IsPointInViewPort(gp) then begin
|
||||||
case dir of
|
dir := GetlabelDirection(TDoublePointBoolArr(gp)[not IsRotated]);
|
||||||
ldLeft : UpdateMinMax(p.X - dist.X, r.Left, r.Right);
|
case dir of
|
||||||
ldRight : UpdateMinMax(p.X + dist.X, r.Left, r.Right);
|
ldLeft : UpdateMinMax(p.X - dist.X, r.Left, r.Right);
|
||||||
ldTop : UpdateMinMax(p.Y - dist.Y, r.Top, r.Bottom);
|
ldRight : UpdateMinMax(p.X + dist.X, r.Left, r.Right);
|
||||||
ldBottom : UpdateMinMax(p.Y + dist.Y, r.Top, r.Bottom);
|
ldTop : UpdateMinMax(p.Y - dist.Y, r.Top, r.Bottom);
|
||||||
|
ldBottom : UpdateMinMax(p.Y + dist.Y, r.Top, r.Bottom);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
prev := curr;
|
prev := curr;
|
||||||
end;
|
end;
|
||||||
{
|
|
||||||
gp := GetGraphPoint(i);
|
|
||||||
p := FChart.GraphToImage(gp);
|
|
||||||
UpdateMinMax(p.X, rExtent.Left, rExtent.Right);
|
|
||||||
UpdateMinMax(p.Y, rExtent.Top, rExtent.Bottom);
|
|
||||||
|
|
||||||
if MarkPositions = lmpInsideCenter then
|
|
||||||
p.y := (p.y + FChart.YGraphToImage(zero)) div 2;
|
|
||||||
|
|
||||||
gp := FChart.ImageToGraph(p);
|
|
||||||
dir := GetLabelDirection(TDoublePointBoolArr(gp)[not IsRotated]);
|
|
||||||
case dir of
|
|
||||||
ldLeft : UpdateMinMax(p.X - distX, r.Left, r.Right);
|
|
||||||
ldRight : UpdateMinMax(p.X + distX, r.Left, r.Right);
|
|
||||||
ldTop : UpdateMinMax(p.Y - distY, r.Top, r.Bottom);
|
|
||||||
ldBottom : UpdateMinMax(p.Y + distY, r.Top, r.Bottom);
|
|
||||||
end;
|
|
||||||
}
|
|
||||||
if IsRotated then begin
|
if IsRotated then begin
|
||||||
UpdateMinMax(p.Y - dist.Y, r.Top, r.Bottom);
|
UpdateMinMax(p.Y - dist.Y, r.Top, r.Bottom);
|
||||||
UpdateMinMax(p.Y + dist.Y, r.Top, r.Bottom);
|
UpdateMinMax(p.Y + dist.Y, r.Top, r.Bottom);
|
||||||
|
@ -63,7 +63,7 @@ type
|
|||||||
procedure SetSeriesColor(AValue: TColor);
|
procedure SetSeriesColor(AValue: TColor);
|
||||||
procedure SetZeroLevel(AValue: Double);
|
procedure SetZeroLevel(AValue: Double);
|
||||||
strict protected
|
strict protected
|
||||||
function GetLabelDataPoint(AIndex: Integer): TDoublePoint; override;
|
function GetLabelDataPoint(AIndex, AYIndex: Integer): TDoublePoint; override;
|
||||||
function ToolTargetDistance(const AParams: TNearestPointParams;
|
function ToolTargetDistance(const AParams: TNearestPointParams;
|
||||||
AGraphPt: TDoublePoint; APointIdx, AXIdx, AYIdx: Integer): Integer; override;
|
AGraphPt: TDoublePoint; APointIdx, AXIdx, AYIdx: Integer): Integer; override;
|
||||||
protected
|
protected
|
||||||
@ -1136,7 +1136,6 @@ var
|
|||||||
Exchange(a.X, a.Y);
|
Exchange(a.X, a.Y);
|
||||||
Exchange(b.X, b.Y);
|
Exchange(b.X, b.Y);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if not RectIntersectsRect(graphBar, ext2) then exit;
|
if not RectIntersectsRect(graphBar, ext2) then exit;
|
||||||
|
|
||||||
with imageBar do begin
|
with imageBar do begin
|
||||||
@ -1177,20 +1176,20 @@ begin
|
|||||||
heights[1] := NumberOr(p.Y, ZeroLevel);
|
heights[1] := NumberOr(p.Y, ZeroLevel);
|
||||||
for stackIndex := 1 to Source.YCount - 1 do begin
|
for stackIndex := 1 to Source.YCount - 1 do begin
|
||||||
y := Source[pointIndex]^.YList[stackIndex - 1];
|
y := Source[pointIndex]^.YList[stackIndex - 1];
|
||||||
if not IsNan(y) then
|
if not IsNaN(y) then
|
||||||
heights[stackIndex + 1] := heights[stackIndex] + y;
|
heights[stackIndex + 1] := heights[stackIndex] + y;
|
||||||
end;
|
end;
|
||||||
for stackIndex := 0 to High(heights) do
|
for stackIndex := 0 to High(heights) do
|
||||||
heights[stackindex] := AxisToGraphY(heights[stackindex]);
|
heights[stackindex] := AxisToGraphY(heights[stackindex]); // wp: what if rotated?
|
||||||
for stackIndex := 0 to Source.YCount - 1 do
|
for stackIndex := 0 to Source.YCount - 1 do
|
||||||
BuildBar(p.X, heights[stackindex], heights[stackIndex+1]);
|
BuildBar(p.X, heights[stackindex], heights[stackIndex+1]);
|
||||||
end else begin
|
end else begin
|
||||||
for stackIndex := 0 to Source.YCount - 1 do begin
|
for stackIndex := 0 to Source.YCount - 1 do begin
|
||||||
y := Source[pointIndex]^.GetY(stackIndex);
|
y := Source[pointIndex]^.GetY(stackIndex);
|
||||||
if not IsNaN(y) then
|
if not IsNaN(y) then
|
||||||
heights[stackIndex + 1] := y
|
heights[stackIndex + 1] := AxisToGraphY(y)
|
||||||
else
|
else
|
||||||
heights[stackIndex + 1] := 0;
|
continue;
|
||||||
end;
|
end;
|
||||||
p.X -= w;
|
p.X -= w;
|
||||||
w := w / High(heights);
|
w := w / High(heights);
|
||||||
@ -1214,7 +1213,7 @@ begin
|
|||||||
if IsEmpty then exit;
|
if IsEmpty then exit;
|
||||||
if BarWidthStyle = bwPercentMin then
|
if BarWidthStyle = bwPercentMin then
|
||||||
UpdateMinXRange;
|
UpdateMinXRange;
|
||||||
UpdateMinMax(ZeroLevel, Result.a.Y, Result.b.Y);
|
// UpdateMinMax(ZeroLevel, Result.a.Y, Result.b.Y);
|
||||||
// Show first and last bars fully.
|
// Show first and last bars fully.
|
||||||
i := 0;
|
i := 0;
|
||||||
x := NearestXNumber(i, +1); // --> x is in graph units
|
x := NearestXNumber(i, +1); // --> x is in graph units
|
||||||
@ -1245,11 +1244,11 @@ begin
|
|||||||
Result := Abs(f(2 * w) - f(0));
|
Result := Abs(f(2 * w) - f(0));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TBarSeries.GetLabelDataPoint(AIndex: Integer): TDoublePoint;
|
function TBarSeries.GetLabelDataPoint(AIndex, AYIndex: Integer): TDoublePoint;
|
||||||
var
|
var
|
||||||
ofs, w: Double;
|
ofs, w: Double;
|
||||||
begin
|
begin
|
||||||
Result := inherited GetLabelDataPoint(AIndex);
|
Result := inherited GetLabelDataPoint(AIndex, AYIndex);
|
||||||
BarOffsetWidth(TDoublePointBoolArr(Result)[IsRotated], AIndex, ofs, w);
|
BarOffsetWidth(TDoublePointBoolArr(Result)[IsRotated], AIndex, ofs, w);
|
||||||
TDoublePointBoolArr(Result)[IsRotated] += ofs;
|
TDoublePointBoolArr(Result)[IsRotated] += ofs;
|
||||||
end;
|
end;
|
||||||
|
Loading…
Reference in New Issue
Block a user