You've already forked lazarus-ccr
fpspreadsheet: ods reader and chart link support bitmap fill patterns.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9040 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -37,9 +37,10 @@ implementation
|
|||||||
const
|
const
|
||||||
// FILE_NAME = '../../../other/chart/bars.ods';
|
// FILE_NAME = '../../../other/chart/bars.ods';
|
||||||
// FILE_NAME = '../../../other/chart/area.ods';
|
// FILE_NAME = '../../../other/chart/area.ods';
|
||||||
|
FILE_NAME = '../../../other/chart/area-sameImg.ods';
|
||||||
// FILE_NAME = '../../../other/chart/pie.ods';
|
// FILE_NAME = '../../../other/chart/pie.ods';
|
||||||
// FILE_NAME = '../../../other/chart/scatter.ods';
|
// FILE_NAME = '../../../other/chart/scatter.ods';
|
||||||
FILE_NAME = '../../../other/chart/regression.ods';
|
// FILE_NAME = '../../../other/chart/regression.ods';
|
||||||
|
|
||||||
{ TForm1 }
|
{ TForm1 }
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ unit fpsChart;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, Contnrs, fpsTypes, fpsUtils;
|
Classes, SysUtils, Contnrs, FPImage, fpsTypes, fpsUtils;
|
||||||
|
|
||||||
const
|
const
|
||||||
clsNoLine = -2;
|
clsNoLine = -2;
|
||||||
@ -55,6 +55,7 @@ type
|
|||||||
CenterX, CenterY: Double; // 0.0 ... 1.0
|
CenterX, CenterY: Double; // 0.0 ... 1.0
|
||||||
Angle: Double; // degrees
|
Angle: Double; // degrees
|
||||||
constructor Create;
|
constructor Create;
|
||||||
|
destructor Destroy; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TsChartGradientList = class(TFPObjectList)
|
TsChartGradientList = class(TFPObjectList)
|
||||||
@ -92,7 +93,7 @@ type
|
|||||||
LineColor: TsColor;
|
LineColor: TsColor;
|
||||||
LineDistance: Double; // mm
|
LineDistance: Double; // mm
|
||||||
LineAngle: Double; // degrees
|
LineAngle: Double; // degrees
|
||||||
Filled: Boolean; // filled with background color or not
|
destructor Destroy; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TsChartHatchList = class(TFPObjectList)
|
TsChartHatchList = class(TFPObjectList)
|
||||||
@ -101,19 +102,38 @@ type
|
|||||||
procedure SetItem(AIndex: Integer; AValue: TsChartHatch);
|
procedure SetItem(AIndex: Integer; AValue: TsChartHatch);
|
||||||
public
|
public
|
||||||
function AddHatch(AName: String; AStyle: TsChartHatchStyle;
|
function AddHatch(AName: String; AStyle: TsChartHatchStyle;
|
||||||
ALineColor: TsColor; ALineDistance, ALineAngle: Double; AFilled: Boolean): Integer;
|
ALineColor: TsColor; ALineDistance, ALineAngle: Double): Integer;
|
||||||
function FindByName(AName: String): TsChartHatch;
|
function FindByName(AName: String): TsChartHatch;
|
||||||
function IndexOfName(AName: String): Integer;
|
function IndexOfName(AName: String): Integer;
|
||||||
property Items[AIndex: Integer]: TsChartHatch read GetItem write SetItem; default;
|
property Items[AIndex: Integer]: TsChartHatch read GetItem write SetItem; default;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TsChartFillStyle = (cfsNoFill, cfsSolid, cfsGradient, cfsHatched);
|
TsChartImage = class
|
||||||
|
Name: String;
|
||||||
|
Image: TFPCustomImage;
|
||||||
|
Width, Height: Double; // mm
|
||||||
|
destructor Destroy; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TsChartImagelist = class(TFPObjectList)
|
||||||
|
private
|
||||||
|
function GetItem(AIndex: Integer): TsChartImage;
|
||||||
|
procedure SetItem(AIndex: Integer; AValue: TsChartImage);
|
||||||
|
public
|
||||||
|
function AddImage(AName: String; AImage: TFPCustomImage): Integer;
|
||||||
|
function FindByName(AName: String): TsChartImage;
|
||||||
|
function IndexOfName(AName: String): Integer;
|
||||||
|
property Items[Aindex: Integer]: TsChartImage read GetItem write SetItem; default;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TsChartFillStyle = (cfsNoFill, cfsSolid, cfsGradient, cfsHatched, cfsSolidHatched, cfsImage);
|
||||||
|
|
||||||
TsChartFill = class
|
TsChartFill = class
|
||||||
Style: TsChartFillStyle;
|
Style: TsChartFillStyle;
|
||||||
Color: TsColor;
|
Color: TsColor;
|
||||||
Gradient: Integer;
|
Gradient: Integer;
|
||||||
Hatch: Integer;
|
Hatch: Integer;
|
||||||
|
Image: Integer;
|
||||||
Transparency: Double; // 0.0 ... 1.0
|
Transparency: Double; // 0.0 ... 1.0
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -519,6 +539,7 @@ type
|
|||||||
FLineStyles: TsChartLineStyleList;
|
FLineStyles: TsChartLineStyleList;
|
||||||
FGradients: TsChartGradientList;
|
FGradients: TsChartGradientList;
|
||||||
FHatches: TsChartHatchList;
|
FHatches: TsChartHatchList;
|
||||||
|
FImages: TsChartImageList;
|
||||||
function GetCategoryLabelRange: TsChartRange;
|
function GetCategoryLabelRange: TsChartRange;
|
||||||
|
|
||||||
public
|
public
|
||||||
@ -596,6 +617,7 @@ type
|
|||||||
property LineStyles: TsChartLineStyleList read FLineStyles;
|
property LineStyles: TsChartLineStyleList read FLineStyles;
|
||||||
property Gradients: TsChartGradientList read FGradients;
|
property Gradients: TsChartGradientList read FGradients;
|
||||||
property Hatches: TsChartHatchList read FHatches;
|
property Hatches: TsChartHatchList read FHatches;
|
||||||
|
property Images: TsChartImageList read FImages;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TsChartList = class(TObjectList)
|
TsChartList = class(TObjectList)
|
||||||
@ -621,6 +643,12 @@ begin
|
|||||||
EndIntensity := 1.0;
|
EndIntensity := 1.0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
destructor TsChartGradient.Destroy;
|
||||||
|
begin
|
||||||
|
Name := '';
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ TsChartGradientList }
|
{ TsChartGradientList }
|
||||||
|
|
||||||
@ -729,10 +757,19 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TsChartHatch }
|
||||||
|
|
||||||
|
destructor TsChartHatch.Destroy;
|
||||||
|
begin
|
||||||
|
Name := '';
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ TsChartHatchList }
|
{ TsChartHatchList }
|
||||||
|
|
||||||
function TsChartHatchList.AddHatch(AName: String; AStyle: TsChartHatchStyle;
|
function TsChartHatchList.AddHatch(AName: String; AStyle: TsChartHatchStyle;
|
||||||
ALineColor: TsColor; ALineDistance, ALineAngle: Double; AFilled: Boolean): Integer;
|
ALineColor: TsColor; ALineDistance, ALineAngle: Double): Integer;
|
||||||
var
|
var
|
||||||
item: TsChartHatch;
|
item: TsChartHatch;
|
||||||
begin
|
begin
|
||||||
@ -750,7 +787,6 @@ begin
|
|||||||
item.LineColor := ALineColor;
|
item.LineColor := ALineColor;
|
||||||
item.LineDistance := ALineDistance;
|
item.LineDistance := ALineDistance;
|
||||||
item.LineAngle := ALineAngle;
|
item.LineAngle := ALineAngle;
|
||||||
item.Filled := AFilled;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TsChartHatchList.FindByName(AName: String): TsChartHatch;
|
function TsChartHatchList.FindByName(AName: String): TsChartHatch;
|
||||||
@ -783,6 +819,62 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TsChartImage }
|
||||||
|
|
||||||
|
destructor TsChartImage.Destroy;
|
||||||
|
begin
|
||||||
|
Name := '';
|
||||||
|
Image.Free;
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TsChartImageList }
|
||||||
|
|
||||||
|
function TsChartImageList.AddImage(AName: String; AImage: TFPCustomImage): Integer;
|
||||||
|
var
|
||||||
|
item: TsChartImage;
|
||||||
|
begin
|
||||||
|
Result := IndexOfName(AName);
|
||||||
|
if Result = -1 then
|
||||||
|
begin
|
||||||
|
item := TsChartImage.Create;
|
||||||
|
item.Name := AName;
|
||||||
|
Result := inherited Add(item);
|
||||||
|
end;
|
||||||
|
Items[Result].Image := AImage;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsChartImageList.FindByName(AName: String): TsChartImage;
|
||||||
|
var
|
||||||
|
idx: Integer;
|
||||||
|
begin
|
||||||
|
idx := IndexOfName(AName);
|
||||||
|
if idx <> -1 then
|
||||||
|
Result := Items[idx]
|
||||||
|
else
|
||||||
|
Result := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsChartImageList.GetItem(AIndex: Integer): TsChartImage;
|
||||||
|
begin
|
||||||
|
Result := TsChartImage(inherited Items[AIndex]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsChartImageList.IndexOfName(AName: String): Integer;
|
||||||
|
begin
|
||||||
|
for Result := 0 to Count-1 do
|
||||||
|
if SameText(Items[Result].Name, AName) then
|
||||||
|
exit;
|
||||||
|
Result := -1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsChartImageList.SetItem(AIndex: Integer; AValue: TsChartImage);
|
||||||
|
begin
|
||||||
|
inherited Items[AIndex] := AValue;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ TsChartLineStyle }
|
{ TsChartLineStyle }
|
||||||
|
|
||||||
function TsChartLineStyle.GetID: String;
|
function TsChartLineStyle.GetID: String;
|
||||||
@ -1094,6 +1186,8 @@ end;
|
|||||||
|
|
||||||
destructor TsChartSeries.Destroy;
|
destructor TsChartSeries.Destroy;
|
||||||
begin
|
begin
|
||||||
|
FLabelBackground.Free;
|
||||||
|
FLabelBorder.Free;
|
||||||
FLabelFont.Free;
|
FLabelFont.Free;
|
||||||
FLine.Free;
|
FLine.Free;
|
||||||
FFill.Free;
|
FFill.Free;
|
||||||
@ -1511,6 +1605,7 @@ begin
|
|||||||
|
|
||||||
FGradients := TsChartGradientList.Create;
|
FGradients := TsChartGradientList.Create;
|
||||||
FHatches := TsChartHatchList.Create;
|
FHatches := TsChartHatchList.Create;
|
||||||
|
FImages := TsChartImageList.Create;
|
||||||
|
|
||||||
FSheetIndex := 0;
|
FSheetIndex := 0;
|
||||||
FRow := 0;
|
FRow := 0;
|
||||||
@ -1576,6 +1671,7 @@ begin
|
|||||||
FSubtitle.Free;
|
FSubtitle.Free;
|
||||||
FFloor.Free;
|
FFloor.Free;
|
||||||
FPlotArea.Free;
|
FPlotArea.Free;
|
||||||
|
FImages.Free;
|
||||||
FHatches.Free;
|
FHatches.Free;
|
||||||
FGradients.Free;
|
FGradients.Free;
|
||||||
FLineStyles.Free;
|
FLineStyles.Free;
|
||||||
|
@ -5,7 +5,7 @@ unit fpsOpenDocumentChart;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, StrUtils,
|
Classes, SysUtils, StrUtils, Contnrs, FPImage,
|
||||||
{$IF FPC_FULLVERSION >= 20701}
|
{$IF FPC_FULLVERSION >= 20701}
|
||||||
zipper,
|
zipper,
|
||||||
{$ELSE}
|
{$ELSE}
|
||||||
@ -24,6 +24,7 @@ type
|
|||||||
FPointSeparatorSettings: TFormatSettings;
|
FPointSeparatorSettings: TFormatSettings;
|
||||||
FNumberFormatList: TStrings;
|
FNumberFormatList: TStrings;
|
||||||
FPieSeriesStartAngle: Integer;
|
FPieSeriesStartAngle: Integer;
|
||||||
|
FStreamList: TFPObjectList;
|
||||||
function FindStyleNode(AStyleNodes: TDOMNode; AStyleName: String): TDOMNode;
|
function FindStyleNode(AStyleNodes: TDOMNode; AStyleName: String): TDOMNode;
|
||||||
procedure GetChartFillProps(ANode: TDOMNode; AChart: TsChart; AFill: TsChartFill);
|
procedure GetChartFillProps(ANode: TDOMNode; AChart: TsChart; AFill: TsChartFill);
|
||||||
procedure GetChartLineProps(ANode: TDOMNode; AChart: TsChart; ALine: TsChartLine);
|
procedure GetChartLineProps(ANode: TDOMNode; AChart: TsChart; ALine: TsChartLine);
|
||||||
@ -48,13 +49,15 @@ type
|
|||||||
procedure ReadChartTitleProps(ANode, AStyleNode: TDOMNode; AChart: TsChart; ATitle: TsChartText);
|
procedure ReadChartTitleProps(ANode, AStyleNode: TDOMNode; AChart: TsChart; ATitle: TsChartText);
|
||||||
procedure ReadChartTitleStyle(AStyleNode: TDOMNode; AChart: TsChart; ATitle: TsChartText);
|
procedure ReadChartTitleStyle(AStyleNode: TDOMNode; AChart: TsChart; ATitle: TsChartText);
|
||||||
|
|
||||||
|
procedure ReadObjectFillImages(ANode: TDOMNode; AChart: TsChart; ARoot: String);
|
||||||
procedure ReadObjectGradientStyles(ANode: TDOMNode; AChart: TsChart);
|
procedure ReadObjectGradientStyles(ANode: TDOMNode; AChart: TsChart);
|
||||||
procedure ReadObjectHatchStyles(ANode: TDOMNode; AChart: TsChart);
|
procedure ReadObjectHatchStyles(ANode: TDOMNode; AChart: TsChart);
|
||||||
procedure ReadObjectLineStyles(ANode: TDOMNode; AChart: TsChart);
|
procedure ReadObjectLineStyles(ANode: TDOMNode; AChart: TsChart);
|
||||||
protected
|
protected
|
||||||
procedure ReadChartFiles(AStream: TStream; AFileList: String);
|
procedure ReadChartFiles(AStream: TStream; AFileList: String);
|
||||||
procedure ReadChart(AChartNode, AStyleNode: TDOMNode; AChart: TsChart);
|
procedure ReadChart(AChartNode, AStyleNode: TDOMNode; AChart: TsChart);
|
||||||
procedure ReadObjectStyles(ANode: TDOMNode; AChart: TsChart);
|
procedure ReadObjectStyles(ANode: TDOMNode; AChart: TsChart; ARoot: String);
|
||||||
|
procedure ReadPictureFile(AStream: TStream; AFileName: String);
|
||||||
public
|
public
|
||||||
constructor Create(AReader: TsBasicSpreadReader); override;
|
constructor Create(AReader: TsBasicSpreadReader); override;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
@ -303,6 +306,42 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{------------------------------------------------------------------------------}
|
||||||
|
{ internal picture storage }
|
||||||
|
{------------------------------------------------------------------------------}
|
||||||
|
type
|
||||||
|
TStreamItem = class
|
||||||
|
Name: String;
|
||||||
|
Stream: TStream;
|
||||||
|
destructor Destroy; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TStreamItem.Destroy;
|
||||||
|
begin
|
||||||
|
Stream.Free;
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
type
|
||||||
|
TStreamList = class(TFPObjectList)
|
||||||
|
public
|
||||||
|
function FindByName(AName: String): TStream;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TStreamList.FindByName(AName: String): TStream;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
for i := 0 to Count-1 do
|
||||||
|
if TStreamItem(Items[i]).Name = AName then
|
||||||
|
begin
|
||||||
|
Result := TStreamItem(Items[i]).Stream;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
Result := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{------------------------------------------------------------------------------}
|
{------------------------------------------------------------------------------}
|
||||||
{ TsSpreadOpenDocChartReader }
|
{ TsSpreadOpenDocChartReader }
|
||||||
{------------------------------------------------------------------------------}
|
{------------------------------------------------------------------------------}
|
||||||
@ -317,12 +356,14 @@ begin
|
|||||||
FChartFiles := TStringList.Create;
|
FChartFiles := TStringList.Create;
|
||||||
FNumberFormatList := TsChartNumberFormatList.Create;
|
FNumberFormatList := TsChartNumberFormatList.Create;
|
||||||
FNumberFormatList.NameValueSeparator := ':';
|
FNumberFormatList.NameValueSeparator := ':';
|
||||||
|
FStreamList := TStreamList.Create;
|
||||||
|
|
||||||
FPieSeriesStartAngle := 999;
|
FPieSeriesStartAngle := 999;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TsSpreadOpenDocChartReader.Destroy;
|
destructor TsSpreadOpenDocChartReader.Destroy;
|
||||||
begin
|
begin
|
||||||
|
FStreamList.Free;
|
||||||
FNumberFormatList.Free;
|
FNumberFormatList.Free;
|
||||||
FChartFiles.Free;
|
FChartFiles.Free;
|
||||||
inherited;
|
inherited;
|
||||||
@ -367,6 +408,9 @@ var
|
|||||||
sc: String;
|
sc: String;
|
||||||
sn: String;
|
sn: String;
|
||||||
opacity: Double;
|
opacity: Double;
|
||||||
|
img: TsChartImage;
|
||||||
|
value: Double;
|
||||||
|
rel: Boolean;
|
||||||
begin
|
begin
|
||||||
nodeName := ANode.NodeName;
|
nodeName := ANode.NodeName;
|
||||||
|
|
||||||
@ -390,6 +434,10 @@ begin
|
|||||||
end;
|
end;
|
||||||
'hatch':
|
'hatch':
|
||||||
begin
|
begin
|
||||||
|
sc := GetAttrValue(ANode, 'draw:fill-hatch-solid');
|
||||||
|
if sc = 'true' then
|
||||||
|
AFill.Style := cfsSolidHatched
|
||||||
|
else
|
||||||
AFill.Style := cfsHatched;
|
AFill.Style := cfsHatched;
|
||||||
sn := GetAttrValue(ANode, 'draw:fill-hatch-name');
|
sn := GetAttrValue(ANode, 'draw:fill-hatch-name');
|
||||||
if sn <> '' then
|
if sn <> '' then
|
||||||
@ -397,10 +445,30 @@ begin
|
|||||||
sc := GetAttrValue(ANode, 'draw:fill-color');
|
sc := GetAttrValue(ANode, 'draw:fill-color');
|
||||||
if sc <> '' then
|
if sc <> '' then
|
||||||
AFill.Color := HTMLColorStrToColor(sc);
|
AFill.Color := HTMLColorStrToColor(sc);
|
||||||
sc := GetAttrValue(ANode, 'draw:fill-hatch-solid');
|
end;
|
||||||
// AFill.Hatch.Filled := (sc = 'true'); // !!!! FIX ME: Filled should not be part of the style
|
'bitmap':
|
||||||
|
begin
|
||||||
|
sn := GetAttrValue(ANode, 'draw:fill-image-name');
|
||||||
|
if sn <> '' then
|
||||||
|
begin
|
||||||
|
AFill.Style := cfsImage;
|
||||||
|
AFill.Image := AChart.Images.IndexOfName(UnASCIIName(sn));
|
||||||
|
img := AChart.Images[AFill.Image];
|
||||||
|
sc := GetAttrValue(ANode, 'draw:fill-image-width');
|
||||||
|
if (sc <> '') and EvalLengthStr(sc, value, rel) then
|
||||||
|
img.Width := value
|
||||||
|
else
|
||||||
|
img.Width := -1;
|
||||||
|
sc := GetAttrValue(ANode, 'draw:fill-image-height');
|
||||||
|
if (sc <> '') and EvalLengthStr(sc, value, rel) then
|
||||||
|
img.Height := value
|
||||||
|
else
|
||||||
|
img.Height := -1;
|
||||||
|
end else
|
||||||
|
AFill.Style := cfsSolid;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
s := GetAttrValue(ANode, 'draw:opacity');
|
s := GetAttrValue(ANode, 'draw:opacity');
|
||||||
if (s <> '') and TryPercentStrToFloat(s, opacity) then
|
if (s <> '') and TryPercentStrToFloat(s, opacity) then
|
||||||
AFill.Transparency := 1.0 - opacity;
|
AFill.Transparency := 1.0 - opacity;
|
||||||
@ -770,8 +838,8 @@ procedure TsSpreadOpenDocChartReader.ReadChartFiles(AStream: TStream;
|
|||||||
AFileList: String);
|
AFileList: String);
|
||||||
var
|
var
|
||||||
sa: TStringArray;
|
sa: TStringArray;
|
||||||
i: Integer;
|
i, p: Integer;
|
||||||
fn: String;
|
root, fn: String;
|
||||||
contentFile: String = '';
|
contentFile: String = '';
|
||||||
stylesFile: String = '';
|
stylesFile: String = '';
|
||||||
XMLStream: TStream;
|
XMLStream: TStream;
|
||||||
@ -789,7 +857,9 @@ begin
|
|||||||
if fn = 'content.xml' then
|
if fn = 'content.xml' then
|
||||||
contentFile := sa[i]
|
contentFile := sa[i]
|
||||||
else if fn = 'styles.xml' then
|
else if fn = 'styles.xml' then
|
||||||
stylesFile := sa[i];
|
stylesFile := sa[i]
|
||||||
|
else if pos('/Pictures/', sa[i]) > 0 then
|
||||||
|
ReadPictureFile(AStream, sa[i]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
for i := 0 to TsWorkbook(Reader.Workbook).GetChartCount-1 do
|
for i := 0 to TsWorkbook(Reader.Workbook).GetChartCount-1 do
|
||||||
@ -822,7 +892,9 @@ begin
|
|||||||
if not ok then
|
if not ok then
|
||||||
raise Exception.Create('ODS chart reader: error reading styles file "' + stylesFile + '"');
|
raise Exception.Create('ODS chart reader: error reading styles file "' + stylesFile + '"');
|
||||||
|
|
||||||
ReadObjectStyles(doc.DocumentElement.FindNode('office:styles'), chart);
|
p := pos('/', stylesFile);
|
||||||
|
root := copy(stylesFile, 1, p);
|
||||||
|
ReadObjectStyles(doc.DocumentElement.FindNode('office:styles'), chart, root);
|
||||||
FreeAndNil(doc);
|
FreeAndNil(doc);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1421,7 +1493,7 @@ end;
|
|||||||
|
|
||||||
{ Reads the styles stored in the Object files. }
|
{ Reads the styles stored in the Object files. }
|
||||||
procedure TsSpreadOpenDocChartReader.ReadObjectStyles(ANode: TDOMNode;
|
procedure TsSpreadOpenDocChartReader.ReadObjectStyles(ANode: TDOMNode;
|
||||||
AChart: TsChart);
|
AChart: TsChart; ARoot: String);
|
||||||
var
|
var
|
||||||
nodeName: String;
|
nodeName: String;
|
||||||
begin
|
begin
|
||||||
@ -1437,11 +1509,38 @@ begin
|
|||||||
ReadObjectHatchStyles(ANode, AChart);
|
ReadObjectHatchStyles(ANode, AChart);
|
||||||
'draw:gradient': // gradient definition
|
'draw:gradient': // gradient definition
|
||||||
ReadObjectGradientStyles(ANode, AChart);
|
ReadObjectGradientStyles(ANode, AChart);
|
||||||
|
'draw:fill-image':
|
||||||
|
ReadObjectFillImages(ANode, AChart, ARoot);
|
||||||
end;
|
end;
|
||||||
ANode := ANode.NextSibling;
|
ANode := ANode.NextSibling;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TsSpreadOpenDocChartReader.ReadObjectFillImages(ANode: TDOMNode;
|
||||||
|
AChart: TsChart; ARoot: String);
|
||||||
|
var
|
||||||
|
styleName: String;
|
||||||
|
imgFileName: string;
|
||||||
|
imgStream: TStream;
|
||||||
|
img: TFPCustomImage;
|
||||||
|
begin
|
||||||
|
styleName := GetAttrValue(ANode, 'draw:display-name');
|
||||||
|
if styleName = '' then
|
||||||
|
styleName := GetAttrValue(ANode, 'draw:name');
|
||||||
|
|
||||||
|
imgFileName := GetAttrValue(ANode, 'xlink:href');
|
||||||
|
if imgFileName = '' then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
imgStream := TStreamList(FStreamList).FindByName(ARoot + imgFileName);
|
||||||
|
if imgStream <> nil then
|
||||||
|
begin
|
||||||
|
img := TFPMemoryImage.Create(0, 0); // do not destroy this image here!
|
||||||
|
img.LoadFromStream(imgStream);
|
||||||
|
AChart.Images.AddImage(styleName, img);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TsSpreadOpenDocChartReader.ReadObjectGradientStyles(ANode: TDOMNode;
|
procedure TsSpreadOpenDocChartReader.ReadObjectGradientStyles(ANode: TDOMNode;
|
||||||
AChart: TsChart);
|
AChart: TsChart);
|
||||||
var
|
var
|
||||||
@ -1547,8 +1646,7 @@ begin
|
|||||||
else
|
else
|
||||||
hatchAngle := 0;
|
hatchAngle := 0;
|
||||||
|
|
||||||
AChart.Hatches.AddHatch(styleName, hatchStyle, hatchColor, hatchDist, hatchAngle, false);
|
AChart.Hatches.AddHatch(styleName, hatchStyle, hatchColor, hatchDist, hatchAngle);
|
||||||
AChart.Hatches.AddHatch(styleName+' filled', hatchStyle, hatchColor, hatchDist, hatchAngle, true);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Reads the line styles stored as "draw:stroke-dash" nodes in the chart's
|
{ Reads the line styles stored as "draw:stroke-dash" nodes in the chart's
|
||||||
@ -1591,6 +1689,31 @@ begin
|
|||||||
AChart.LineStyles.Add(styleName, dots1Length, dots1, dots2Length, dots2, distance, rel1 or rel2 or relDist);
|
AChart.LineStyles.Add(styleName, dots1Length, dots1, dots2Length, dots2, distance, rel1 or rel2 or relDist);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TsSpreadOpenDocChartReader.ReadPictureFile(AStream: TStream;
|
||||||
|
AFileName: String);
|
||||||
|
var
|
||||||
|
memStream: TMemoryStream;
|
||||||
|
img: TFPCustomImage;
|
||||||
|
item: TStreamItem;
|
||||||
|
begin
|
||||||
|
memStream := TMemoryStream.Create;
|
||||||
|
try
|
||||||
|
if UnzipToStream(AStream, AFileName, memStream) then
|
||||||
|
begin
|
||||||
|
memstream.Position := 0;
|
||||||
|
item := TStreamItem.Create;
|
||||||
|
item.Name := AFileName;
|
||||||
|
item.Stream := TMemoryStream.Create;
|
||||||
|
item.Stream.CopyFrom(memStream, memStream.Size);
|
||||||
|
item.Stream.Position := 0;
|
||||||
|
FStreamList.Add(item);
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
memstream.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{------------------------------------------------------------------------------}
|
{------------------------------------------------------------------------------}
|
||||||
{ TsSpreadOpenDocChartWriter }
|
{ TsSpreadOpenDocChartWriter }
|
||||||
{------------------------------------------------------------------------------}
|
{------------------------------------------------------------------------------}
|
||||||
@ -1879,10 +2002,10 @@ begin
|
|||||||
[ ASCIIName(gradient.Name) ]
|
[ ASCIIName(gradient.Name) ]
|
||||||
);
|
);
|
||||||
end;
|
end;
|
||||||
cfsHatched:
|
cfsHatched, cfsSolidHatched:
|
||||||
begin
|
begin
|
||||||
hatch := AChart.Hatches[AFill.Hatch];
|
hatch := AChart.Hatches[AFill.Hatch];
|
||||||
if hatch.Filled then
|
if AFill.Style = cfsSolidHatched then
|
||||||
fillStr := 'draw:fill-hatch-solid="true" ';
|
fillStr := 'draw:fill-hatch-solid="true" ';
|
||||||
Result := Format(
|
Result := Format(
|
||||||
'draw:fill="hatch" draw:fill-color="%s" ' +
|
'draw:fill="hatch" draw:fill-color="%s" ' +
|
||||||
|
@ -123,8 +123,8 @@ function GetCellRangeString_R1C1(ASheet1, ASheet2: String;
|
|||||||
function SheetNameNeedsQuotes(ASheet: String): Boolean;
|
function SheetNameNeedsQuotes(ASheet: String): Boolean;
|
||||||
|
|
||||||
// OpenDocument Syntax
|
// OpenDocument Syntax
|
||||||
function TryStrToCellRange_ODS(const AStr: String; out ASheet1, ASheet2: String;
|
function TryStrToCellRange_ODS(const AStr: String; var ASheet1, ASheet2: String;
|
||||||
out ARow1, ACol1, ARow2, ACol2: Cardinal; out AFlags: TsRelFlags): Boolean;
|
var ARow1, ACol1, ARow2, ACol2: Cardinal; var AFlags: TsRelFlags): Boolean;
|
||||||
|
|
||||||
function GetCellRangeString_ODS(ASheet1, ASheet2: String; ARow1, ACol1, ARow2, ACol2: Cardinal;
|
function GetCellRangeString_ODS(ASheet1, ASheet2: String; ARow1, ACol1, ARow2, ACol2: Cardinal;
|
||||||
AFlags: TsRelFlags = rfAllRel; WithBrackets: Boolean = true): String; overload;
|
AFlags: TsRelFlags = rfAllRel; WithBrackets: Boolean = true): String; overload;
|
||||||
@ -1345,8 +1345,8 @@ end;
|
|||||||
Extracts sheets names and cell coordinates from a cell range string in
|
Extracts sheets names and cell coordinates from a cell range string in
|
||||||
OpenDocument syntax, e.g. "Table1.A1:Table2.B4"
|
OpenDocument syntax, e.g. "Table1.A1:Table2.B4"
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function TryStrToCellRange_ODS(const AStr: String; out ASheet1, ASheet2: String;
|
function TryStrToCellRange_ODS(const AStr: String; var ASheet1, ASheet2: String;
|
||||||
out ARow1, ACol1, ARow2, ACol2: Cardinal; out AFlags: TsRelFlags): Boolean;
|
var ARow1, ACol1, ARow2, ACol2: Cardinal; var AFlags: TsRelFlags): Boolean;
|
||||||
var
|
var
|
||||||
p: Integer;
|
p: Integer;
|
||||||
cell1Str, cell2Str: String;
|
cell1Str, cell2Str: String;
|
||||||
|
@ -18,9 +18,9 @@ interface
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
// RTL/FCL
|
// RTL/FCL
|
||||||
Classes, SysUtils, Types,
|
Classes, Contnrs, SysUtils, Types,
|
||||||
// LCL
|
// LCL
|
||||||
LCLVersion, Forms, Controls, Graphics, Dialogs,
|
LCLVersion, Forms, Controls, Graphics, GraphUtil, Dialogs,
|
||||||
// TAChart
|
// TAChart
|
||||||
TATypes, TATextElements, TAChartUtils, TALegend, TACustomSource,
|
TATypes, TATextElements, TAChartUtils, TALegend, TACustomSource,
|
||||||
TACustomSeries, TASeries, TARadialSeries, TAFitUtils, TAFuncSeries,
|
TACustomSeries, TASeries, TARadialSeries, TAFitUtils, TAFuncSeries,
|
||||||
@ -102,6 +102,7 @@ type
|
|||||||
FWorkbookSource: TsWorkbookSource;
|
FWorkbookSource: TsWorkbookSource;
|
||||||
FWorkbook: TsWorkbook;
|
FWorkbook: TsWorkbook;
|
||||||
FWorkbookChartIndex: Integer;
|
FWorkbookChartIndex: Integer;
|
||||||
|
FBrushBitmaps: TFPObjectList;
|
||||||
procedure SetChart(AValue: TChart);
|
procedure SetChart(AValue: TChart);
|
||||||
procedure SetWorkbookChartIndex(AValue: Integer);
|
procedure SetWorkbookChartIndex(AValue: Integer);
|
||||||
procedure SetWorkbookSource(AValue: TsWorkbookSource);
|
procedure SetWorkbookSource(AValue: TsWorkbookSource);
|
||||||
@ -120,12 +121,14 @@ type
|
|||||||
procedure UpdateChartAxisLabels(AWorkbookChart: TsChart);
|
procedure UpdateChartAxisLabels(AWorkbookChart: TsChart);
|
||||||
procedure UpdateChartBackground(AWorkbookChart: TsChart);
|
procedure UpdateChartBackground(AWorkbookChart: TsChart);
|
||||||
procedure UpdateBarSeries(AWorkbookChart: TsChart);
|
procedure UpdateBarSeries(AWorkbookChart: TsChart);
|
||||||
procedure UpdateChartBrush(AWorkbookFill: TsChartFill; ABrush: TBrush);
|
procedure UpdateChartBrush(AWorkbookChart: TsChart; AWorkbookFill: TsChartFill; ABrush: TBrush);
|
||||||
procedure UpdateChartLegend(AWorkbookLegend: TsChartLegend; ALegend: TChartLegend);
|
procedure UpdateChartLegend(AWorkbookLegend: TsChartLegend; ALegend: TChartLegend);
|
||||||
procedure UpdateChartPen(AWorkbookLine: TsChartLine; APen: TPen);
|
procedure UpdateChartPen(AWorkbookLine: TsChartLine; APen: TPen);
|
||||||
procedure UpdateChartSeriesMarks(AWorkbookSeries: TsChartSeries; AChartSeries: TChartSeries);
|
procedure UpdateChartSeriesMarks(AWorkbookSeries: TsChartSeries; AChartSeries: TChartSeries);
|
||||||
procedure UpdateChartTitle(AWorkbookTitle: TsChartText; AChartTitle: TChartTitle);
|
procedure UpdateChartTitle(AWorkbookTitle: TsChartText; AChartTitle: TChartTitle);
|
||||||
|
|
||||||
|
procedure UpdateAreaSeries(AWorkbookSeries: TsAreaSeries; AChartSeries: TAreaSeries);
|
||||||
|
procedure UpdateBarSeries(AWorkbookSeries: TsBarSeries; AChartSeries: TBarSeries);
|
||||||
procedure UpdateLineSeries(AWorkbookSeries: TsLineSeries; AChartSeries: TLineSeries);
|
procedure UpdateLineSeries(AWorkbookSeries: TsLineSeries; AChartSeries: TLineSeries);
|
||||||
procedure UpdatePieSeries(AWorkbookSeries: TsPieSeries; AChartSeries: TPieSeries);
|
procedure UpdatePieSeries(AWorkbookSeries: TsPieSeries; AChartSeries: TPieSeries);
|
||||||
procedure UpdateScatterSeries(AWorkbookSeries: TsScatterSeries; AChartSeries: TLineSeries);
|
procedure UpdateScatterSeries(AWorkbookSeries: TsScatterSeries; AChartSeries: TLineSeries);
|
||||||
@ -622,6 +625,7 @@ end;
|
|||||||
constructor TsWorkbookChartLink.Create(AOwner: TComponent);
|
constructor TsWorkbookChartLink.Create(AOwner: TComponent);
|
||||||
begin
|
begin
|
||||||
inherited;
|
inherited;
|
||||||
|
FBrushBitmaps := TFPObjectList.Create;
|
||||||
FWorkbookChartIndex := -1;
|
FWorkbookChartIndex := -1;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -632,6 +636,7 @@ end;
|
|||||||
destructor TsWorkbookChartLink.Destroy;
|
destructor TsWorkbookChartLink.Destroy;
|
||||||
begin
|
begin
|
||||||
if FWorkbookSource <> nil then FWorkbookSource.RemoveListener(self);
|
if FWorkbookSource <> nil then FWorkbookSource.RemoveListener(self);
|
||||||
|
FBrushBitmaps.Free;
|
||||||
inherited;
|
inherited;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -668,16 +673,9 @@ begin
|
|||||||
|
|
||||||
case ASeries.ChartType of
|
case ASeries.ChartType of
|
||||||
ctArea:
|
ctArea:
|
||||||
begin
|
UpdateAreaSeries(TsAreaSeries(ASeries), TAreaSeries(ser));
|
||||||
UpdateChartBrush(ASeries.Fill, TAreaSeries(ser).AreaBrush);
|
|
||||||
UpdateChartPen(ASeries.Line, TAreaSeries(ser).AreaContourPen);
|
|
||||||
TAreaSeries(ser).AreaLinesPen.Style := psClear;
|
|
||||||
end;
|
|
||||||
ctBar:
|
ctBar:
|
||||||
begin
|
UpdateBarSeries(TsBarSeries(ASeries), TBarSeries(ser));
|
||||||
UpdateChartBrush(ASeries.Fill, TBarSeries(ser).BarBrush);
|
|
||||||
UpdateChartPen(ASeries.Line, TBarSeries(ser).BarPen);
|
|
||||||
end;
|
|
||||||
ctLine:
|
ctLine:
|
||||||
UpdateLineSeries(TsLineSeries(ASeries), TLineSeries(ser));
|
UpdateLineSeries(TsLineSeries(ASeries), TLineSeries(ser));
|
||||||
ctScatter:
|
ctScatter:
|
||||||
@ -863,6 +861,21 @@ begin
|
|||||||
UpdateChart;
|
UpdateChart;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TsWorkbookChartLink.UpdateAreaSeries(AWorkbookSeries: TsAreaSeries;
|
||||||
|
AChartSeries: TAreaSeries);
|
||||||
|
begin
|
||||||
|
UpdateChartBrush(AWorkbookSeries.Chart, AWorkbookSeries.Fill, AChartSeries.AreaBrush);
|
||||||
|
UpdateChartPen(AWorkbookSeries.Line, AChartSeries.AreaContourPen);
|
||||||
|
AChartSeries.AreaLinesPen.Style := psClear;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsWorkbookChartLink.UpdateBarSeries(AWorkbookSeries: TsBarSeries;
|
||||||
|
AChartSeries: TBarSeries);
|
||||||
|
begin
|
||||||
|
UpdateChartBrush(AWorkbookSeries.Chart, AWorkbookSeries.Fill, AChartSeries.BarBrush);
|
||||||
|
UpdateChartPen(AWorkbookSeries.Line, AChartSeries.BarPen);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TsWorkbookChartLink.UpdateChart;
|
procedure TsWorkbookChartLink.UpdateChart;
|
||||||
var
|
var
|
||||||
ch: TsChart;
|
ch: TsChart;
|
||||||
@ -1036,18 +1049,42 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsWorkbookChartLink.UpdateChartBrush(AWorkbookFill: TsChartFill;
|
procedure TsWorkbookChartLink.UpdateChartBrush(AWorkbookChart: TsChart;
|
||||||
ABrush: TBrush);
|
AWorkbookFill: TsChartFill; ABrush: TBrush);
|
||||||
|
var
|
||||||
|
img: TsChartImage;
|
||||||
|
png: TCustomBitmap;
|
||||||
|
w, h, ppi: Integer;
|
||||||
begin
|
begin
|
||||||
if (AWorkbookFill <> nil) and (ABrush <> nil) then
|
if (AWorkbookFill <> nil) and (ABrush <> nil) then
|
||||||
begin
|
begin
|
||||||
ABrush.Color := Convert_sColor_to_Color(AWorkbookFill.Color);
|
ABrush.Color := Convert_sColor_to_Color(AWorkbookFill.Color);
|
||||||
if AWorkbookFill.Style = cfsNoFill then
|
case AWorkbookFill.Style of
|
||||||
ABrush.Style := bsClear
|
cfsNoFill:
|
||||||
else
|
ABrush.Style := bsClear;
|
||||||
|
cfsSolid:
|
||||||
ABrush.Style := bsSolid;
|
ABrush.Style := bsSolid;
|
||||||
// NOTE: TAChart will ignore gradient.
|
cfsGradient:
|
||||||
// To be completed: hatched filles.
|
ABrush.Style := bsSolid; // NOTE: TAChart cannot display gradients
|
||||||
|
cfsHatched, cfsSolidHatched:
|
||||||
|
ABrush.Style := bsSolid;
|
||||||
|
cfsImage:
|
||||||
|
begin
|
||||||
|
img := AWorkbookChart.Images[AWorkbookFill.Image];
|
||||||
|
if img <> nil then
|
||||||
|
begin
|
||||||
|
ppi := GetParentForm(FChart).PixelsPerInch;
|
||||||
|
w := mmToPx(img.Width, ppi);
|
||||||
|
h := mmToPx(img.Height, ppi);
|
||||||
|
png := TPortableNetworkGraphic.Create;
|
||||||
|
png.Assign(img.Image);
|
||||||
|
ScaleImg(png, w, h);
|
||||||
|
FBrushBitmaps.Add(png);
|
||||||
|
ABrush.Bitmap := png;
|
||||||
|
end else
|
||||||
|
ABrush.Style := bsSolid;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1065,7 +1102,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
Convert_sFont_to_Font(AWorkbookLegend.Font, ALegend.Font);
|
Convert_sFont_to_Font(AWorkbookLegend.Font, ALegend.Font);
|
||||||
UpdateChartPen(AWorkbookLegend.Border, ALegend.Frame);
|
UpdateChartPen(AWorkbookLegend.Border, ALegend.Frame);
|
||||||
UpdateChartBrush(AWorkbookLegend.Background, ALegend.BackgroundBrush);
|
UpdateChartBrush(AWorkbookLegend.Chart, AWorkbookLegend.Background, ALegend.BackgroundBrush);
|
||||||
ALegend.Frame.Visible := (ALegend.Frame.Style <> psClear);
|
ALegend.Frame.Visible := (ALegend.Frame.Style <> psClear);
|
||||||
ALegend.Alignment := LEG_POS[AWorkbookLegend.Position];
|
ALegend.Alignment := LEG_POS[AWorkbookLegend.Position];
|
||||||
ALegend.UseSidebar := not AWorkbookLegend.CanOverlapPlotArea;
|
ALegend.UseSidebar := not AWorkbookLegend.CanOverlapPlotArea;
|
||||||
@ -1137,7 +1174,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
UpdateChartPen(AWorkbookSeries.LabelBorder, AChartSeries.Marks.Frame);
|
UpdateChartPen(AWorkbookSeries.LabelBorder, AChartSeries.Marks.Frame);
|
||||||
UpdateChartBrush(AWorkbookSeries.LabelBackground, AChartSeries.Marks.LabelBrush);
|
UpdateChartBrush(AWorkbookSeries.Chart, AWorkbookSeries.LabelBackground, AChartSeries.Marks.LabelBrush);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ Updates title and footer of the linked TAChart.
|
{@@ Updates title and footer of the linked TAChart.
|
||||||
@ -1153,7 +1190,7 @@ begin
|
|||||||
AChartTitle.WordWrap := true;
|
AChartTitle.WordWrap := true;
|
||||||
Convert_sFont_to_Font(AWorkbookTitle.Font, AChartTitle.Font);
|
Convert_sFont_to_Font(AWorkbookTitle.Font, AChartTitle.Font);
|
||||||
UpdateChartPen(AWorkbookTitle.Border, AChartTitle.Frame);
|
UpdateChartPen(AWorkbookTitle.Border, AChartTitle.Frame);
|
||||||
UpdateChartBrush(AWorkbookTitle.Background, AChartTitle.Brush);
|
UpdateChartBrush(AWorkbookTitle.Chart, AWorkbookTitle.Background, AChartTitle.Brush);
|
||||||
AChartTitle.Font.Orientation := round(AWorkbookTitle.RotationAngle * 10);
|
AChartTitle.Font.Orientation := round(AWorkbookTitle.RotationAngle * 10);
|
||||||
AChartTitle.Frame.Visible := (AChartTitle.Frame.Style <> psClear);
|
AChartTitle.Frame.Visible := (AChartTitle.Frame.Style <> psClear);
|
||||||
end;
|
end;
|
||||||
@ -1185,7 +1222,7 @@ begin
|
|||||||
AChartSeries.ShowPoints := AWorkbookSeries.ShowSymbols;
|
AChartSeries.ShowPoints := AWorkbookSeries.ShowSymbols;
|
||||||
if AChartSeries.ShowPoints then
|
if AChartSeries.ShowPoints then
|
||||||
begin
|
begin
|
||||||
UpdateChartBrush(AWorkbookSeries.Fill, AChartSeries.Pointer.Brush);
|
UpdateChartBrush(AWorkbookSeries.Chart, AWorkbookSeries.Fill, AChartSeries.Pointer.Brush);
|
||||||
AChartSeries.Pointer.Pen.Color := AChartSeries.LinePen.Color;
|
AChartSeries.Pointer.Pen.Color := AChartSeries.LinePen.Color;
|
||||||
AChartSeries.Pointer.Style := POINTER_STYLES[AWorkbookSeries.Symbol];
|
AChartSeries.Pointer.Style := POINTER_STYLES[AWorkbookSeries.Symbol];
|
||||||
AChartSeries.Pointer.HorizSize := mmToPx(AWorkbookSeries.SymbolWidth, ppi);
|
AChartSeries.Pointer.HorizSize := mmToPx(AWorkbookSeries.SymbolWidth, ppi);
|
||||||
|
Reference in New Issue
Block a user