TAChart: Fix incomplete support of multiple x values in TListChartSource and DataPointEditor. Issue #35089.

git-svn-id: trunk@60425 -
This commit is contained in:
wp 2019-02-15 11:45:51 +00:00
parent 71a8ee49c6
commit 7c5fdfc1d4
6 changed files with 103 additions and 54 deletions

View File

@ -2,48 +2,50 @@ object DataPointsEditorForm: TDataPointsEditorForm
Left = 418
Height = 303
Top = 235
Width = 357
Width = 288
ClientHeight = 303
ClientWidth = 357
ClientWidth = 288
OnCreate = FormCreate
LCLVersion = '1.7'
Position = poScreenCenter
ShowHint = True
LCLVersion = '2.1.0.0'
object sgData: TStringGrid
Left = 0
Height = 257
Top = 0
Width = 357
Left = 6
Height = 251
Top = 6
Width = 276
Align = alClient
AutoFillColumns = True
BorderSpacing.Around = 6
Columns = <
item
Alignment = taRightJustify
Title.Alignment = taCenter
Title.Font.Style = [fsBold]
Title.Caption = 'X'
Width = 80
Width = 63
end
item
Alignment = taRightJustify
Title.Alignment = taCenter
Title.Font.Style = [fsBold]
Title.Caption = 'Y'
Width = 80
Width = 63
end
item
ButtonStyle = cbsEllipsis
Title.Alignment = taCenter
Title.Font.Style = [fsBold]
Title.Caption = 'Color'
Width = 80
Width = 63
end
item
Title.Alignment = taCenter
Title.Font.Style = [fsBold]
Title.Caption = 'Text'
Width = 81
Width = 63
end>
DefaultColWidth = 32
Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goColSizing, goRowMoving, goEditing, goAutoAddRows, goAlwaysShowEditor, goSmoothScroll, goFixedRowNumbering]
Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goColSizing, goRowMoving, goEditing, goAutoAddRows, goAlwaysShowEditor, goSmoothScroll, goFixedRowNumbering, goTruncCellHints, goCellEllipsis]
PopupMenu = pmRows
TabOrder = 0
OnDrawCell = sgDataDrawCell
@ -51,17 +53,17 @@ object DataPointsEditorForm: TDataPointsEditorForm
OnPrepareCanvas = sgDataPrepareCanvas
ColWidths = (
32
80
80
80
81
63
63
63
63
)
end
object ButtonPanel1: TButtonPanel
Left = 6
Height = 34
Top = 263
Width = 345
Width = 276
OKButton.Name = 'OKButton'
OKButton.DefaultCaption = True
HelpButton.Name = 'HelpButton'

View File

