jvcllaz: Better layout of title and x axis positions.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7180 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2019-11-10 20:03:43 +00:00
parent 1508d443ac
commit 2b16ccc6bf
6 changed files with 235 additions and 142 deletions

View File

@ -29,10 +29,8 @@ object JvChartDemoForm: TJvChartDemoForm
Options.XOrigin = 0 Options.XOrigin = 0
Options.YOrigin = 0 Options.YOrigin = 0
Options.XStartOffset = 60 Options.XStartOffset = 60
Options.YStartOffset = 42
Options.PrimaryYAxis.YMax = 20 Options.PrimaryYAxis.YMax = 20
Options.PrimaryYAxis.YMin = 0 Options.PrimaryYAxis.YMin = 0
Options.PrimaryYAxis.YDivisions = 20
Options.PrimaryYAxis.YLegendDecimalPlaces = 1 Options.PrimaryYAxis.YLegendDecimalPlaces = 1
Options.SecondaryYAxis.YMax = 140 Options.SecondaryYAxis.YMax = 140
Options.SecondaryYAxis.YMin = 0 Options.SecondaryYAxis.YMin = 0
@ -41,8 +39,6 @@ object JvChartDemoForm: TJvChartDemoForm
Options.MouseDragObjects = False Options.MouseDragObjects = False
Options.Legend = clChartLegendBelow Options.Legend = clChartLegendBelow
Options.LegendRowCount = 1 Options.LegendRowCount = 1
Options.PenLineWidth = 2
Options.AxisLineWidth = 3
Options.XValueCount = 20 Options.XValueCount = 20
Options.HeaderFont.Color = clWindowText Options.HeaderFont.Color = clWindowText
Options.LegendFont.Color = clWindowText Options.LegendFont.Color = clWindowText
@ -50,8 +46,6 @@ object JvChartDemoForm: TJvChartDemoForm
Options.AxisTitleFont.Height = -16 Options.AxisTitleFont.Height = -16
Options.AxisTitleFont.Orientation = 900 Options.AxisTitleFont.Orientation = 900
Options.AxisTitleFont.Style = [fsBold] Options.AxisTitleFont.Style = [fsBold]
Options.PaperColor = clWhite
Options.AxisLineColor = clBlack
Options.CursorColor = clBlack Options.CursorColor = clBlack
Options.CursorStyle = psDot Options.CursorStyle = psDot
OnBeginFloatingMarkerDrag = ChartBeginFloatingMarkerDrag OnBeginFloatingMarkerDrag = ChartBeginFloatingMarkerDrag
@ -578,9 +572,9 @@ object JvChartDemoForm: TJvChartDemoForm
Caption = 'Use Positive and Negative Demo Values (-20..+20)' Caption = 'Use Positive and Negative Demo Values (-20..+20)'
OnClick = MenuNegValueTestClick OnClick = MenuNegValueTestClick
end end
object MenuSecondaryAxisMode: TMenuItem object mnuSecondaryAxisMode: TMenuItem
Caption = '&Plot Markers+Values using Alternate Scale (0-120%)' Caption = '&Plot Markers+Values using Alternate Scale (0-120%)'
OnClick = MenuSecondaryAxisModeClick OnClick = mnuSecondaryAxisModeClick
end end
object N4: TMenuItem object N4: TMenuItem
Caption = '-' Caption = '-'

View File

