diff --git a/components/fpspreadsheet/examples/other/chart/bubblechart_write_demo.lpi b/components/fpspreadsheet/examples/other/chart/bubblechart_write_demo.lpi new file mode 100644 index 000000000..91a9ca97a --- /dev/null +++ b/components/fpspreadsheet/examples/other/chart/bubblechart_write_demo.lpi @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectOptions> + <Version Value="12"/> + <PathDelim Value="\"/> + <General> + <Flags> + <MainUnitHasCreateFormStatements Value="False"/> + <MainUnitHasTitleStatement Value="False"/> + <MainUnitHasScaledStatement Value="False"/> + </Flags> + <SessionStorage Value="InProjectDir"/> + <Title Value="bubblechart_write_demo"/> + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + </General> + <BuildModes> + <Item Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + <UseFileFilters Value="True"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + </RunParams> + <RequiredPackages> + <Item> + <PackageName Value="laz_fpspreadsheet"/> + </Item> + </RequiredPackages> + <Units> + <Unit> + <Filename Value="bubblechart_write_demo.lpr"/> + <IsPartOfProject Value="True"/> + </Unit> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="bubblechart_write_demo"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Linking> + <Debugging> + <DebugInfoType Value="dsDwarf3"/> + </Debugging> + </Linking> + <Other> + <ConfigFile> + <WriteConfigFilePath Value=""/> + </ConfigFile> + </Other> + </CompilerOptions> + <Debugging> + <Exceptions> + <Item> + <Name Value="EAbort"/> + </Item> + <Item> + <Name Value="ECodetoolError"/> + </Item> + <Item> + <Name Value="EFOpenError"/> + </Item> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/components/fpspreadsheet/examples/other/chart/bubblechart_write_demo.lpr b/components/fpspreadsheet/examples/other/chart/bubblechart_write_demo.lpr new file mode 100644 index 000000000..407da5a51 --- /dev/null +++ b/components/fpspreadsheet/examples/other/chart/bubblechart_write_demo.lpr @@ -0,0 +1,84 @@ +program bubblechart_write_demo; + +{.$DEFINE DARK_MODE} + +uses + SysUtils, + fpspreadsheet, fpstypes, fpsUtils, fpschart, xlsxooxml, fpsopendocument; + +const + FILE_NAME = 'bubble'; + sDISTANCE = 'Distance from Sun' + LineEnding + '(relative to Earth)'; + sPERIOD = 'Orbital period' + LineEnding + '(relative to Earth)'; + sDIAMETER = 'Diameter (km)'; +var + book: TsWorkbook; + sheet: TsWorksheet; + ch: TsChart; + ser: TsBubbleSeries; +begin + book := TsWorkbook.Create; + try + // worksheet + sheet := book.AddWorksheet('bubble_series'); + + // Enter data + sheet.WriteText( 0,0, 'Solar System'); + sheet.WriteFont( 0,0, '', 12, [fssBold], scBlack); + + sheet.WriteText( 2,0, 'Planet' ); sheet.WriteText ( 2,1, sDistance); sheet.WriteText ( 2,2, sPERIOD); sheet.WriteText (2, 3, sDIAMETER); + sheet.WriteText( 3,0, 'Mercury'); sheet.WriteNumber( 3,1, 0.387); sheet.WriteNumber( 3,2, 0.241); sheet.WriteNumber( 3,3, 4.879E3); + sheet.WriteText( 4,0, 'Venus' ); sheet.WriteNumber( 4,1, 0.723); sheet.WriteNumber( 4,2, 0.615); sheet.WriteNumber( 4,3, 1.210E4); + sheet.WriteText( 5,0, 'Earth' ); sheet.WriteNumber( 5,1, 1.000); sheet.WriteNumber( 5,2, 1.000); sheet.WriteNumber( 5,3, 1.276E4); + sheet.WriteText( 6,0, 'Mars' ); sheet.WriteNumber( 6,1, 1.524); sheet.WriteNumber( 6,2, 1.881); sheet.WriteNumber( 6,3, 6.792E3); + sheet.WriteText( 7,0, 'Jupiter'); sheet.WriteNumber( 7,1, 5.204); sheet.WriteNumber( 7,2, 11.862); sheet.WriteNumber( 7,3, 1.430E5); + sheet.WriteText( 8,0, 'Saturn' ); sheet.WriteNumber( 8,1, 9.582); sheet.WriteNumber( 8,2, 29.445); sheet.WriteNumber( 8,3, 1.205E5); + sheet.WriteText( 9,0, 'Uranus' ); sheet.WriteNumber( 9,1,19.201); sheet.WriteNumber( 9,2, 84.011); sheet.WriteNumber( 9,3, 5.112E4); + sheet.WriteText(10,0, 'Neptune'); sheet.WriteNumber(10,1,30.047); sheet.WriteNumber(10,2,164.79); sheet.WriteNumber(10,3, 4.953E4); + + sheet.WriteText(12,0, 'Source: wikipedia'); + sheet.WriteFont(12,0, '', 8, [], scBlack); + + sheet.WriteColWidth(1, 40.0, suMillimeters); + sheet.WriteColWidth(2, 40.0, suMillimeters); + + // Create chart: left/top in cell D4, 150 mm x 150 mm + ch := book.AddChart(sheet, 2, 4, 150, 150); + + // Chart properties + ch.Border.Style := clsNoLine; + ch.Title.Caption := 'Solar System'; + ch.Title.Font.Style := [fssBold]; + ch.Legend.Visible := false; + ch.XAxis.Title.Caption := 'Distance from Sun (relative to Earth)'; + ch.XAxis.MinorGridLines.Style := clsNoLine; + ch.XAxis.Logarithmic := true; + ch.YAxis.Title.Caption := 'Orbital period (relative to Earth)'; + ch.YAxis.AxisLine.Color := scSilver; + ch.YAxis.MinorGridLines.Style := clsNoLine; + ch.YAxis.Logarithmic := true; + + // Add data as bubble series + ser := TsBubbleSeries.Create(ch); + ser.SetLabelRange(3, 0, 10, 0); + ser.SetXRange(3, 1, 10, 1); + ser.SetYRange(3, 2, 10, 2); + ser.SetBubbleRange(3, 3, 10, 3); + ser.Line.Style := clsNoLine; + ser.Fill.Color := $c47244; //72c4 scBlue; + ser.Fill.Transparency := 0.25; + ser.DataLabels := [cdlCategory]; + ch.AddSeries(ser); + + { + book.WriteToFile(FILE_NAME + '.xlsx', true); // Excel fails to open the file + WriteLn('Data saved with chart in ', FILENAME, '.xlsx'); + } + + book.WriteToFile(FILE_NAME + '.ods', true); + WriteLn('Data saved with chart in ', FILE_NAME, '.ods'); + finally + book.Free; + end; +end. + diff --git a/components/fpspreadsheet/examples/visual/fpschart/fpschartlink/main.pas b/components/fpspreadsheet/examples/visual/fpschart/fpschartlink/main.pas index 7fb91b4fe..251cecc0b 100644 --- a/components/fpspreadsheet/examples/visual/fpschart/fpschartlink/main.pas +++ b/components/fpspreadsheet/examples/visual/fpschart/fpschartlink/main.pas @@ -35,7 +35,8 @@ implementation {$R *.lfm} const - FILE_NAME = '../../../other/chart/bars.ods'; +// FILE_NAME = '../../../other/chart/bars.ods'; + FILE_NAME = '../../../other/chart/bubble.ods'; // FILE_NAME = '../../../other/chart/area.ods'; // FILE_NAME = '../../../other/chart/area-sameImg.ods'; // FILE_NAME = '../../../other/chart/pie.ods'; diff --git a/components/fpspreadsheet/source/common/fpschart.pas b/components/fpspreadsheet/source/common/fpschart.pas index ee2e9d0fc..a55c13d9a 100644 --- a/components/fpspreadsheet/source/common/fpschart.pas +++ b/components/fpspreadsheet/source/common/fpschart.pas @@ -391,6 +391,7 @@ type end; TsBubbleSeries = class(TsChartSeries) + // to do: inherited from ScatterSeries, but without symbols private FBubbleRange: TsChartRange; public @@ -1629,6 +1630,7 @@ begin FSubTitle.Font.Size := 12; FLegend := TsChartLegend.Create(self); + FLegend.Visible := false; FXAxis := TsChartAxis.Create(self); FXAxis.Title.Caption := 'x axis'; diff --git a/components/fpspreadsheet/source/visual/fpspreadsheetchart.pas b/components/fpspreadsheet/source/visual/fpspreadsheetchart.pas index f2c04fa96..d3665d230 100644 --- a/components/fpspreadsheet/source/visual/fpspreadsheetchart.pas +++ b/components/fpspreadsheet/source/visual/fpspreadsheetchart.pas @@ -23,7 +23,7 @@ uses LCLVersion, Forms, Controls, Graphics, GraphUtil, Dialogs, // TAChart TATypes, TATextElements, TAChartUtils, TALegend, TACustomSource, TASources, - TACustomSeries, TASeries, TARadialSeries, TAFitUtils, TAFuncSeries, + TACustomSeries, TASeries, TARadialSeries, TAFitUtils, TAFuncSeries, TAMultiSeries, TAChartAxisUtils, TAChartAxis, TAStyles, TAGraph, // FPSpreadsheet fpsTypes, fpSpreadsheet, fpsUtils, fpsChart, @@ -140,6 +140,7 @@ type procedure UpdateAreaSeries(AWorkbookSeries: TsAreaSeries; AChartSeries: TAreaSeries); procedure UpdateBarSeries(AWorkbookSeries: TsBarSeries; AChartSeries: TBarSeries); + procedure UpdateBubbleSeries(AWorkbookSeries: TsBubbleSeries; AChartSeries: TBubbleSeries); procedure UpdateLineSeries(AWorkbookSeries: TsLineSeries; AChartSeries: TLineSeries); procedure UpdatePieSeries(AWorkbookSeries: TsPieSeries; AChartSeries: TPieSeries); procedure UpdatePolarSeries(AWorkbookSeries: TsRadarSeries; AChartSeries: TPolarSeries); @@ -830,8 +831,8 @@ begin SetLength(FWorksheets[ARangeIndex], Length(FWorksheets[ARangeIndex]) + 1); case ARangeIndex of - rngX: XCount := Length(FRanges[ARangeIndex]); - rngY: YCount := Length(FRanges[ARangeIndex]); + rngX: XCount := Max(XCount, Length(FRanges[ARangeIndex])); + rngY: YCount := Max(YCount, Length(FRanges[ARangeIndex])); end; SetLength(FRanges[ARangeIndex, AListIndex], 1); // FIXME: Assuming here single-block range !!! @@ -968,7 +969,7 @@ begin if (calcSrc.Origin is TsWorkbookChartSource) then src := TsWorkbookChartSource(calcSrc.Origin); end else - // ... otherwise we use the workbook chartsource directly. + // ... otherwise we use the workbook chart source directly. if (firstSeries.Source is TsWorkbookChartSource) then begin src := (firstSeries.Source as TsWorkbookChartSource); @@ -978,12 +979,14 @@ begin src.SetYRange(src.YCount, ASeries.YRange); // <--- This updates also the YCount src.FRangeStr[rngY] := src.BuildRangeStr(rngY); + if Result is TBarSeries then TBarSeries(Result).Styles := FChartStyles else if Result is TLineSeries then TLineSeries(Result).Styles := FChartStyles else if Result is TAreaSeries then TAreaSeries(Result).Styles := FChartStyles; + Result.Legend.Multiplicity := lmStyle; src.SetTitleAddr(ASeries.TitleAddr); @@ -997,6 +1000,9 @@ begin else begin // This is either for a non-stackable or the first stackable series. + src := TsWorkbookChartSource.Create(self); + src.WorkbookSource := FWorkbookSource; + case ASeries.ChartType of ctBar: Result := TBarSeries.Create(FChart); @@ -1006,10 +1012,15 @@ begin Result := TAreaSeries.Create(FChart); ctRadar, ctFilledRadar: Result := TPolarSeries.Create(FChart); + ctBubble: + begin + Result := TBubbleSeries.Create(FChart); + src.SetYRange(1, TsBubbleSeries(ASeries).BubbleRange); + end; + else + exit(nil); end; - src := TsWorkbookChartSource.Create(self); - src.WorkbookSource := FWorkbookSource; if not ASeries.LabelRange.IsEmpty then src.SetLabelRange(ASeries.LabelRange); if not ASeries.XRange.IsEmpty then src.SetXRange(0, ASeries.XRange); if not ASeries.YRange.IsEmpty then src.SetYRange(0, ASeries.YRange); @@ -1039,6 +1050,12 @@ var axis: TsChartAxis; begin ser := ActiveChartSeries(ASeries); + if ser = nil then + begin + FWorkbook.AddErrorMsg('Series could not be loaded.'); + exit; + end; + ser.Transparency := round(ASeries.Fill.Transparency); axis := ASeries.Chart.YAxis; UpdateChartSeriesMarks(ASeries, ser); @@ -1059,6 +1076,8 @@ begin UpdateAreaSeries(TsAreaSeries(ASeries), TAreaSeries(ser)); ctBar: UpdateBarSeries(TsBarSeries(ASeries), TBarSeries(ser)); + ctBubble: + UpdateBubbleSeries(TsBubbleSeries(ASeries), TBubbleSeries(ser)); ctLine: UpdateLineSeries(TsLineSeries(ASeries), TLineSeries(ser)); ctScatter: @@ -1403,6 +1422,13 @@ begin TCalculatedChartSource(AChartSeries.Source).Percentage := (AWorkbookSeries.Chart.StackMode = csmStackedPercentage); end; +procedure TsWorkbookChartlink.UpdateBubbleSeries(AWorkbookSeries: TsBubbleSeries; + AChartSeries: TBubbleSeries); +begin + UpdateChartBrush(AWorkbookSeries.Chart, AWorkbookSeries.Fill, AChartSeries.BubbleBrush); + UpdateChartPen(AWorkbookSeries.Chart, AWorkbookSeries.Line, AChartSeries.BubblePen); +end; + procedure TsWorkbookChartLink.UpdateChart; var ch: TsChart;