@ -41,9 +41,10 @@ type
strict private
FCurrentRow: Integer;
FDataPoints: TStrings;
FXCount: Integer;
FYCount: Integer;
public
procedure InitData(AYCount: Integer; ADataPoints: TStrings);
procedure InitData(AXCount, AYCount: Integer; ADataPoints: TStrings);
procedure ExtractData(out AModified: Boolean);
end;
@ -52,7 +53,7 @@ procedure Register;
implementation
uses
LCLIntf, Math, PropEdits,
LCLIntf, LCLType, Math, PropEdits,
TAChartStrConsts, TAChartUtils, TASources;
{$R *.lfm}
@ -100,26 +101,47 @@ begin
end;
procedure TDataPointsEditorForm.InitData(
AYCount: Integer; ADataPoints: TStrings);
AXCount, AYCount: Integer; ADataPoints: TStrings);
var
i: Integer;
w: Integer;
begin
FXCount := AXCount;
FYCount := AYCount;
FDataPoints := ADataPoints;
sgData.RowCount := Max(ADataPoints.Count + 1, 2);
{ wp: What is this good for?
for i := sgData.Columns.Count - 1 downto 0 do
with sgData.Columns[i].Title do
if (Caption[1] = 'Y') and (Caption <> 'Y') then
sgData.Columns.Delete(i);
for i := 2 to AYCount do begin
}
if AXCount > 1 then
sgData.Columns[0].Title.Caption := 'X1';
if AYCount > 1 then
sgData.Columns[1].Title.Caption := 'Y1';
for i := 2 to AYCount do
with sgData.Columns.Add do begin
Assign(sgData.Columns[1]);
Title.Caption := 'Y' + IntToStr(i);
Index := i;
end;
end;
for i := 2 to AXCount do
with sgData.Columns.Add do begin
Assign(sgData.Columns[0]);
Title.Caption := 'X' + IntToStr(i);
Index := i - 1;
end;
for i := 0 to ADataPoints.Count - 1 do
Split('|' + ADataPoints[i], sgData.Rows[i + 1])
Split('|' + ADataPoints[i], sgData.Rows[i + 1]);
// Adjust column widths
w := sgData.Canvas.TextWidth('$000000') + 3*varCellPadding + sgData.DefaultRowHeight;
for i := 0 to sgData.Columns.Count-1 do
sgData.Columns[i].Width := w;
Width := sgData.ColWidths[0] + sgData.Columns.Count * w + 2*sgData.Left +
sgData.GridLineWidth * (sgData.Columns.Count-1);
end;
procedure TDataPointsEditorForm.miDeleteRowClick(Sender: TObject);
@ -158,7 +180,7 @@ procedure TDataPointsEditorForm.sgDataButtonClick(
ASender: TObject; ACol, ARow: Integer);
begin
Unused(ASender);
if (ARow < 1) or (ACol <> FYCount + 2) then exit;
if (ARow < 1) or (ACol <> FXCount + FYCount + 1) then exit;
cdItemColor.Color := StrToIntDef(sgData.Cells[ACol, ARow], clRed);
if not cdItemColor.Execute then exit;
sgData.Cells[ACol, ARow] := IntToColorHex(cdItemColor.Color);
@ -170,12 +192,12 @@ var
c: Integer;
begin
Unused(ASender, AState);
if (ARow < 1) or (ACol <> FYCount + 2) then exit;
if (ARow < 1) or (ACol <> FXCount + FYCount + 1) then exit;
if not TryStrToInt(sgData.Cells[ACol, ARow], c) then exit;
sgData.Canvas.Pen.Color := clBlack;
sgData.Canvas.Brush.Color := c;
InflateRect(ARect, -2, -2);
ARect.Left := ARect.Right - 12;
InflateRect(ARect, -varCellPadding, -varCellPadding);
ARect.Left := ARect.Right - (ARect.Bottom - ARect.Top);;
sgData.Canvas.Rectangle(ARect);
end;
@ -201,8 +223,10 @@ begin
with TDataPointsEditorForm.Create(nil) do
try
InitData(
(GetComponent(0) as TListChartsource).XCount,
(GetComponent(0) as TListChartSource).YCount,
GetObjectValue as TStrings);
GetObjectValue as TStrings
);
if ShowModal = mrOK then begin
ExtractData(dataModified);
if dataModified then Modified;

View File

@ -93,7 +93,7 @@ type
implementation
uses
GraphType, Math, LCLIntf, LCLType, IntfGraphics,
GraphType, LCLIntf, LCLType, IntfGraphics,
TAGeometry;
function CanvasGetFontOrientationFunc(AFont: TFPCustomFont): Integer;

View File