@ -37,9 +37,9 @@ unit JvChartDemoFm;
interface interface
uses uses
Windows, SysUtils, Messages, Classes, Graphics, Controls, SysUtils, Classes, Graphics, Controls, Menus,
Forms, Dialogs, ExtCtrls, StdCtrls, Buttons, Spin, PrintersDlgs, Forms, Dialogs, ExtCtrls, StdCtrls, Buttons, Spin, PrintersDlgs,
JvChart, JvComponent, JvExControls, StatsClasses, Menus; JvChart, StatsClasses;
type type
@ -109,7 +109,7 @@ type
PrintOptions1: TMenuItem; PrintOptions1: TMenuItem;
PrinterSetupDialog1: TPrinterSetupDialog; PrinterSetupDialog1: TPrinterSetupDialog;
PrintDialog1: TPrintDialog; PrintDialog1: TPrintDialog;
MenuSecondaryAxisMode: TMenuItem; mnuSecondaryAxisMode: TMenuItem;
MenuNegValueTest: TMenuItem; MenuNegValueTest: TMenuItem;
SpeedButtonTestMouseOver: TSpeedButton; SpeedButtonTestMouseOver: TSpeedButton;
NewFeaturesfor20071: TMenuItem; NewFeaturesfor20071: TMenuItem;
@ -151,7 +151,7 @@ type
procedure FormDestroy(Sender: TObject); procedure FormDestroy(Sender: TObject);
procedure PrintOptions1Click(Sender: TObject); procedure PrintOptions1Click(Sender: TObject);
procedure MenuSecondaryAxisModeClick(Sender: TObject); procedure mnuSecondaryAxisModeClick(Sender: TObject);
procedure ListBox1Click(Sender: TObject); procedure ListBox1Click(Sender: TObject);
procedure ListBox1DblClick(Sender: TObject); procedure ListBox1DblClick(Sender: TObject);
@ -203,6 +203,7 @@ var
implementation implementation
uses uses
LCLIntf, // OpenURL
LCLType, // MB_OK LCLType, // MB_OK
Math, // Math:NaN handling, function isNan in D6 and higher. Math, // Math:NaN handling, function isNan in D6 and higher.
JvPenEditor; JvPenEditor;
@ -289,7 +290,7 @@ begin
// if Chart.Options.XAxisDateTimeMode was also set. // if Chart.Options.XAxisDateTimeMode was also set.
Chart.Options.XLegends.Add(FormatDateTime('hh:nn:ss', Fds)); Chart.Options.XLegends.Add(FormatDateTime('hh:nn:ss', Fds));
if MenuSecondaryAxisMode.Checked then if mnuSecondaryAxisMode.Checked then
begin begin
if I = 1 then if I = 1 then
Chart.Data.Value[3, I] := 100 Chart.Data.Value[3, I] := 100
@ -461,7 +462,7 @@ begin
PenStyle[1] := psDash; PenStyle[1] := psDash;
PenStyle[2] := psDot; PenStyle[2] := psDot;
if MenuSecondaryAxisMode.Checked then if mnuSecondaryAxisMode.Checked then
begin begin
PenCount := 4; // Add a pen for right side demo. PenCount := 4; // Add a pen for right side demo.
SecondaryYAxis.YMax := 140; // Example shows Q/A percentage. Experimental results SecondaryYAxis.YMax := 140; // Example shows Q/A percentage. Experimental results
@ -488,14 +489,14 @@ begin
PenLegends.Add('HgT'); PenLegends.Add('HgT');
PenLegends.Add('Hg0'); PenLegends.Add('Hg0');
PenLegends.Add('Hg2+'); PenLegends.Add('Hg2+');
if MenuSecondaryAxisMode.Checked then if mnuSecondaryAxisMode.Checked then
PenLegends.Add('Quality%'); PenLegends.Add('Quality%');
PenUnit.Clear; PenUnit.Clear;
PenUnit.Add('ug/m3'); PenUnit.Add('ug/m3');
PenUnit.Add('ug/m3'); PenUnit.Add('ug/m3');
PenUnit.Add('ug/m3'); PenUnit.Add('ug/m3');
if MenuSecondaryAxisMode.Checked then if mnuSecondaryAxisMode.Checked then
PenUnit.Add('%'); // Optional Pen in percentage scale. PenUnit.Add('%'); // Optional Pen in percentage scale.
//ShowLegend := TRUE; //ShowLegend := TRUE;
@ -586,8 +587,8 @@ end;
procedure TJvChartDemoForm.SpinEdit1Change(Sender: TObject); procedure TJvChartDemoForm.SpinEdit1Change(Sender: TObject);
begin begin
// Chart.Options.PrimaryYAxis.YPixelGap := SpinEdit1.Value; // Chart.Options.PrimaryYAxis.YPixelGap := SpinEdit1.Value;
// Chart.Options.YStartOffset := SpinEdit1.Value; Chart.Options.YStartOffset := SpinEdit1.Value;
Chart.Options.XStartOffset := SpinEdit1.Value; // Chart.Options.XStartOffset := SpinEdit1.Value;
// Chart.Options.ColorScheme := SpinEdit1.Value; // Chart.Options.ColorScheme := SpinEdit1.Value;
// Chart.PlotGraph; // Chart.PlotGraph;
end; end;
@ -622,7 +623,8 @@ end;
procedure TJvChartDemoForm.Panel2DblClick(Sender: TObject); procedure TJvChartDemoForm.Panel2DblClick(Sender: TObject);
begin begin
ShellExecute(HWND(nil), 'show', 'http://jvcl.delphi-jedi.org/', nil, nil, SW_SHOW); OpenURL('http://jvcl.delphi-jedi.org/');
// ShellExecute(HWND(nil), 'show', 'http://jvcl.delphi-jedi.org/', nil, nil, SW_SHOW);
end; end;
procedure TJvChartDemoForm.ShowgapinLineChart1Click(Sender: TObject); procedure TJvChartDemoForm.ShowgapinLineChart1Click(Sender: TObject);
@ -679,7 +681,7 @@ var
w: Integer; w: Integer;
begin begin
s := InputBox('Set Axis Linewidth', 'Value:', IntToStr(Chart.Options.AxisLineWidth)); s := InputBox('Set Axis Linewidth', 'Value:', IntToStr(Chart.Options.AxisLineWidth));
if TryStrToInt(s, w) and (w > 0) then if TryStrToInt(s, w) and (w >= 0) then
Chart.Options.AxisLineWidth := w Chart.Options.AxisLineWidth := w
else else
MessageDlg('No valid number for axis linewidth', mtError, [mbOk], 0); MessageDlg('No valid number for axis linewidth', mtError, [mbOk], 0);
@ -889,11 +891,11 @@ begin
PrinterSetupDialog1.Execute; PrinterSetupDialog1.Execute;
end; end;
procedure TJvChartDemoForm.MenuSecondaryAxisModeClick(Sender: TObject); procedure TJvChartDemoForm.mnuSecondaryAxisModeClick(Sender: TObject);
begin begin
MenuSecondaryAxisMode.Checked := not MenuSecondaryAxisMode.Checked; mnuSecondaryAxisMode.Checked := not mnuSecondaryAxisMode.Checked;
if MenuSecondaryAxisMode.Checked then if mnuSecondaryAxisMode.Checked then
begin begin
ButtonLine.Down := true; ButtonLine.Down := true;
ButtonLineClick(Sender); ButtonLineClick(Sender);

View File

