diff --git a/components/fpspreadsheet/examples/chartdemo/chartdemo.lpi b/components/fpspreadsheet/examples/chartdemo/chartdemo.lpi
new file mode 100644
index 000000000..0dd0d610a
--- /dev/null
+++ b/components/fpspreadsheet/examples/chartdemo/chartdemo.lpi
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/fpspreadsheet/examples/chartdemo/chartdemo.lpr b/components/fpspreadsheet/examples/chartdemo/chartdemo.lpr
new file mode 100644
index 000000000..fab54660d
--- /dev/null
+++ b/components/fpspreadsheet/examples/chartdemo/chartdemo.lpr
@@ -0,0 +1,44 @@
+program chartdemo;
+
+uses
+ fpspreadsheet, fpsutils, fpstypes, fpschart;
+
+var
+ wb: TsWorkbook;
+ sh: TsWorksheet;
+ chart: TsChart;
+ ser: TsChartSeries;
+ idx: Integer;
+
+begin
+ wb := TsWorkbook.Create;
+ try
+ ws := wb.AddWorksheet('Test');
+ // x values
+ ws.WriteNumber(0, 0, 1.0);
+ ws.WriteNumber(1, 0, 2.1);
+ ws.WriteNumber(2, 0, 2.9);
+ ws.WriteNumber(3, 0, 4.15);
+ ws.WriteNumber(4, 0, 5.05);
+ // y values
+ ws.WriteNumber(0, 1, 10.0);
+ ws.WriteNumber(1, 1, 12.0);
+ ws.WriteNumber(2, 1, 9.0);
+ ws.WriteNumber(3, 1, 7.5);
+ ws.WriteNumber(4, 1, 11.2);
+
+ idx := ws.WriteChart(0, 0, 12, 9);
+ chart := ws.GetChart(idx);
+ ser := TsLineSeries.Create(chart);
+ ser.XRange := Range(0, 0, 4, 0);
+ ser.YRange := Range(0, 1, 4, 1);
+ ser.Title := 'Scatter series';
+ ser.ShowSymbols := true;
+ ser.ShowLines := true;
+
+ chart.AddSeries(
+ finally
+ wb.Free;
+ end;
+end.
+
diff --git a/components/fpspreadsheet/laz_fpspreadsheet.lpk b/components/fpspreadsheet/laz_fpspreadsheet.lpk
index 300e81067..16029f3a7 100644
--- a/components/fpspreadsheet/laz_fpspreadsheet.lpk
+++ b/components/fpspreadsheet/laz_fpspreadsheet.lpk
@@ -34,7 +34,7 @@
This package is all you need if you don't want graphical components (like grids and charts)."/>
-
+
@@ -258,6 +258,10 @@ This package is all you need if you don't want graphical components (like grids
+
+
+
+
@@ -278,7 +282,6 @@ This package is all you need if you don't want graphical components (like grids
-
<_ExternHelp Items="Count"/>
diff --git a/components/fpspreadsheet/source/common/fpschart.pas b/components/fpspreadsheet/source/common/fpschart.pas
new file mode 100644
index 000000000..8ae46d7ba
--- /dev/null
+++ b/components/fpspreadsheet/source/common/fpschart.pas
@@ -0,0 +1,426 @@
+unit fpschart;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, Contnrs, fpsTypes, fpsUtils;
+
+type
+ TsChart = class;
+
+ TsChartFill = record
+ Style: TsFillStyle;
+ FgColor: TsColor;
+ BgColor: TsColor;
+ end;
+
+ TsChartPenStyle = (cpsSolid, cpsDashed, cpsDotted, cpsDashDot, cpsDashDotDot, cpsClear);
+
+ TsChartLine = record
+ Style: TsChartPenStyle;
+ Width: Double; // mm
+ Color: TsColor;
+ end;
+
+ TsChartObj = class
+ private
+ FOwner: TsChartObj;
+ FVisible: Boolean;
+ public
+ constructor Create(AOwner: TsChartObj);
+ property Visible: Boolean read FVisible write FVisible;
+ end;
+
+ TsChartFillObj = class(TsChartObj)
+ private
+ FBackground: TsChartFill;
+ FBorder: TsChartLine;
+ public
+ constructor Create(AOwner: TsChartObj);
+ property Background: TsChartFill read FBackground write FBackground;
+ property Border: TsChartLine read FBorder write FBorder;
+ end;
+
+ TsChartText = class(TsChartObj)
+ private
+ FCaption: String;
+ FShowCaption: Boolean;
+ FFont: TsFont;
+ public
+ constructor Create(AOwner: TsChartObj);
+ property Caption: String read FCaption write FCaption;
+ property Font: TsFont read FFont write FFont;
+ property ShowCaption: Boolean read FShowCaption write FShowCaption;
+ end;
+
+ TsChartAxis = class(TsChartText)
+ private
+ FAutomaticMax: Boolean;
+ FAutomaticMin: Boolean;
+ FAutomaticMajorInterval: Boolean;
+ FAutomaticMinorSteps: Boolean;
+ FAxisLine: TsChartLine;
+ FGridLines: TsChartLine;
+ FInverted: Boolean;
+ FLabelFont: TsFont;
+ FLogarithmic: Boolean;
+ FMajorInterval: Double;
+ FMajorTickLines: TsChartLine;
+ FMax: Double;
+ FMin: Double;
+ FMinorSteps: Double;
+ FMinorTickLines: TsChartLine;
+ FShowGrid: Boolean;
+ FShowLabels: Boolean;
+ public
+ constructor Create(AOwner: TsChartObj);
+ property AutomaticMax: Boolean read FAutomaticMax write FAutomaticMax;
+ property AutomaticMin: Boolean read FAutomaticMin write FAutomaticMin;
+ property AutomaticMajorInterval: Boolean read FAutomaticMajorInterval write FAutomaticMajorInterval;
+ property AutomaticMinorSteps: Boolean read FAutomaticMinorSteps write FAutomaticMinorSteps;
+ property AxisLine: TsChartLine read FAxisLine write FAxisLine;
+ property GridLines: TsChartLine read FGridLines write FGridLines;
+ property Inverted: Boolean read FInverted write FInverted;
+ property LabelFont: TsFont read FLabelFont write FLabelFont;
+ property Logarithmic: Boolean read FLogarithmic write FLogarithmic;
+ property MajorInterval: Double read FMajorInterval write FMajorInterval;
+ property MajorTickLines: TsChartLine read FMajorTickLines write FMajorTickLines;
+ property Max: Double read FMax write FMax;
+ property Min: Double read FMin write FMin;
+ property MinorSteps: Double read FMinorSteps write FMinorSteps;
+ property MinorTickLines: TsChartLine read FMinorTickLines write FMinorTickLines;
+ property ShowGrid: Boolean read FShowGrid write FShowGrid;
+ property ShowLabels: Boolean read FShowLabels write FShowLabels;
+ end;
+
+ TsChartLegend = class(TsChartFillObj)
+ end;
+
+ TsChartAxisLink = (alPrimary, alSecondary);
+
+ TsChartSeries = class(TsChartObj)
+ private
+ FXRange: TsCellRange; // cell range containing the x data
+ FYRange: TsCellRange;
+ FLabelsRange: TsCellRange;
+ FXIndex: array of Integer; // index of data point's x value within XRange
+ FYIndex: array of Integer;
+ FLabelsIndex: array of Integer;
+ FYAxis: TsChartAxisLink;
+ FTitle: String;
+ function GetCount: Integer;
+ public
+ constructor Create(AChart: TsChart);
+ property Count: Integer read GetCount;
+ property LabelsRange: TsCellRange read FLabelsRange;
+ property Title: String read FTitle;
+ property XRange: TsCellRange read FXRange write FXRange;
+ property YRange: TsCellRange read FYRange write FYRange;
+ property YAxis: TsChartAxisLink read FYAxis write FYAxis;
+ end;
+
+ TsChartSeriesSymbol = (cssRect, cssDiamond, cssTriangle, cssTriangleDown,
+ cssCircle, cssStar);
+
+ TsLineSeries = class(TsChartSeries)
+ private
+ FLineStyle: TsChartLine;
+ FShowLines: Boolean;
+ FShowSymbols: Boolean;
+ FSymbol: TsChartSeriesSymbol;
+ FSymbolFill: TsChartFill;
+ FSymbolBorder: TsChartLine;
+ FSymbolHeight: Double; // in mm
+ FSymbolWidth: Double; // in mm
+ public
+ constructor Create(AChart: TsChart);
+ property LineStyle: TsChartLine read FLineStyle write FLineStyle;
+ property ShowLines: Boolean read FShowLines write FShowLines;
+ property ShowSymbols: Boolean read FShowSymbols write FShowSymbols;
+ property Symbol: TsChartSeriesSymbol read FSymbol write FSymbol;
+ property SymbolBorder: TsChartLine read FSymbolBorder write FSymbolBorder;
+ property SymbolFill: TsChartFill read FSymbolFill write FSymbolFill;
+ property SymbolHeight: double read FSymbolHeight write FSymbolHeight;
+ property SymbolWidth: double read FSymbolWidth write FSymbolWidth;
+ end;
+
+ TsChartSeriesList = class(TFPList)
+ private
+ function GetItem(AIndex: Integer): TsChartSeries;
+ procedure SetItem(AIndex: Integer; AValue: TsChartSeries);
+ public
+ property Items[AIndex: Integer]: TsChartSeries read GetItem write SetItem; default;
+ end;
+
+ TsChart = class(TsChartFillObj)
+ private
+ FSheetIndex: Integer;
+ FRow, FCol: Cardinal;
+ FOffsetX, FOffsetY: Double;
+ FWidth, FHeight: Double; // Width, Height of the chart, in mm.
+
+ FPlotArea: TsChartFillObj;
+ FXAxis: TsChartAxis;
+ FYAxis: TsChartAxis;
+ FY2Axis: TsChartAxis;
+
+ FTitle: TsChartText;
+ FSubTitle: TsChartText;
+ FLegend: TsChartLegend;
+ FSeriesList: TsChartSeriesList;
+ public
+ constructor Create;
+ destructor Destroy; override;
+ function AddSeries(ASeries: TsChartSeries): Integer;
+
+ { Index of worksheet sheet which contains the chart. }
+ property SheetIndex: Integer read FSheetIndex write FSheetIndex;
+ { Row index of the cell in which the chart has its top/left corner (anchor) }
+ property Row: Cardinal read FRow write FRow;
+ { Column index of the cell in which the chart has its top/left corner (anchor) }
+ property Col: Cardinal read FCol write FCol;
+ { Offset of the left chart edge relative to the anchor cell, in mm }
+ property OffsetX: double read FOffsetX write FOffsetX;
+ { Offset of the top chart edge relative to the anchor cell, in mm }
+ property OffsetY: double read FOffsetY write FOffsetY;
+ { Width of the chart, in mm }
+ property Width: double read FWidth write FHeight;
+ { Height of the chart, in mm }
+ property Height: double read FHeight write FHeight;
+
+ { Attributes of the plot area (rectangle enclosed by axes) }
+ property PlotArea: TsChartFillObj read FPlotArea write FPlotArea;
+
+ { Attributes of the chart's title }
+ property Title: TsChartText read FTitle write FTitle;
+ { Attributes of the chart's subtitle }
+ property Subtitle: TsChartText read FSubtitle write FSubTitle;
+ { Attributs of the chart's legend }
+ property Legend: TsChartLegend read FLegend write FLegend;
+
+ { Attributes of the plot's primary x axis (bottom) }
+ property XAxis: TsChartAxis read FXAxis write FXAxis;
+ { Attributes of the plot's primary y axis (left) }
+ property YAxis: TsChartAxis read FYAxis write FYAxis;
+ { Attributes of the plot's secondary y axis (right) }
+ property Y2Axis: TsChartAxis read FY2Axis write FY2Axis;
+
+ { Attributes of the series }
+ property Series: TsChartSeriesList read FSeriesList write FSeriesList;
+ end;
+
+ TsChartList = class(TObjectList)
+ private
+ function GetItem(AIndex: Integer): TsChart;
+ procedure SetItem(AIndex: Integer; AValue: TsChart);
+ public
+ property Items[AIndex: Integer]: TsChart read GetItem write SetItem; default;
+ end;
+
+
+implementation
+
+const
+ DEFAULT_LINE_WIDTH = 0.75; // pts
+
+
+{ TsChartObj }
+
+constructor TsChartObj.Create(AOwner: TsChartObj);
+begin
+ inherited Create;
+ FOwner := AOwner;
+ FVisible := true;
+end;
+
+
+{ TsChartFillObj }
+
+constructor TsChartFillObj.Create(AOwner: TsChartObj);
+begin
+ inherited Create(AOwner);
+ FBackground.Style := fsSolidFill;
+ FBackground.BgColor := scWhite;
+ FBackground.FgColor := scWhite;
+ FBorder.Style := cpsSolid;
+ FBorder.Width := PtsToMM(DEFAULT_LINE_WIDTH);
+ FBorder.Color := scBlack;
+end;
+
+
+{ TsChartText }
+
+constructor TsChartText.Create(AOwner: TsChartObj);
+begin
+ inherited Create(AOwner);
+ FShowCaption := true;
+ FFont.FontName := ''; // replace by workbook's default font
+ FFont.Size := 0; // replace by workbook's default font size
+ FFont.Style := [];
+ FFont.Color := scBlack;
+end;
+
+
+{ TsChartAxis }
+
+constructor TsChartAxis.Create(AOwner: TsChartObj);
+begin
+ inherited Create(AOwner);
+
+ FAutomaticMajorInterval := true;
+ FAutomaticMinorSteps := true;
+
+ FLabelFont.FontName := ''; // replace by workbook's default font
+ FLabelFont.Size := 0; // Replace by workbook's default font size
+ FLabelFont.Style := [];
+ FLabelFont.Color := scBlack;
+
+ FShowLabels := true;
+
+ FAxisLine.Color := scBlack;
+ FAxisLine.Style := cpsSolid;
+ FAxisLine.Width := PtsToMM(DEFAULT_LINE_WIDTH);
+
+ FMajorTickLines.Color := scBlack;
+ FMajorTickLines.Style := cpsSolid;
+ FMajorTickLines.Width := PtsToMM(DEFAULT_LINE_WIDTH);
+
+ FMinorTickLines.Color := scBlack;
+ FMinorTickLines.Style := cpsSolid;
+ FMinorTickLines.Width := PtsToMM(DEFAULT_LINE_WIDTH);
+
+ FGridLines.Color := scSilver;
+ FGridLines.Style := cpsDotted;
+ FGridLines.Width := PtsToMM(DEFAULT_LINE_WIDTH);
+end;
+
+
+{ TsChartSeries }
+
+constructor TsChartSeries.Create(AChart: TsChart);
+begin
+ inherited Create(AChart);
+ AChart.AddSeries(self);
+ FTitle := 'Series ' + IntToStr(AChart.Series.Count);
+end;
+
+function TsChartSeries.GetCount: Integer;
+begin
+ Result := Length(FYIndex);
+end;
+
+
+{ TsChartSeriesList }
+
+function TsChartSeriesList.GetItem(AIndex: Integer): TsChartSeries;
+begin
+ Result := TsChartSeries(inherited Items[AIndex]);
+end;
+
+procedure TsChartSeriesList.SetItem(AIndex: Integer; AValue: TsChartSeries);
+begin
+ inherited Items[AIndex] := AValue;
+end;
+
+
+{ TsLineSeries }
+
+constructor TsLineSeries.Create(AChart: TsChart);
+begin
+ inherited Create(AChart);
+
+ FLineStyle.Color := scBlack;
+ FLineStyle.Style := cpsSolid;
+ FLineStyle.Width := PtsToMM(DEFAULT_LINE_WIDTH);
+
+ FSymbolBorder.Color := scBlack;
+ FSymbolBorder.Style := cpsSolid;
+ FSymbolBorder.Width := PtsToMM(DEFAULT_LINE_WIDTH);
+
+ FSymbolFill.FgColor := scWhite;
+ FSymbolFill.BgColor := scWhite;
+ FSymbolFill.Style := fsSolidFill;
+
+ FSymbolWidth := 2.5;
+ FSymbolHeight := 2.5;
+end;
+
+
+{ TsChart }
+
+constructor TsChart.Create;
+begin
+ inherited Create(nil);
+
+ FSheetIndex := 0;
+ FRow := 0;
+ FCol := 0;
+ FOffsetX := 0.0;
+ FOffsetY := 0.0;
+ FWidth := 12;
+ FHeight := 9;
+
+ FTitle := TsChartText.Create(self);
+ FTitle.Font.Size := 14;
+
+ FSubTitle := TsChartText.Create(self);
+ FSubTitle.Font.Size := 12;
+
+ FLegend := TsChartLegend.Create(self);
+
+ FXAxis := TsChartAxis.Create(self);
+ FXAxis.Caption := 'x axis';
+ FXAxis.LabelFont.Size := 9;
+ FXAxis.Font.Size := 10;
+ FXAxis.Font.Style := [fssBold];
+
+ FYAxis := TsChartAxis.Create(self);
+ FYAxis.Caption := 'y axis';
+ FYAxis.LabelFont.Size := 9;
+ FYAxis.Font.Size := 10;
+ FYAxis.Font.Style := [fssBold];
+
+ FY2Axis := TsChartAxis.Create(self);
+ FY2Axis.Caption := 'Secondary y axis';
+ FY2Axis.LabelFont.Size := 9;
+ FY2Axis.Font.Size := 10;
+ FY2Axis.Font.Style := [fssBold];
+ FYAxis.Visible := false;
+
+ FSeriesList := TsChartSeriesList.Create;
+end;
+
+destructor TsChart.Destroy;
+begin
+ FSeriesList.Free;
+ FXAxis.Free;
+ FYAxis.Free;
+ FY2Axis.Free;
+ FLegend.Free;
+ FTitle.Free;
+ FSubtitle.Free;
+ inherited;
+end;
+
+function TsChart.AddSeries(ASeries: TsChartSeries): Integer;
+begin
+ Result := FSeriesList.Add(ASeries);
+end;
+
+
+{ TsChartList }
+
+function TsChartList.GetItem(AIndex: Integer): TsChart;
+begin
+ Result := TsChart(inherited Items[AIndex]);
+end;
+
+procedure TsChartlist.SetItem(AIndex: Integer; AValue: TsChart);
+begin
+ inherited Items[AIndex] := AValue;
+end;
+
+end.
+
diff --git a/components/fpspreadsheet/source/common/fpspreadsheet.pas b/components/fpspreadsheet/source/common/fpspreadsheet.pas
index 316bf55b1..dc0903799 100644
--- a/components/fpspreadsheet/source/common/fpspreadsheet.pas
+++ b/components/fpspreadsheet/source/common/fpspreadsheet.pas
@@ -23,7 +23,8 @@ uses
clocale,
{$endif}{$endif}{$endif}
Classes, SysUtils, fpimage, avglvltree, lconvencoding,
- fpsTypes, fpsExprParser, fpsClasses, fpsNumFormat, fpsPageLayout, fpsImages;
+ fpsTypes, fpsExprParser, fpsClasses, fpsNumFormat, fpsPageLayout,
+ fpsImages, fpsChart;
type
{ Forward declarations }
@@ -69,6 +70,7 @@ type
FHyperlinks: TsHyperlinks;
FFormulas: TsFormulas;
FImages: TFPList;
+ FCharts: TsChartList;
FRows, FCols: TIndexedAVLTree; // This lists contain only rows or cols with styles different from default
FActiveCellRow: Cardinal;
FActiveCellCol: Cardinal;
@@ -558,6 +560,10 @@ type
procedure AddHyperlinkToImage(AImageIndex: Integer; ATarget: String;
AToolTip: String = '');
+ { Charts }
+ function WriteChart(ARow, ACol: Cardinal; AWidth, AHeight: Double;
+ AOffsetX: Double = 0.0; AOffsetY: Double = 0.0): Integer;
+
{ Protection }
procedure Protect(AEnable: Boolean);
@@ -1137,6 +1143,7 @@ begin
FHyperlinks := TsHyperlinks.Create;
FFormulas := TsFormulas.Create;
FImages := TFPList.Create;
+ FCharts := TsChartList.Create;
FPageLayout := TsPageLayout.Create(self);
@@ -1179,6 +1186,7 @@ begin
FHyperlinks.Free;
FFormulas.Free;
FImages.Free;
+ FCharts.Free;
inherited Destroy;
end;
@@ -3732,6 +3740,26 @@ begin
DeleteFormula(ACell);
end;
+{@@ ----------------------------------------------------------------------------
+ Creates a chart object with its top/left corner in the specified row/colum and
+ having the specified width. Inserts the chart in the FCharts list of the
+ worksheet and returns its index.
+-------------------------------------------------------------------------------}
+function TsWorksheet.WriteChart(ARow, ACol: Cardinal; AWidth, AHeight: Double;
+ AOffsetX: Double = 0.0; AOffsetY: Double = 0.0): Integer;
+var
+ chart: TsChart;
+begin
+ chart := TsChart.Create;
+ chart.Row := ARow;
+ chart.Col := ACol;
+ chart.OffsetX := AOffsetX;
+ chart.OffsetY := AOffsetY;
+ chart.Width := AWidth;
+ chart.Height := AHeight;
+ Result := FCharts.Add(chart);
+end;
+
{@@ ----------------------------------------------------------------------------
Returns the parameters of the image stored in the internal image list at
the specified index.