@ -1620,28 +1620,28 @@ begin
if not RectIntersectsRect(ext, ParentChart.CurrentExtent) then exit;
lPen := TPen.Create;
lPen.Assign(FPen);
if (AxisIndexX < 0) and (AxisIndexY < 0) then begin
// Optimization: bypass transformations in the default case
for i := 0 to Count - 1 do
if GetVectorPoints(i, p1, p2) then begin
lPen.Color := GetColor(i);
DrawVector(ADrawer, p1, p2, lPen);
end;
end else begin
for i := 0 to Count - 1 do
if GetVectorPoints(i, p1, p2) then begin
p1 := AxisToGraph(p1);
p2 := AxisToGraph(p2);
//p1 := DoublePoint(AxisToGraphX(p1.X), AxisToGraphY(p1.Y));
//p2 := DoublePoint(AxisToGraphX(p2.X), AxisToGraphY(p2.Y));
lPen.Color := GetColor(i);
DrawVector(ADrawer, p1, p2, lPen);
end;
try
lPen.Assign(FPen);
if (AxisIndexX < 0) and (AxisIndexY < 0) then begin
// Optimization: bypass transformations in the default case
for i := 0 to Count - 1 do
if GetVectorPoints(i, p1, p2) then begin
lPen.Color := GetColor(i);
DrawVector(ADrawer, p1, p2, lPen);
end;
end else begin
for i := 0 to Count - 1 do
if GetVectorPoints(i, p1, p2) then begin
p1 := AxisToGraph(p1);
p2 := AxisToGraph(p2);
lPen.Color := GetColor(i);
DrawVector(ADrawer, p1, p2, lPen);
end;
end;
DrawLabels(ADrawer);
finally
lPen.Free;
end;
lPen.Free;
end;
procedure TFieldSeries.DrawVector(ADrawer: IChartDrawer;

View File

@ -1671,7 +1671,7 @@ var
procedure CollectPoints(AStart, AEnd: Integer);
var
i, j: Integer;
i: Integer;
a, b: TDoublePoint;
singlePoint: Boolean;
begin

View File

@ -41,6 +41,7 @@ type
procedure SetYCount(AValue: Cardinal); override;
public
type
EXListEmptyError = class(EChartError);
EYListEmptyError = class(EChartError);
public
constructor Create(AOwner: TComponent); override;
@ -49,6 +50,8 @@ type
function Add(
AX, AY: Double; const ALabel: String = '';
AColor: TChartColor = clTAColor): Integer;
function AddXListYList(const AX, AY: array of Double; ALabel: String = '';
AColor: TChartColor = clTAColor): Integer;
function AddXYList(
AX: Double; const AY: array of Double; const ALabel: String = '';
AColor: TChartColor = clTAColor): Integer;
@ -68,6 +71,7 @@ type
published
property DataPoints: TStrings read FDataPoints write SetDataPoints;
property Sorted: Boolean read FSorted write SetSorted default false;
property XCount;
property XErrorBarData;
property YErrorBarData;
property YCount;
@ -301,6 +305,8 @@ begin
fs.DecimalSeparator := '.';
with FSource[Index]^ do begin
Result := Format('%g', [X], fs);
for i := 0 to High(XList) do
Result += Format('|%g', [XList[i]], fs);
if FSource.YCount > 0 then
Result += Format('|%g', [Y], fs);
for i := 0 to High(YList) do
@ -344,10 +350,13 @@ var
begin
parts := Split(AString);
try
if FSource.YCount + 3 < Cardinal(parts.Count) then
if (FSource.XCount = 1) and (FSource.YCount + 3 < Cardinal(parts.Count)) then
FSource.YCount := parts.Count - 3;
with ADataItem^ do begin
X := StrToFloatOrDateTimeDef(NextPart);
if FSource.XCount > 1 then
for i := 0 to High(XList) do
XList[i] := StrToFloatOrDateTimeDef(NextPart);
if FSource.YCount > 0 then begin
Y := StrToFloatOrDateTimeDef(NextPart);
for i := 0 to High(YList) do
@ -365,7 +374,7 @@ procedure TListChartSourceStrings.Put(Index: Integer; const S: String);
begin
FSource.BeginUpdate;
try
Parse(S, FSource[Index]);
Parse(S, FSource[Index]);
finally
FSource.EndUpdate;
end;
@ -410,6 +419,20 @@ begin
UpdateCachesAfterAdd(AX, AY);
end;
function TListChartSource.AddXListYList(const AX, AY: array of Double;
ALabel: String = ''; AColor: TChartColor = clTAColor): Integer;
begin
if Length(AX) = 0 then
raise EXListEmptyError.Create('AddXListYList: XList is empty');
if Length(AY) = 0 then
raise EYListEmptyError.Create('AddXListYList: YList is empty');
Result := Add(AX[0], AY[0], ALabel, AColor);
if Length(AX) > 1 then
SetXList(Result, AX[1..High(AX)]);
if Length(AY) > 1 then
SetYList(Result, AY[1..High(AY)]);
end;
function TListChartSource.AddXYList(
AX: Double; const AY: array of Double;
const ALabel: String; AColor: TChartColor): Integer;