@ -1,10 +1,11 @@
object PenEditorForm: TPenEditorForm object PenEditorForm: TPenEditorForm
Left = 347 Left = 347
Height = 291 Height = 302
Top = 128 Top = 128
Width = 505 Width = 505
BorderStyle = bsDialog
Caption = 'PenEditorForm' Caption = 'PenEditorForm'
ClientHeight = 291 ClientHeight = 302
ClientWidth = 505 ClientWidth = 505
OnCreate = FormCreate OnCreate = FormCreate
OnDestroy = FormDestroy OnDestroy = FormDestroy
@ -13,7 +14,7 @@ object PenEditorForm: TPenEditorForm
object btnPenColor: TButton object btnPenColor: TButton
Left = 232 Left = 232
Height = 25 Height = 25
Top = 216 Top = 232
Width = 64 Width = 64
AutoSize = True AutoSize = True
Caption = 'Color...' Caption = 'Color...'
@ -22,7 +23,7 @@ object PenEditorForm: TPenEditorForm
end end
object rgPenStyle: TRadioGroup object rgPenStyle: TRadioGroup
Left = 224 Left = 224
Height = 160 Height = 168
Top = 40 Top = 40
Width = 121 Width = 121
AutoFill = True AutoFill = True
@ -34,7 +35,7 @@ object PenEditorForm: TPenEditorForm
ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 1 ChildSizing.ControlsPerLine = 1
ClientHeight = 140 ClientHeight = 148
ClientWidth = 117 ClientWidth = 117
Items.Strings = ( Items.Strings = (
'Solid' 'Solid'
@ -50,7 +51,7 @@ object PenEditorForm: TPenEditorForm
object ButtonPanel1: TButtonPanel object ButtonPanel1: TButtonPanel
Left = 6 Left = 6
Height = 34 Height = 34
Top = 251 Top = 262
Width = 493 Width = 493
OKButton.Name = 'OKButton' OKButton.Name = 'OKButton'
OKButton.DefaultCaption = True OKButton.DefaultCaption = True
@ -65,7 +66,7 @@ object PenEditorForm: TPenEditorForm
end end
object lbPens: TListBox object lbPens: TListBox
Left = 8 Left = 8
Height = 200 Height = 216
Top = 8 Top = 8
Width = 200 Width = 200
ItemHeight = 0 ItemHeight = 0
@ -77,7 +78,7 @@ object PenEditorForm: TPenEditorForm
object btnAdd: TButton object btnAdd: TButton
Left = 11 Left = 11
Height = 25 Height = 25
Top = 216 Top = 232
Width = 48 Width = 48
AutoSize = True AutoSize = True
Caption = 'Add' Caption = 'Add'
@ -87,7 +88,7 @@ object PenEditorForm: TPenEditorForm
object btnDelete: TButton object btnDelete: TButton
Left = 64 Left = 64
Height = 25 Height = 25
Top = 216 Top = 232
Width = 59 Width = 59
AutoSize = True AutoSize = True
Caption = 'Delete' Caption = 'Delete'
@ -105,7 +106,7 @@ object PenEditorForm: TPenEditorForm
object btnClear: TButton object btnClear: TButton
Left = 128 Left = 128
Height = 25 Height = 25
Top = 216 Top = 232
Width = 53 Width = 53
AutoSize = True AutoSize = True
Caption = 'Clear' Caption = 'Clear'
@ -123,12 +124,12 @@ object PenEditorForm: TPenEditorForm
object ColorSample: TShape object ColorSample: TShape
Left = 304 Left = 304
Height = 25 Height = 25
Top = 216 Top = 232
Width = 25 Width = 25
end end
object rgMarker: TRadioGroup object rgMarker: TRadioGroup
Left = 376 Left = 376
Height = 160 Height = 136
Top = 40 Top = 40
Width = 112 Width = 112
AutoFill = True AutoFill = True
@ -140,7 +141,7 @@ object PenEditorForm: TPenEditorForm
ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 1 ChildSizing.ControlsPerLine = 1
ClientHeight = 140 ClientHeight = 116
ClientWidth = 108 ClientWidth = 108
Items.Strings = ( Items.Strings = (
'None' 'None'
@ -152,6 +153,29 @@ object PenEditorForm: TPenEditorForm
OnClick = rgMarkerClick OnClick = rgMarkerClick
TabOrder = 8 TabOrder = 8
end end
object rgAxis: TRadioGroup
Left = 376
Height = 64
Top = 192
Width = 113
AutoFill = True
Caption = 'y Axis'
ChildSizing.LeftRightSpacing = 6
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
ChildSizing.EnlargeVertical = crsHomogenousChildResize
ChildSizing.ShrinkHorizontal = crsScaleChilds
ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 1
ClientHeight = 44
ClientWidth = 109
Items.Strings = (
'Primary'
'Secondary'
)
OnClick = rgAxisClick
TabOrder = 9
end
object ColorDialog: TColorDialog object ColorDialog: TColorDialog
Color = clBlack Color = clBlack
CustomColors.Strings = ( CustomColors.Strings = (

View File

@ -15,6 +15,7 @@ type
Color: TColor; Color: TColor;
Style: TPenStyle; Style: TPenStyle;
Marker: TJvChartPenMarkerKind; Marker: TJvChartPenMarkerKind;
SecondaryAxis: Boolean;
end; end;
{ TPenEditorForm } { TPenEditorForm }
@ -29,6 +30,7 @@ type
edPenLegend: TEdit; edPenLegend: TEdit;
lblLegend: TLabel; lblLegend: TLabel;
lbPens: TListBox; lbPens: TListBox;
rgAxis: TRadioGroup;
rgMarker: TRadioGroup; rgMarker: TRadioGroup;
rgPenStyle: TRadioGroup; rgPenStyle: TRadioGroup;
ColorSample: TShape; ColorSample: TShape;
@ -42,6 +44,7 @@ type
procedure lbPensDrawItem(Control: TWinControl; Index: Integer; procedure lbPensDrawItem(Control: TWinControl; Index: Integer;
ARect: TRect; State: TOwnerDrawState); ARect: TRect; State: TOwnerDrawState);
procedure lbPensSelectionChange(Sender: TObject; User: boolean); procedure lbPensSelectionChange(Sender: TObject; User: boolean);
procedure rgAxisClick(Sender: TObject);
procedure rgMarkerClick(Sender: TObject); procedure rgMarkerClick(Sender: TObject);
procedure rgPenStyleClick(Sender: TObject); procedure rgPenStyleClick(Sender: TObject);
private private
@ -62,7 +65,7 @@ implementation
{$R *.lfm} {$R *.lfm}
uses uses
LCLType; Math, LCLType;
{ TPenEditorForm } { TPenEditorForm }
@ -94,6 +97,7 @@ begin
pen.Style := psSolid; pen.Style := psSolid;
pen.Color := clBlack; pen.Color := clBlack;
pen.Marker := pmkNone; pen.Marker := pmkNone;
pen.SecondaryAxis := false;
FPens.Add(pen); FPens.Add(pen);
lbPens.Items.Add(''); lbPens.Items.Add('');
end; end;
@ -141,6 +145,7 @@ begin
pen.Style := TPenStyle(rgPenStyle.ItemIndex); pen.Style := TPenStyle(rgPenStyle.ItemIndex);
pen.Marker := TJvChartPenMarkerKind(rgMarker.ItemIndex); pen.Marker := TJvChartPenMarkerKind(rgMarker.ItemIndex);
pen.Color := ColorSample.Brush.Color; pen.Color := ColorSample.Brush.Color;
pen.SecondaryAxis := rgAxis.ItemIndex = 1;
end; end;
procedure TPenEditorForm.edPenLegendEditingDone(Sender: TObject); procedure TPenEditorForm.edPenLegendEditingDone(Sender: TObject);
@ -257,21 +262,34 @@ begin
exit; exit;
pen := TPenObj(FPens[AIndex]); pen := TPenObj(FPens[AIndex]);
edPenLegend.Text := pen.Legend; edPenLegend.Text := pen.Legend;
if pen.Style = psClear then if pen.Style = psClear then
rgPenStyle.ItemIndex := rgPenStyle.Items.Count-1 rgPenStyle.ItemIndex := rgPenStyle.Items.Count-1
else else
rgPenStyle.ItemIndex := ord(pen.Style); rgPenStyle.ItemIndex := ord(pen.Style);
rgMarker.ItemIndex := ord(pen.Marker); rgMarker.ItemIndex := ord(pen.Marker);
rgAxis.ItemIndex := IfThen(pen.SecondaryAxis, 1, 0);
ColorSample.Brush.Color := pen.Color; ColorSample.Brush.Color := pen.Color;
edPenLegend.Enabled := true; edPenLegend.Enabled := true;
rgPenStyle.Enabled := true; rgPenStyle.Enabled := true;
rgMarker.Enabled := true; rgMarker.Enabled := true;
rgAxis.Enabled := true;
btnPenColor.Enabled := true; btnPenColor.Enabled := true;
ColorSample.Visible := true; ColorSample.Visible := true;
end; end;
procedure TPenEditorForm.rgAxisClick(Sender: TObject);
var
pen: TPenObj;
begin
pen := GetCurrentPen;
if pen = nil then
exit;
pen.SecondaryAxis := rgAxis.ItemIndex = 1;
end;
procedure TPenEditorForm.rgMarkerClick(Sender: TObject); procedure TPenEditorForm.rgMarkerClick(Sender: TObject);
var var
pen: TPenObj; pen: TPenObj;
@ -314,6 +332,7 @@ begin
pen.Color := AChart.Options.PenColor[i]; pen.Color := AChart.Options.PenColor[i];
pen.Style := AChart.Options.PenStyle[i]; pen.Style := AChart.Options.PenStyle[i];
pen.Marker := AChart.Options.PenMarkerKind[i]; pen.Marker := AChart.Options.PenMarkerKind[i];
pen.SecondaryAxis := AChart.Options.PenSecondaryAxisFlag[i];;
FPens.Add(pen); FPens.Add(pen);
lbPens.Items.Add(''); lbPens.Items.Add('');
end; end;
@ -321,6 +340,7 @@ begin
edPenLegend.Enabled := false; edPenLegend.Enabled := false;
rgPenStyle.Enabled := false; rgPenStyle.Enabled := false;
rgMarker.Enabled := false; rgMarker.Enabled := false;
rgAxis.Enabled := false;
btnPenColor.Enabled := false; btnPenColor.Enabled := false;
ColorSample.Visible := false; ColorSample.Visible := false;
end; end;

View File

@ -33,55 +33,45 @@ Known Issues:
unit StatsClasses; unit StatsClasses;
interface interface
type type
TStatArray = class TStatArray = class
protected protected
//FFirst:Boolean; //FFirst:Boolean;
FGrows:Boolean; // false=rolling average (circular buffer mode), true=average or sd of any number of samples (array grows without limit) FGrows: Boolean; // false=rolling average (circular buffer mode), true=average or sd of any number of samples (array grows without limit)
FValues:Array of Double; FValues: Array of Double;
FLength, // Array absolute size (may still be no data even if this is >0) FLength: Integer; // Array absolute size (may still be no data even if this is >0)
FIndex, // Where will the next sample be stored into the array? FIndex: Integer; // Where will the next sample be stored into the array?
FCount: // How many valid samples are in the array right now? FCount: Integer; // How many valid samples are in the array right now?
Integer; procedure SetLen(aLength:Integer);
procedure SetLen(aLength:Integer);
public public
procedure AddValue(aValue:Double);
function Average:Double;
function StandardDeviation:Double;
property Grows:Boolean read FGrows write FGrows; // false=rolling average, true=average ALL samples (grows to fit)
property Length:Integer read FLength write SetLen;
property Count:Integer read FCount;
//property First:Boolean read FFirst;
procedure Reset; // Clear everything!
constructor Create; overload; constructor Create; overload;
constructor Create(initialLength:Integer); overload; constructor Create(initialLength:Integer); overload;
destructor Destroy; override; destructor Destroy; override;
procedure AddValue(aValue:Double);
function Average:Double;
function StandardDeviation:Double;
property Grows:Boolean read FGrows write FGrows; // false=rolling average, true=average ALL samples (grows to fit)
property Length:Integer read FLength write SetLen;
property Count:Integer read FCount;
//property First:Boolean read FFirst;
procedure Reset; // Clear everything!
end; end;
implementation implementation
uses //Windows, // OutputDebugString uses
SysUtils, // FloatToStr SysUtils, // FloatToStr
Math; // VCL's statistics routines. StdDev, etc. Math; // VCL's statistics routines. StdDev, etc.
// Begin Rolling Average // Begin Rolling Average
constructor TStatArray.Create; // overload; constructor TStatArray.Create; // overload;
begin begin
//FFirst := true; //FFirst := true;
FLength := 0; FLength := 0;
@ -123,24 +113,24 @@ begin
end; end;
function TStatArray.Average:Double; function TStatArray.Average:Double;
var var
last,i:Integer; last,i:Integer;
sum:Double; sum:Double;
begin begin
if FCount <= 0 then begin if FCount <= 0 then begin
result := 0; result := 0;
end else begin end else begin
sum := 0; sum := 0;
if (FCount>FLength) then if (FCount>FLength) then
last :=FLength-1 last :=FLength-1
else else
last :=FCount-1; last :=FCount-1;
for i := 0 to last do begin for i := 0 to last do begin
sum := sum + FValues[i]; sum := sum + FValues[i];
end; end;
result := sum / (last+1); result := sum / (last+1);
end; end;
end; end;
function TStatArray.StandardDeviation:Double; function TStatArray.StandardDeviation:Double;

View File

@ -98,7 +98,7 @@ unit JvChart;
{$MODE OBJFPC}{$H+} {$MODE OBJFPC}{$H+}
{$DEFINE TJVCHART_ARRAY_OF_ARRAY} {$DEFINE TJVCHART_ARRAY_OF_ARRAY}
//{$I jvcl.inc} {.$DEFINE TEXT_BOX}
interface interface
@ -112,8 +112,8 @@ const
JvDefaultHintColor = TColor($00DDFBFA); JvDefaultHintColor = TColor($00DDFBFA);
JvDefaultAvgLineColor = TColor($00EEDDDD); JvDefaultAvgLineColor = TColor($00EEDDDD);
JvDefaultDivisionLineColor = clLtGray; //NEW! JvDefaultDivisionLineColor = clLtGray;
JvDefaultShadowColor = clDkGray; //NEW! JvDefaultShadowColor = clDkGray;
JvDefaultPaperColor = clWhite; JvDefaultPaperColor = clWhite;
JvDefaultYLegends = 20; JvDefaultYLegends = 20;
@ -749,12 +749,13 @@ type
procedure MyYHeader(ACanvas: TCanvas; StrText: string); // NEW procedure MyYHeader(ACanvas: TCanvas; StrText: string); // NEW
procedure MyHeaderFont(ACanvas: TCanvas); procedure MyHeaderFont(ACanvas: TCanvas);
procedure MyAxisFont(ACanvas: TCanvas); procedure MyAxisFont(ACanvas: TCanvas);
procedure MyAxisTitleFont(ACanvas: TCanvas; Vertical: Boolean);
procedure MySmallGraphFont(ACanvas: TCanvas); procedure MySmallGraphFont(ACanvas: TCanvas);
function MyTextHeight(ACanvas: TCanvas; StrText: string): Longint; function MyTextHeight(ACanvas: TCanvas; StrText: string): Longint;
{ TEXTOUT stuff } { TEXTOUT stuff }
procedure MyRightTextOut(ACanvas: TCanvas; X, Y: Integer; const AText: string); // RIGHT TEXT procedure MyRightTextOut(ACanvas: TCanvas; X, Y: Integer; const AText: string); // RIGHT TEXT
procedure MyCenterTextOut(ACanvas: TCanvas; X, Y: Integer; const AText: string); // CENTER TEXT procedure MyCenterTextOut(ACanvas: TCanvas; X, Y: Integer; const AText: string); // CENTER TEXT
procedure MyLeftTextOut(ACanvas: TCanvas; X, Y: Integer; const AText: string); // LEFT ALIGN TEXT procedure MyLeftTextOut(ACanvas: TCanvas; X, Y: Integer; const AText: string; Vertical: Boolean = false); // LEFT ALIGN TEXT
// Use HintColor: // Use HintColor:
procedure MyLeftTextOutHint(ACanvas: TCanvas; X, Y: Integer; const AText: string); procedure MyLeftTextOutHint(ACanvas: TCanvas; X, Y: Integer; const AText: string);
@ -808,6 +809,7 @@ type
procedure GraphYAxis; procedure GraphYAxis;
procedure GraphYAxisDivisionMarkers; procedure GraphYAxisDivisionMarkers;
procedure GraphXAxisDivisionMarkers; // new. procedure GraphXAxisDivisionMarkers; // new.
function CalcXAxisTextHeight: Integer; // calculate height of x axis labels and title;
procedure CalcYEnd; // Determine where the below-the bottom axis area starts procedure CalcYEnd; // Determine where the below-the bottom axis area starts
function GetChartCanvas(isFloating:Boolean): TCanvas; // Get Picture.Bitmap Canvas. function GetChartCanvas(isFloating:Boolean): TCanvas; // Get Picture.Bitmap Canvas.
@ -987,6 +989,9 @@ const
DEFAULT_VALUE_COUNT = 100; DEFAULT_VALUE_COUNT = 100;
// By Default TJvChartData holds 100 values per pen. Grows autofragellisticexpialidociously. :-) // By Default TJvChartData holds 100 values per pen. Grows autofragellisticexpialidociously. :-)
X_TITLE_LABEL_DISTANCE = 4;
TITLE_MARGIN = 4;
// NEW 2007: // NEW 2007:
// HELPER FUNCTIONS - NEW 2007 // HELPER FUNCTIONS - NEW 2007
@ -1868,7 +1873,6 @@ begin
FLegendFont := TFont.Create; FLegendFont := TFont.Create;
FAxisFont := TFont.Create; FAxisFont := TFont.Create;
FAxisTitleFont := TFont.Create; FAxisTitleFont := TFont.Create;
FAxisTitleFont.Orientation := 900;
//FShowLegend := True; //FShowLegend := True;
FMouseEdit := True; FMouseEdit := True;
@ -3785,11 +3789,11 @@ begin { Enough local functions for ya? -WP }
begin begin
MyHeaderFont(ACanvas); MyHeaderFont(ACanvas);
// nOldY := Options.YStartOffset; // nOldY := Options.YStartOffset;
nMaxTextHeight := CanvasMaxTextHeight(ACanvas) + 8; nMaxTextHeight := CanvasMaxTextHeight(ACanvas) + 2 * TITLE_MARGIN;
// Bump bottom margins if the fonts don't fit! // Bump bottom margins if the fonts don't fit!
if Options.YStartOffset < 2 * nMaxTextHeight then if Options.YStartOffset < nMaxTextHeight then
begin begin
Options.YStartOffset := nMaxTextHeight * 2; Options.YStartOffset := nMaxTextHeight;
//Options.YEnd := Options.YEnd + (nOldY - Options.YStartOffset); //Options.YEnd := Options.YEnd + (nOldY - Options.YStartOffset);
CalcYEnd; CalcYEnd;
Options.PrimaryYAxis.Normalize; Options.PrimaryYAxis.Normalize;
@ -3898,20 +3902,17 @@ end;
procedure TJvChart.DrawChartLegendBelow(ACanvas: TCanvas); {accidentally deleted during Jedi_new to Jedi_2009 branch. Restored by WP June 2009} procedure TJvChart.DrawChartLegendBelow(ACanvas: TCanvas); {accidentally deleted during Jedi_new to Jedi_2009 branch. Restored by WP June 2009}
var var
I,Y,nTextHeight:Integer; I,Y,nTextHeight:Integer;
BoxWidth:Integer; BoxWidth:Integer;
LLabel:String; LLabel:String;
begin begin
if (Options.Legend <> clChartLegendBelow) then exit;
if (Options.Legend <> clChartLegendBelow) then exit; if (Options.YStartOffset<=0) or (Options.XStartOffset<=0) then exit;
if (Options.YStartOffset<=0) or (Options.XStartOffset<=0) then exit; // space-saving pen-legend below chart
MySmallGraphFont(ACanvas);
// space-saving pen-legend below chart nTextHeight := CanvasMaxTextHeight(ACanvas);
MySmallGraphFont(ACanvas);
{10 % extra space for line height}
nTextHeight := Round(CanvasMaxTextHeight(ACanvas) * 1.01);
//BoxHeight := nTextHeight - 2; //BoxHeight := nTextHeight - 2;
@ -3922,7 +3923,7 @@ begin
if Options.GetPenMarkerKind(I) = pmkNone then if Options.GetPenMarkerKind(I) = pmkNone then
Continue; // Skip invisible pens. Continue; // Skip invisible pens.
Y := Options.YStartOffset + Options.YEnd + (nTextHeight div 2); Y := Options.YStartOffset + Options.YEnd + X_TITLE_LABEL_DISTANCE; //(nTextHeight div 2);
// If chart has X legends: // If chart has X legends:
if (Options.XLegends.Count > 0) or Options.XAxisDateTimeMode then if (Options.XLegends.Count > 0) or Options.XAxisDateTimeMode then
@ -3944,7 +3945,7 @@ begin
BoxWidth - 2, {width} BoxWidth - 2, {width}
nTextHeight - 2, {height} nTextHeight - 2, {height}
Options.FXLegendHoriz, {X=} Options.FXLegendHoriz, {X=}
Y + 4); {Y=} Y + 2); {Y=}
end; end;
//SetFontColor(ACanvas, jvChartAxisColorIndex); XXX //SetFontColor(ACanvas, jvChartAxisColorIndex); XXX
@ -3997,6 +3998,8 @@ var
{ draw x axis text at various alignments:} { draw x axis text at various alignments:}
function LeftXAxisText: Boolean; function LeftXAxisText: Boolean;
var
Y: Integer;
begin begin
Result := True; Result := True;
// Don't exceed right margin - causes some undesirable clipping. removed. -wpostma. // Don't exceed right margin - causes some undesirable clipping. removed. -wpostma.
@ -4022,9 +4025,8 @@ var
begin begin
if Options.FXLegendHoriz < XOverlap then if Options.FXLegendHoriz < XOverlap then
Exit; // would overlap, don't draw it. Exit; // would overlap, don't draw it.
MyLeftTextOut(ACanvas, Options.FXLegendHoriz, Y := FXAxisPosition + Options.AxisLineWidth div 2;
{bottom:}FXAxisPosition + Options.AxisLineWidth {top: Round(YTempOrigin - Options.PrimaryYAxis.YPixelGap)}, MyLeftTextOut(ACanvas, Options.FXLegendHoriz, Y, Options.XLegends[I]);
Options.XLegends[I]);
XOverlap := Options.FXLegendHoriz + ACanvas.TextWidth(Options.XLegends[I]); XOverlap := Options.FXLegendHoriz + ACanvas.TextWidth(Options.XLegends[I]);
end end
else else
@ -4032,6 +4034,8 @@ var
end; end;
function RightXAxisText: Boolean; function RightXAxisText: Boolean;
var
Y: Integer;
begin begin
Result := True; Result := True;
// Label X axis above or below? // Label X axis above or below?
@ -4039,17 +4043,18 @@ var
begin begin
if I < Options.XLegends.Count then // fix exception. June 23, 2004- WPostma. if I < Options.XLegends.Count then // fix exception. June 23, 2004- WPostma.
MyRightTextOut(ACanvas, Options.FXLegendHoriz, Options.YEnd + 3, Options.XLegends[I]) MyRightTextOut(ACanvas, Options.FXLegendHoriz, Options.YEnd + 3, Options.XLegends[I])
end end else
else
if I < Options.XLegends.Count then if I < Options.XLegends.Count then
MyRightTextOut(ACanvas, Options.FXLegendHoriz, begin
{bottom:}FXAxisPosition + Options.AxisLineWidth {top: Round(YTempOrigin - Options.PrimaryYAxis.YPixelGap)}, Y := FXAxisPosition + Options.AxisLineWidth div 2;
Options.XLegends[I]) MyRightTextOut(ACanvas, Options.FXLegendHoriz, Y, Options.XLegends[I]);
else end else
Result := False; Result := False;
end; end;
function CenterXAxisText: Boolean; function CenterXAxisText: Boolean;
var
Y: Integer;
begin begin
Result := True; Result := True;
// Label X axis above or below? // Label X axis above or below?
@ -4060,16 +4065,17 @@ var
end end
else else
if I < Options.XLegends.Count then if I < Options.XLegends.Count then
MyCenterTextOut(ACanvas, Options.FXLegendHoriz, begin
{bottom:}FXAxisPosition + Options.AxisLineWidth {top: Round(YTempOrigin - Options.PrimaryYAxis.YPixelGap)}, Y := FXAxisPosition + Options.AxisLineWidth div 2;
Options.XLegends[I]) MyCenterTextOut(ACanvas, Options.FXLegendHoriz, Y, Options.XLegends[I]);
else end else
Result := False; Result := False;
end; end;
procedure XAxisDateTimeModeLabels1; // Classic mode [REFACTORED 2007] procedure XAxisDateTimeModeLabels1; // Classic mode [REFACTORED 2007]
var var
L: Integer; L: Integer;
Y: Integer;
begin begin
// classic JvChart XAxisDateTime mode labels painting code. // classic JvChart XAxisDateTime mode labels painting code.
@ -4095,10 +4101,8 @@ var
// Check if writing this label would collide with previous label, if not, plot it // Check if writing this label would collide with previous label, if not, plot it
if (Options.FXLegendHoriz - (ACanvas.TextWidth(TimestampStr) div 2)) > XOverlap then if (Options.FXLegendHoriz - (ACanvas.TextWidth(TimestampStr) div 2)) > XOverlap then
begin begin
MyCenterTextOut(ACanvas, Options.FXLegendHoriz, Y := FXAxisPosition + Options.AxisLineWidth div 2;
{bottom:}FXAxisPosition + Options.AxisLineWidth MyCenterTextOut(ACanvas, Options.FXLegendHoriz, Y, TimeStampStr);
{top: Round(YTempOrigin - Options.PrimaryYAxis.YPixelGap)},
TimestampStr);
// draw a ticky-boo (technical term used by scientists the world over) // draw a ticky-boo (technical term used by scientists the world over)
// so that we can see where on the chart the X axis datetime is pointing to. // so that we can see where on the chart the X axis datetime is pointing to.
@ -4119,7 +4123,7 @@ var
procedure XAxisDateTimeModeLabels2; // [NEW 2007] procedure XAxisDateTimeModeLabels2; // [NEW 2007]
var var
L: Integer; L: Integer;
X: Integer; X, Y: Integer;
DivPixels: Integer; DivPixels: Integer;
TextWidth: Integer; TextWidth: Integer;
Modn: Integer; Modn: Integer;
@ -4158,9 +4162,8 @@ var
if X = Options.XStartOffset then if X = Options.XStartOffset then
Continue; // don't draw dotted line right at X Axis. Continue; // don't draw dotted line right at X Axis.
MyCenterTextOut(ACanvas, X, Y := FXAxisPosition + Options.AxisLineWidth div 2;
{bottom:}FXAxisPosition + Options.AxisLineWidth, MyCenterTextOut(ACanvas, X, Y, TimeStampStr);
TimestampStr);
ACanvas.Pen.Color := Options.GetPenColor(jvChartDivisionLineColorIndex); ACanvas.Pen.Color := Options.GetPenColor(jvChartDivisionLineColorIndex);
MyDrawDotLine(ACanvas, X, Options.YStartOffset + 1, X, FXAxisPosition - 1); MyDrawDotLine(ACanvas, X, Options.YStartOffset + 1, X, FXAxisPosition - 1);
@ -4169,8 +4172,8 @@ var
procedure DefaultXAxisLegendMode; procedure DefaultXAxisLegendMode;
var var
count:Integer; count: Integer;
K:Integer; K: Integer;
begin begin
{default X axis legend mode: use text legends} {default X axis legend mode: use text legends}
if Options.FXAxisLegendSkipBy < 1 then if Options.FXAxisLegendSkipBy < 1 then
@ -4185,12 +4188,9 @@ var
Options.FXLegendHoriz := Round(Options.XStartOffset + Options.XPixelGap * I ); Options.FXLegendHoriz := Round(Options.XStartOffset + Options.XPixelGap * I );
case Options.FXAxisLabelAlignment of case Options.FXAxisLabelAlignment of
taLeftJustify: taLeftJustify: if not leftXAxisText then break;
if not leftXAxisText then break; taRightJustify: if not rightXAxisText then break;
taRightJustify: taCenter: if not centerXAxisText then break;
if not rightXAxisText then break;
taCenter:
if not centerXAxisText then break;
end; end;
end; {for K} end; {for K}
end; {default mode} end; {default mode}
@ -4457,6 +4457,27 @@ begin
Result := Self.Height; Result := Self.Height;
end; end;
function TJvChart.CalcXAxisTextHeight: Integer;
var
lCanvas: TCanvas;
begin
lCanvas := GetChartCanvas(false);
Result := TITLE_MARGIN;
if FOptions.XLegends.Count > 0 then
begin
MyAxisFont(lCanvas);
Result := Result + lCanvas.TextHeight('Tg')
end;
if FOptions.XAxisHeader <> '' then
begin
MyAxisTitleFont(lCanvas, false);
Result := Result + lCanvas.TextHeight('Tg') + X_TITLE_LABEL_DISTANCE;
end;
end;
procedure TJvChart.CalcYEnd; procedure TJvChart.CalcYEnd;
var var
aHeight: Integer; aHeight: Integer;
@ -4468,7 +4489,8 @@ begin
aHeight := FBitmap.Height; aHeight := FBitmap.Height;
end; end;
Options.YEnd := aHeight - 2 * Options.YStartOffset; {canvas size, excluding margin} // Options.YEnd := aHeight - 2 * Options.YStartOffset; {canvas size, excluding margin}
Options.YEnd := aHeight - Options.YStartOffset - CalcXAxisTextHeight;
end; end;
@ -4588,9 +4610,11 @@ begin
if StrText = '' then if StrText = '' then
exit; exit;
H := ACanvas.TextHeight(StrText);
MyAxisFont(ACanvas); MyAxisFont(ACanvas);
Y := Options.YStartOffset + Options.YEnd + Round(1.6 * H); H := ACanvas.TextHeight(StrText); // Height of labels
MyAxisTitleFont(ACanvas, false);
Y := Options.YStartOffset + Options.YEnd + H + X_TITLE_LABEL_DISTANCE;
if Options.Legend = clChartLegendBelow then if Options.Legend = clChartLegendBelow then
begin begin
{ left aligned X Axis Title, right after the legend itself} { left aligned X Axis Title, right after the legend itself}
@ -4611,17 +4635,19 @@ var
begin begin
if Length(StrText) = 0 then if Length(StrText) = 0 then
Exit; Exit;
ACanvas.Brush.Color := Color; ACanvas.Brush.Color := Color;
ACanvas.Font.Assign(FOptions.AxisTitleFont); MyAxisTitleFont(ACanvas, true);
if Options.XStartOffset > 10 then if Options.XStartOffset > 10 then
begin begin
WD := ACanvas.TextWidth(StrText); WD := ACanvas.TextWidth(StrText);
//Vert := Options.YStartOffset + WD; // top-aligned //Vert := Options.YStartOffset + WD; // top-aligned
Vert := Max(0, Options.YStartOffset + (Options.YEnd + WD) div 2); // centered Vert := Max(0, Options.YStartOffset + (Options.YEnd + WD) div 2); // centered
Horiz := 2; Horiz := 2;
MyLeftTextOut(ACanvas, Horiz, Vert, StrText); MyLeftTextOut(ACanvas, Horiz, Vert, StrText, true);
end; end;
MyAxisFont(ACanvas); // MyAxisFont(ACanvas);
end; end;
@ -5427,7 +5453,7 @@ begin
MyHeaderFont(ACanvas); MyHeaderFont(ACanvas);
MyCenterTextOut(ACanvas, MyCenterTextOut(ACanvas,
(Options.XStartOffset + Round(Options.XEnd)) div 2, (Options.XStartOffset + Round(Options.XEnd)) div 2,
(Options.YStartOffset - MyTextHeight(ACanvas, StrText)) div 2, TITLE_MARGIN,
StrText StrText
); );
MyAxisFont(ACanvas); MyAxisFont(ACanvas);
@ -5449,6 +5475,19 @@ begin
ACanvas.Font.Assign(Options.AxisFont); ACanvas.Font.Assign(Options.AxisFont);
end; end;
procedure TJvChart.MyAxisTitleFont(ACanvas: TCanvas; Vertical: Boolean);
const
ORIENTATION: Array[boolean] of Integer = (0, 900);
begin
Assert(Assigned(ACanvas));
Assert(Assigned(ACanvas.Brush));
Assert(Assigned(ACanvas.Font));
Assert(Assigned(Options));
ACanvas.Brush.Color := Options.PaperColor; // was hard coded to clWhite.
ACanvas.Font.Assign(Options.AxisTitleFont);
ACanvas.Font.Orientation := ORIENTATION[Vertical];
end;
(* (*
{ !!warning: uses Win32 only font-handle stuff!!} { !!warning: uses Win32 only font-handle stuff!!}
@ -5498,11 +5537,20 @@ end;
{ Text Left Aligned to X,Y boundary } { Text Left Aligned to X,Y boundary }
procedure TJvChart.MyLeftTextOut(ACanvas: TCanvas; X, Y: Integer; const AText: string); procedure TJvChart.MyLeftTextOut(ACanvas: TCanvas; X, Y: Integer;
const AText: string; Vertical: Boolean = false);
begin begin
Assert(Assigned(ACanvas)); Assert(Assigned(ACanvas));
Assert(Assigned(ACanvas.Brush)); Assert(Assigned(ACanvas.Brush));
ACanvas.Brush.Color := Options.PaperColor; // non default paper color. ACanvas.Brush.Color := Options.PaperColor; // non default paper color.
{$IFDEF TEXT_BOX}
ACanvas.Brush.Style := bsSolid;
if Vertical then
ACanvas.Rectangle(X, Y, X + ACanvas.TextHeight(AText), Y - ACanvas.TextWidth(AText))
else
ACanvas.Rectangle(X, Y, X + ACanvas.TextWidth(AText), Y + ACanvas.TextHeight(AText));
ACanvas.Brush.Style := bsClear;
{$ENDIF}
ACanvas.TextOut(X, Y + 1, AText); ACanvas.TextOut(X, Y + 1, AText);
end; end;
@ -5511,6 +5559,11 @@ begin
Assert(Assigned(ACanvas)); Assert(Assigned(ACanvas));
Assert(Assigned(ACanvas.Brush)); Assert(Assigned(ACanvas.Brush));
ACanvas.Brush.Color := Options.HintColor; ACanvas.Brush.Color := Options.HintColor;
{$IFDEF TEXT_BOX}
ACanvas.Brush.Style := bsSolid;
ACanvas.Rectangle(X, Y, X + ACanvas.TextWidth(AText), Y + ACanvas.TextHeight(AText));
ACanvas.Brush.Style := bsClear;
{$ENDIF}
ACanvas.TextOut(X, Y + 1, AText); ACanvas.TextOut(X, Y + 1, AText);
end; end;
@ -5519,7 +5572,14 @@ begin
Assert(Assigned(ACanvas)); Assert(Assigned(ACanvas));
Assert(Assigned(ACanvas.Brush)); Assert(Assigned(ACanvas.Brush));
ACanvas.Brush.Color := Options.PaperColor; // non default paper color. ACanvas.Brush.Color := Options.PaperColor; // non default paper color.
ACanvas.TextOut(X - Round(ACanvas.TextWidth(AText) / 2), Y + 1, AText); X := X - ACanvas.TextWidth(AText) div 2;
Y := Y + 1;
{$IFDEF TEXT_BOX}
ACanvas.Brush.Style := bsSolid;
ACanvas.Rectangle(X, Y, X + ACanvas.TextWidth(AText), Y + ACanvas.TextHeight(AText));
ACanvas.Brush.Style := bsClear;
{$ENDIF}
ACanvas.TextOut(X, Y, AText);
end; end;
procedure TJvChart.MyRightTextOut(ACanvas: TCanvas; X, Y: Integer; const AText: string); procedure TJvChart.MyRightTextOut(ACanvas: TCanvas; X, Y: Integer; const AText: string);
@ -5527,11 +5587,14 @@ begin
Assert(Assigned(ACanvas)); Assert(Assigned(ACanvas));
Assert(Assigned(ACanvas.Brush)); Assert(Assigned(ACanvas.Brush));
ACanvas.Brush.Color := Options.PaperColor; // non default paper color. ACanvas.Brush.Color := Options.PaperColor; // non default paper color.
ACanvas.TextOut( X := X - ACanvas.TextWidth(AText);
X - ACanvas.TextWidth(AText), Y := Y - ACanvas.TextHeight(AText) div 2;
Y - Round(ACanvas.TextHeight(AText) / 2), {$IFDEF TEXT_BOX}
AText ACanvas.Brush.Style := bsSolid;
); ACanvas.Rectangle(X, Y, X + ACanvas.TextWidth(AText), Y + ACanvas.TextHeight(AText));
ACanvas.Brush.Style := bsClear;
{$ENDIF}
ACanvas.TextOut(X, Y, AText);
end; end;
procedure TJvChart.MyRectangle(ACanvas: TCanvas; X, Y, X2, Y2: Integer); procedure TJvChart.MyRectangle(ACanvas: TCanvas; X, Y, X2, Y2: Integer);