1455 lines
43 KiB
ObjectPascal
1455 lines
43 KiB
ObjectPascal
|
|
||
|
{******************************************}
|
||
|
{ }
|
||
|
{ FastReport VCL }
|
||
|
{ TeeChart Add-In Object }
|
||
|
{ }
|
||
|
{ Copyright (c) 1998-2021 }
|
||
|
{ by Fast Reports Inc. }
|
||
|
{ }
|
||
|
{******************************************}
|
||
|
|
||
|
unit frxChart;
|
||
|
|
||
|
interface
|
||
|
|
||
|
{$I frx.inc}
|
||
|
{$I tee.inc}
|
||
|
|
||
|
uses
|
||
|
Windows, Messages, SysUtils, Classes, Graphics, Menus, Controls, frxCollections,
|
||
|
frxClass, frxThreading,
|
||
|
{$IFDEF DELPHI16}
|
||
|
VCLTee.TeeProcs, VCLTee.TeEngine, VCLTee.Chart, VCLTee.Series, VCLTee.TeCanvas
|
||
|
{$ELSE}
|
||
|
TeeProcs, TeEngine, Chart, Series, TeCanvas
|
||
|
{$ENDIF}
|
||
|
{$IFDEF DELPHI16}
|
||
|
{$IFDEF TeeChartPro}, VCLTEE.TeeEdit{$IFNDEF TeeChart4}, VCLTEE.TeeEditCha{$ENDIF} {$ENDIF}
|
||
|
{$ELSE}
|
||
|
{$IFDEF TeeChartPro}, TeeEdit{$IFNDEF TeeChart4}, TeeEditCha{$ENDIF} {$ENDIF}
|
||
|
{$ENDIF}
|
||
|
{$IFDEF Delphi6}
|
||
|
, Variants
|
||
|
{$ENDIF};
|
||
|
|
||
|
|
||
|
type
|
||
|
{$IFDEF DELPHI16}
|
||
|
/// <summary>
|
||
|
/// The TfrxChartBoxObject lets you use the Chart component in your report.
|
||
|
/// TfrxChartObject is an empty component. It is used to add the frxChart.pas
|
||
|
/// file to the "uses" list. The main component is TfrxChartView.
|
||
|
/// </summary>
|
||
|
[ComponentPlatformsAttribute(pidWin32 or pidWin64)]
|
||
|
{$ENDIF}
|
||
|
TfrxChartObject = class(TComponent); // fake component
|
||
|
TChartClass = class of TCustomChart;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Data type of the series: DB data, band data or fixed data.
|
||
|
/// </summary>
|
||
|
TfrxSeriesDataType = (dtDBData, dtBandData, dtFixedData);
|
||
|
/// <summary>
|
||
|
/// Sort type of the series data.
|
||
|
/// </summary>
|
||
|
TfrxSeriesSortOrder = (soNone, soAscending, soDescending);
|
||
|
/// <summary>
|
||
|
/// The X-axis data type: text, numeric, date.
|
||
|
/// </summary>
|
||
|
TfrxSeriesXType = (xtText, xtNumber, xtDate);
|
||
|
TSeriesClass = class of TChartSeries;
|
||
|
/// <summary>
|
||
|
/// Series types.
|
||
|
/// </summary>
|
||
|
TfrxChartSeries = (csLine, csArea, csPoint, csBar, csHorizBar,
|
||
|
csPie, csGantt, csFastLine, csArrow, csBubble, csChartShape, csHorizArea,
|
||
|
csHorizLine, csPolar, csRadar, csPolarBar, csGauge, csSmith, csPyramid,
|
||
|
csDonut, csBezier, csCandle, csVolume, csPointFigure, csHistogram,
|
||
|
csHorizHistogram, csErrorBar, csError, csHighLow, csFunnel, csBox,
|
||
|
csHorizBox, csSurface, csContour, csWaterFall, csColorGrid, csVector3D,
|
||
|
csTower, csTriSurface, csPoint3D, csBubble3D, csMyPoint, csBarJoin, csBar3D,
|
||
|
//new
|
||
|
csPolarContourSeries, csEquiVolumeSeries, csCircularGauge, csClockGauge,
|
||
|
csNumericGauge, csBigCandle, csDeltaPoint, TImageBar, TImagePoint,
|
||
|
csWindRose, csErrorPoint3D, csErrorPoint, csEqualizer, csPolarGrid,
|
||
|
csOrg, csKagi, csRenko, csTagCloud, csHighLowLine, csVolumePipe, csTreeMap,
|
||
|
csKnobGauge, csRose, csTernary
|
||
|
);
|
||
|
|
||
|
|
||
|
/// <summary>
|
||
|
/// The TfrxSeriesItem class represents one series.
|
||
|
/// </summary>
|
||
|
TfrxSeriesItem = class(TfrxCollectionItem)
|
||
|
private
|
||
|
FDataBand: TfrxDataBand;
|
||
|
FDataSet: TfrxDataSet;
|
||
|
FDataSetName: String;
|
||
|
FDataType: TfrxSeriesDataType;
|
||
|
FSortOrder: TfrxSeriesSortOrder;
|
||
|
FTopN: Integer;
|
||
|
FTopNCaption: String;
|
||
|
FSource1: String;
|
||
|
FSource2: String;
|
||
|
FSource3: String;
|
||
|
FSource4: String;
|
||
|
FSource5: String;
|
||
|
FSource6: String;
|
||
|
FSource7: String;
|
||
|
FSource8: String;
|
||
|
FSource9: String;
|
||
|
FSource10: String;
|
||
|
FXType: TfrxSeriesXType;
|
||
|
FValues1: String;
|
||
|
FValues2: String;
|
||
|
FValues3: String;
|
||
|
FValues4: String;
|
||
|
FValues5: String;
|
||
|
FValues6: String;
|
||
|
FValues7: String;
|
||
|
FValues8: String;
|
||
|
FValues9: String;
|
||
|
FValues10: String;
|
||
|
Fsl1: TStringList;
|
||
|
Fsl2: TStringList;
|
||
|
Fsl3: TStringList;
|
||
|
Fsl4: TStringList;
|
||
|
Fsl5: TStringList;
|
||
|
Fsl6: TStringList;
|
||
|
Fsl7: TStringList;
|
||
|
Fsl8: TStringList;
|
||
|
Fsl9: TStringList;
|
||
|
Fsl10: TStringList;
|
||
|
FValueIndex1: Integer;
|
||
|
FValueIndex2: Integer;
|
||
|
FValueIndex3: Integer;
|
||
|
FValueIndex4: Integer;
|
||
|
FValueIndex5: Integer;
|
||
|
FValueIndex6: Integer;
|
||
|
FValueIndex7: Integer;
|
||
|
FValueIndex8: Integer;
|
||
|
FValueIndex9: Integer;
|
||
|
FValueIndex10: Integer;
|
||
|
procedure FillSeries(Series: TChartSeries);
|
||
|
procedure SetDataSet(const Value: TfrxDataSet);
|
||
|
procedure SetDataSetName(const Value: String);
|
||
|
function GetDataSetName: String;
|
||
|
public
|
||
|
constructor Create(Collection: TCollection); override;
|
||
|
destructor Destroy; override;
|
||
|
function IsUniqueNameStored: Boolean; override;
|
||
|
published
|
||
|
/// <summary>
|
||
|
/// Type of series data.
|
||
|
/// </summary>
|
||
|
property DataType: TfrxSeriesDataType read FDataType write FDataType;
|
||
|
/// <summary>
|
||
|
/// Band which the series is connected to. Used if DataType = dtBandData.
|
||
|
/// </summary>
|
||
|
property DataBand: TfrxDataBand read FDataBand write FDataBand;
|
||
|
/// <summary>
|
||
|
/// Dataset which is series connected to. This property is used if
|
||
|
/// property DataType = dtDBData.
|
||
|
/// </summary>
|
||
|
property DataSet: TfrxDataSet read FDataSet write SetDataSet;
|
||
|
property DataSetName: String read GetDataSetName write SetDataSetName;
|
||
|
/// <summary>
|
||
|
/// Sort order of series data.
|
||
|
/// </summary>
|
||
|
property SortOrder: TfrxSeriesSortOrder read FSortOrder write FSortOrder;
|
||
|
/// <summary>
|
||
|
/// Show TopN values. Sum of other values shows as a separate value with
|
||
|
/// caption set in the TopNCaption property.
|
||
|
/// </summary>
|
||
|
property TopN: Integer read FTopN write FTopN;
|
||
|
/// <summary>
|
||
|
/// Show TopN values. Sum of other values shows as a separate value with
|
||
|
/// caption set in the TopNCaption property.
|
||
|
/// </summary>
|
||
|
property TopNCaption: String read FTopNCaption write FTopNCaption;
|
||
|
/// <summary>
|
||
|
/// The X-axis data type: text, numeric, date.
|
||
|
/// </summary>
|
||
|
property XType: TfrxSeriesXType read FXType write FXType;
|
||
|
|
||
|
{ source expressions }
|
||
|
/// <summary>
|
||
|
/// Datasource1 for axis values. This property may contain an expression
|
||
|
/// or list of fixed data (in case DataType property is dtFixedData).
|
||
|
/// </summary>
|
||
|
property Source1: String read FSource1 write FSource1;
|
||
|
/// <summary>
|
||
|
/// Datasource2 for axis values. This property may contain an expression
|
||
|
/// or list of fixed data (in case DataType property is dtFixedData).
|
||
|
/// </summary>
|
||
|
property Source2: String read FSource2 write FSource2;
|
||
|
/// <summary>
|
||
|
/// Datasource3 for axis values. This property may contain an expression
|
||
|
/// or list of fixed data (in case DataType property is dtFixedData).
|
||
|
/// </summary>
|
||
|
property Source3: String read FSource3 write FSource3;
|
||
|
/// <summary>
|
||
|
/// Datasource4 for axis values. This property may contain an expression
|
||
|
/// or list of fixed data (in case DataType property is dtFixedData).
|
||
|
/// </summary>
|
||
|
property Source4: String read FSource4 write FSource4;
|
||
|
/// <summary>
|
||
|
/// Datasource5 for axis values. This property may contain an expression
|
||
|
/// or list of fixed data (in case DataType property is dtFixedData).
|
||
|
/// </summary>
|
||
|
property Source5: String read FSource5 write FSource5;
|
||
|
/// <summary>
|
||
|
/// Datasource6 for axis values. This property may contain an expression
|
||
|
/// or list of fixed data (in case DataType property is dtFixedData).
|
||
|
/// </summary>
|
||
|
property Source6: String read FSource6 write FSource6;
|
||
|
/// <summary>
|
||
|
/// Datasource7 for axis values. This property may contain an expression
|
||
|
/// or list of fixed data (in case DataType property is dtFixedData).
|
||
|
/// </summary>
|
||
|
property Source7: String read FSource7 write FSource7;
|
||
|
/// <summary>
|
||
|
/// Datasource8 for axis values. This property may contain an expression
|
||
|
/// or list of fixed data (in case DataType property is dtFixedData).
|
||
|
/// </summary>
|
||
|
property Source8: String read FSource8 write FSource8;
|
||
|
/// <summary>
|
||
|
/// Datasource9 for axis values. This property may contain an expression
|
||
|
/// or list of fixed data (in case DataType property is dtFixedData).
|
||
|
/// </summary>
|
||
|
property Source9: String read FSource9 write FSource9;
|
||
|
/// <summary>
|
||
|
/// Datasource10 for axis values. This property may contain an expression
|
||
|
/// or list of fixed data (in case DataType property is dtFixedData).
|
||
|
/// </summary>
|
||
|
property Source10: String read FSource10 write FSource10;
|
||
|
|
||
|
{ ready values. For internal use only. }
|
||
|
property Values1: String read FValues1 write FValues1;
|
||
|
property Values2: String read FValues2 write FValues2;
|
||
|
property Values3: String read FValues3 write FValues3;
|
||
|
property Values4: String read FValues4 write FValues4;
|
||
|
property Values5: String read FValues5 write FValues5;
|
||
|
property Values6: String read FValues6 write FValues6;
|
||
|
property Values7: String read FValues7 write FValues7;
|
||
|
property Values8: String read FValues8 write FValues8;
|
||
|
property Values9: String read FValues9 write FValues9;
|
||
|
property Values10: String read FValues10 write FValues10;
|
||
|
|
||
|
{ backward compatibility }
|
||
|
property XSource: String read FSource1 write FSource1;
|
||
|
property YSource: String read FSource2 write FSource2;
|
||
|
property XValues: String read FValues1 write FValues1;
|
||
|
property YValues: String read FValues2 write FValues2;
|
||
|
|
||
|
{ deprecated V5 }
|
||
|
property InheritedName: String read GetInheritedName write SetInheritedName stored False;
|
||
|
end;
|
||
|
|
||
|
/// <summary>
|
||
|
/// The TfrxSeriesData class represents collection of series.
|
||
|
/// </summary>
|
||
|
TfrxSeriesData = class(TfrxCollection)
|
||
|
private
|
||
|
FReport: TfrxReport;
|
||
|
function GetSeries(Index: Integer): TfrxSeriesItem;
|
||
|
public
|
||
|
constructor Create(Report: TfrxReport);
|
||
|
/// <summary>
|
||
|
/// Adds a new item to the collection.
|
||
|
/// </summary>
|
||
|
function Add: TfrxSeriesItem;
|
||
|
/// <summary>
|
||
|
/// List of series.
|
||
|
/// </summary>
|
||
|
property Items[Index: Integer]: TfrxSeriesItem read GetSeries; default;
|
||
|
end;
|
||
|
|
||
|
|
||
|
/// <summary>
|
||
|
/// The TfrxChartView component represents a chart. The component uses
|
||
|
/// TeeChart library to render charts. It may show several series on one
|
||
|
/// chart. The series settings are stored in the SeriesData collection.
|
||
|
/// </summary>
|
||
|
TfrxChartView = class(TfrxView)
|
||
|
private
|
||
|
FChart: TCustomChart;
|
||
|
FSeriesData: TfrxSeriesData;
|
||
|
FIgnoreNulls: Boolean;
|
||
|
FLockFillSeries: Boolean;
|
||
|
FSeriesFilled: Boolean;
|
||
|
FSavedColor: TColor;
|
||
|
FHlIndex: Integer;
|
||
|
FClickedVal1: String;
|
||
|
FClickedVal2: String;
|
||
|
FClickedVal3: String;
|
||
|
FClickedVal4: String;
|
||
|
FClickedVal5: String;
|
||
|
FClickedVal6: String;
|
||
|
FClickedVal7: String;
|
||
|
FClickedVal8: String;
|
||
|
FClickedVal9: String;
|
||
|
FClickedVal10: String;
|
||
|
FHighlightColor: TColor;
|
||
|
FPenWidth: Integer;
|
||
|
{$IFDEF DELPHI12}
|
||
|
FPenStyle: TPenStyle;
|
||
|
{$ENDIF}
|
||
|
FSeriesIndex: Integer;
|
||
|
FMouseDown: Boolean;
|
||
|
FMouseOffsetX: Extended;
|
||
|
FMouseOffsetY: Extended;
|
||
|
FMacroLoaded: Boolean;
|
||
|
FEMF: TMetafile;
|
||
|
//FChart: TCustomChart;
|
||
|
procedure FillChart;
|
||
|
procedure ReadData(Stream: TStream);
|
||
|
procedure ReadData1(Reader: TReader);
|
||
|
procedure ReadData2(Reader: TReader);
|
||
|
procedure WriteData(Stream: TStream);
|
||
|
procedure WriteData1(Writer: TWriter);
|
||
|
procedure WriteData2(Writer: TWriter);
|
||
|
function CreateMetafile: TMetafile;
|
||
|
function ResetHighlightSelection: Boolean;
|
||
|
procedure DrawOnMetaFile;
|
||
|
procedure ResetClickedValues;
|
||
|
protected
|
||
|
procedure DefineProperties(Filer: TFiler); override;
|
||
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
||
|
procedure CreateChart; virtual;
|
||
|
class function GetChartClass: TChartClass; virtual;
|
||
|
function CheckMoveSelector(X, Y: Extended): Boolean;
|
||
|
procedure ReaderError(Reader: TReader; const Message: string;
|
||
|
var Handled: Boolean);
|
||
|
public
|
||
|
constructor Create(AOwner: TComponent); override;
|
||
|
destructor Destroy; override;
|
||
|
procedure DoMouseMove(X, Y: Integer; Shift: TShiftState;
|
||
|
var EventParams: TfrxInteractiveEventsParams); override;
|
||
|
procedure DoMouseEnter(aPreviousObject: TfrxComponent;
|
||
|
var EventParams: TfrxInteractiveEventsParams); override;
|
||
|
procedure DoMouseLeave(aNextObject: TfrxComponent;
|
||
|
var EventParams: TfrxInteractiveEventsParams); override;
|
||
|
procedure DoMouseUp(X, Y: Integer; Button: TMouseButton;
|
||
|
Shift: TShiftState;
|
||
|
var EventParams: TfrxInteractiveEventsParams); override;
|
||
|
function DoMouseDown(X, Y: Integer; Button: TMouseButton;
|
||
|
Shift: TShiftState; var EventParams: TfrxInteractiveEventsParams)
|
||
|
: Boolean; override;
|
||
|
function DoMouseWheel(Shift: TShiftState;
|
||
|
WheelDelta: Integer; MousePos: TPoint;
|
||
|
var EventParams: TfrxInteractiveEventsParams): Boolean; override;
|
||
|
class function GetDescription: String; override;
|
||
|
procedure Draw(Canvas: TCanvas; ScaleX, ScaleY, OffsetX, OffsetY: Extended); override;
|
||
|
procedure AfterPrint; override;
|
||
|
procedure GetData; override;
|
||
|
procedure BeforeStartReport; override;
|
||
|
procedure OnNotify(Sender: TObject); override;
|
||
|
procedure ClearSeries;
|
||
|
procedure AddSeries(Series: TfrxChartSeries);
|
||
|
procedure UpdateSeriesData;
|
||
|
|
||
|
procedure SaveContentToDictionary(aReport: TfrxReport; PostProcessor: TfrxPostProcessor); override;
|
||
|
procedure ProcessDictionary(aItem: TfrxMacrosItem; aReport: TfrxReport; PostProcessor: TfrxPostProcessor); override;
|
||
|
function LoadContentFromDictionary(aReport: TfrxReport; aItem: TfrxMacrosItem): Boolean; override;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reference to internal TChart object.
|
||
|
/// </summary>
|
||
|
property Chart: TCustomChart read FChart;
|
||
|
/// <summary>
|
||
|
/// Settings of the series.
|
||
|
/// </summary>
|
||
|
property SeriesData: TfrxSeriesData read FSeriesData;
|
||
|
property HighlightIndex: Integer read FHLIndex;
|
||
|
property ClickedVal1: String read FClickedVal1;
|
||
|
property ClickedVal2: String read FClickedVal2;
|
||
|
property ClickedVal3: String read FClickedVal3;
|
||
|
property ClickedVal4: String read FClickedVal4;
|
||
|
property ClickedVal5: String read FClickedVal5;
|
||
|
property ClickedVal6: String read FClickedVal6;
|
||
|
property ClickedVal7: String read FClickedVal7;
|
||
|
property ClickedVal8: String read FClickedVal8;
|
||
|
property ClickedVal9: String read FClickedVal9;
|
||
|
property ClickedVal10: String read FClickedVal10;
|
||
|
published
|
||
|
property IgnoreNulls: Boolean read FIgnoreNulls write FIgnoreNulls default False;
|
||
|
property HighlightColor: TColor read FHighlightColor write FHighlightColor default clHotLight;
|
||
|
property FillType;
|
||
|
property Fill;
|
||
|
property Cursor;
|
||
|
property Frame;
|
||
|
property Editable default [ferAllowInPreview];
|
||
|
property TagStr;
|
||
|
property URL;
|
||
|
property Processing;
|
||
|
end;
|
||
|
|
||
|
|
||
|
implementation
|
||
|
|
||
|
uses
|
||
|
frxChartHelpers, frxChartRTTI,
|
||
|
{$IFNDEF NO_EDITORS}
|
||
|
frxChartEditor,
|
||
|
{$ENDIF}
|
||
|
frxChartInPlaceEditor,
|
||
|
frxChartClipboard,
|
||
|
frxDsgnIntf, frxUtils, frxRes, Math
|
||
|
{$IFNDEF NO_CRITICAL_SECTION}
|
||
|
, SyncObjs
|
||
|
{$ENDIF};
|
||
|
|
||
|
{$IFNDEF NO_CRITICAL_SECTION}
|
||
|
var
|
||
|
frxCSChart: TCriticalSection;
|
||
|
{$ENDIF}
|
||
|
|
||
|
|
||
|
{ TfrxSeriesItem }
|
||
|
|
||
|
procedure TfrxSeriesItem.SetDataSet(const Value: TfrxDataSet);
|
||
|
begin
|
||
|
FDataSet := Value;
|
||
|
if FDataSet = nil then
|
||
|
FDataSetName := '' else
|
||
|
FDataSetName := FDataSet.UserName;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxSeriesItem.SetDataSetName(const Value: String);
|
||
|
begin
|
||
|
FDataSetName := Value;
|
||
|
if FDataSetName = '' then
|
||
|
FDataSet := nil
|
||
|
else if TfrxSeriesData(Collection).FReport <> nil then
|
||
|
FDataSet := TfrxSeriesData(Collection).FReport.FindDataSet(FDataSet, FDataSetName);
|
||
|
end;
|
||
|
|
||
|
function TfrxSeriesItem.GetDataSetName: String;
|
||
|
begin
|
||
|
if FDataSet = nil then
|
||
|
Result := FDataSetName else
|
||
|
Result := FDataSet.UserName;
|
||
|
end;
|
||
|
|
||
|
function TfrxSeriesItem.IsUniqueNameStored: Boolean;
|
||
|
begin
|
||
|
Result := True;
|
||
|
end;
|
||
|
|
||
|
|
||
|
constructor TfrxSeriesItem.Create(Collection: TCollection);
|
||
|
begin
|
||
|
inherited Create(Collection);
|
||
|
Fsl1 := TStringList.Create;
|
||
|
Fsl2 := TStringList.Create;
|
||
|
Fsl3 := TStringList.Create;
|
||
|
Fsl4 := TStringList.Create;
|
||
|
Fsl5 := TStringList.Create;
|
||
|
Fsl6 := TStringList.Create;
|
||
|
Fsl7 := TStringList.Create;
|
||
|
Fsl8 := TStringList.Create;
|
||
|
Fsl9 := TStringList.Create;
|
||
|
Fsl10 := TStringList.Create;
|
||
|
end;
|
||
|
|
||
|
destructor TfrxSeriesItem.Destroy;
|
||
|
begin
|
||
|
Fsl1.Free;
|
||
|
Fsl2.Free;
|
||
|
Fsl3.Free;
|
||
|
Fsl4.Free;
|
||
|
Fsl5.Free;
|
||
|
Fsl6.Free;
|
||
|
Fsl7.Free;
|
||
|
Fsl8.Free;
|
||
|
Fsl9.Free;
|
||
|
Fsl10.Free;
|
||
|
|
||
|
inherited;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxSeriesItem.FillSeries(Series: TChartSeries);
|
||
|
var
|
||
|
i: Integer;
|
||
|
v1, v2, v3, v4, v5, v6, v7, v8, v9, v10: String;
|
||
|
Helper: TfrxSeriesHelper;
|
||
|
|
||
|
procedure Sort;
|
||
|
var
|
||
|
i, idx, iStart, SortOrd: Integer;
|
||
|
d, mMax: Double;
|
||
|
s: String;
|
||
|
begin
|
||
|
if Fsl1.Count <> Fsl2.Count then exit;
|
||
|
|
||
|
{bug fix, stringList sort all negative values as string }
|
||
|
if FSortOrder = soAscending then SortOrd := 1
|
||
|
else SortOrd := -1;
|
||
|
iStart := 0;
|
||
|
|
||
|
while Fsl2.Count > iStart do
|
||
|
begin
|
||
|
idx := 0;
|
||
|
mMax := MaxDouble * SortOrd;
|
||
|
for i := iStart to Fsl2.Count - 1 do
|
||
|
begin
|
||
|
s := Fsl2[i];
|
||
|
if not frxIsValidFloat(s) then d := 0
|
||
|
else d := frxStrToFloat(s);
|
||
|
if d * SortOrd < mMax * SortOrd then
|
||
|
begin
|
||
|
mMax := d;
|
||
|
idx := i;
|
||
|
end;
|
||
|
end;
|
||
|
Fsl1.Move(idx,iStart);
|
||
|
Fsl2.Move(idx,iStart);
|
||
|
if idx < Fsl3.Count then Fsl3.Move(idx, iStart);
|
||
|
if idx < Fsl4.Count then Fsl4.Move(idx, iStart);
|
||
|
if idx < Fsl5.Count then Fsl5.Move(idx, iStart);
|
||
|
if idx < Fsl6.Count then Fsl6.Move(idx, iStart);
|
||
|
if idx < Fsl7.Count then Fsl7.Move(idx, iStart);
|
||
|
if idx < Fsl8.Count then Fsl8.Move(idx, iStart);
|
||
|
if idx < Fsl9.Count then Fsl9.Move(idx, iStart);
|
||
|
if idx < Fsl10.Count then Fsl10.Move(idx, iStart);
|
||
|
inc(iStart);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure MakeTopN;
|
||
|
var
|
||
|
i: Integer;
|
||
|
d: Double;
|
||
|
begin
|
||
|
if Fsl1.Count <> Fsl2.Count then exit;
|
||
|
{ for future using
|
||
|
if FSortOrder <> soNone then Sort;}
|
||
|
|
||
|
FSortOrder := soDescending;
|
||
|
Sort;
|
||
|
d := 0;
|
||
|
for i := Fsl2.Count - 1 downto FTopN - 1 do
|
||
|
begin
|
||
|
d := d + frxStrToFloat(Fsl2[i]);
|
||
|
Fsl1.Delete(i);
|
||
|
Fsl2.Delete(i);
|
||
|
if i < Fsl3.Count then Fsl3.Delete(i);
|
||
|
if i < Fsl4.Count then Fsl4.Delete(i);
|
||
|
if i < Fsl5.Count then Fsl5.Delete(i);
|
||
|
if i < Fsl6.Count then Fsl6.Delete(i);
|
||
|
if i < Fsl7.Count then Fsl7.Delete(i);
|
||
|
if i < Fsl8.Count then Fsl8.Delete(i);
|
||
|
if i < Fsl9.Count then Fsl9.Delete(i);
|
||
|
if i < Fsl10.Count then Fsl10.Delete(i);
|
||
|
end;
|
||
|
|
||
|
Fsl1.Add(FTopNCaption);
|
||
|
Fsl2.Add(FloatToStr(d));
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
Fsl1.Clear;
|
||
|
Fsl2.Clear;
|
||
|
Fsl3.Clear;
|
||
|
Fsl4.Clear;
|
||
|
Fsl5.Clear;
|
||
|
Fsl6.Clear;
|
||
|
Fsl7.Clear;
|
||
|
Fsl8.Clear;
|
||
|
Fsl9.Clear;
|
||
|
Fsl10.Clear;
|
||
|
|
||
|
Series.Clear;
|
||
|
|
||
|
v1 := FValues1;
|
||
|
if (v1 <> '') and (v1[1] = ';') then
|
||
|
Delete(v1, 1, 1);
|
||
|
v2 := FValues2;
|
||
|
if (v2 <> '') and (v2[1] = ';') then
|
||
|
Delete(v2, 1, 1);
|
||
|
v3 := FValues3;
|
||
|
if (v3 <> '') and (v3[1] = ';') then
|
||
|
Delete(v3, 1, 1);
|
||
|
v4 := FValues4;
|
||
|
if (v4 <> '') and (v4[1] = ';') then
|
||
|
Delete(v4, 1, 1);
|
||
|
v5 := FValues5;
|
||
|
if (v5 <> '') and (v5[1] = ';') then
|
||
|
Delete(v5, 1, 1);
|
||
|
v6 := FValues6;
|
||
|
if (v6 <> '') and (v6[1] = ';') then
|
||
|
Delete(v6, 1, 1);
|
||
|
v7 := FValues7;
|
||
|
if (v7 <> '') and (v7[1] = ';') then
|
||
|
Delete(v7, 1, 1);
|
||
|
v8 := FValues8;
|
||
|
if (v8 <> '') and (v8[1] = ';') then
|
||
|
Delete(v8, 1, 1);
|
||
|
v9 := FValues9;
|
||
|
if (v9 <> '') and (v9[1] = ';') then
|
||
|
Delete(v9, 1, 1);
|
||
|
v10 := FValues10;
|
||
|
if (v10 <> '') and (v10[1] = ';') then
|
||
|
Delete(v10, 1, 1);
|
||
|
|
||
|
frxSetCommaText(v1, Fsl1);
|
||
|
frxSetCommaText(v2, Fsl2);
|
||
|
frxSetCommaText(v3, Fsl3);
|
||
|
frxSetCommaText(v4, Fsl4);
|
||
|
frxSetCommaText(v5, Fsl5);
|
||
|
frxSetCommaText(v6, Fsl6);
|
||
|
frxSetCommaText(v7, Fsl7);
|
||
|
frxSetCommaText(v8, Fsl8);
|
||
|
frxSetCommaText(v9, Fsl9);
|
||
|
frxSetCommaText(v10, Fsl10);
|
||
|
|
||
|
Helper := frxFindSeriesHelper(Series);
|
||
|
|
||
|
try
|
||
|
if Fsl2.Count > 0 then
|
||
|
begin
|
||
|
if (FTopN > 0) and (FTopN < Fsl2.Count) then
|
||
|
MakeTopN
|
||
|
else if FSortOrder <> soNone then
|
||
|
Sort;
|
||
|
|
||
|
for i := 0 to Fsl2.Count - 1 do
|
||
|
begin
|
||
|
if i < Fsl1.Count then v1 := Fsl1[i] else v1 := '';
|
||
|
if i < Fsl2.Count then v2 := Fsl2[i] else v2 := '';
|
||
|
if i < Fsl3.Count then v3 := Fsl3[i] else v3 := '';
|
||
|
if i < Fsl4.Count then v4 := Fsl4[i] else v4 := '';
|
||
|
if i < Fsl5.Count then v5 := Fsl5[i] else v5 := '';
|
||
|
if i < Fsl6.Count then v6 := Fsl6[i] else v6 := '';
|
||
|
if i < Fsl7.Count then v7 := Fsl7[i] else v7 := '';
|
||
|
if i < Fsl8.Count then v8 := Fsl8[i] else v8 := '';
|
||
|
if i < Fsl9.Count then v9 := Fsl9[i] else v9 := '';
|
||
|
if i < Fsl10.Count then v10 := Fsl10[i] else v10 := '';
|
||
|
Helper.AddValues(Series, v1, v2, v3, v4, v5, v6, v7, v8 ,v9, v10, FXType)
|
||
|
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
finally
|
||
|
Helper.Free;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{ TfrxSeriesData }
|
||
|
|
||
|
constructor TfrxSeriesData.Create(Report: TfrxReport);
|
||
|
begin
|
||
|
inherited Create(TfrxSeriesItem);
|
||
|
FReport := Report;
|
||
|
end;
|
||
|
|
||
|
function TfrxSeriesData.Add: TfrxSeriesItem;
|
||
|
begin
|
||
|
Result := TfrxSeriesItem(inherited Add);
|
||
|
end;
|
||
|
|
||
|
function TfrxSeriesData.GetSeries(Index: Integer): TfrxSeriesItem;
|
||
|
begin
|
||
|
Result := TfrxSeriesItem(inherited Items[Index]);
|
||
|
end;
|
||
|
|
||
|
|
||
|
{ TfrxChartView }
|
||
|
|
||
|
constructor TfrxChartView.Create(AOwner: TComponent);
|
||
|
begin
|
||
|
inherited Create(AOwner);
|
||
|
frxThreadSynchronize(CreateChart);
|
||
|
FSeriesData := TfrxSeriesData.Create(Report);
|
||
|
FHlIndex := -1;
|
||
|
FSeriesIndex := -1;
|
||
|
FPenWidth := 0;
|
||
|
Editable := [ferAllowInPreview];
|
||
|
end;
|
||
|
|
||
|
destructor TfrxChartView.Destroy;
|
||
|
begin
|
||
|
FChart.Free;
|
||
|
inherited Destroy;
|
||
|
FSeriesData.Free;
|
||
|
end;
|
||
|
|
||
|
class function TfrxChartView.GetDescription: String;
|
||
|
begin
|
||
|
Result := frxResources.Get('obChart');
|
||
|
end;
|
||
|
|
||
|
function TfrxChartView.LoadContentFromDictionary(aReport: TfrxReport;
|
||
|
aItem: TfrxMacrosItem): Boolean;
|
||
|
var
|
||
|
i, ItemIdx: Integer;
|
||
|
function LoadValue(s: String): String;
|
||
|
begin
|
||
|
Result := s;
|
||
|
if TryStrToInt(s, ItemIdx) then
|
||
|
begin
|
||
|
Result := aItem.Item[ItemIdx];
|
||
|
end;
|
||
|
end;
|
||
|
begin
|
||
|
Result := False;
|
||
|
if (aItem = nil) or FMacroLoaded then Exit;
|
||
|
FMacroLoaded := True;
|
||
|
for i := FSeriesData.Count - 1 downto 0 do
|
||
|
begin
|
||
|
FSeriesData[i].FValues1 := LoadValue(FSeriesData[i].FValues1);
|
||
|
FSeriesData[i].FValues2 := LoadValue(FSeriesData[i].FValues2);
|
||
|
FSeriesData[i].FValues3 := LoadValue(FSeriesData[i].FValues3);
|
||
|
FSeriesData[i].FValues4 := LoadValue(FSeriesData[i].FValues4);
|
||
|
FSeriesData[i].FValues5 := LoadValue(FSeriesData[i].FValues5);
|
||
|
FSeriesData[i].FValues6 := LoadValue(FSeriesData[i].FValues6);
|
||
|
FSeriesData[i].FValues7 := LoadValue(FSeriesData[i].FValues7);
|
||
|
FSeriesData[i].FValues8 := LoadValue(FSeriesData[i].FValues8);
|
||
|
FSeriesData[i].FValues9 := LoadValue(FSeriesData[i].FValues9);
|
||
|
FSeriesData[i].FValues10 := LoadValue(FSeriesData[i].FValues10);
|
||
|
end;
|
||
|
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.ProcessDictionary(aItem: TfrxMacrosItem; aReport: TfrxReport; PostProcessor: TfrxPostProcessor);
|
||
|
var
|
||
|
i: Integer;
|
||
|
procedure SetItemByIndex(aIndex: Integer; aContent: WideString);
|
||
|
begin
|
||
|
aItem.Item[aIndex] := aContent;
|
||
|
end;
|
||
|
begin
|
||
|
for i := FSeriesData.Count - 1 downto 0 do
|
||
|
begin
|
||
|
SetItemByIndex(FSeriesData[i].FValueIndex10, FSeriesData[i].FValues10);
|
||
|
SetItemByIndex(FSeriesData[i].FValueIndex9, FSeriesData[i].FValues9);
|
||
|
SetItemByIndex(FSeriesData[i].FValueIndex8, FSeriesData[i].FValues8);
|
||
|
SetItemByIndex(FSeriesData[i].FValueIndex7, FSeriesData[i].FValues7);
|
||
|
SetItemByIndex(FSeriesData[i].FValueIndex6, FSeriesData[i].FValues6);
|
||
|
SetItemByIndex(FSeriesData[i].FValueIndex5, FSeriesData[i].FValues5);
|
||
|
SetItemByIndex(FSeriesData[i].FValueIndex4, FSeriesData[i].FValues4);
|
||
|
SetItemByIndex(FSeriesData[i].FValueIndex3, FSeriesData[i].FValues3);
|
||
|
SetItemByIndex(FSeriesData[i].FValueIndex2, FSeriesData[i].FValues2);
|
||
|
SetItemByIndex(FSeriesData[i].FValueIndex1, FSeriesData[i].FValues1);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.Notification(AComponent: TComponent; Operation: TOperation);
|
||
|
var
|
||
|
i: Integer;
|
||
|
begin
|
||
|
inherited;
|
||
|
if Operation = opRemove then
|
||
|
begin
|
||
|
for i := 0 to FSeriesData.Count - 1 do
|
||
|
if AComponent is TfrxDataSet then
|
||
|
begin
|
||
|
if FSeriesData[i].DataSet = AComponent then
|
||
|
FSeriesData[i].DataSet := nil;
|
||
|
end
|
||
|
else if AComponent is TfrxBand then
|
||
|
begin
|
||
|
if FSeriesData[i].DataBand = AComponent then
|
||
|
FSeriesData[i].DataBand := nil;
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
|
||
|
procedure TfrxChartView.ReaderError(Reader: TReader; const Message: string;
|
||
|
var Handled: Boolean);
|
||
|
begin
|
||
|
Handled := Pos('PROPERTY', UpperCase(Message)) > 0;
|
||
|
end;
|
||
|
|
||
|
class function TfrxChartView.GetChartClass: TChartClass;
|
||
|
begin
|
||
|
Result := TChart;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.CreateChart;
|
||
|
begin
|
||
|
FChart := GetChartClass.Create(nil);
|
||
|
with FChart do
|
||
|
begin
|
||
|
Color := clWhite;
|
||
|
BevelInner := bvNone;
|
||
|
BevelOuter := bvNone;
|
||
|
//{$IFDEF DELPHI19}
|
||
|
// if FChart.ParentWindow = 0 then
|
||
|
// FChart.ParentWindow := frxParentForm.Handle;
|
||
|
//{$ENDIF}
|
||
|
Name := 'Chart';
|
||
|
Frame.Visible := False;
|
||
|
View3DOptions.Rotation := 0;
|
||
|
Title.Text.Text := '';
|
||
|
end;
|
||
|
FHlIndex := -1;
|
||
|
FSeriesIndex := -1;
|
||
|
FPenWidth := 0;
|
||
|
if IsSelected and (Report <> nil) and (Report.Designer <> nil) then
|
||
|
TfrxCustomDesigner(Report.Designer).ReloadObjects;
|
||
|
end;
|
||
|
|
||
|
function TfrxChartView.CreateMetafile: TMetafile;
|
||
|
var
|
||
|
PrinterHandle: THandle;
|
||
|
aScaleX, aScaleY: Extended;
|
||
|
begin
|
||
|
PrinterHandle := GetDC(0);
|
||
|
try
|
||
|
GetDisplayScale(PrinterHandle, False, aScaleX, aScaleY);
|
||
|
finally
|
||
|
ReleaseDC(0, PrinterHandle);
|
||
|
end;
|
||
|
Result := TMetafile.Create;
|
||
|
// if aScaleX > 1 then
|
||
|
// aScaleX := 1;
|
||
|
// if aScaleY > 1 then
|
||
|
// aScaleY := 1;
|
||
|
Result.Width := Round(Width * aScaleX);
|
||
|
Result.Height := Round(Height * aScaleY);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.DefineProperties(Filer: TFiler);
|
||
|
var
|
||
|
SaveEvent: TReaderError;
|
||
|
begin
|
||
|
inherited;
|
||
|
SaveEvent := nil;
|
||
|
ResetHighlightSelection;
|
||
|
if Filer is TReader then
|
||
|
begin
|
||
|
SaveEvent := TReader(Filer).OnError;
|
||
|
TReader(Filer).OnError := ReaderError;
|
||
|
end;
|
||
|
try
|
||
|
Filer.DefineBinaryProperty('Chart', ReadData, WriteData, True);
|
||
|
Filer.DefineProperty('ChartElevation', ReadData1, WriteData1, True);
|
||
|
Filer.DefineProperty('SeriesData', ReadData2, WriteData2, True);
|
||
|
finally
|
||
|
if Assigned(SaveEvent) then
|
||
|
TReader(Filer).OnError := SaveEvent;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.ReadData(Stream: TStream);
|
||
|
var
|
||
|
Reader: TReader;
|
||
|
begin
|
||
|
{$IFNDEF NO_CRITICAL_SECTION}
|
||
|
frxCSChart.Enter;
|
||
|
try
|
||
|
{$ENDIF}
|
||
|
FChart.Free;
|
||
|
{$IFNDEF NO_CRITICAL_SECTION}
|
||
|
finally
|
||
|
frxCSChart.Leave;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
frxThreadSynchronize(CreateChart);
|
||
|
// Stream.ReadComponent(FChart);
|
||
|
|
||
|
Reader := TReader.Create(Stream, 4096);
|
||
|
Reader.OnError := ReaderError;
|
||
|
try
|
||
|
Reader.ReadRootComponent(FChart);
|
||
|
finally
|
||
|
Reader.Free;
|
||
|
end;
|
||
|
FSeriesFilled := False;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.WriteData(Stream: TStream);
|
||
|
begin
|
||
|
Stream.WriteComponent(FChart);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.ReadData1(Reader: TReader);
|
||
|
begin
|
||
|
FChart.View3DOptions.Elevation := Reader.ReadInteger;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.WriteData1(Writer: TWriter);
|
||
|
begin
|
||
|
Writer.WriteInteger(FChart.View3DOptions.Elevation);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.ReadData2(Reader: TReader);
|
||
|
begin
|
||
|
frxReadCollection(FSeriesData, Reader, Self);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.ResetClickedValues;
|
||
|
begin
|
||
|
FClickedVal1 := '';
|
||
|
FClickedVal2 := '';
|
||
|
FClickedVal3 := '';
|
||
|
FClickedVal4 := '';
|
||
|
FClickedVal5 := '';
|
||
|
FClickedVal6 := '';
|
||
|
FClickedVal7 := '';
|
||
|
FClickedVal8 := '';
|
||
|
FClickedVal9 := '';
|
||
|
FClickedVal10 := '';
|
||
|
end;
|
||
|
|
||
|
function TfrxChartView.ResetHighlightSelection: Boolean;
|
||
|
begin
|
||
|
Result := False;
|
||
|
if FHlIndex <> -1 then
|
||
|
begin
|
||
|
FChart.Series[FSeriesIndex].ValueColor[FHlIndex] := FSavedColor;
|
||
|
if FPenWidth > 0 then
|
||
|
begin
|
||
|
//TODO D7
|
||
|
{$IFDEF DELPHI12}
|
||
|
FChart.Series[FSeriesIndex].Pen.Style := FPenStyle;
|
||
|
FChart.Series[FSeriesIndex].Pen.Width := FPenWidth;
|
||
|
{$ENDIF}
|
||
|
FPenWidth := 0;
|
||
|
end;
|
||
|
FHlIndex := -1;
|
||
|
FSeriesIndex := -1;
|
||
|
Result := True;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.SaveContentToDictionary(aReport: TfrxReport;
|
||
|
PostProcessor: TfrxPostProcessor);
|
||
|
var
|
||
|
i: Integer;
|
||
|
|
||
|
function AddValue(var sValue: String): Integer;
|
||
|
begin
|
||
|
Result := PostProcessor.Add('', Name, sValue, Processing.ProcessAt, Self,
|
||
|
(Processing.ProcessAt <> paDefault), False);
|
||
|
if Result <> -1 then
|
||
|
sValue := IntToStr(Result)
|
||
|
else
|
||
|
sValue := '';
|
||
|
end;
|
||
|
begin
|
||
|
|
||
|
for i := 0 to FSeriesData.Count - 1 do
|
||
|
begin
|
||
|
FSeriesData[i].FValues1 := FSeriesData[i].FSource1;
|
||
|
FSeriesData[i].FValues2 := FSeriesData[i].FSource2;
|
||
|
FSeriesData[i].FValues3 := FSeriesData[i].FSource3;
|
||
|
FSeriesData[i].FValues4 := FSeriesData[i].FSource4;
|
||
|
FSeriesData[i].FValues5 := FSeriesData[i].FSource5;
|
||
|
FSeriesData[i].FValues6 := FSeriesData[i].FSource6;
|
||
|
FSeriesData[i].FValues7 := FSeriesData[i].FSource7;
|
||
|
FSeriesData[i].FValues8 := FSeriesData[i].FSource8;
|
||
|
FSeriesData[i].FValues9 := FSeriesData[i].FSource9;
|
||
|
FSeriesData[i].FValues10 := FSeriesData[i].FSource10;
|
||
|
FSeriesData[i].FValueIndex1 := AddValue(FSeriesData[i].FValues1);
|
||
|
FSeriesData[i].FValueIndex2 := AddValue(FSeriesData[i].FValues2);
|
||
|
FSeriesData[i].FValueIndex3 := AddValue(FSeriesData[i].FValues3);
|
||
|
FSeriesData[i].FValueIndex4 := AddValue(FSeriesData[i].FValues4);
|
||
|
FSeriesData[i].FValueIndex5 := AddValue(FSeriesData[i].FValues5);
|
||
|
FSeriesData[i].FValueIndex6 := AddValue(FSeriesData[i].FValues6);
|
||
|
FSeriesData[i].FValueIndex7 := AddValue(FSeriesData[i].FValues7);
|
||
|
FSeriesData[i].FValueIndex8 := AddValue(FSeriesData[i].FValues8);
|
||
|
FSeriesData[i].FValueIndex9 := AddValue(FSeriesData[i].FValues9);
|
||
|
FSeriesData[i].FValueIndex10 := AddValue(FSeriesData[i].FValues10);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
|
||
|
procedure TfrxChartView.UpdateSeriesData;
|
||
|
begin
|
||
|
FSeriesFilled := False;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.WriteData2(Writer: TWriter);
|
||
|
begin
|
||
|
frxWriteCollection(FSeriesData, Writer, Self);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.FillChart;
|
||
|
var
|
||
|
i: Integer;
|
||
|
begin
|
||
|
if FLockFillSeries or (IsDesigning and FSeriesFilled) then Exit;
|
||
|
|
||
|
for i := 0 to FSeriesData.Count - 1 do
|
||
|
begin
|
||
|
if IsDesigning then
|
||
|
FChart.Series[i].FillSampleValues(5)
|
||
|
else
|
||
|
FSeriesData[i].FillSeries(FChart.Series[i]);
|
||
|
end;
|
||
|
FSeriesFilled := True;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.Draw(Canvas: TCanvas; ScaleX, ScaleY, OffsetX,
|
||
|
OffsetY: Extended);
|
||
|
var
|
||
|
rgn: HRGN;
|
||
|
sDC: Integer;
|
||
|
|
||
|
procedure PrintChart;
|
||
|
begin
|
||
|
FEMF := CreateMetafile;
|
||
|
try
|
||
|
frxThreadSynchronize(DrawOnMetaFile);
|
||
|
Canvas.StretchDraw(Rect(FX, FY, FX1, FY1), FEMF);
|
||
|
finally
|
||
|
FEMF.Free;
|
||
|
FEMF := nil;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
sDC := 0; rgn := 0; // To prevent warnings
|
||
|
BeginDraw(Canvas, ScaleX, ScaleY, OffsetX, OffsetY);
|
||
|
|
||
|
DrawBackground;
|
||
|
if IsDesigning or ((Processing.ProcessAt <> paDefault) and FMacroLoaded) or (Processing.ProcessAt = paDefault) then
|
||
|
FillChart;
|
||
|
FChart.BufferedDisplay := True;
|
||
|
// if Color = clTransparent then
|
||
|
// FChart.Color := clWhite else
|
||
|
// FChart.Color := Color;
|
||
|
if not IsPrinting and not FObjAsMetafile then
|
||
|
begin
|
||
|
sDC := SaveDC(Canvas.Handle);
|
||
|
|
||
|
rgn := CreateRectRgn(0, 0, MaxInt, MaxInt);
|
||
|
GetClipRgn(Canvas.Handle, rgn);
|
||
|
IntersectClipRect(Canvas.Handle,
|
||
|
Round(FX),
|
||
|
Round(FY),
|
||
|
Round(FX1),
|
||
|
Round(FY1));
|
||
|
end;
|
||
|
|
||
|
try
|
||
|
if IsDesigning then
|
||
|
FChart.DrawToMetaCanvas(Canvas, Rect(FX, FY, FX1, FY1))
|
||
|
else
|
||
|
PrintChart;
|
||
|
|
||
|
finally
|
||
|
if not IsPrinting and not FObjAsMetafile then
|
||
|
begin
|
||
|
SelectClipRgn(Canvas.Handle, rgn);
|
||
|
DeleteObject(rgn);
|
||
|
RestoreDC(Canvas.Handle, sDC);
|
||
|
end;
|
||
|
end;
|
||
|
if not FObjAsMetafile then
|
||
|
DrawFrame;
|
||
|
if IsDesigning and IsSelected then
|
||
|
frxResources.MainButtonImages.Draw(Canvas, FX, FY, 110);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.DrawOnMetaFile;
|
||
|
var
|
||
|
EMFCanvas: TMetafileCanvas;
|
||
|
cWidth, cHeight: Integer;
|
||
|
begin
|
||
|
if not Assigned(FEMF) then Exit;
|
||
|
cWidth := Round(Width);
|
||
|
cHeight := Round(Height);
|
||
|
if FEMF.Width / Width > 1 then
|
||
|
begin
|
||
|
cWidth := FEMF.Width;
|
||
|
cHeight := FEMF.Height;
|
||
|
end;
|
||
|
EMFCanvas := TMetafileCanvas.Create(FEMF, 0);
|
||
|
// EMF.Transparent := True;
|
||
|
EMFCanvas.Lock;
|
||
|
try
|
||
|
FChart.DrawToMetaCanvas(EMFCanvas, Rect(0, 0, cWidth, cHeight));
|
||
|
finally
|
||
|
EMFCanvas.Unlock;
|
||
|
EMFCanvas.Free;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.AfterPrint;
|
||
|
var
|
||
|
i: Integer;
|
||
|
begin
|
||
|
for i := 0 to FSeriesData.Count - 1 do
|
||
|
with FSeriesData[i] do
|
||
|
begin
|
||
|
Values1 := '';
|
||
|
Values2 := '';
|
||
|
Values3 := '';
|
||
|
Values4 := '';
|
||
|
Values5 := '';
|
||
|
Values6 := '';
|
||
|
Values7 := '';
|
||
|
Values8 := '';
|
||
|
Values9 := '';
|
||
|
Values10 := '';
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.GetData;
|
||
|
var
|
||
|
i: Integer;
|
||
|
function ConvertVarToStr(Val: Variant): String;
|
||
|
begin
|
||
|
if not FIgnoreNulls and VarIsNull(Val) then
|
||
|
Result := '0'
|
||
|
else
|
||
|
Result := VarToStr(Val)
|
||
|
end;
|
||
|
begin
|
||
|
inherited;
|
||
|
for i := 0 to FSeriesData.Count - 1 do
|
||
|
with FSeriesData[i] do
|
||
|
if (DataType = dtDBData) and (DataSet <> nil) then
|
||
|
begin
|
||
|
Values1 := '';
|
||
|
Values2 := '';
|
||
|
Values3 := '';
|
||
|
Values4 := '';
|
||
|
Values5 := '';
|
||
|
Values6 := '';
|
||
|
Values7 := '';
|
||
|
Values8 := '';
|
||
|
Values9 := '';
|
||
|
Values10 := '';
|
||
|
|
||
|
DataSet.First;
|
||
|
while not DataSet.Eof do
|
||
|
begin
|
||
|
if Source1 <> '' then
|
||
|
Values1 := Values1 + ';' + VarToStr(Report.Calc(Source1));
|
||
|
if Source2 <> '' then
|
||
|
Values2 := Values2 + ';' + ConvertVarToStr(Report.Calc(Source2));
|
||
|
if Source3 <> '' then
|
||
|
Values3 := Values3 + ';' + ConvertVarToStr(Report.Calc(Source3));
|
||
|
if Source4 <> '' then
|
||
|
Values4 := Values4 + ';' + ConvertVarToStr(Report.Calc(Source4));
|
||
|
if Source5 <> '' then
|
||
|
Values5 := Values5 + ';' + ConvertVarToStr(Report.Calc(Source5));
|
||
|
if Source6 <> '' then
|
||
|
Values6 := Values6 + ';' + ConvertVarToStr(Report.Calc(Source6));
|
||
|
if Source7 <> '' then
|
||
|
Values7 := Values7 + ';' + ConvertVarToStr(Report.Calc(Source7));
|
||
|
if Source8 <> '' then
|
||
|
Values8 := Values8 + ';' + ConvertVarToStr(Report.Calc(Source8));
|
||
|
if Source9 <> '' then
|
||
|
Values9 := Values9 + ';' + ConvertVarToStr(Report.Calc(Source9));
|
||
|
if Source10 <> '' then
|
||
|
Values10 := Values10 + ';' + ConvertVarToStr(Report.Calc(Source10));
|
||
|
DataSet.Next;
|
||
|
end;
|
||
|
end
|
||
|
else if DataType = dtFixedData then
|
||
|
begin
|
||
|
Values1 := Source1;
|
||
|
Values2 := Source2;
|
||
|
Values3 := Source3;
|
||
|
Values4 := Source4;
|
||
|
Values5 := Source5;
|
||
|
Values6 := Source6;
|
||
|
Values7 := Source7;
|
||
|
Values8 := Source8;
|
||
|
Values9 := Source9;
|
||
|
Values10 := Source10;
|
||
|
end
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.BeforeStartReport;
|
||
|
var
|
||
|
i: Integer;
|
||
|
begin
|
||
|
for i := 0 to FSeriesData.Count - 1 do
|
||
|
with FSeriesData[i] do
|
||
|
begin
|
||
|
Values1 := '';
|
||
|
Values2 := '';
|
||
|
Values3 := '';
|
||
|
Values4 := '';
|
||
|
Values5 := '';
|
||
|
Values6 := '';
|
||
|
Values7 := '';
|
||
|
Values8 := '';
|
||
|
Values9 := '';
|
||
|
Values10 := '';
|
||
|
end;
|
||
|
Report.Engine.NotifyList.Add(Self);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.OnNotify(Sender: TObject);
|
||
|
var
|
||
|
i: Integer;
|
||
|
function ConvertVarToStr(Val: Variant): String;
|
||
|
begin
|
||
|
if FIgnoreNulls and VarIsNull(Val) then
|
||
|
Result := '0'
|
||
|
else
|
||
|
Result := VarToStr(Val)
|
||
|
end;
|
||
|
begin
|
||
|
inherited;
|
||
|
for i := 0 to FSeriesData.Count - 1 do
|
||
|
with FSeriesData[i] do
|
||
|
if (DataType = dtBandData) and (DataBand = Sender) then
|
||
|
begin
|
||
|
Report.CurObject := Self.Name;
|
||
|
if Source1 <> '' then
|
||
|
Values1 := Values1 + ';' + VarToStr(Report.Calc(Source1));
|
||
|
if Source2 <> '' then
|
||
|
Values2 := Values2 + ';' + ConvertVarToStr(Report.Calc(Source2));
|
||
|
if Source3 <> '' then
|
||
|
Values3 := Values3 + ';' + ConvertVarToStr(Report.Calc(Source3));
|
||
|
if Source4 <> '' then
|
||
|
Values4 := Values4 + ';' + ConvertVarToStr(Report.Calc(Source4));
|
||
|
if Source5 <> '' then
|
||
|
Values5 := Values5 + ';' + ConvertVarToStr(Report.Calc(Source5));
|
||
|
if Source6 <> '' then
|
||
|
Values6 := Values6 + ';' + ConvertVarToStr(Report.Calc(Source6));
|
||
|
if Source7 <> '' then
|
||
|
Values7 := Values7 + ';' + ConvertVarToStr(Report.Calc(Source7));
|
||
|
if Source8 <> '' then
|
||
|
Values8 := Values8 + ';' + ConvertVarToStr(Report.Calc(Source8));
|
||
|
if Source9 <> '' then
|
||
|
Values9 := Values9 + ';' + ConvertVarToStr(Report.Calc(Source9));
|
||
|
if Source10 <> '' then
|
||
|
Values10 := Values10 + ';' + ConvertVarToStr(Report.Calc(Source10));
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.AddSeries(Series: TfrxChartSeries);
|
||
|
var
|
||
|
sc: TSeriesClass;
|
||
|
s: TChartSeries;
|
||
|
b: Boolean;
|
||
|
begin
|
||
|
sc := frxChartSeries[Integer(Series)];
|
||
|
s := TChartSeries(sc.NewInstance);
|
||
|
s.Create(Chart);
|
||
|
Chart.AddSeries(s);
|
||
|
SeriesData.Add;
|
||
|
|
||
|
with Chart do
|
||
|
begin
|
||
|
b := not (s is TPieSeries);
|
||
|
View3DOptions.Orthogonal := b;
|
||
|
AxisVisible := b;
|
||
|
View3DWalls := b;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function TfrxChartView.CheckMoveSelector(X, Y: Extended): Boolean;
|
||
|
begin
|
||
|
Result := (AbsLeft <= X) and (AbsLeft + Width >= X) and (AbsTop <= Y) and (AbsTop + 20 >= Y);
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.ClearSeries;
|
||
|
begin
|
||
|
FSeriesIndex := -1;
|
||
|
FHlIndex := -1;
|
||
|
{$IFNDEF NO_CRITICAL_SECTION}
|
||
|
frxCSChart.Enter;
|
||
|
try
|
||
|
{$ENDIF}
|
||
|
FChart.Free;
|
||
|
{$IFNDEF NO_CRITICAL_SECTION}
|
||
|
finally
|
||
|
frxCSChart.Leave;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
frxThreadSynchronize(CreateChart);
|
||
|
SeriesData.Clear;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.DoMouseMove(X, Y: Integer; Shift: TShiftState;
|
||
|
var EventParams: TfrxInteractiveEventsParams);
|
||
|
var
|
||
|
i, Index, SeriesIndex: Integer;
|
||
|
begin
|
||
|
Index := -1;
|
||
|
if (FChart.SeriesCount = 0) then Exit;
|
||
|
if FChart.ParentWindow = 0 then
|
||
|
FChart.ParentWindow := frxParentForm.Handle;
|
||
|
SeriesIndex := -1;
|
||
|
for i := FChart.SeriesCount - 1 downto 0 do
|
||
|
begin
|
||
|
if EventParams.EventSender = esDesigner then
|
||
|
Index := FChart.Series[i].Clicked(FX + Round(X - AbsLeft * FScaleX), FY + Round(Y - AbsTop * FScaleY))
|
||
|
else
|
||
|
Index := FChart.Series[i].Clicked(Round(X / FScaleX - AbsLeft), Round(Y / FScaleY - AbsTop));
|
||
|
SeriesIndex := i;
|
||
|
if Index <> -1 then Break;
|
||
|
end;
|
||
|
|
||
|
if (Index <> -1) and (Index = FHlIndex) and (FSeriesIndex = SeriesIndex) then
|
||
|
Exit;
|
||
|
|
||
|
EventParams.Refresh := ResetHighlightSelection or EventParams.Refresh;
|
||
|
if Index <> - 1 then
|
||
|
begin
|
||
|
FSeriesIndex := SeriesIndex;
|
||
|
FSavedColor := FChart.Series[FSeriesIndex].ValueColor[Index];
|
||
|
FHlIndex := Index;
|
||
|
if EventParams.EventSender = esDesigner then
|
||
|
begin
|
||
|
//TODO D7
|
||
|
{$IFDEF DELPHI12}
|
||
|
FPenStyle := FChart.Series[FSeriesIndex].Pen.Style;
|
||
|
FPenWidth := FChart.Series[FSeriesIndex].Pen.Width;
|
||
|
FChart.Series[FSeriesIndex].Pen.Style := psDash;
|
||
|
FChart.Series[FSeriesIndex].Pen.Width := 3;
|
||
|
{$ENDIF}
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
if not Hyperlink.IsEmpty then
|
||
|
FChart.Series[FSeriesIndex].ValueColor[Index] := FHighlightColor;
|
||
|
if SeriesData[FSeriesIndex].Fsl1.Count > Index then
|
||
|
FClickedVal1 := SeriesData[FSeriesIndex].Fsl1[Index];
|
||
|
if SeriesData[FSeriesIndex].Fsl2.Count > Index then
|
||
|
FClickedVal2 := SeriesData[FSeriesIndex].Fsl2[Index];
|
||
|
if SeriesData[FSeriesIndex].Fsl3.Count > Index then
|
||
|
FClickedVal3 := SeriesData[FSeriesIndex].Fsl3[Index];
|
||
|
if SeriesData[FSeriesIndex].Fsl4.Count > Index then
|
||
|
FClickedVal4 := SeriesData[FSeriesIndex].Fsl4[Index];
|
||
|
if SeriesData[FSeriesIndex].Fsl5.Count > Index then
|
||
|
FClickedVal5 := SeriesData[FSeriesIndex].Fsl5[Index];
|
||
|
if SeriesData[FSeriesIndex].Fsl6.Count > Index then
|
||
|
FClickedVal6 := SeriesData[FSeriesIndex].Fsl6[Index];
|
||
|
if SeriesData[FSeriesIndex].Fsl7.Count > Index then
|
||
|
FClickedVal7 := SeriesData[FSeriesIndex].Fsl7[Index];
|
||
|
if SeriesData[FSeriesIndex].Fsl8.Count > Index then
|
||
|
FClickedVal8 := SeriesData[FSeriesIndex].Fsl8[Index];
|
||
|
if SeriesData[FSeriesIndex].Fsl9.Count > Index then
|
||
|
FClickedVal9 := SeriesData[FSeriesIndex].Fsl9[Index];
|
||
|
if SeriesData[FSeriesIndex].Fsl10.Count > Index then
|
||
|
FClickedVal10 := SeriesData[FSeriesIndex].Fsl10[Index];
|
||
|
end;
|
||
|
EventParams.Refresh := not Hyperlink.IsEmpty;
|
||
|
end
|
||
|
else
|
||
|
ResetClickedValues;
|
||
|
|
||
|
if {(i <> -1) or } not FMouseDown or not FChart.View3D then
|
||
|
Exit;
|
||
|
//todo D7
|
||
|
{$IFDEF DELPHI12}
|
||
|
FChart.Aspect.Orthogonal := false;
|
||
|
FChart.Aspect.RotationFloat := Round(FChart.Aspect.RotationFloat - (X - FMouseOffsetX) / 10) mod 360;
|
||
|
FChart.Aspect.ElevationFloat := Round(FChart.Aspect.ElevationFloat - (Y - FMouseOffsetY) / 10) mod 360;
|
||
|
EventParams.Refresh := True;
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.DoMouseUp(X, Y: Integer;
|
||
|
Button: TMouseButton; Shift: TShiftState;
|
||
|
var EventParams: TfrxInteractiveEventsParams);
|
||
|
begin
|
||
|
inherited;
|
||
|
FMouseDown := False;
|
||
|
EventParams.Modified := True;
|
||
|
end;
|
||
|
|
||
|
function TfrxChartView.DoMouseWheel(Shift: TShiftState;
|
||
|
WheelDelta: Integer; MousePos: TPoint;
|
||
|
var EventParams: TfrxInteractiveEventsParams): Boolean;
|
||
|
begin
|
||
|
Result := inherited DoMouseWheel(Shift, WheelDelta, MousePos, EventParams);
|
||
|
if {(i <> -1) or } not FMouseDown then
|
||
|
Exit;
|
||
|
{$IFDEF DELPHI12}
|
||
|
FChart.Aspect.Orthogonal := false;
|
||
|
FChart.Aspect.ZoomFloat := Round(FChart.Aspect.ZoomFloat - WheelDelta / 10) mod 360;
|
||
|
EventParams.Refresh := True;
|
||
|
{$ENDIF}
|
||
|
Result := True;
|
||
|
end;
|
||
|
|
||
|
function TfrxChartView.DoMouseDown(X, Y: Integer;
|
||
|
Button: TMouseButton; Shift: TShiftState;
|
||
|
var EventParams: TfrxInteractiveEventsParams): Boolean;
|
||
|
var
|
||
|
i, j: Integer;
|
||
|
begin
|
||
|
Result := inherited DoMouseDown(X, Y, Button, Shift, EventParams);
|
||
|
if (EventParams.EventSender = esPreview) then
|
||
|
begin
|
||
|
FMouseDown := True;
|
||
|
FMouseOffsetX := X;
|
||
|
FMouseOffsetY := Y;
|
||
|
Result := FChart.View3D;
|
||
|
Exit;
|
||
|
end;
|
||
|
if (FX + 4 >= X) or (FX1 - 4 <= X) or (FY + 4 >= Y) or (FY1 - 4 <= Y) or
|
||
|
(EventParams.EventSender <> esDesigner) or (FChart.SeriesCount = 0) or
|
||
|
(EventParams.EventSender <> esDesigner) or CheckMoveSelector(X / FScaleX,
|
||
|
Y / FScaleY) or not IsSelected then Exit;
|
||
|
if FChart.ParentWindow = 0 then
|
||
|
FChart.ParentWindow := frxParentForm.Handle;
|
||
|
EventParams.SelectionList.ClearInspectorList;
|
||
|
i := -1;
|
||
|
for j := 0 to FChart.SeriesCount - 1 do
|
||
|
begin
|
||
|
i := FChart.Series[j].Clicked(FX + Round(X - AbsLeft * FScaleX),
|
||
|
FY + Round(Y - AbsTop * FScaleY));
|
||
|
if i <> - 1 then
|
||
|
begin
|
||
|
EventParams.SelectionList.Add(FChart.Series[j]);
|
||
|
break;
|
||
|
end;
|
||
|
end;
|
||
|
if (i = -1) then
|
||
|
EventParams.SelectionList.Add(FChart);
|
||
|
Result := True;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.DoMouseEnter(aPreviousObject: TfrxComponent;
|
||
|
var EventParams: TfrxInteractiveEventsParams);
|
||
|
begin
|
||
|
{ don't update series for interactive Chart }
|
||
|
// if EventParams.EventSender = esPreview then
|
||
|
FLockFillSeries := FSeriesFilled;
|
||
|
end;
|
||
|
|
||
|
procedure TfrxChartView.DoMouseLeave(aNextObject: TfrxComponent;
|
||
|
var EventParams: TfrxInteractiveEventsParams);
|
||
|
begin
|
||
|
Inherited;
|
||
|
ResetHighlightSelection;
|
||
|
FLockFillSeries := False;
|
||
|
FMouseDown := False;
|
||
|
end;
|
||
|
|
||
|
initialization
|
||
|
{$IFNDEF TeeChartStd}
|
||
|
{$IFNDEF TeeChartStd7}
|
||
|
{$IFNDEF TeeChartStd8}
|
||
|
{$IFNDEF TeeChartStd9}
|
||
|
{$IFNDEF TeeChart4}
|
||
|
RegisterTeeStandardSeries;
|
||
|
{$ENDIF}
|
||
|
{$ENDIF}
|
||
|
{$ENDIF}
|
||
|
{$ENDIF}
|
||
|
{$ENDIF}
|
||
|
{$IFDEF DELPHI16}
|
||
|
StartClassGroup(TControl);
|
||
|
ActivateClassGroup(TControl);
|
||
|
GroupDescendentsWith(TfrxChartObject, TControl);
|
||
|
{$ENDIF}
|
||
|
{$IFNDEF NO_CRITICAL_SECTION}
|
||
|
frxCSChart := TCriticalSection.Create;
|
||
|
{$ENDIF}
|
||
|
frxObjects.RegisterObject1(TfrxChartView, nil, '', '', 0, 25);
|
||
|
|
||
|
finalization
|
||
|
{$IFNDEF NO_CRITICAL_SECTION}
|
||
|
frxCSChart.Free;
|
||
|
{$ENDIF}
|
||
|
frxObjects.UnRegister(TfrxChartView);
|
||
|
|
||
|
end.
|