diff --git a/components/jvcllaz/design/JvCustomControls/images/images.txt b/components/jvcllaz/design/JvCustomControls/images/images.txt index 227b8afdb..88a99214b 100644 --- a/components/jvcllaz/design/JvCustomControls/images/images.txt +++ b/components/jvcllaz/design/JvCustomControls/images/images.txt @@ -1,7 +1,6 @@ tjvtabbar.bmp tjvmoderntabbarpainter.bmp tjvtabbarxppainter.bmp -tjvchart.bmp tjvgammapanel.png tjvgammapanel_150.png tjvgammapanel_200.png diff --git a/components/jvcllaz/design/JvCustomControls/images/tjvchart.bmp b/components/jvcllaz/design/JvCustomControls/images/tjvchart.bmp deleted file mode 100644 index dadad9636..000000000 Binary files a/components/jvcllaz/design/JvCustomControls/images/tjvchart.bmp and /dev/null differ diff --git a/components/jvcllaz/design/JvCustomControls/jvcustomreg.pas b/components/jvcllaz/design/JvCustomControls/jvcustomreg.pas index 728dcb011..a1fe21a5a 100644 --- a/components/jvcllaz/design/JvCustomControls/jvcustomreg.pas +++ b/components/jvcllaz/design/JvCustomControls/jvcustomreg.pas @@ -22,8 +22,7 @@ uses // JvTabBar, JvTabBarXPPainter, JvThumbImage, JvThumbnails, JvThumbViews, JvTimeLine, JvTMTimeLine, JvTimeLineEditor, - JvImagesViewer, JvImageListViewer, JvOwnerDrawViewer, - JvChart; + JvImagesViewer, JvImageListViewer, JvOwnerDrawViewer; procedure Register; begin @@ -34,8 +33,7 @@ begin TJvThumbView, TJvThumbnail, TJvThumbImage, TJvTimeLine, TJvTMTimeLine, TJvGammaPanel, - TJvImagesViewer, TJvImageListViewer, TJvOwnerDrawViewer, - TJvChart + TJvImagesViewer, TJvImageListViewer, TJvOwnerDrawViewer ]); // Timeline diff --git a/components/jvcllaz/examples/JvChartDemo/JvChartDemo.lpi b/components/jvcllaz/examples/JvChartDemo/JvChartDemo.lpi deleted file mode 100644 index eac80a3b3..000000000 --- a/components/jvcllaz/examples/JvChartDemo/JvChartDemo.lpi +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - <Scaled Value="True"/> - <ResourceType Value="res"/> - <UseXPManifest Value="True"/> - <XPManifest> - <DpiAware Value="True"/> - </XPManifest> - <Icon Value="0"/> - </General> - <BuildModes> - <Item Name="Default" Default="True"/> - </BuildModes> - <PublishOptions> - <Version Value="2"/> - <UseFileFilters Value="True"/> - </PublishOptions> - <RunParams> - <FormatVersion Value="2"/> - <Modes Count="0"/> - </RunParams> - <RequiredPackages Count="3"> - <Item1> - <PackageName Value="Printer4Lazarus"/> - </Item1> - <Item2> - <PackageName Value="JvCustomLazR"/> - </Item2> - <Item3> - <PackageName Value="LCL"/> - </Item3> - </RequiredPackages> - <Units> - <Unit> - <Filename Value="JvChartDemo.lpr"/> - <IsPartOfProject Value="True"/> - </Unit> - <Unit> - <Filename Value="jvchartdemofm.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="JvChartDemoForm"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <UnitName Value="JvChartDemoFm"/> - </Unit> - <Unit> - <Filename Value="statsclasses.pas"/> - <IsPartOfProject Value="True"/> - <UnitName Value="StatsClasses"/> - </Unit> - <Unit> - <Filename Value="jvpeneditor.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="PenEditorForm"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <UnitName Value="jvPenEditor"/> - </Unit> - </Units> - </ProjectOptions> - <CompilerOptions> - <Version Value="11"/> - <PathDelim Value="\"/> - <Target> - <Filename Value="..\..\bin\$(TargetCPU)-$(TargetOS)\JvChartDemo"/> - </Target> - <SearchPaths> - <IncludeFiles Value="$(ProjOutDir)"/> - <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> - </SearchPaths> - <Linking> - <Options> - <Win32> - <GraphicApplication Value="True"/> - </Win32> - </Options> - </Linking> - </CompilerOptions> - <Debugging> - <Exceptions Count="3"> - <Item1> - <Name Value="EAbort"/> - </Item1> - <Item2> - <Name Value="ECodetoolError"/> - </Item2> - <Item3> - <Name Value="EFOpenError"/> - </Item3> - </Exceptions> - </Debugging> -</CONFIG> diff --git a/components/jvcllaz/examples/JvChartDemo/JvChartDemo.lpr b/components/jvcllaz/examples/JvChartDemo/JvChartDemo.lpr deleted file mode 100644 index 188fba0f3..000000000 --- a/components/jvcllaz/examples/JvChartDemo/JvChartDemo.lpr +++ /dev/null @@ -1,20 +0,0 @@ -program JvChartDemo; - -{$MODE OBJFPC}{$H+} - -uses - Interfaces, - Forms, printer4lazarus, - JvChartDemoFm in 'JvChartDemoFm.pas' {JvChartDemoForm}, - StatsClasses in 'StatsClasses.pas', jvPenEditor; - -{$R *.res} - - -begin - Application.Initialize; - Application.Title:='JvChartDemo'; - Application.Scaled := true; - Application.CreateForm(TJvChartDemoForm, JvChartDemoForm); - Application.Run; -end. diff --git a/components/jvcllaz/examples/JvChartDemo/jvchartdemofm.lfm b/components/jvcllaz/examples/JvChartDemo/jvchartdemofm.lfm deleted file mode 100644 index 768f31efb..000000000 --- a/components/jvcllaz/examples/JvChartDemo/jvchartdemofm.lfm +++ /dev/null @@ -1,621 +0,0 @@ -object JvChartDemoForm: TJvChartDemoForm - Left = 436 - Height = 453 - Top = 278 - Width = 785 - Caption = 'JEDI JvChart Demo' - ClientHeight = 433 - ClientWidth = 785 - Color = clWindow - Menu = MainMenu1 - OnCreate = FormCreate - OnDestroy = FormDestroy - OnResize = FormResize - Position = poScreenCenter - LCLVersion = '2.1.0.0' - object Chart: TJvChart - Left = 164 - Height = 398 - Top = 35 - Width = 621 - Align = alClient - Options.XAxisValuesPerDivision = 10 - Options.XAxisLabelAlignment = taLeftJustify - Options.XAxisDateTimeMode = False - Options.XAxisDateTimeDivision = 0 - Options.XAxisLegendSkipBy = 2 - Options.PenCount = 3 - Options.XGap = 0 - Options.XOrigin = 0 - Options.YOrigin = 0 - Options.XStartOffset = 60 - Options.PrimaryYAxis.YMax = 20 - Options.PrimaryYAxis.YMin = 0 - Options.PrimaryYAxis.YLegendDecimalPlaces = 1 - Options.SecondaryYAxis.YMax = 140 - Options.SecondaryYAxis.YMin = 0 - Options.SecondaryYAxis.YLegendDecimalPlaces = 0 - Options.SecondaryYAxis.DefaultYLegends = 60 - Options.MouseDragObjects = False - Options.Legend = clChartLegendBelow - Options.LegendRowCount = 1 - Options.XValueCount = 20 - Options.HeaderFont.Color = clWindowText - Options.LegendFont.Color = clWindowText - Options.AxisFont.Color = clWindowText - Options.AxisTitleFont.Height = -16 - Options.AxisTitleFont.Orientation = 900 - Options.AxisTitleFont.Style = [fsBold] - Options.CursorColor = clBlack - Options.CursorStyle = psDot - OnBeginFloatingMarkerDrag = ChartBeginFloatingMarkerDrag - OnEndFloatingMarkerDrag = ChartEndFloatingMarkerDrag - end - object Splitter1: TSplitter - Left = 159 - Height = 398 - Top = 35 - Width = 5 - end - object PanelTop: TPanel - Left = 0 - Height = 35 - Top = 0 - Width = 785 - Align = alTop - ClientHeight = 35 - ClientWidth = 785 - Font.CharSet = ANSI_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Verdana' - ParentFont = False - TabOrder = 0 - object ButtonBarChart: TSpeedButton - Left = 5 - Height = 25 - Hint = 'Bar Chart' - Top = 5 - Width = 25 - Flat = True - Glyph.Data = { - 76010000424D7601000000000000760000002800000020000000100000000100 - 04000000000000010000120B0000120B00001000000000000000000000000000 - 800000800000008080008000000080008000808000007F7F7F00BFBFBF000000 - FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00333300030003 - 0003333377737773777333333333333333333FFFFFFFFFFFFFFF770000000000 - 0000777777777777777733039993BBB3CCC3337F737F737F737F37039993BBB3 - CCC3377F737F737F737F33039993BBB3CCC33F7F737F737F737F77079997BBB7 - CCC77777737773777377330399930003CCC3337F737F7773737F370399933333 - CCC3377F737F3333737F330399933333CCC33F7F737FFFFF737F770700077777 - CCC77777777777777377330333333333CCC3337F33333333737F370333333333 - 0003377F33333333777333033333333333333F7FFFFFFFFFFFFF770777777777 - 7777777777777777777733333333333333333333333333333333 - } - GroupIndex = 1 - NumGlyphs = 2 - OnClick = ButtonBarChartClick - ShowHint = True - ParentShowHint = False - end - object ButtonLine: TSpeedButton - Left = 58 - Height = 25 - Hint = 'Line Chart' - Top = 5 - Width = 25 - Down = True - Flat = True - Glyph.Data = { - 76010000424D7601000000000000760000002800000020000000100000000100 - 04000000000000010000120B0000120B00001000000000000000000000000000 - 800000800000008080008000000080008000808000007F7F7F00BFBFBF000000 - FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00337333733373 - 3373337F3F7F3F7F3F7F33737373737373733F7F7F7F7F7F7F7F770000000000 - 000077777777777777773303333333333333337FF333333F33333709333333C3 - 333337773F3FF373F333330393993C3C33333F7F7F77F7F7FFFF77079797977C - 77777777777777777777330339339333C333337FF73373F37F33370C333C3933 - 933337773F3737F37FF33303C3C33939C9333F7F7F7FF7F777FF7707C7C77797 - 7C97777777777777777733033C3333333C33337F37F33333373F37033C333333 - 33C3377F37333333337333033333333333333F7FFFFFFFFFFFFF770777777777 - 7777777777777777777733333333333333333333333333333333 - } - GroupIndex = 1 - NumGlyphs = 2 - OnClick = ButtonLineClick - ShowHint = True - ParentShowHint = False - end - object ButtonStackedBarAve: TSpeedButton - Left = 345 - Height = 25 - Hint = 'Stacked Bars with Average' - Top = 7 - Width = 25 - Enabled = False - Flat = True - Glyph.Data = { - 76010000424D7601000000000000760000002800000020000000100000000100 - 0400000000000001000000000000000000001000000000000000000000000000 - 80000080000000808000800000008000800080800000C0C0C000808080000000 - FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00333300030003 - 0003333388838883888333333333333333333FFFFFFFFFFFFFFF880000000000 - 000088888888888888883303999399939993338F838F838F838F38039993BBB3 - 9993388F838F838F838F3303BBB3BBB399933F8F838F838F838F8808BBB8AAA8 - 999888888388838883883303AAA300039993338F838F8883838F3803AAA30003 - BBB3388F838F3333838F3303AAA30003BBB33F8F838FFFFF838F880800080008 - BBB88888888888888388330300030003AAA3338F33333333838F380300030003 - 0003388F33333333888333030003000300033F8FFFFFFFFFFFFF880888888888 - 8888888888888888888833333333333333333333333333333333 - } - GroupIndex = 1 - NumGlyphs = 2 - OnClick = ButtonStackedBarAveClick - ShowHint = True - ParentShowHint = False - end - object ButtonStackedBar: TSpeedButton - Left = 111 - Height = 25 - Hint = 'Stacked Bars' - Top = 5 - Width = 26 - Flat = True - Glyph.Data = { - 76010000424D7601000000000000760000002800000020000000100000000100 - 0400000000000001000000000000000000001000000000000000000000000000 - 80000080000000808000800000008000800080800000C0C0C000808080000000 - FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00333300030003 - 0003333388838883888333333333333333333FFFFFFFFFFFFFFF880000000000 - 000088888888888888883303999399939993338F838F838F838F38039993BBB3 - BBB3388F838F838F838F3303BBB3BBB3BBB33F8F838F838F838F8808BBB8AAA8 - BBB888888388838883883303AAA30003BBB3338F838F8883838F3803AAA33333 - BBB3388F838F3333838F3303AAA33333BBB33F8F838FFFFF838F880800088888 - BBB88888888888888388330333333333AAA3338F33333333838F380333333333 - 0003388F33333333888333033333333333333F8FFFFFFFFFFFFF880888888888 - 8888888888888888888833333333333333333333333333333333 - } - GroupIndex = 1 - NumGlyphs = 2 - OnClick = ButtonStackedBarClick - ShowHint = True - ParentShowHint = False - end - object ButtonBarAve: TSpeedButton - Left = 32 - Height = 25 - Hint = 'Bar Chart with Average Line' - Top = 5 - Width = 25 - Flat = True - Glyph.Data = { - 76010000424D7601000000000000760000002800000020000000100000000100 - 0400000000000001000000000000000000001000000000000000000000000000 - 80000080000000808000800000008000800080800000C0C0C000808080000000 - FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00333300030003 - 0003333388838883888333333333333333333FFFFFFFFFFFFFFF880000000000 - 0000888888888888888833039BA39BA39BA3338F838F838F838F38039BA39BA3 - 9BA3388F838F838F838F33039BA39BA39BA33F8F838F838F838F88089BA89BA8 - 9BA8888883888388838833039BA390A39BA3338F838F8883838F38039BA30B03 - 9BA3388F838F3333838F33039BA03B309BA33F8F838FFFFF838F88089B088B88 - 0BA8888888888888838833039033333390A3338F33333333838F380393333333 - 9BA3388F3333333388833303333333333B333F8FFFFFFFFFFFFF880888888888 - 8B88888888888888888833333333333333333333333333333333 - } - GroupIndex = 1 - NumGlyphs = 2 - OnClick = ButtonBarAveClick - ShowHint = True - ParentShowHint = False - end - object ButtonPie: TSpeedButton - Left = 371 - Height = 25 - Hint = 'Show Pie Chart (one series only)' - Top = 7 - Width = 25 - Enabled = False - Flat = True - Glyph.Data = { - 76010000424D7601000000000000760000002800000020000000100000000100 - 04000000000000010000120B0000120B00001000000000000000000000000000 - 800000800000008080008000000080008000808000007F7F7F00BFBFBF000000 - FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00333333333333 - 3333333333FFFFF3333333333700073333333FFF3777773F3FFF00030990BB03 - 000077737337F373777733309990BBB0333333373337F3373F3333099990BBBB - 033333733337F33373F337999990BBBBB73337F33337F33337F330999990BBBB - B03337F33337FFFFF7F3309999900000003337F33337777777F33099990A0CCC - C03337F3337373F337F3379990AAA0CCC733373F3733373F373333090AAAAA0C - 033333737333337373333330AAAAAAA033333FF73F33333733FF00330AAAAA03 - 3000773373FFFF73377733333700073333333333377777333333333333333333 - 3333333333333333333333333333333333333333333333333333 - } - GroupIndex = 1 - NumGlyphs = 2 - OnClick = ButtonPieClick - ShowHint = True - ParentShowHint = False - end - object ButtonMarkers: TSpeedButton - Left = 291 - Height = 25 - Hint = 'Show Markers' - Top = 7 - Width = 25 - Enabled = False - Flat = True - Glyph.Data = { - 76010000424D7601000000000000760000002800000020000000100000000100 - 0400000000000001000000000000000000001000000000000000000000000000 - 80000080000000808000800000008000800080800000C0C0C000808080000000 - FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00338333833383 - 3383338F3F8F3F8F3F8F33838383838383833F8F8F8F8F8F8F8F880000000000 - 000088888888888888883303333333333333338F33333333333338033393A333 - 333A388833333333333333033C333C3333333F8FFFFFFFFFFFFF88088888988C - 888A88888888888888883303333333333333338F333333333333380A33A33333 - 3333388833333333333333033333333A33333F8FFFFFFFFFFFFF880888888898 - 889888888888888888883303933C33333333338F333333333333380333333333 - 3A33388F3333333333333303C333333333333F8FFFFFFFFFFFFF880888888888 - 8888888888888888888833333333333333333333333333333333 - } - GroupIndex = 1 - NumGlyphs = 2 - OnClick = ButtonMarkersClick - ShowHint = True - ParentShowHint = False - end - object ButtonDeltaAverage: TSpeedButton - Left = 319 - Height = 25 - Hint = 'Delta Average' - Top = 7 - Width = 25 - Enabled = False - Flat = True - Glyph.Data = { - 76010000424D7601000000000000760000002800000020000000100000000100 - 0400000000000001000000000000000000001000000000000000000000000000 - 80000080000000808000800000008000800080800000C0C0C000808080000000 - FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00333300030003 - 0003333388838883888333333333333333333FFFFFFFFFFFFFFF888000000000 - 0000888888888888888833333333033333333333333F33333333333333330333 - 33333333333F3333333333CCCCCC033333333333333F3333333388CCCCCC0333 - 33333333333F3333333333333333033333333333333F33333333333333330AAA - A3333333333F33333333333333330AAAA3333333333F33333333833333330333 - 33333333333F3333333333333333099999993333333F33333333333333330999 - 99993333333F3333333333333333033333333FFFFFFFFFFFFFFF888000000000 - 0000888888888888888833333333333333333333333333333333 - } - GroupIndex = 1 - NumGlyphs = 2 - OnClick = ButtonDeltaAverageClick - ShowHint = True - ParentShowHint = False - end - object ButtonLineMarker: TSpeedButton - Left = 84 - Height = 25 - Hint = 'Line with Markers' - Top = 5 - Width = 25 - Flat = True - Glyph.Data = { - 76010000424D7601000000000000760000002800000020000000100000000100 - 04000000000000010000120B0000120B00001000000000000000000000000000 - 800000800000008080008000000080008000808000007F7F7F00BFBFBF000000 - FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00337333733373 - 3373337F3F7F3F7F3F7F33737373737373733F7F7F7F7F7F7F7F770000000000 - 000077777777777777773303333333333333337FF333333F33333709333333C3 - 333337773F3FF373F333330393993C3C33333F7F7F77F7F7FFFF77079797977C - 77777777777777777777330339339333C333337FF73373F37F33370C333C3933 - 933337773F3737F37FF33303C3C33939C9333F7F7F7FF7F777FF7707C7C79797 - 7C97777777777777777733033C3393933C33337F37F33333373F37033C333933 - 33C3377F3733333333733303CCC3393333C33F7FFFFFFFFFFFFF77077C777777 - 7CCC777777777777777733333333333333C33333333333333333 - } - GroupIndex = 1 - NumGlyphs = 2 - OnClick = ButtonLineMarkerClick - ShowHint = True - ParentShowHint = False - end - object Label1: TLabel - Left = 398 - Height = 16 - Top = 10 - Width = 210 - Caption = '(TODO: Fix broken chart types)' - Enabled = False - ParentColor = False - end - object SpeedButtonTestMouseOver: TSpeedButton - Left = 139 - Height = 25 - Hint = 'Floating Markers Demo (new JAN 2005!)' - Top = 5 - Width = 26 - Flat = True - Glyph.Data = { - F6000000424DF600000000000000760000002800000010000000100000000100 - 0400000000008000000000000000000000001000000000000000000000000000 - 8000008000000080800080000000800080008080000080808000C0C0C0000000 - FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00D88888888888 - 888D79FFFFFFFFFFFF98999FFFFFFFFFF99979CFFFFFFFFFCF987FFCFFFFFFFF - CFF87FFCFFFFFFFCFFF87FFCFFFFFFFCFFF87FFFCFFFFFCFFFF87FFFCFFFFFCF - FFF87FFFCFFFFFCFFFF87FFFFCFFFCFFFFF87FFFFCFFFCFFFFF87FFFFFCFFCFF - FFF87FFFFFC9CFFFFFF87FFFFF999FFFFFF8D77777797777777D - } - GroupIndex = 1 - OnClick = SpeedButtonTestMouseOverClick - ShowHint = True - ParentShowHint = False - end - object SpinEdit1: TSpinEdit - Left = 656 - Height = 24 - Top = 6 - Width = 66 - MaxValue = 1000 - OnChange = SpinEdit1Change - TabOrder = 0 - end - end - object ListBox1: TListBox - Left = 0 - Height = 398 - Top = 35 - Width = 159 - Align = alLeft - Color = clBtnFace - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Courier New' - Items.Strings = ( - '<Pen Values>' - ) - ItemHeight = 14 - OnClick = ListBox1Click - OnDblClick = ListBox1DblClick - ParentFont = False - TabOrder = 1 - Visible = False - end - object ColorDialog1: TColorDialog - Color = clBlack - CustomColors.Strings = ( - 'ColorA=000000' - 'ColorB=000080' - 'ColorC=008000' - 'ColorD=008080' - 'ColorE=800000' - 'ColorF=800080' - 'ColorG=808000' - 'ColorH=808080' - 'ColorI=C0C0C0' - 'ColorJ=0000FF' - 'ColorK=00FF00' - 'ColorL=00FFFF' - 'ColorM=FF0000' - 'ColorN=FF00FF' - 'ColorO=FFFF00' - 'ColorP=FFFFFF' - 'ColorQ=C0DCC0' - 'ColorR=F0CAA6' - 'ColorS=F0FBFF' - 'ColorT=A4A0A0' - ) - left = 504 - top = 160 - end - object FontDialog1: TFontDialog - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'System' - MinFontSize = 0 - MaxFontSize = 0 - Options = [] - left = 592 - top = 160 - end - object MainMenu1: TMainMenu - left = 464 - top = 48 - object Demo1: TMenuItem - Caption = '&Demo' - object MenuItem2: TMenuItem - Caption = '-' - end - object mnuSetTitle: TMenuItem - Caption = 'Set Title...' - OnClick = mnuSetTitleClick - end - object mnuSetXAxisHeader: TMenuItem - Caption = 'Set X Axis Header...' - OnClick = mnuSetXAxisHeaderClick - end - object mnuSetYAxisHeader: TMenuItem - Caption = 'Set Y Axis Header...' - OnClick = mnuSetYAxisHeaderClick - end - object MenuItem3: TMenuItem - Caption = '-' - end - object mnuFonts: TMenuItem - Caption = 'Fonts' - object mnuSetHeaderFont: TMenuItem - Caption = 'Set Header Font...' - OnClick = mnuSetHeaderFontClick - end - object mnuSetAxisTitlefont: TMenuItem - Caption = 'Set Axis Title Font...' - OnClick = mnuSetAxisTitlefontClick - end - object mnuSetAxisFont: TMenuItem - Caption = 'Set Axis Label Font...' - OnClick = mnuSetAxisFontClick - end - object mnuSetLegendFont: TMenuItem - Caption = 'Set Legend Font...' - OnClick = mnuSetLegendFontClick - end - end - object mnuColors: TMenuItem - Caption = 'Colors' - object mnuSetPaperColor: TMenuItem - Caption = 'Set Paper Color...' - OnClick = mnuSetPaperColorClick - end - object mnuSetDivisionLineColor: TMenuItem - Caption = 'Set Division Line Color...' - OnClick = mnuSetDivisionLineColorClick - end - object mnuSetShadowColor: TMenuItem - Caption = 'Set Shadow Color..' - OnClick = mnuSetShadowColorClick - end - object mnuSetCursorColor: TMenuItem - Caption = 'Set Cursor Color...' - OnClick = mnuSetCursorColorClick - end - object mnuSetHintColor: TMenuItem - Caption = 'Set Hint Color...' - OnClick = mnuSetHintColorClick - end - end - object mnuSetLineWidths: TMenuItem - Caption = 'Line Widths' - object mnuSetAxisLineWidth: TMenuItem - Caption = 'Set Axis Line Width...' - OnClick = mnuSetAxisLineWidthClick - end - object mnuSetPenLineWidth: TMenuItem - Caption = 'Set Pen Line Width...' - OnClick = mnuSetPenLineWidthClick - end - end - object mnuPens: TMenuItem - Caption = 'Pens...' - OnClick = mnuPensClick - end - object mnuSetMarkerSize: TMenuItem - Caption = 'Marker Size...' - OnClick = mnuSetMarkerSizeClick - end - object mnuFillUnderLine: TMenuItem - Caption = 'Fill under line' - OnClick = mnuFillUnderLineClick - end - object mnuLegend: TMenuItem - Caption = 'Legend' - object mnuLegendNone: TMenuItem - Caption = 'None' - GroupIndex = 113 - OnClick = mnuLegenClick - end - object mnuLegendRight: TMenuItem - Caption = 'Right' - GroupIndex = 113 - OnClick = mnuLegenClick - end - object mnuLegendBelow: TMenuItem - Caption = 'Below' - Checked = True - GroupIndex = 113 - OnClick = mnuLegenClick - end - end - object mnuSetXStartOffset: TMenuItem - Caption = 'X Start Offset...' - OnClick = mnuSetXStartOffsetClick - end - object N2: TMenuItem - Caption = '-' - end - object mnuScrolling: TMenuItem - Caption = 'Scrolling' - ShortCut = 16467 - OnClick = mnuScrollingClick - end - object CopyToClipboard1: TMenuItem - Caption = 'Copy To Clipboard' - ShortCut = 16451 - OnClick = CopyToClipboard1Click - end - object Print1: TMenuItem - Caption = 'Print Chart to Printer' - ShortCut = 16464 - OnClick = Print1Click - end - object PrintOptions1: TMenuItem - Caption = '&Print Options' - OnClick = PrintOptions1Click - end - object N1: TMenuItem - Caption = '-' - end - object Generatenewrandomvalues1: TMenuItem - Caption = '&Generate new random values' - ShortCut = 16466 - OnClick = Generatenewrandomvalues1Click - end - object ShowgapinLineChart1: TMenuItem - Caption = '&Show gap in Line Chart' - ShortCut = 16455 - OnClick = ShowgapinLineChart1Click - end - object mnuDateTimeAxisMode: TMenuItem - Caption = 'Date/Time Axis Mode' - OnClick = mnuDateTimeAxisModeClick - end - object MenuNegValueTest: TMenuItem - AutoCheck = True - Caption = 'Use Positive and Negative Demo Values (-20..+20)' - OnClick = MenuNegValueTestClick - end - object mnuSecondaryAxisMode: TMenuItem - Caption = '&Plot Markers+Values using Alternate Scale (0-120%)' - OnClick = mnuSecondaryAxisModeClick - end - object N4: TMenuItem - Caption = '-' - end - object ShowDataInListbox1: TMenuItem - Caption = '&Show Data in listbox' - ShortCut = 16452 - OnClick = ShowDataInListbox1Click - end - object LargeDataset576samples1: TMenuItem - Caption = '&Large Dataset (576 samples)' - ShortCut = 16460 - OnClick = LargeDataset576samples1Click - end - object NewFeaturesfor20071: TMenuItem - Caption = 'New Features for 2007' - OnClick = NewFeaturesfor20071Click - end - end - object Help1: TMenuItem - Caption = '&Help' - object About1: TMenuItem - Caption = '&About JvChart Component' - ShortCut = 16449 - OnClick = About1Click - end - end - end - object Timer1: TTimer - Enabled = False - Interval = 100 - OnTimer = Timer1Timer - left = 344 - top = 48 - end - object PrinterSetupDialog1: TPrinterSetupDialog - left = 264 - top = 160 - end - object PrintDialog1: TPrintDialog - left = 392 - top = 160 - end -end diff --git a/components/jvcllaz/examples/JvChartDemo/jvchartdemofm.pas b/components/jvcllaz/examples/JvChartDemo/jvchartdemofm.pas deleted file mode 100644 index 65e95e6fa..000000000 --- a/components/jvcllaz/examples/JvChartDemo/jvchartdemofm.pas +++ /dev/null @@ -1,1046 +0,0 @@ -{----------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/MPL-1.1.html - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: JvChartDemoFm.Pas, released on 2002-10-04. - -The Initial Developer of the Original Code is AABsoft and MÃ¥rten Henrichson. -(C) 1996 AABsoft and MÃ¥rten Henrichson. -All Rights Reserved. - -Contributor(s): - - -Last Modified: 2005-01-14 - - Modified March 2007 by Warren Postma - Show new JvChart 2007 Features. - - -You may retrieve the latest version of this file at the Project JEDI's JVCL home page, -located at http://jvcl.delphi-jedi.org - -Description: - BAR/LINE Charting Component for JEDI [Updated March 2007] - -Known Issues: ------------------------------------------------------------------------------} - -{$MODE OBJFPC}{$H+} - -unit JvChartDemoFm; - -interface - -uses - SysUtils, Classes, Graphics, Controls, Menus, - Forms, Dialogs, ExtCtrls, StdCtrls, Buttons, Spin, PrintersDlgs, - JvChart, StatsClasses; - -type - - { TJvChartDemoForm } - - TJvChartDemoForm = class(TForm) - mnuSetTitle: TMenuItem; - mnuFillUnderLine: TMenuItem; - mnuLegendNone: TMenuItem; - mnuLegendRight: TMenuItem; - mnuLegendBelow: TMenuItem; - mnuLegend: TMenuItem; - mnuSetXStartOffset: TMenuItem; - mnuSetPenLineWidth: TMenuItem; - mnuSetAxisLineWidth: TMenuItem; - mnuSetLineWidths: TMenuItem; - mnuSetHintColor: TMenuItem; - mnuSetCursorColor: TMenuItem; - mnuPens: TMenuItem; - mnuSetPaperColor: TMenuItem; - mnuSetShadowColor: TMenuItem; - mnuFonts: TMenuItem; - mnuSetDivisionLineColor: TMenuItem; - mnuColors: TMenuItem; - MenuItem3: TMenuItem; - mnuSetMarkerSize: TMenuItem; - mnuSetYAxisHeader: TMenuItem; - mnuSetXAxisHeader: TMenuItem; - MenuItem2: TMenuItem; - mnuSetAxisTitlefont: TMenuItem; - mnuSetLegendFont: TMenuItem; - mnuSetHeaderFont: TMenuItem; - PanelTop: TPanel; - ButtonBarChart: TSpeedButton; - ButtonLine: TSpeedButton; - ButtonStackedBarAve: TSpeedButton; - ButtonStackedBar: TSpeedButton; - ButtonBarAve: TSpeedButton; - ColorDialog1: TColorDialog; - ButtonPie: TSpeedButton; - FontDialog1: TFontDialog; - ButtonMarkers: TSpeedButton; - ButtonDeltaAverage: TSpeedButton; - Chart: TJvChart; - ButtonLineMarker: TSpeedButton; - Label1: TLabel; - MainMenu1: TMainMenu; - Demo1: TMenuItem; - Help1: TMenuItem; - About1: TMenuItem; - ShowgapinLineChart1: TMenuItem; - N1: TMenuItem; - Print1: TMenuItem; - Generatenewrandomvalues1: TMenuItem; - CopyToClipboard1: TMenuItem; - N2: TMenuItem; - mnuSetAxisFont: TMenuItem; - mnuScrolling: TMenuItem; - ListBox1: TListBox; - SpinEdit1: TSpinEdit; - Splitter1: TSplitter; - Timer1: TTimer; - ShowDataInListbox1: TMenuItem; - N4: TMenuItem; - LargeDataset576samples1: TMenuItem; - mnuDateTimeAxisMode: TMenuItem; - PrintOptions1: TMenuItem; - PrinterSetupDialog1: TPrinterSetupDialog; - PrintDialog1: TPrintDialog; - mnuSecondaryAxisMode: TMenuItem; - MenuNegValueTest: TMenuItem; - SpeedButtonTestMouseOver: TSpeedButton; - NewFeaturesfor20071: TMenuItem; - procedure FormResize(Sender: TObject); - procedure ButtonLineClick(Sender: TObject); - procedure ButtonBarChartClick(Sender: TObject); - procedure ButtonStackedBarAveClick(Sender: TObject); - procedure ButtonStackedBarClick(Sender: TObject); - procedure mnuFillUnderLineClick(Sender: TObject); - procedure mnuLegenClick(Sender: TObject); - procedure mnuSetAxisLineWidthClick(Sender: TObject); - procedure mnuSetCursorColorClick(Sender: TObject); - procedure mnuSetHintColorClick(Sender: TObject); - procedure mnuSetPenLineWidthClick(Sender: TObject); - procedure mnuSetTitleClick(Sender: TObject); - procedure mnuSetXStartOffsetClick(Sender: TObject); - procedure SpeedButton7Click(Sender: TObject); - procedure ButtonBarAveClick(Sender: TObject); - procedure SpinEdit1Change(Sender: TObject); - procedure Button2Click(Sender: TObject); - procedure ButtonPieClick(Sender: TObject); - procedure Button4Click(Sender: TObject); - procedure ButtonMarkersClick(Sender: TObject); - procedure ButtonDeltaAverageClick(Sender: TObject); - procedure ButtonLineMarkerClick(Sender: TObject); - procedure Panel2DblClick(Sender: TObject); - procedure ShowgapinLineChart1Click(Sender: TObject); - procedure Print1Click(Sender: TObject); - procedure Generatenewrandomvalues1Click(Sender: TObject); - procedure CopyToClipboard1Click(Sender: TObject); - procedure About1Click(Sender: TObject); - procedure mnuScrollingClick(Sender: TObject); - procedure Timer1Timer(Sender: TObject); - procedure ShowDataInListbox1Click(Sender: TObject); - procedure LargeDataset576samples1Click(Sender: TObject); - procedure mnuDateTimeAxisModeClick(Sender: TObject); - - procedure FormCreate(Sender: TObject); - procedure FormDestroy(Sender: TObject); - - procedure PrintOptions1Click(Sender: TObject); - procedure mnuSecondaryAxisModeClick(Sender: TObject); - - procedure ListBox1Click(Sender: TObject); - procedure ListBox1DblClick(Sender: TObject); - - procedure mnuSetAxisFontClick(Sender: TObject); - procedure mnuSetAxisTitlefontClick(Sender: TObject); - procedure mnuSetHeaderFontClick(Sender: TObject); - procedure mnuSetLegendFontClick(Sender: TObject); - procedure mnuSetMarkerSizeClick(Sender: TObject); - procedure mnuSetPaperColorClick(Sender: TObject); - procedure mnuPensClick(Sender: TObject); - procedure mnuSetShadowColorClick(Sender: TObject); - procedure mnuSetXAxisHeaderClick(Sender: TObject); - procedure mnuSetYAxisHeaderClick(Sender: TObject); - - procedure mnuSetDivisionLineColorClick(Sender: TObject); - procedure mnuSetPenCountClick(Sender: TObject); - - procedure MenuNegValueTestClick(Sender: TObject); - procedure SpeedButtonTestMouseOverClick(Sender: TObject); - procedure ChartEndFloatingMarkerDrag(Sender: TJvChart; - FloatingMarker: TJvChartFloatingMarker); - procedure ChartBeginFloatingMarkerDrag(Sender: TJvChart; - FloatingMarker: TJvChartFloatingMarker); - procedure NewFeaturesfor20071Click(Sender: TObject); - private - - // Our waveform generator uses the following as state-variables: - FGenerationIndex: Integer; - Foo, Foo1, Foo2: Integer; - Fhgt, Fhg0, Fhg2p: Double; - FStatHgt, FStatHg0: TStatArray; - Fdt, Fds: Double; - FNegValueFlag: Boolean; - - protected - procedure _Generate; - procedure _StoreValue(I: integer); - function _QAProblemScatter: Integer; - procedure MakePensMenu; - - public - procedure NewValues; - end; - -var - JvChartDemoForm: TJvChartDemoForm; - -implementation - -uses - LCLIntf, // OpenURL - LCLType, // MB_OK - Math, // Math:NaN handling, function isNan in D6 and higher. - JvPenEditor; - -{$R *.lfm} - -const - TAG_PENCOLORS = 991; - MAX_PEN = 100; - - -{ Bogus vageuly sinusoidal signal generator } - -procedure TJvChartDemoForm._Generate; -begin - FHgt := Abs(Random(80) + (Random(((FGenerationIndex div foo) mod foo1) * 250) * 5 + 9500)); - FHg0 := Abs(Random(280) + Random(((FGenerationIndex div foo) mod foo2) * 650) * 5 + 1003); - if FNegValueFlag then - begin - if (Random(80) > 75) or (FGenerationIndex = 2) then - begin - FHg0 := -1 * FHg0; // Generate a negative value! (just to show what it looks like) - end; - end; - Inc(FGenerationIndex); -end; - -{ Bogus random spiky-looking function to simulate a QA value, - which hovers within +/- 10% of perfect (100%), but - with relatively infrequent spiky errors } - -function TJvChartDemoForm._QAProblemScatter: Integer; -var - n, m: Double; -begin - n := Log10(Random(10000) + 1); // Random is my favourite function. How about you? -WP - n := n * Log10(Random(10000) + 1); - m := Log10(Random(10000) + 1); - m := m * Log10(Random(10000) + 1); - n := Abs(100 + n - m); - if (n < 0) then - n := 0; - if (n > 150) then - n := 150; - - Result := Round(n); -end; - -procedure TJvChartDemoForm._StoreValue(I: integer); -begin - FStatHgt.AddValue(Fhgt); - FStatHg0.AddValue(Fhg0); - - // PAY ATTENTION HERE, this is where we set the Chart.Data.Value[ index,pen] := <values> - // stuff which is the MOST IMPORTANT THING, unless you like blank charts: - - // Set Data.Value[Pen, Series] := dataValue ... - Chart.Data.Value[0, I] := FStatHgt.Average / 1000; - - if FHg0 < 0 then - begin - Chart.Data.Value[1, I] := FHg0 / 1000; - // Don't show average with negative samples or my negative demo ability goes away (averaged out!) - end - else - begin - // Test blanks on big chart, show missing data: - Chart.Data.Value[1, I] := FStatHg0.Average / 1000; - end; - - Fhg2p := (FStatHgt.Average - FStatHg0.Average) / 1000; - if Fhg2p < 0.0 then - Fhg2p := 0.0; - Chart.Data.Value[2, I] := Fhg2p; - - Fds := Fdt + (FGenerationIndex / 576); - - // There are TWO ways to get an X Axis label plotted: - if mnuDateTimeAxisMode.Checked then - Chart.Data.Timestamp[I] := Fds // X legends generated by timestamps - else - // X Legends generated by user are used by default. - // This would be redundant, and would be a waste of memory - // if Chart.Options.XAxisDateTimeMode was also set. - Chart.Options.XLegends.Add(FormatDateTime('hh:nn:ss', Fds)); - - if mnuSecondaryAxisMode.Checked then - begin - if I = 1 then - Chart.Data.Value[3, I] := 100 - else - if (I mod 4) = 3 then - begin - //Chart.Data.Value[3,I] := 1+ ((I mod 12) * 10) // stairstep - //random: - Chart.Data.Value[3, I] := _QAProblemScatter; - end - else - Chart.Data.Value[3, I] := NaN; // leave some blanks. - end; -end; - -procedure TJvChartDemoForm.NewFeaturesfor20071Click(Sender: TObject); -var - vbar:TJvChartVerticalBar; - hbar:TJvChartHorizontalBar; -begin - // Try out new features for 2007: - - // Gradients. - Chart.Options.GradientColor := $00FDEEDB; // powder blue (baby blue) mostly white. - Chart.Options.GradientDirection :=grDown; - - - - // Vertical Bar. - vbar := Chart.AddVerticalBar; - vbar.Color := $00FDDDC7; - vbar.Visible := true; - vbar.XLeft := 6; - vbar.XRight := 7; - - // Horizontal Bar. - hbar := Chart.AddHorizontalBar; - hbar.Color := $007CCAC7; - hbar.Visible := true; - hbar.YTop := 3; - hbar.YBottom := 2; - - - - - - // Lots of things not shown here are new in 2007: - // Floating Marker Count, Delete a floating marker, etc, - // search for 'NEW 2007' in JvChart.pas for a complete - // look at new things. - - // last thing, always update graph: - Chart.PlotGraph; - //Chart.Refresh; - - -end; - -procedure TJvChartDemoForm.NewValues; -var - I: Integer; - nValueCount: Integer; -begin -//Chart.Options.Title := 'Click on the Chart Title to change it!'; - Chart.Options.PenCount := 3; - - Chart.ClearFloatingMarkers; // remove any previous markers. - - - ListBox1.Clear; - Chart.Data.Clear; - - Chart.Options.PrimaryYAxis.YMax := 20; - - Randomize; - - Chart.Options.XAxisDateTimeMode := mnuDateTimeAxisMode.Checked; // Use datetime timestamp labels, just Fer Instance. - - if not Chart.Options.XAxisDateTimeMode then - Chart.Options.XAxisLegendSkipBy := 5; - - if LargeDataset576samples1.Checked then - begin - // A larger bogus data set for demonstration purposes. - nValueCount := 576; // 2.5 minute sample period, 576 samples = 1 day. - foo := 5; // Used in generating our bogus data below, not really important. - Chart.Options.XAxisValuesPerDivision := 24; - // 24 samples * 150 seconds = 1 hour time divisions ( Chart.Options.XAxisValuesPerDivision := 4; - end - else - begin - // A smaller bogus data set for demonstration purposes. - nValueCount := 24; // 2.5 minute sample period, 24 samples =1 hour. - foo := 1; // Used in generating our bogus data below, not really important. - Chart.Options.XAxisValuesPerDivision := 4; // five divisions, 4 values per division - end; - - //Chart.ResetGraphModule; // Clears YMax. - Fdt := Trunc(now - 1.0); // yesterday, midnight. - Foo1 := Random(5) + 2; // more randomness - Foo2 := Random(3) + 5; // more randomness - FGenerationIndex := 1; - for I := 0 to nValueCount - 1 do - begin - if i > 0 then - begin // generate random data that appears to show a sawtooth-frequency-pattern plus a lot of random noise: - _Generate; - end - else - begin - Fhgt := 7000; // First sample always known value, helps me troubleshoot. - Fhg0 := 1000; - end; - - _StoreValue(I); - - // Override stored value in special cases: - - { How to make a gap in the data! } - if (nValueCount > 100) and ShowgapinLineChart1.Checked then - begin - if (I > 100) and (I < 130) then - begin - Chart.Data.Value[0, I] := NaN; // Use special Math.NaN const - Chart.Data.Value[1, I] := NaN; // Use special Math.NaN const - Chart.Data.Value[2, I] := NaN; // Use special Math.NaN const - end; - end; - - // Just so that the last two values are visibly different, to make sure - // the chart handles the final vaulues correctly, we set all the final - // values to known amounts also: - if I = nValueCount - 2 then - begin - Chart.Data.Value[0, I] := 6.0; // Use special Math.NaN const - Chart.Data.Value[1, I] := 4.0; // Use special Math.NaN const - Chart.Data.Value[2, I] := 2.0; // Use special Math.NaN const - end - else - if I = nValueCount - 1 then - begin - Chart.Data.Value[0, I] := 3.0; // Use special Math.NaN const - Chart.Data.Value[1, I] := 2.0; // Use special Math.NaN const - Chart.Data.Value[2, I] := 1.0; // Use special Math.NaN const - - end; - - ListBox1.Items.Append(Chart.Data.DebugStr(I)); - end; - - with Chart.Options do - begin - Title := 'Chart Title'; - XAxisHeader := 'Date/Time'; - YAxisHeader := 'Readings (ng/m3)'; - - if FNegValueFlag then - begin - PrimaryYAxis.YMin := -20; - PrimaryYAxis.YMax := 20; - end - else - PrimaryYAxis.YMin := 0; - // Try out the pen styles: - if ChartKind = ckChartStackedBar then - PenStyle[0] := psClear // THIS IS HOW YOU TEMPORARILY HIDE ONE PEN! - else - PenStyle[0] := psSolid; - PenStyle[1] := psDash; - PenStyle[2] := psDot; - - if mnuSecondaryAxisMode.Checked then - begin - PenCount := 4; // Add a pen for right side demo. - SecondaryYAxis.YMax := 140; // Example shows Q/A percentage. Experimental results - // results are compared to expected results, and the - // response percentage, is plotted from 0% to 140% - // of expected value. - - SecondaryYAxis.YLegendDecimalPlaces := 2; - - PenSecondaryAxisFlag[3] := True; // Move pen index 3 (Fourth pen) to secondary axis. - PenMarkerKind[3] := pmkDiamond; - PenValueLabels[3] := true; // Label with text. - PenStyle[3] := psClear; // Markers only, no lines. - PenColor[3] := clGray; - MarkerSize := 5; // Make 'em bigger. - end - else - begin - PenCount := 3; - MarkerSize := 3; // Make 'em little - end; - - PenLegends.Clear; - PenLegends.Add('HgT'); - PenLegends.Add('Hg0'); - PenLegends.Add('Hg2+'); - if mnuSecondaryAxisMode.Checked then - PenLegends.Add('Quality%'); - - PenUnit.Clear; - PenUnit.Add('ug/m3'); - PenUnit.Add('ug/m3'); - PenUnit.Add('ug/m3'); - if mnuSecondaryAxisMode.Checked then - PenUnit.Add('%'); // Optional Pen in percentage scale. - - //ShowLegend := TRUE; -// Legend := clChartLegendBelow; - - //ChartKind := ckChartLine; - end; -// Chart.AutoFormatGraph; - Chart.PlotGraph; - - //Chart.ResizeChartCanvas; -end; - -procedure TJvChartDemoForm.FormResize(Sender: TObject); -begin - if Assigned(Chart) then - Chart.ResizeChartCanvas; -end; - -procedure TJvChartDemoForm.ButtonBarChartClick(Sender: TObject); -begin - Chart.Options.ChartKind := ckChartBar; - NewValues; -end; - -procedure TJvChartDemoForm.ButtonLineClick(Sender: TObject); -var - I: Integer; -begin - Chart.Options.ChartKind := ckChartLine; - for I := 0 to Chart.Options.PenCount - 1 do - begin - Chart.Options.PenMarkerKind[I] := pmkNone; - end; - - NewValues; -end; - -procedure TJvChartDemoForm.ButtonLineMarkerClick(Sender: TObject); -//var -// I:Integer; -begin - Chart.Options.ChartKind := ckChartLine; - Chart.Options.PenMarkerKind[0] := pmkDiamond; // demonstrate both Diamond and Circle Marks. - Chart.Options.PenMarkerKind[1] := pmkDiamond; - Chart.Options.PenMarkerKind[2] := pmkCircle; - - NewValues; -end; - -procedure TJvChartDemoForm.ButtonStackedBarAveClick(Sender: TObject); -begin - Chart.Options.ChartKind := ckChartStackedBarAverage; - NewValues; -end; - -procedure TJvChartDemoForm.ButtonStackedBarClick(Sender: TObject); -begin - Chart.Options.ChartKind := ckChartStackedBar; - NewValues; -end; - -procedure TJvChartDemoForm.SpeedButton7Click(Sender: TObject); -begin -// Chart.PivotData; // TODO: This causes exceptions. not sure why we want this. -end; - -procedure TJvChartDemoForm.ButtonBarAveClick(Sender: TObject); -begin - //Chart.ShowAsBarWithAve; - Chart.Options.ChartKind := ckChartBarAverage; - - NewValues; -end; - -procedure TJvChartDemoForm.ButtonPieClick(Sender: TObject); -begin - // Chart.ShowAsPie; - Chart.Options.ChartKind := ckChartPieChart; -end; - -procedure TJvChartDemoForm.ButtonMarkersClick(Sender: TObject); -begin - //Chart.ShowAsMark; - Chart.Options.ChartKind := ckChartMarkers; -end; - -procedure TJvChartDemoForm.SpinEdit1Change(Sender: TObject); -begin -// Chart.Options.PrimaryYAxis.YPixelGap := SpinEdit1.Value; - Chart.Options.YStartOffset := SpinEdit1.Value; -// Chart.Options.XStartOffset := SpinEdit1.Value; -// Chart.Options.ColorScheme := SpinEdit1.Value; -// Chart.PlotGraph; -end; - -procedure TJvChartDemoForm.Button2Click(Sender: TObject); -begin - Chart.PlotGraph; -end; - -procedure TJvChartDemoForm.Button4Click(Sender: TObject); -begin -// Chart.AutoFormatGraph; WAP Removed. BAD CODE. - Chart.PlotGraph; -end; - -procedure TJvChartDemoForm.ButtonDeltaAverageClick(Sender: TObject); -begin - Chart.Options.ChartKind := ckChartDeltaAverage; -end; - -procedure TJvChartDemoForm.FormCreate(Sender: TObject); -begin - MakePensMenu; - - FStatHgt := TStatArray.Create(10); // Initialize for rolling average of last 10 samples. - FStatHg0 := TStatArray.Create(10); - - if Assigned(Chart) then - // Chart.ShowAsLineWithMark; - NewValues; -end; - -procedure TJvChartDemoForm.Panel2DblClick(Sender: TObject); -begin - OpenURL('http://jvcl.delphi-jedi.org/'); -// ShellExecute(HWND(nil), 'show', 'http://jvcl.delphi-jedi.org/', nil, nil, SW_SHOW); -end; - -procedure TJvChartDemoForm.ShowgapinLineChart1Click(Sender: TObject); -begin - ShowgapinLineChart1.Checked := not ShowgapinLineChart1.Checked; - ButtonLine.Down := true; - NewValues; -end; - -procedure TJvChartDemoForm.Print1Click(Sender: TObject); -begin - if PrintDialog1.Execute then - Chart.PrintGraph; -end; - -procedure TJvChartDemoForm.Generatenewrandomvalues1Click(Sender: TObject); -begin - if SpeedButtonTestMouseOver.Down then exit; - - NewValues; -end; - -procedure TJvChartDemoForm.CopyToClipboard1Click(Sender: TObject); -begin - Chart.GraphToClipboard; -end; - -procedure TJvChartDemoForm.MakePensMenu; -var - i: Integer; - mnu: TMenuItem; -begin - for i := mnuPens.Count-1 downto 0 do begin - mnu := mnuPens.Items[i]; - if (mnu <> nil) and (mnu.Tag >= TAG_PENCOLORS) and (mnu.tag < TAG_PENCOLORS + MAX_PEN) then - mnuPens.Delete(i); - end; -end; - -procedure TJvChartDemoForm.mnuSetAxisFontClick(Sender: TObject); -begin - {Get the current font for the axis label texts...} - FontDialog1.Font.Assign(Chart.Options.AxisFont); - - if FontDialog1.Execute then - {Set the font for the Header text...} - Chart.Options.AxisFont := FontDialog1.Font; - Chart.PlotGraph; -end; - -procedure TJvChartDemoForm.mnuSetAxisLineWidthClick(Sender: TObject); -var - s: String; - w: Integer; -begin - s := InputBox('Set Axis Linewidth', 'Value:', IntToStr(Chart.Options.AxisLineWidth)); - if TryStrToInt(s, w) and (w >= 0) then - Chart.Options.AxisLineWidth := w - else - MessageDlg('No valid number for axis linewidth', mtError, [mbOk], 0); -end; - -procedure TJvChartDemoForm.mnuSetAxisTitleFontClick(Sender: TObject); -begin - {Get the current font for the axis titles...} - FontDialog1.Font.Assign(Chart.Options.AxisTitleFont); - - if FontDialog1.Execute then - {Set the font for the Header text...} - Chart.Options.AxisTitleFont := FontDialog1.Font; - Chart.PlotGraph; -end; - -procedure TJvChartDemoForm.mnuSetCursorColorClick(Sender: TObject); -begin - ColorDialog1.Color := Chart.Options.CursorColor; - if ColorDialog1.Execute then - Chart.Options.CursorColor := ColorDialog1.Color; -end; - -procedure TJvChartDemoForm.mnuSetDivisionLineColorClick(Sender: TObject); -begin - ColorDialog1.Color := Chart.Options.DivisionLineColor; - if ColorDialog1.Execute then - Chart.Options.DivisionLineColor := ColorDialog1.Color; -end; - -procedure TJvChartDemoForm.mnuSetHeaderFontClick(Sender: TObject); -begin - {Get the current font for the header (title) text...} - FontDialog1.Font.Assign(Chart.Options.HeaderFont); - - if FontDialog1.Execute then - {Set the font for the Header text...} - Chart.Options.HeaderFont := FontDialog1.Font; - Chart.PlotGraph; -end; - -procedure TJvChartDemoForm.mnuSetHintColorClick(Sender: TObject); -begin - ColorDialog1.Color := Chart.Options.HintColor; - if ColorDialog1.Execute then - Chart.Options.HintColor := ColorDialog1.Color; -end; - -procedure TJvChartDemoForm.mnuSetLegendFontClick(Sender: TObject); -begin - {Get the current font for the header (title) text...} - FontDialog1.Font.Assign(Chart.Options.LegendFont); - - if FontDialog1.Execute then - {Set the font for the Header text...} - Chart.Options.LegendFont := FontDialog1.Font; - Chart.PlotGraph; -end; - -procedure TJvChartDemoForm.mnuSetMarkerSizeClick(Sender: TObject); -var - s: String; -begin - s := InputBox('Set Marker Size', 'Value:', IntToStr(Chart.Options.MarkerSize)); - Chart.Options.MarkerSize := StrToInt(s); -end; - -procedure TJvChartDemoForm.mnuSetPaperColorClick(Sender: TObject); -begin - ColorDialog1.Color := Chart.Options.PaperColor; - if ColorDialog1.Execute then - Chart.Options.PaperColor := ColorDialog1.Color; -end; - - -procedure TJvChartDemoForm.mnuSetPenCountClick(Sender: TObject); -var - s: String; - n: Integer; -begin - s := InputBox('Set pen count', 'Value:', IntToStr(Chart.Options.PenCount)); - if TryStrToInt(s, n) then - begin - Chart.Options.PenCount := n; - //MakePenColorMenu; - end else - MessageDlg('No valid number of pens.', mtError, [mbOK], 0); - -end; - -procedure TJvChartDemoForm.mnuSetPenLineWidthClick(Sender: TObject); -var - s: String; - w: Integer; -begin - s := InputBox('Set Pen Linewidth', 'Value:', IntToStr(Chart.Options.PenLineWidth)); - if TryStrToInt(s, w) and (w > 0) then - Chart.Options.PenLineWidth := w - else - MessageDlg('No valid number for pen linewidth', mtError, [mbOk], 0); -end; - -procedure TJvChartDemoForm.mnuSetShadowColorClick(Sender: TObject); -begin - ColorDialog1.Color := Chart.Options.ShadowColor; - if ColorDialog1.Execute then - Chart.Options.ShadowColor := ColorDialog1.Color; -end; - -procedure TJvChartDemoForm.mnuSetTitleClick(Sender: TObject); -var - s: String; -begin - s := InputBox('Set Chart Title', 'Text:', Chart.Options.Title); - Chart.Options.Title := s; -end; - -procedure TJvChartDemoForm.mnuSetXAxisHeaderClick(Sender: TObject); -var - s: String; -begin - s := InputBox('Set X Axis Title', 'Text:', Chart.Options.XAxisHeader); - Chart.Options.XAxisHeader := s; -end; - -procedure TJvChartDemoForm.mnuSetXStartOffsetClick(Sender: TObject); -var - s: String; - x: Integer; -begin - s := InputBox('Set X Axis Start Offset', 'Value:', IntToStr(Chart.Options.XStartOffset)); - if TryStrToInt(s, x) and (x >= 0) then - Chart.Options.XStartOffset := x - else - MessageDlg('No valid number for X Start Offset.', mtError, [mbOK], 0); -end; - -procedure TJvChartDemoForm.mnuSetYAxisHeaderClick(Sender: TObject); -var - s: String; -begin - s := InputBox('Set Y Axis Title', 'Text:', Chart.Options.YAxisHeader); - Chart.Options.YAxisHeader := s; -end; - -procedure TJvChartDemoForm.About1Click(Sender: TObject); -begin - Application.MessageBox(PChar( - 'JvChart comes from AABSoft Graph written by MÃ¥rten Henrichson, JVCL 3.0 ' + - 'version by Warren Postma. '), 'About JvChart', MB_OK); -end; - -procedure TJvChartDemoForm.mnuScrollingClick(Sender: TObject); -begin - if SpeedButtonTestMouseOver.Down then exit; - - mnuScrolling.Checked := not mnuScrolling.Checked; - Timer1.Enabled := mnuScrolling.Checked; -end; - -procedure TJvChartDemoForm.Timer1Timer(Sender: TObject); -begin - if SpeedButtonTestMouseOver.Down then exit; - - Chart.Data.Scroll; - _Generate; - _StoreValue(Chart.Data.ValueCount - 1); - Chart.PlotGraph; -end; - -procedure TJvChartDemoForm.ShowDataInListbox1Click(Sender: TObject); -begin - ShowDataInListbox1.Checked := not ShowDataInListbox1.Checked; - ListBox1.Visible := ShowDataInListbox1.Checked; - - if not ShowDataInListbox1.Checked then - begin - Chart.CursorPosition := -1; // Invisible. - end; -end; - -procedure TJvChartDemoForm.LargeDataset576samples1Click(Sender: TObject); -begin - if SpeedButtonTestMouseOver.Down then exit; - - LargeDataset576samples1.Checked := not LargeDataset576samples1.Checked; - NewValues; -end; - -procedure TJvChartDemoForm.mnuDateTimeAxisModeClick(Sender: TObject); -begin - mnuDateTimeAxisMode.Checked := not mnuDateTimeAxisMode.Checked; - if SpeedButtonTestMouseOver.Down then begin - Chart.Options.XLegends.Clear; - end else - NewValues; -end; - -procedure TJvChartDemoForm.FormDestroy(Sender: TObject); -begin - FreeAndNil(FStatHgt); - FreeAndNil(FStatHg0); -end; - -procedure TJvChartDemoForm.PrintOptions1Click(Sender: TObject); -begin - PrinterSetupDialog1.Execute; -end; - -procedure TJvChartDemoForm.mnuSecondaryAxisModeClick(Sender: TObject); -begin - mnuSecondaryAxisMode.Checked := not mnuSecondaryAxisMode.Checked; - - if mnuSecondaryAxisMode.Checked then - begin - ButtonLine.Down := true; - ButtonLineClick(Sender); - end - else - NewValues; -end; - -procedure TJvChartDemoForm.mnuFillUnderLineClick(Sender: TObject); -begin - mnuFillUnderLine.Checked := not mnuFillUnderLine.Checked; - Chart.Options.FillUnderLine := mnuFillUnderLine.Checked; -end; - -procedure TJvChartDemoForm.mnuLegenClick(Sender: TObject); -begin - mnuLegendNone.Checked := (Sender = mnuLegendNone); - mnuLegendBelow.Checked := (Sender = mnuLegendBelow); - mnuLegendRight.Checked := (Sender = mnuLegendRight); - if mnuLegendNone.Checked then - Chart.Options.Legend := clChartLegendNone - else if mnuLegendRight.Checked then - Chart.Options.Legend := clChartLegendRight - else if mnuLegendBelow.Checked then - Chart.Options.Legend := clChartLegendBelow; -end; - -procedure TJvChartDemoForm.mnuPensClick(Sender: TObject); -var - F: TPenEditorForm; -begin - F := TPenEditorForm.Create(nil); - try - F.UseChart(Chart); - if F.ShowModal = mrOK then - F.ApplyToChart(Chart); - finally - F.Free; - end; -end; - -procedure TJvChartDemoForm.ListBox1DblClick(Sender: TObject); -begin - Chart.CursorPosition := ListBox1.ItemIndex; // Highlight one sample. -end; - -procedure TJvChartDemoForm.ListBox1Click(Sender: TObject); -begin - Chart.CursorPosition := ListBox1.ItemIndex; // Highlight one sample. -end; - -procedure TJvChartDemoForm.MenuNegValueTestClick(Sender: TObject); -begin - FNegValueFlag := MenuNegValueTest.Checked; - NewValues; -end; - -{ Simple Chart Tests for finding bug } -procedure TJvChartDemoForm.SpeedButtonTestMouseOverClick(Sender: TObject); -var - i:Integer; - n:Double; - marker1,marker2,draggableCursor:TJvChartFloatingMarker; -begin - ListBox1.Clear; - mnuScrolling.Checked := false; - - Chart.Options.Title := 'Click on the Red Diamonds or the vertical gray line and Drag them!'; - Chart.Options.ChartKind := ckChartLine; - Chart.Options.XLegends.Clear; - Chart.Options.XAxisHeader := ''; - - Chart.Options.MouseDragObjects := true; // NEW: MOUSE DRAG FLOATING OBJECTS! - - for i := 0 to Chart.Options.PenCount - 1 do - begin - Chart.Options.PenMarkerKind[I] := pmkNone; - end; - Chart.Data.Clear; - Chart.Options.XValueCount := 80; - Chart.Data.ValueCount := 6; - Chart.Options.PenCount := 1; - for i := 0 to Chart.Options.XValueCount-1 do begin - n := 30-(25*((1-((i-25)/15))*(1-((i-25)/15)))); - if n<5 then - n := 5 -(Sqrt((Abs(n))/15)); - ListBox1.Items.Add( FloatToStrF(n,ffFixed,6,4)); - Chart.Data.Value[0,i] := n; - end; - Chart.Options.PrimaryYAxis.YMax := 50; - - Chart.Options.PenStyle[0] := psSolid; - - // NEW: Add a floating marker: - marker1 := Chart.AddFloatingMarker; - marker1.XPosition := 13; - marker1.YPosition := Chart.Data.Value[0,marker1.XPosition]; // Snap to Pen 1 - marker1.XDraggable := true; // make it mouse-moveable. - marker1.YDraggable := true; - marker1.Caption :='Start'; - marker1.Visible := true; - - marker2 := Chart.AddFloatingMarker; - marker2.XPosition := 66; - marker2.YPosition := Chart.Data.Value[0,marker2.XPosition]; // Snap to Pen 1 - marker2.LineToMarker := marker1.index; // Connect with a line to marker1 - marker2.XDraggable := true; // make it mouse-moveable. - marker2.YDraggable := true; - marker2.Caption := 'End'; - marker2.Visible := true; - - // NOTE: Do not Free marker1 or marker2. - // Marker objects are freed automatically - // by the Chart. - - // a draggable cursor object: - draggableCursor := Chart.AddFloatingMarker; - draggableCursor.LineVertical := true; // Make a vertical Line - draggableCursor.Marker := pmkNone; // No marker. So it is a line only. - draggableCursor.XDraggable := true; // make it draggable. - draggableCursor.XPosition := 40; - draggableCursor.LineColor := clDkGray; - draggableCursor.LineStyle := psSolid; - draggableCursor.LineWidth := 2; - draggableCursor.Caption := FloatToStrF( Chart.Data.Value[0,draggableCursor.XPosition], ffFixed, 6,4 ); - draggableCursor.Visible := true; - - Chart.PlotGraph; -end; - -procedure TJvChartDemoForm.ChartEndFloatingMarkerDrag(Sender: TJvChart; - FloatingMarker: TJvChartFloatingMarker); -begin - // Snap to line: - if (FloatingMarker.Index<2) then // One of the first two markers? - FloatingMarker.YPosition := Chart.Data.Value[0, FloatingMarker.XPosition] - else // update caption - FloatingMarker.Caption := FloatToStrF( Chart.Data.Value[0,FloatingMarker.XPosition],ffFixed,6,4 ); -end; - -procedure TJvChartDemoForm.ChartBeginFloatingMarkerDrag(Sender: TJvChart; - FloatingMarker: TJvChartFloatingMarker); -begin - if FloatingMarker.Index = 2 then - FloatingMarker.Caption := '?'; -end; - -end. diff --git a/components/jvcllaz/examples/JvChartDemo/jvpeneditor.lfm b/components/jvcllaz/examples/JvChartDemo/jvpeneditor.lfm deleted file mode 100644 index 8e882e78d..000000000 --- a/components/jvcllaz/examples/JvChartDemo/jvpeneditor.lfm +++ /dev/null @@ -1,206 +0,0 @@ -object PenEditorForm: TPenEditorForm - Left = 347 - Height = 302 - Top = 128 - Width = 505 - BorderStyle = bsDialog - Caption = 'PenEditorForm' - ClientHeight = 302 - ClientWidth = 505 - OnCreate = FormCreate - OnDestroy = FormDestroy - Position = poScreenCenter - LCLVersion = '2.1.0.0' - object btnPenColor: TButton - Left = 232 - Height = 25 - Top = 232 - Width = 64 - AutoSize = True - Caption = 'Color...' - OnClick = btnPenColorClick - TabOrder = 0 - end - object rgPenStyle: TRadioGroup - Left = 224 - Height = 168 - Top = 40 - Width = 121 - AutoFill = True - Caption = 'Style' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.EnlargeHorizontal = crsHomogenousChildResize - ChildSizing.EnlargeVertical = crsHomogenousChildResize - ChildSizing.ShrinkHorizontal = crsScaleChilds - ChildSizing.ShrinkVertical = crsScaleChilds - ChildSizing.Layout = cclLeftToRightThenTopToBottom - ChildSizing.ControlsPerLine = 1 - ClientHeight = 148 - ClientWidth = 117 - Items.Strings = ( - 'Solid' - 'Dash' - 'Dot' - 'Dash-dot' - 'Dash-dot-dot' - 'Clear' - ) - OnClick = rgPenStyleClick - TabOrder = 1 - end - object ButtonPanel1: TButtonPanel - Left = 6 - Height = 34 - Top = 262 - Width = 493 - OKButton.Name = 'OKButton' - OKButton.DefaultCaption = True - HelpButton.Name = 'HelpButton' - HelpButton.DefaultCaption = True - CloseButton.Name = 'CloseButton' - CloseButton.DefaultCaption = True - CancelButton.Name = 'CancelButton' - CancelButton.DefaultCaption = True - TabOrder = 2 - ShowButtons = [pbOK, pbCancel] - end - object lbPens: TListBox - Left = 8 - Height = 216 - Top = 8 - Width = 200 - ItemHeight = 0 - OnDrawItem = lbPensDrawItem - OnSelectionChange = lbPensSelectionChange - Style = lbOwnerDrawFixed - TabOrder = 3 - end - object btnAdd: TButton - Left = 11 - Height = 25 - Top = 232 - Width = 48 - AutoSize = True - Caption = 'Add' - OnClick = btnAddClick - TabOrder = 4 - end - object btnDelete: TButton - Left = 64 - Height = 25 - Top = 232 - Width = 59 - AutoSize = True - Caption = 'Delete' - OnClick = btnDeleteClick - TabOrder = 5 - end - object edPenLegend: TEdit - Left = 304 - Height = 23 - Top = 8 - Width = 185 - OnEditingDone = edPenLegendEditingDone - TabOrder = 6 - end - object btnClear: TButton - Left = 128 - Height = 25 - Top = 232 - Width = 53 - AutoSize = True - Caption = 'Clear' - OnClick = btnClearClick - TabOrder = 7 - end - object lblLegend: TLabel - Left = 224 - Height = 15 - Top = 8 - Width = 39 - Caption = 'Legend' - ParentColor = False - end - object ColorSample: TShape - Left = 304 - Height = 25 - Top = 232 - Width = 25 - end - object rgMarker: TRadioGroup - Left = 376 - Height = 136 - Top = 40 - Width = 112 - AutoFill = True - Caption = 'Marker' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.EnlargeHorizontal = crsHomogenousChildResize - ChildSizing.EnlargeVertical = crsHomogenousChildResize - ChildSizing.ShrinkHorizontal = crsScaleChilds - ChildSizing.ShrinkVertical = crsScaleChilds - ChildSizing.Layout = cclLeftToRightThenTopToBottom - ChildSizing.ControlsPerLine = 1 - ClientHeight = 116 - ClientWidth = 108 - Items.Strings = ( - 'None' - 'Diamond' - 'Circle' - 'Square' - 'Cross' - ) - OnClick = rgMarkerClick - TabOrder = 8 - 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 - Color = clBlack - CustomColors.Strings = ( - 'ColorA=000000' - 'ColorB=000080' - 'ColorC=008000' - 'ColorD=008080' - 'ColorE=800000' - 'ColorF=800080' - 'ColorG=808000' - 'ColorH=808080' - 'ColorI=C0C0C0' - 'ColorJ=0000FF' - 'ColorK=00FF00' - 'ColorL=00FFFF' - 'ColorM=FF0000' - 'ColorN=FF00FF' - 'ColorO=FFFF00' - 'ColorP=FFFFFF' - 'ColorQ=C0DCC0' - 'ColorR=F0CAA6' - 'ColorS=F0FBFF' - 'ColorT=A4A0A0' - ) - left = 144 - top = 88 - end -end diff --git a/components/jvcllaz/examples/JvChartDemo/jvpeneditor.pas b/components/jvcllaz/examples/JvChartDemo/jvpeneditor.pas deleted file mode 100644 index cbb6823bc..000000000 --- a/components/jvcllaz/examples/JvChartDemo/jvpeneditor.pas +++ /dev/null @@ -1,349 +0,0 @@ -unit jvPenEditor; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, - ButtonPanel, Contnrs, Types, - JvChart; - -type - TPenObj = class - Legend: String; - Color: TColor; - Style: TPenStyle; - Marker: TJvChartPenMarkerKind; - SecondaryAxis: Boolean; - end; - - { TPenEditorForm } - - TPenEditorForm = class(TForm) - btnPenColor: TButton; - btnAdd: TButton; - btnDelete: TButton; - btnClear: TButton; - ButtonPanel1: TButtonPanel; - ColorDialog: TColorDialog; - edPenLegend: TEdit; - lblLegend: TLabel; - lbPens: TListBox; - rgAxis: TRadioGroup; - rgMarker: TRadioGroup; - rgPenStyle: TRadioGroup; - ColorSample: TShape; - procedure btnAddClick(Sender: TObject); - procedure btnClearClick(Sender: TObject); - procedure btnDeleteClick(Sender: TObject); - procedure btnPenColorClick(Sender: TObject); - procedure edPenLegendEditingDone(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure FormDestroy(Sender: TObject); - procedure lbPensDrawItem(Control: TWinControl; Index: Integer; - ARect: TRect; State: TOwnerDrawState); - procedure lbPensSelectionChange(Sender: TObject; User: boolean); - procedure rgAxisClick(Sender: TObject); - procedure rgMarkerClick(Sender: TObject); - procedure rgPenStyleClick(Sender: TObject); - private - FPens: TObjectList; - procedure ControlsToPen(AIndex: Integer); - procedure PenToControls(AIndex: Integer); - function GetCurrentPen: TPenObj; - - public - procedure ApplyToChart(AChart: TJvChart); - procedure UseChart(AChart: TJvChart); - - end; - - -implementation - -{$R *.lfm} - -uses - Math, LCLType; - - -{ TPenEditorForm } - -procedure TPenEditorForm.ApplyToChart(AChart: TJvChart); -var - i: Integer; - pen: TPenObj; -begin - Assert(AChart <> nil); - AChart.Options.PenCount := FPens.Count; - AChart.Options.PenLegends.Clear; - for i := 0 to FPens.Count - 1 do - begin - pen := TPenObj(FPens[i]); - AChart.Options.PenLegends.Add(pen.Legend); - AChart.Options.PenColor[i] := pen.Color; - AChart.Options.PenStyle[i] := pen.Style; - AChart.Options.PenMarkerKind[i] := pen.Marker; - end; -end; - -procedure TPenEditorForm.btnAddClick(Sender: TObject); -var - pen: TPenObj; -begin - pen := TPenObj.Create; - pen.Legend := ''; - pen.Style := psSolid; - pen.Color := clBlack; - pen.Marker := pmkNone; - pen.SecondaryAxis := false; - FPens.Add(pen); - lbPens.Items.Add(''); -end; - -procedure TPenEditorForm.btnClearClick(Sender: TObject); -begin - FPens.Clear; - lbPens.Items.Clear; -end; - -procedure TPenEditorForm.btnDeleteClick(Sender: TObject); -begin - if lbPens.ItemIndex = -1 then - exit; - FPens.Delete(lbPens.ItemIndex); - lbPens.Items.Delete(lbPens.ItemIndex); -end; - -procedure TPenEditorForm.btnPenColorClick(Sender: TObject); -var - pen: TPenObj; -begin - pen := GetCurrentPen; - if pen = nil then - exit; - - ColorDialog.Color := pen.Color; - if ColorDialog.Execute then begin - pen.Color := ColorDialog.Color; - lbPens.Invalidate; - end; -end; - -procedure TPenEditorForm.ControlsToPen(AIndex: Integer); -var - pen: TPenObj; -begin - if AIndex = -1 then - exit; - pen := TPenObj(FPens[AIndex]); - pen.Legend := edPenLegend.Text; - if rgPenStyle.ItemIndex = rgPenStyle.Items.Count-1 then - pen.Style := psClear - else - pen.Style := TPenStyle(rgPenStyle.ItemIndex); - pen.Marker := TJvChartPenMarkerKind(rgMarker.ItemIndex); - pen.Color := ColorSample.Brush.Color; - pen.SecondaryAxis := rgAxis.ItemIndex = 1; -end; - -procedure TPenEditorForm.edPenLegendEditingDone(Sender: TObject); -var - pen: TPenObj; -begin - pen := GetCurrentPen; - if pen = nil then - exit; - pen.Legend := edPenLegend.Text; - lbPens.Invalidate; -end; - -procedure TPenEditorForm.FormCreate(Sender: TObject); -begin - FPens := TObjectList.Create; -end; - -procedure TPenEditorForm.FormDestroy(Sender: TObject); -begin - FPens.Free; -end; - -function TPenEditorForm.GetCurrentPen: TPenObj; -begin - if lbPens.ItemIndex = -1 then - Result := nil - else - Result := TPenObj(FPens[lbPens.ItemIndex]); -end; - -procedure TPenEditorForm.lbPensDrawItem(Control: TWinControl; Index: Integer; - ARect: TRect; State: TOwnerDrawState); -var - R: TRect; - pen: TPenObj; - x, y, dx, dy: Integer; -begin - pen := TPenObj(FPens[Index]); - lbPens.Canvas.Font.Assign(lbPens.Font); - - // Background - if [odSelected, odFocused] * State <> [] then - begin - lbPens.Canvas.Brush.Color := clHighlight; - lbPens.Canvas.Font.Color := clHighlightText; - end else - begin - lbPens.Canvas.Brush.Color := lbPens.Color; - lbPens.Canvas.Font.Color := lbPens.Font.Color; - end; - lbPens.Canvas.FillRect(ARect); - - // Line - R := ARect; - R.Right := R.Left + 50; - InflateRect(R, -2, -2); - lbPens.Canvas.Pen.Style := pen.Style; - lbPens.Canvas.Pen.Color := pen.Color; - lbPens.Canvas.Line(R.Left, (R.Top + R.Bottom) div 2, R.Right, (R.Top + R.Bottom) div 2); - - // Marker - x := (R.Left + R.Right) div 2; - y := (R.Top + R.Bottom) div 2; - dx := (R.Bottom - R.Top) div 2; - dy := dx; - lbPens.Canvas.Pen.Style := psSolid; - case pen.Marker of - pmkNone: ; - pmkDiamond: - begin - lbPens.Canvas.Brush.Color := pen.Color; - lbPens.Canvas.Brush.Style := bsSolid; - lbPens.Canvas.Polygon([Point(x, y-dy), Point(x-dx, y), Point(x, y+dy), Point(x+dx, y)]); - end; - pmkCircle: - begin - lbPens.Canvas.Brush.Style := bsClear; - lbPens.Canvas.Ellipse(x-dx, y-dy, x+dx, y+dy); - end; - pmkSquare: - begin - lbPens.Canvas.Brush.Style := bsClear; - lbPens.Canvas.Rectangle(x-dx, y-dy, x+dx, y+dy); - end; - pmkCross: - begin - lbPens.Canvas.Line(x-dx, y, x+dx, y); - lbPens.Canvas.Line(x, y-dy, x, y+dy); - end; - else - raise Exception.Create('Marker style not supported.'); - end; - - // Text - lbPens.Canvas.Brush.Style := bsClear; - lbPens.Canvas.TextOut(R.Right + 2, (R.Top + R.Bottom - lbPens.Canvas.TextHeight('Rg')) div 2, pen.Legend); - - // Focus rect - if odFocused in State then - lbPens.Canvas.DrawFocusRect(ARect); -end; - -procedure TPenEditorForm.lbPensSelectionChange(Sender: TObject; User: boolean); -begin - PenToControls(lbPens.ItemIndex); -end; - -procedure TPenEditorForm.PenToControls(AIndex: Integer); -var - pen: TPenObj; -begin - if AIndex = -1 then - exit; - - pen := TPenObj(FPens[AIndex]); - - edPenLegend.Text := pen.Legend; - if pen.Style = psClear then - rgPenStyle.ItemIndex := rgPenStyle.Items.Count-1 - else - rgPenStyle.ItemIndex := ord(pen.Style); - rgMarker.ItemIndex := ord(pen.Marker); - rgAxis.ItemIndex := IfThen(pen.SecondaryAxis, 1, 0); - ColorSample.Brush.Color := pen.Color; - - edPenLegend.Enabled := true; - rgPenStyle.Enabled := true; - rgMarker.Enabled := true; - rgAxis.Enabled := true; - btnPenColor.Enabled := true; - ColorSample.Visible := true; -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); -var - pen: TPenObj; -begin - pen := GetCurrentPen; - if pen = nil then - exit; - pen.Marker := TJvChartPenMarkerKind(rgMarker.ItemIndex); - lbPens.Invalidate; -end; - -procedure TPenEditorForm.rgPenStyleClick(Sender: TObject); -var - pen: TPenObj; -begin - pen := GetCurrentPen; - if pen = nil then - exit; - - if rgPenStyle.itemIndex = rgPenStyle.Items.Count -1 then - pen.Style := psClear - else - pen.Style := TPenStyle(rgPenStyle.ItemIndex); - lbPens.Invalidate; -end; - -procedure TPenEditorForm.UseChart(AChart: TJvChart); -var - i: Integer; - pen: TPenObj; -begin - Assert(AChart <> nil); - - FPens.Clear; - lbPens.Items.Clear; - for i := 0 to AChart.Options.PenLegends.Count - 1 do - begin - pen := TPenObj.Create; - pen.Legend := AChart.Options.PenLegends[i]; - pen.Color := AChart.Options.PenColor[i]; - pen.Style := AChart.Options.PenStyle[i]; - pen.Marker := AChart.Options.PenMarkerKind[i]; - pen.SecondaryAxis := AChart.Options.PenSecondaryAxisFlag[i];; - FPens.Add(pen); - lbPens.Items.Add(''); - end; - - edPenLegend.Enabled := false; - rgPenStyle.Enabled := false; - rgMarker.Enabled := false; - rgAxis.Enabled := false; - btnPenColor.Enabled := false; - ColorSample.Visible := false; -end; - -end. - diff --git a/components/jvcllaz/examples/JvChartDemo/statsclasses.pas b/components/jvcllaz/examples/JvChartDemo/statsclasses.pas deleted file mode 100644 index 82e832f79..000000000 --- a/components/jvcllaz/examples/JvChartDemo/statsclasses.pas +++ /dev/null @@ -1,258 +0,0 @@ -{----------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/MPL-1.1.html - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: JvChartDemoFm.Pas, released on 2002-10-04. - -The Initial Developer of the Original Code is AABsoft and MÃ¥rten Henrichson. -(C) 1996 AABsoft and MÃ¥rten Henrichson. -All Rights Reserved. - -Contributor(s): - - -Last Modified: 2004-01-07 - Modified 2003 Warren Postma - -You may retrieve the latest version of this file at the Project JEDI's JVCL home page, -located at http://jvcl.delphi-jedi.org - -Description: - TStatArray - Statistics, Rolling average helper class. - -Known Issues: - This version is part of JvChartDemo. ------------------------------------------------------------------------------} - -{$MODE OBJFPC}{$H+} - -unit StatsClasses; - -interface - -type - - TStatArray = class - protected - //FFirst:Boolean; - 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; - FLength: Integer; // Array absolute size (may still be no data even if this is >0) - FIndex: Integer; // Where will the next sample be stored into the array? - FCount: Integer; // How many valid samples are in the array right now? - procedure SetLen(aLength:Integer); - public - constructor Create; overload; - constructor Create(initialLength:Integer); overload; - 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; - - -implementation - -uses - SysUtils, // FloatToStr - Math; // VCL's statistics routines. StdDev, etc. - -// Begin Rolling Average - -constructor TStatArray.Create; // overload; -begin - //FFirst := true; - FLength := 0; - FIndex := 0; - FCount:= 0; - FGrows := true; - SetLength(FValues,0); -end; - -procedure TStatArray.Reset; -var - i:Integer; -begin - FIndex := 0; - FCount := 0; - for i := 0 to FLength-1 do begin - FValues[i] := -999.0; // debug helper. - end; - //FFirst := true; -end; - -constructor TStatArray.Create(initialLength:Integer); // overload; -begin -// FFirst := true; - SetLength(FValues,initialLength); - if (initialLength>0) then - FGrows := false - else - FGrows := true; - FLength := initialLength; - FIndex := 0; - FCount:= 0; -end; - - -destructor TStatArray.Destroy; -begin - SetLength(FValues,0); -end; - - -function TStatArray.Average:Double; -var - last,i:Integer; - sum:Double; -begin - if FCount <= 0 then begin - result := 0; - end else begin - sum := 0; - if (FCount>FLength) then - last :=FLength-1 - else - last :=FCount-1; - for i := 0 to last do begin - sum := sum + FValues[i]; - end; - result := sum / (last+1); - end; -end; - -function TStatArray.StandardDeviation:Double; -var - i:Integer; -// sum:Double; - TempArray:Array of Double; -begin - if (FCount <= 0) then - result := 0 - else if (FCount >= FLength) then begin - result := Math.StdDev( FValues ) - end else begin - SetLength(TempArray,FCount); - for i := 0 to FCount-1 do begin - TempArray[i] := FValues[i]; - end; - result := Math.StdDev( TempArray ); - SetLength(TempArray,0); - end; -end; - -procedure TStatArray.AddValue(aValue:Double); -//var -// i:Integer; -begin - (*if FFirst then begin - FFirst := false; - FIndex := 0; - FValues[0] := aValue; - FCount := 1; - end else begin*) - - // First time in we might need to create an array: - if FIndex>=Length then begin - Assert(FGrows); // Illegal condition. - FLength := FIndex+1; - SetLength( FValues,FLength); // uninitialized, as of yet. - end; - - FValues[FIndex] := aValue; - Inc(FIndex); - Inc(FCount); - if (not FGrows) then begin // circular? - if (FIndex>=FLength) then begin - FIndex := 0; - //FCount := FLength;//FCount does not exceed FLength in wraparounds. - end; - end else begin // grow after, in doublings of size, scales better! - if (FIndex>=FLength) then begin - FLength := FLength * 2; - SetLength( FValues,FLength); // uninitialized, as of yet. -{$ifdef DEBUG_ASSERTIONS} - Assert(FLength<20000); // Debug limit -{$endif} - end; - end; - -end; - -procedure TStatArray.SetLen(aLength:Integer); -begin - if(aLength<1) then - aLength := 1; - FLength := aLength; - SetLength(FValues, FLength); - -end; - - -// End Stats - - -{$ifdef UNIT_TESTS} -procedure StatsUnitTests; -var - diff:Double; - a1:TStatArray; - procedure _outs(s:String); - begin - OutputDebugString(PChar(s)); - end; - procedure _outd(d:Double); - begin - OutputDebugString(PChar(FloatToStr(d))); - end; - -begin - _outs('StatsUnitTests begins'); - - a1 := TStatArray.Create(0); // Growing array. - a1.AddValue( 3.5 ); - a1.AddValue( 1.5 ); - a1.AddValue( 25.5 ); - a1.AddValue( 100.5 ); - _outd( a1.Average ); - - diff := Abs(((3.5+1.5+25.5+100.5)/4.0)-a1.Average); - Assert(diff<0.001); - - a1.Reset; - Assert(Abs(a1.Average)<0.0001); - - a1.AddValue( 3.5 ); - a1.AddValue( 1.5 ); - a1.AddValue( 25.5 ); - a1.AddValue( 100.5 ); - _outd( a1.Average ); - - diff := Abs(((3.5+1.5+25.5+100.5)/4.0)-a1.Average); - Assert(diff<0.001); - - _outd( a1.StandardDeviation ); - Assert(trunc(a1.StandardDeviation)=46); - - _outs('StatsUnitTests ends'); -end; - -initialization - StatsUnitTests; - -{$endif} - - -end. diff --git a/components/jvcllaz/packages/jvcustomlazr.lpk b/components/jvcllaz/packages/jvcustomlazr.lpk index dee0e68ad..0d0ca45e9 100644 --- a/components/jvcllaz/packages/jvcustomlazr.lpk +++ b/components/jvcllaz/packages/jvcustomlazr.lpk @@ -16,7 +16,7 @@ TimeLine, OutlookBar, Thumbnail viewer, ImageViewer, ImageListViewer, OwnerDrawViewer"/> <License Value="The JVCL is released in accordance with the MPL 1.1 license. To get your own copy or read it, go to http://www.mozilla.org/MPL/MPL-1.1.html. "/> <Version Major="1" Release="6"/> - <Files Count="14"> + <Files Count="13"> <Item1> <Filename Value="..\run\JvCustomControls\jvtimeline.pas"/> <UnitName Value="JvTimeLine"/> @@ -69,10 +69,6 @@ TimeLine, OutlookBar, Thumbnail viewer, ImageViewer, ImageListViewer, OwnerDrawV <Filename Value="..\run\JvCustomControls\jvgammapanel.pas"/> <UnitName Value="JvGammaPanel"/> </Item13> - <Item14> - <Filename Value="..\run\JvCustomControls\jvchart.pas"/> - <UnitName Value="JvChart"/> - </Item14> </Files> <RequiredPkgs Count="2"> <Item1> diff --git a/components/jvcllaz/resource/jvcustomreg.res b/components/jvcllaz/resource/jvcustomreg.res index b04dbee13..18f1a287c 100644 Binary files a/components/jvcllaz/resource/jvcustomreg.res and b/components/jvcllaz/resource/jvcustomreg.res differ diff --git a/components/jvcllaz/run/JvCustomControls/jvchart.pas b/components/jvcllaz/run/JvCustomControls/jvchart.pas deleted file mode 100644 index 962d0d981..000000000 --- a/components/jvcllaz/run/JvCustomControls/jvchart.pas +++ /dev/null @@ -1,6247 +0,0 @@ -{----------------------------------------------------------------------------- -JvChart - TJvChart Component - 2009 Public - -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/MPL-1.1.html - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: JvChart.PAS, released on 2003-09-30. - -The Initial Developers of the Original Code are - Warren Postma (TJvChart which was originally based on TAABGraph) - Mårten Henrichson (TAABGraph) - -Contributor(s): - Warren Postma (warrenpstma att hotmail dott com) - Mårten Henrichson/AABSoft (no email known) - - Contains some code which is - (C) 1996-1998 AABsoft and Mårten Henrichson - - The rest is - (C) 2003-2009 Warren Postma - warren.postma att sympatico dott ca - warrenpstma att hotmail dott com - -Last Modified: - - 2003-09-30 - (WP) - Alpha-Initial checkin of new component, into JVCL3 CVS tree. - 2004-02-26 - (WP) - Pre-JVCL3.0-Has been substantially jedified, also new - properties/events, and some renaming has occurred. See - cvs logs. NEW: OnChartClick event. - RENAME: Options.ThickLineWidth -> Options.PenLineWidth - RENAME: Values -> ValueIndex - 2004-04-10 - (WP) - Much improved Charting! Beta-Quality in most places. - Significant property reorganization and renaming. - Primary and Secondary Y (vertical) Axis support. - 2004-07-06 - (WP)- Added events OnYAxisClick (Left margin click), - OnXAxisClick (Bottom margin), OnAltYAxisClick (Right margin) - and OnTitleClick (Top Margin). - - 2005-01-14 - (WP) - Floating Chart Markers added. Major changes to painting - code to allow canvas as a parameter. This is in preparation - for fixing up the printing code to allow printing to work - once again, and because the floating objects require us to - draw the chart into a bitmap, and then decorate the bitmap - dynamically with the floating objects, different - canvases are used to paint the bitmap, and to paint the - floating layer on top, thus the need for the changes. - - 2005-04-15 - (WP) - Changed internal Data storage from Array of Array to - simple single-dimension array. This has many benefits, - and at least one drawback. The benefit is that much - larger sets of pens/data values can be accomodated. - The drawback is that you can't add a pen to an already displayed - chart without regenerating all the data points in it. - If you change the pen count you now MUST clear the data, - and re-plot the chart. Any attempt to add a pen, - write the new pen, and then plot without rewriting the other - values will cause data to be displayed in a corrupt fashion. - I think this obscure limitation is better to live with than - the many alternatives. The problem I have is that the chart - supports extremely large data sets, and clearing the data - MULTIPLE times would be a huge performance penalty in - any application. You can enable the OLD mode, with it's - limitations, by defining TJVCHART_ARRAY_OF_ARRAY. - - 2007-04-26 - (WP) - Merged upstream changes. - - Added gradients (TJvChartGradientBar) - - Added new way of doing date/time markers (Options.XAxisDateTimeMode), - GraphXAxisLegend, and JvChart.Data properties StartDateTime, EndDateTime. - - Added vertical markers (AddVerticalBar) - - Added horizontal bars (TJvChartHorizontalBar) ClearHorizontalBars - - Added FloatingMarkerCount. - - New property in jvfloatingMarker: CaptionColor - - Added DeleteFloatingMarkerObj - - Graphical glitches/chart-display-bug-fixes. - 2007-04-27 - (WP) - Fixes - - Calls only JclMath.IsNaN, not Math.IsNaN, which doesn't - exist on older Delphi/BCB versions. - - Added CopyFloatingMarkers (thought I did that yesterday but missed it) - -You may retrieve the latest version of this file at the Project JEDI's JVCL home page, -located at http://jvcl.delphi-jedi.org - -To do: -- Drawing of legend at right (clChartLegendRight) not implemented -- Printing uses screen coordinates. -- Update to changes made in the object inspector. - ------------------------------------------------------------------------------} -// $Id$ - -unit JvChart; - -{$MODE OBJFPC}{$H+} -{$DEFINE TJVCHART_ARRAY_OF_ARRAY} -{.$DEFINE TEXT_BOX} - -interface - -uses - LCLType, LCLIntf, - Classes, Types, Graphics, Controls, Contnrs, - JvComponent; - -const - JvChartVersion = 300; // ie, version 3.00 - - JvDefaultHintColor = TColor($00DDFBFA); - JvDefaultAvgLineColor = TColor($00EEDDDD); - JvDefaultDivisionLineColor = clLtGray; - JvDefaultShadowColor = clDkGray; - JvDefaultPaperColor = clWhite; - - JvDefaultYLegends = 20; - MaxShowXValueInLegends = 10; - - // Special indices to GetPenColor(Index) - jvChartAverageLineColorIndex = -6; - jvChartDivisionLineColorIndex = -5; - jvChartShadowColorIndex = -4; - jvChartAxisColorIndex = -3; - jvChartHintColorIndex = -2; - jvChartPaperColorIndex = -1; - - JvChartDefaultMarkerSize = 3; - -type - { CHART TYPES } - TJvChartKind = - ( - ckChartNone, // Blank graph. - ckChartLine, // default type. Line and Marker plots. - ckChartBar, - ckChartStackedBar, - ckChartBarAverage, - ckChartStackedBarAverage, - ckChartPieChart, - //ckChartLineWithMarkers, // obsolete. use ckChartLine, and set PenMarkerKind to cmDiamond. - ckChartMarkers, - ckChartDeltaAverage - ); - - // ckChartLine can have a different pen type for each pen: - - TJvChartPenMarkerKind = (pmkNone, pmkDiamond, pmkCircle, pmkSquare, pmkCross); - - TJvChartGradientDirection = (grNone, grUp, grDown, grLeft, grRight); // WP - - TJvChartLegend = (clChartLegendNone, clChartLegendRight, clChartLegendBelow); - - {$IFDEF TJVCHART_ARRAY_OF_ARRAY} - TJvChartDataArray = array of array of Double; - {$ENDIF TJVCHART_ARRAY_OF_ARRAY} - - TJvChart = class; - - // TJvChartFloatingMarker.Caption position enumerator: - TJvChartCaptionPosition = - ( - cpMarker, // put right where the marker is - cpXAxisBottom, // put below the symbol marker, in the bottom margin - cpXAxisTop, // put above the symbol marker, in the top margin - cpTitleArea - ); - - TJvChartFloatingMarker = class(TPersistent) // was from TObject - private - FOwner: TJvChart; - procedure SetCaptionColor(const Value: TColor); // Which chart does it belong to? - protected - FRawXPosition: Integer; // raw pixel-based X position. - FRawYPosition: Integer; // raw pixel-based Y position. - FDragging: Boolean; // drag in progress! - FVisible: Boolean; // Make chart marker object visible or invisible. - FIndex: Integer; // Which marker is this? - FTag: Integer; // User assignable Integer like TComponent.Tag - FMarker: TJvChartPenMarkerKind; // What symbol to plot at this position? - FMarkerColor: TColor; // Marker color. - FXPosition: Integer; // Plot at same X co-ordinates as Data Sample X. - FYPosition: Double; // Plot at Y height as data - FXDraggable: Boolean; // Can marker be dragged horizontally? - FXDragMin: Integer; // Minimum X Position that we can drag to. - FXDragMax: Integer; // Maximum X Position that we can drag to. - FYDraggable: Boolean; // Can marker be dragged vertically? - //FYPositionToPen:Integer; // YPosition copied from Pen Values. (-1=disable feature, 0=first pen,1=second pen,...) - FLineToMarker: Integer; // If -1 then none. Otherwise, index of another marker object - FLineVertical: Boolean; // If true, then this object plots a vertical divider line. - FLineStyle: TPenStyle; // Line style (solid,dashed,etc) - FLineColor: TColor; // Line color. - FLineWidth: Integer; - FCaption: string; // Caption to print above the marker, or if no marker, then just this text is plotted. - FCaptionColor: TColor; // New 2007 - WP - Color of floating marker caption - FCaptionPosition: TJvChartCaptionPosition; - FCaptionBoxed: Boolean; // Marker caption can have a box around it to make it more readable for some uses. - - //FCaptionBorderStyle:TPenStyle; // Style of border around caption, or psClear if no border. - //FCaptionBorderColor:TColor; // - - //PROTECTED CONSTRUCTOR: Only TJvChart should create a new marker object: - constructor Create(Owner: TJvChart); - - procedure SetCaption(ACaption: string); - procedure SetXPosition(XPos: Integer); // should invalidate the chart (FOwner) if changed. - procedure SetYPosition(YPos: Double); // should invalidate the chart (FOwner) if changed. - - procedure SetVisible(AVisible: Boolean); - public - property Index: Integer read FIndex; - - procedure Assign(Source: TPersistent); override; // Should be able to copy from one floating marker to another - - property Marker: TJvChartPenMarkerKind read FMarker write FMarker; - property MarkerColor: TColor read FMarkerColor write FMarkerColor; // Marker color. - property Visible: Boolean read FVisible write FVisible; // Make chart marker object visible or invisible. - property XPosition: Integer read FXPosition write SetXPosition; - property YPosition: Double read FYPosition write SetYPosition; - property XDraggable: Boolean read FXDraggable write FXDraggable; - property XDragMin: Integer read FXDragMin write FXDragMin; - property XDragMax: Integer read FXDragMax write FXDragMax; - property YDraggable: Boolean read FYDraggable write FYDraggable; - //property YPositionToPen :Integer read FYPositionToPen write FYPositionToPen; - property LineToMarker: Integer read FLineToMarker write FLineToMarker; - property LineVertical: Boolean read FLineVertical write FLineVertical; - property LineStyle: TPenStyle read FLineStyle write FLineStyle; - property LineColor: TColor read FLineColor write FLineColor; - property LineWidth: Integer read FLineWidth write FLineWidth; - property Caption: string read FCaption write FCaption; - property CaptionColor: TColor read FCaptionColor write SetCaptionColor; - property CaptionPosition: TJvChartCaptionPosition read FCaptionPosition write FCaptionPosition; - property CaptionBoxed: Boolean read FCaptionBoxed write FCaptionBoxed; - - property Tag: Integer read FTag write FTag; // User assignable Integer like TComponent.Tag - - //property CaptionBorderStyle :TPenStyle read FCaptionBorderStyle write FCaptionBorderStyle; - //property CaptionBorderColor :TColor read FCaptionBorderColor write FCaptionBorderColor; - end; - - TJvChartGradientBar = class(TObject) // NEW 2007 - private - FOwner: TJvChart; // Which chart does it belongs to? - FVisible: Boolean; - //FRawRect: TRect; // raw pixel-based X position. - FColor: TColor; - FIndex: Integer; - FGradDirection: TJvChartGradientDirection; - FGradColor: TColor; - FPenStyle:TPenStyle; // april 2009 - FPenColor:TColor; // april 2009 - protected - FYTop, FYBottom: Double; - constructor Create(Owner: TJvChart); - procedure SetVisible(AVisible: Boolean); - procedure SetColor(AColor: TColor); - procedure SetGradientColor(AColor: TColor); - procedure SetGradientType(AType: TJvChartGradientDirection); - public - property Visible: boolean read FVisible write SetVisible; - property YTop: Double read FYTop write FYTop; - property YBottom: Double read FYBottom write FYBottom; - property Color: TColor read FColor write SetColor; - property GradDirection: TJvChartGradientDirection read FGradDirection write FGradDirection; - property GradColor: TColor read FGradColor write FGradColor; - property PenStyle:TPenStyle read FPenStyle write FPenStyle; // april 2009 - property PenColor:TColor read FPenCOlor write FPenColor; // april 2009 - end; - - TJvChartHorizontalBar = class(TJvChartGradientBar) // NEW 2007 - { - private - FYTop: Double; - FYBottom: Double; - } - protected - constructor Create(Owner: TJvChart); - public - property YTop: Double read FYTop write FYTop; - property YBottom: Double read FYBottom write FYBottom; - end; - - TJvChartVerticalBar = class(TJvChartGradientBar) // NEW 2007 - private - FXLeft: Integer; - FXRight: Integer; - protected - constructor Create(Owner: TJvChart); - public - property XLeft: Integer read FXLeft write FXLeft; - property XRight: Integer read FXRight write FXRight; - end; - - { TJvChartData : Holds NxN array of Reals, Resizes automatically within preset - limits. Provides a functionality mix of dynamic memory use, but with - a memory cap, so we don't thrash the system or leak forever. -WAP.} - TJvChartData = class(TObject) - private - {$IFDEF TJVCHART_ARRAY_OF_ARRAY} - FData: TJvChartDataArray; - {$ELSE} - FData: array of Double; - {$ENDIF TJVCHART_ARRAY_OF_ARRAY} - - FClearToValue: Double; // Typically either 0.0 or NaN - FTimeStamp: array of TDateTime; // Time-series as a TDateTime - // Dynamic array of dynamic array of Double. - // is empty until data is stored in them. - // *** Order of indexing: FData[ValueIndex,Pen] *** - FDataAlloc: Integer; // Last Allocated Value. - FValueCount: Integer; // Number of sample indices used - FPenCount: Integer; // can't be changed without erasing all data! - - FStartDateTime: TDateTime; // needed for DateTime mode, and datetime axis labels! NEW 2007 - FEndDateTime: TDateTime; - procedure SetEndDateTime(const Value: TDateTime); - procedure SetStartDateTime(const Value: TDateTime); - // needed for DateTime mode, and datetime axis labels! NEW 2007 - protected - procedure Grow(Pen, ValueIndex: Integer); - //GetValue/SetValue resizer, also throws exception if Pen,ValueIndex is negative or just way too big. - function GetValue(Pen, ValueIndex: Integer): Double; - procedure SetValue(Pen, ValueIndex: Integer; NewValue: Double); - function GetTimestamp(ValueIndex: Integer): TDateTime; - procedure SetTimestamp(ValueIndex: Integer; AValue: TDateTime); - public - constructor Create; - destructor Destroy; override; - - procedure PreGrow(Pen, ValueIndex: Integer); // Advanced users. Allocate a large batch of memory in advance. - - function DebugStr(ValueIndex: Integer): string; // dump all pens for particular valueindex, as string. - - procedure Clear; // Resets All Data to zero. - procedure ClearPenValues; // Clears all pen values to NaN but does not reset pen definitions etc. - procedure Scroll; - property Value[Pen, ValueIndex: Integer]: Double read GetValue write SetValue; default; - property Timestamp[ValueIndex: Integer]: TDateTime read GetTimestamp write SetTimestamp; - property ValueCount: Integer read FValueCount write FValueCount; - property ClearToValue: Double read FClearToValue write FClearToValue; // Typically either 0.0 or NaN. default 0.0 - - // NEW 2007 [for DateTimeMode XAxis Labels] - property StartDateTime: TDateTime read FStartDateTime write SetStartDateTime; - // needed for DateTime mode, and datetime axis labels! NEW 2007 - property EndDateTime: TDateTime read FEndDateTime write SetEndDateTime; - // needed for DateTime mode, and datetime axis labels! NEW 2007 - end; - - TJvChartPaintEvent = procedure(Sender: TJvChart; ACanvas: TCanvas) of object; - TJvChartEvent = procedure(Sender: TJvChart) of object; - TJvChartFloatingMarkerDragEvent = procedure(Sender: TJvChart; FloatingMarker: TJvChartFloatingMarker) of object; {NEW} - - TJvChartClickEvent = procedure(Sender: TJvChart; - Button: TMouseButton; { left/right mouse click?} - Shift: TShiftState; { keyboard shift state?} - X, Y: Integer; { mouse position} - ChartValueIndex: Integer; { what value in the chart? } - ChartPenIndex: Integer; { what pen was clicked? } - { User modifiable return values for custom hinting! } - var ShowHint, HintFirstLineBold: Boolean; HintStrs: TStrings) of object; {NEW} - - TJvChartOptions = class; - - { There are TWO Y Axis per graph, optionally: - Chart.Options.PenAxis[I] -and- - Chart.Options.SecondaryYAxisOne - The primary one is displayed along the left side, and the one - for the right side is only displayed if you need it. - Properties for each side are grouped by the - TJvChartYAxisOptions persistent-properties-object. - } - TJvChartYAxisOptions = class(TPersistent) - private - FOwner: TJvChartOptions; - FActive: Boolean; // One or more pens use this Y Axis. - protected - FYMax: Double; // Y Scale value at the top left hand side of chart. - FYMin: Double; // Y Scale value at the bottom left hand side of the chart (default 0) - FYGap: Double; // Number of values per Y scale division - FYGap1: Double; // Gap multiplication factor for value scaling. - FMarkerValueDecimals: Integer; // Decimal places on marker-values (only applies to Marker Pens with Values) - FYDivisions: Integer; // Number of vertical divisions in the chart. (default 10) - FMaxYDivisions: Integer; - FMinYDivisions: Integer; - FYLegendDecimalPlaces: Integer; - FYLegends: TStringList; - FDefaultYLegends: Integer; // Number of default Y legends. - FYPixelGap: Double; - procedure SetYMax(NewYMax: Double); - procedure SetYMin(NewYMin: Double); - // procedure SetYGap(newYgap: Double); - function GetYLegends: TStrings; - procedure SetYLegends(Value: TStrings); - procedure SetYDivisions(AValue: Integer); - procedure SetYPixelGap(AValue: Double); - public - constructor Create(Owner: TJvChartOptions); virtual; - destructor Destroy; override; - procedure Assign(Source:TPersistent); override;// Added Sept 2009 - procedure Normalize; - procedure Clear; - // runtime only properties - property YPixelGap: Double read FYPixelGap write SetYPixelGap; - property Active: Boolean read FActive; - property YGap: Double read FYGap; - property YGap1: Double read FYGap1; // Gap multiplication factor for value scaling. - property YLegends: TStrings read GetYLegends write SetYLegends; { Y Axis Legends as Strings } - published - property YMax: Double read FYMax write SetYMax; - property YMin: Double read FYMin write SetYMin; - property YDivisions: Integer read FYDivisions write SetYDivisions default 10; - // Number of vertical divisions in the chart - // YDivisions->YDivisions - property MaxYDivisions: Integer read FMaxYDivisions write FMaxYDivisions default 20; - property MinYDivisions: Integer read FMinYDivisions write FMinYDivisions default 5; - property MarkerValueDecimals: Integer read FMarkerValueDecimals write FMarkerValueDecimals default -1; - // Decimal places on marker-values (only applies to Marker Pens with Values) - property YLegendDecimalPlaces: Integer read FYLegendDecimalPlaces write FYLegendDecimalPlaces; - property DefaultYLegends: Integer read FDefaultYLegends write FDefaultYLegends default JvDefaultYLegends; - end; - - TJvChartOptions = class(TPersistent) - private - FOwner: TJvChart; - {accessors} - function GetAverageValue(Index: Integer): Double; - procedure SetAverageValue(Index: Integer; AValue: Double); - function GetPenColor(Index: Integer): TColor; - function GetPenStyle(Index: Integer): TPenStyle; - function GetPenMarkerKind(Index: Integer): TJvChartPenMarkerKind; - function GetPenSecondaryAxisFlag(Index: Integer): Boolean; - procedure SetPenSecondaryAxisFlag(Index: Integer; NewValue: Boolean); - function GetPenValueLabels(Index: Integer): Boolean; - procedure SetPenValueLabels(Index: Integer; NewValue: Boolean); - // TStrings<->TStringList transmogrifiers - function GetPenLegends: TStrings; - function GetPenUnit: TStrings; - procedure SetPenUnit(Value: TStrings); - function GetXLegends: TStrings; - procedure SetXLegends(Value: TStrings); - procedure SetHeaderFont(AFont: TFont); - procedure SetLegendFont(AFont: TFont); - procedure SetAxisFont(AFont: TFont); - procedure SetPrimaryYAxis(AssignFrom: TJvChartYAxisOptions); - procedure SetSecondaryYAxis(AssignFrom: TJvChartYAxisOptions); - // Each pen can be associated with either the primary or secondary axis, - // this function decides which axis to return depending on the pen configuration: - function GetPenAxis(Index: Integer): TJvChartYAxisOptions; - - procedure SetAxisLineWidth(const Value: Integer); - procedure SetAxisTitleFont(const Value: TFont); - procedure SetChartKind(AKind: TJvChartKind); - procedure SetDivisionLineColor(const AColor: TColor); - procedure SetFillUnderline(const AValue: Boolean); - procedure SetLegend(const ALegend: TJvChartLegend); - procedure SetMarkerSize(const Value: Integer); - procedure SetPaperColor(const AColor: TColor); - procedure SetPenColor(Index: Integer; AColor: TColor); - procedure SetPenCount(Count: Integer); - procedure SetPenLegends(Value: TStrings); - procedure SetPenLineWidth(const Value: Integer); - procedure SetPenMarkerKind(Index: Integer; AMarkKind: TJvChartPenMarkerKind); - procedure SetPenStyle(Index: Integer; APenStyle: TPenStyle); - procedure SetShadowColor(const AColor: TColor); - procedure SetTitle(const Value: String); - procedure SetXAxisDateTimeDivision(const Value: Double); - procedure SetXAxisHeader(const Value: String); - procedure SetXStartOffset(Offset: Integer); - procedure SetYAxisHeader(const Value: String); - procedure SetYStartOffset(Offset: Integer); - protected - FChartKind: TJvChartKind; // default JvChartLine - {runtime pixel spacing multipliers} - FXPixelGap: Double; - {Fonts} - FHeaderFont: TFont; - FLegendFont: TFont; - FAxisFont: TFont; - FAxisTitleFont: TFont; - FTitle: string; - FNoDataMessage: string; - FYAxisHeader: string; - FYAxisDivisionMarkers: Boolean; // Do you want grid-paper look? - FXAxisDivisionMarkers: Boolean; // Do you want grid-paper look? - FXAxisHeader: string; - FMarkerSize:Integer; - FFillUnderLine : Boolean; - FXLegends: TStringList; // Text labels. - FXLegendMaxTextWidth: Integer; // runtime: display width (pixels) of widest string in FXLegends[1:X]. - FXAxisValuesPerDivision: Integer; - // Number of Values (aka samples) in each vertical dotted lines that are divisision marker. - FXAxisLegendSkipBy: Integer; //1=print every X axis label, 2=every other, and so on. default=1 - FXLegendHoriz: Integer; // Horizontally oriented GraphXAxisLegend ends at this X Point. - FXAxisLabelAlignment: TAlignment; // New: Text alignment for X axis labels. Default is left alignment. - FXAxisDateTimeMode: Boolean; - // False=use custom text labels, True=Use Date/Time Stamps as X axis labels. [REWORKED LOGIC IN 2007!] - FXAxisDateTimeDivision: Double; // NEW 2007 : What is the nominal date/time division (1.0=day, 1.0/24=1 hour) - FXAxisDateTimeFormat: string; // Usually a short date-time label, hh:nn:ss is good. - FDateTimeFormat: string; - // Usually a long date-time label, ISO standard yyyy-mm-dd hh:nn:ss is fine, as is Windows locale defaults. - FXValueCount: Integer; - // Number of pens: - FPenCount: Integer; - // Per-pen array/list properties - FPenColors: array of TColor; - FPenStyles: array of TPenStyle; // solid, dotted - FPenMarkerKind: array of TJvChartPenMarkerKind; - FPenSecondaryAxisFlag: array of Boolean; // False=Primary Y Axis, True=Secondary Y Axis. - FPenValueLabels: array of Boolean; - FPenLegends: TStringList; - FPenUnit: TStringList; - FAverageValue: array of Double; // Used in averaging chart types only. - FPrimaryYAxis: TJvChartYAxisOptions; - FSecondaryYAxis: TJvChartYAxisOptions; - FXGap: Double; // Number of pixels per X scale unit. - FXOrigin: Integer; {which value corresponds to Origin} - FYOrigin: Integer; // Vertical (Y) Position of the Origin point, and X axis. - FXStartOffset: Longint; {margin} // Horizontal (X) Position of the Origin point, and Y Axis - FYStartOffset: Longint; // height of the top margin above the charting area. - FXEnd: Longint; { From top left of control, add XEnd to find where the right margin starts } - FYEnd: Longint; { from top left of control, add YEnd to find where the below-the bottom margin starts } - { more design time } - FLegendWidth: Integer; - FLegendRowCount: Integer; // Number of lines of text in legend. - FAutoUpdateGraph: Boolean; - FMouseEdit: Boolean; - FMouseDragObjects: Boolean; // Can mouse drag floating objects? - FMouseInfo: Boolean; - FLegend: TJvChartLegend; // was FShowLegend, now Legend=clChartLegendRight - FPenLineWidth: Integer; - FAxisLineWidth: Integer; - - //COLORS: - FPaperColor: TColor; - FDivisionLineColor: TColor; // NEW! Division line - FShadowColor: TColor; // NEW! Shadow color - FAxisLineColor: TColor; // Color of box around chart plot area. - FHintColor: TColor; // Hint box color - FAverageLineColor: TColor; // Pen color for Charts with auto-average lines. - FCursorColor: TColor; // Sample indicator Cursor color - - FCursorStyle: TPenStyle; // Cursor style. - FGradientColor: TColor; // new 2007 - FGradientDirection: TJvChartGradientDirection; // new 2007 - - // INTERNALS :NEW STUFF IN 2007 - FXAxisDateTimeFirstMarker: Integer; // at XValue initial offset NEW 2007 - FXAxisDateTimeSkipBy: Integer; // an XValue indexing multiplier NEW 2007 - FXAxisDateTimeLines: Integer; // number of lines we're displaying NEW 2007 - - { event interface } - procedure NotifyOptionsChange; - public - constructor Create(Owner: TJvChart); virtual; - destructor Destroy; override; - procedure Assign(Source:TPersistent); override;// Warren Added Sept 2009. - - { runtime properties } - property AverageValue[Index: Integer]: Double read GetAverageValue write SetAverageValue; - property PenAxis[Index: Integer]: TJvChartYAxisOptions read GetPenAxis; - property XLegends: TStrings read GetXLegends write SetXLegends; { X Axis Legends as Strings } - { plot-canvas size, depends on size of control } - property XEnd: Longint read FXEnd write FXEnd; - property YEnd: Longint read FYEnd write FYEnd; - {Gradient NEW 2007 } - property GradientColor: TColor read FGradientColor write FGradientColor; // new 2007 - property GradientDirection: TJvChartGradientDirection read FGradientDirection write FGradientDirection; // new 2007 - - { pixel spacing : multipliers to scale real values into X/Y pixel amounts before plotting. CRITICALLY important. } - property XPixelGap: Double read FXPixelGap write FXPixelGap; - property XLegendMaxTextWidth: Integer read FXLegendMaxTextWidth write FXLegendMaxTextWidth; - { Per Pen Array/List Properties -- settable at RUNTIME only. } - property PenColor[Index: Integer]: TColor read GetPenColor write SetPenColor; - property PenStyle[Index: Integer]: TPenStyle read GetPenStyle write SetPenStyle; - property PenMarkerKind[Index: Integer]: TJvChartPenMarkerKind read GetPenMarkerKind write SetPenMarkerKind; - property PenSecondaryAxisFlag[Index: Integer]: Boolean read GetPenSecondaryAxisFlag write SetPenSecondaryAxisFlag; - property PenValueLabels[Index: Integer]: Boolean read GetPenValueLabels write SetPenValueLabels; - published - { design time} - { Per Pen Array/List Properties - settable at DESIGNTIME. Others (color/style, marker) are runtime only. } - property PenLegends: TStrings read GetPenLegends write SetPenLegends; - property PenUnit: TStrings read GetPenUnit write SetPenUnit; - property ChartKind: TJvChartKind read FChartKind write SetChartKind default ckChartLine; - property Title: string read FTitle write SetTitle; - property NoDataMessage: string read FNoDataMessage write FNoDataMessage; - //NEW! NOV 2004. Optionally display this instead of fixed resource string rsNoData - - { X Axis Properties } - // Do you want grid-paper look? - { X Axis Properties } - property XAxisDivisionMarkers: Boolean read FXAxisDivisionMarkers write FXAxisDivisionMarkers default True; - // Do you want grid-paper look? - property XAxisValuesPerDivision: Integer read FXAxisValuesPerDivision write FXAxisValuesPerDivision; - // Number of Values (aka samples) in each vertical dotted lines that are divisision marker. - property XAxisLabelAlignment: TAlignment read FXAxisLabelAlignment write FXAxisLabelAlignment; - // New: Text alignment for X axis labels. Default is left alignment. - property XAxisDateTimeMode: Boolean read FXAxisDateTimeMode write FXAxisDateTimeMode; - // REWORKED LOGIC NEW IN 2007! See GraphXAxisDivisionMarkers - property XAxisDateTimeDivision: Double read FXAxisDateTimeDivision write SetXAxisDateTimeDivision; - // NEW 2007 : What is the nominal date/time division (1.0=day, 1.0/24=1 hour) - property XAxisDateTimeFormat: string read FXAxisDateTimeFormat write FXAxisDateTimeFormat; - property XAxisHeader: string read FXAxisHeader write SetXAxisHeader; - property XAxisLegendSkipBy: Integer read FXAxisLegendSkipBy write FXAxisLegendSkipBy default 1; - - property DateTimeFormat: string read FDateTimeFormat write FDateTimeFormat; - // Usually a long date-time label, ISO standard yyyy-mm-dd hh:nn:ss is fine, as is Windows locale defaults. - property PenCount: Integer read FPenCount write SetPenCount default 1; - property XGap: Double read FXGap write FXGap; - property XOrigin: Integer read FXOrigin write FXOrigin; - property YOrigin: Integer read FYOrigin write FYOrigin; // Position of bottom of chart (not always the zero origin) - property XStartOffset: Longint read FXStartOffset write SetXStartOffset default 45; - property YStartOffset: Longint read FYStartOffset write SetYStartOffset default 10; - - { Y Axis Properties } - property YAxisHeader: string read FYAxisHeader write SetYAxisHeader; - property YAxisDivisionMarkers: Boolean read FYAxisDivisionMarkers write FYAxisDivisionMarkers default True; - - { Y Range } - { plotting markers } - property MarkerSize: Integer read FMarkerSize write SetMarkerSize default JvChartDefaultMarkerSize; - property FillUnderLine : Boolean read FFillUnderLine write SetFillUnderLine default False; - { !! New: Primary (left side) Y axis, and Secondary (right side) Y Axis !!} - property PrimaryYAxis: TJvChartYAxisOptions read FPrimaryYAxis write SetPrimaryYAxis; - property SecondaryYAxis: TJvChartYAxisOptions read FSecondaryYAxis write SetSecondaryYAxis; - //1=print every X axis label, 2=every other, and so on. default=1 - { vertical numeric decimal places } - { more design time } - property AutoUpdateGraph: Boolean read FAutoUpdateGraph write FAutoUpdateGraph default True; - property MouseEdit: Boolean read FMouseEdit write FMouseEdit default True; - property MouseDragObjects: Boolean read FMouseDragObjects write FMouseDragObjects; - // Can mouse drag floating objects? - property MouseInfo: Boolean read FMouseInfo write FMouseInfo default True; - //OLD:property ShowLegend: Boolean read FShowLegend write FShowLegend default True; - //CHANGEDTO: - property Legend: TJvChartLegend read FLegend write SetLegend default clChartLegendNone; - property LegendRowCount: Integer read FLegendRowCount write FLegendRowCount; - property LegendWidth: Integer read FLegendWidth write FLegendWidth default 150; - property PenLineWidth: Integer read FPenLineWidth write SetPenLineWidth default 1; - property AxisLineWidth: Integer read FAxisLineWidth write SetAxisLineWidth default 2; - { more and more design time. these ones not sure about whether they are designtime or not.} - property XValueCount: Integer read FXValueCount write FXValueCount default 10; - {Font properties} - property HeaderFont: TFont read FHeaderFont write SetHeaderFont; - property LegendFont: TFont read FLegendFont write SetLegendFont; - property AxisFont: TFont read FAxisFont write SetAxisFont; - property AxisTitleFont: TFont read FAxisTitleFont write SetAxisTitleFont; - { Color properties} - property DivisionLineColor: TColor read FDivisionLineColor write SetDivisionLineColor default - JvDefaultDivisionLineColor; // NEW! Division line - property ShadowColor: TColor read FShadowColor write SetShadowColor default JvDefaultShadowColor; // NEW! Shadow color - - property PaperColor: TColor read FPaperColor write SetPaperColor default clWhite; - property AxisLineColor: TColor read FAxisLineColor write FAxisLineColor; - property HintColor: TColor read FHintColor write FHintColor default JvDefaultHintColor; - property AverageLineColor: TColor read FAverageLineColor write FAverageLineColor default JvDefaultAvgLineColor; - property CursorColor: TColor read FCursorColor write FCursorColor; - property CursorStyle: TPenStyle read FCursorStyle write FCursorStyle; - end; - - TJvChart = class(TJvGraphicControl) - private - FUpdating: Boolean; // PREVENT ENDLESS EVENT LOOPING. - FAutoPlotDone: Boolean; // If Options.AutoUpdateGraph is set, then has paint method called PlotGraph already? - FPlotGraphCalled: Boolean; // Has bitmap ever been painted? - FInPlotGraph: Boolean; // recursion blocker. - - // NEW: The component has always had a feature when you click on margin areas - // that the user can enter a value (Y Axis Scale, title, and X header) - // The right margin however didn't do anything. Now all four have a user - // event that can be fired. If you don't want the default editor behaviours - // turn off Options.MouseEdit to make it 100% user-defined what happens when - // the user clicks on an area of the chart. - FOnYAxisClick: TJvChartEvent; // Left margin (Primary Y Axis labels) click - FOnXAxisClick: TJvChartEvent; // Bottom margin (X Axis Header) click - FOnAltYAxisClick: TJvChartEvent; // Right margin click (Secondary Y Axis labels) - FOnTitleClick: TJvChartEvent; // Title area click (Top margin) - FOnChartClick: TJvChartClickEvent; // mouse click event - FOnBeginFloatingMarkerDrag: TJvChartFloatingMarkerDragEvent; - FOnEndFloatingMarkerDrag: TJvChartFloatingMarkerDragEvent; - //FOnChartPaint: TJvChartPaintEvent; // wrong event. bugfix requires removal. - FMouseDownShowHint: Boolean; // True=showing hint. - FMouseDownHintBold: Boolean; // True=first line of hint is bold. - FMouseDownHintStrs: TStringList; - - FExtPicture:TPicture; // An external image! - - { TImage stuff} - FPicture: TPicture; // An image drawn via GDI primitives, saveable as - // bitmap or WMF, or displayable to screen - FData: TJvChartData; - - FDragFloatingMarker: TJvChartFloatingMarker; //Current object we are dragging ( nil=none ) - FFloatingMarker: TObjectList; // NEW: collection of TJvChartFloatingMarker objects. - FHorizontalBars: TObjectList; // NEW 2007 - FVerticalBars: TObjectList; // NEW 2007 - - FAverageData: TJvChartData; - FBitmap: TBitmap; - FOptions: TJvChartOptions; //^TOptions; - //Options2 : ^TOptions2; // now FData - PrintInSession: Boolean; - FStartDrag: Boolean; - FMouseLegend: Boolean; - FContainsNegative: Boolean; - { strColorFile: string;}// not used (ahuser) - FOldYOrigin: Integer; - FOldYGap: Double; - FMouseDownX: Longint; - FMouseDownY: Longint; - FMouseValue: Integer; - FMousePen: Integer; -// FYFont: TFont; // Delphi Font object wrapper. - //NEW: - FXOrigin: Double; {was in TJvChart.PlotGraph} - FYOrigin: Double; {was in TJvChart.PlotGraph} - FXAxisPosition: Integer; // how far down (in Y dimension) is the X axis? - FOnOptionsChangeEvent: TJvChartEvent; { Component fires this event for when options change.} - FOnPaint: TJvChartPaintEvent; {NEW JAN 2005: Custom paint event called from TjvChart.Paint.} - - FCursorPosition: Integer; // NEW: -1 means no visible cursor, 0..n means make - // particular value highlighted. The highlight is painted - // over top of the TImage, so that we can just restore the TImage - // without replotting the whole chart. - // Y Axis Vertical Font - // FYFontHandle: HFONT; // Y AXIS VERTICAL TEXT: Vertical Font Handle (remember to DeleteObject) -// FYLogFont: TLogFont; // Y AXIS VERTICAL TEXT: Logical Font Options Record -// procedure MakeVerticalFont; // Call GDI calls to get the Y Axis Vertical Font handle -// procedure MyGraphVertFont(ACanvas: TCanvas); // vertical font handle - procedure PaintCursor; // called from Paint iif a Cursor is visible. does NOT modify FPicture! - protected - procedure DrawFloatingMarkers; - procedure DrawHorizontalBars; // NEW 2007 - procedure DrawVerticalBars; // NEW 2007 - procedure DrawGradient; // NEW 2007 - - procedure DrawChartLegendBelow(ACanvas: TCanvas); {accidentally deleted during Jedi_new to Jedi_2009 branch. Restored by WP Sept 2009} - - function GetFloatingMarker(Index: Integer): TJvChartFloatingMarker; - function GetHorizontalBar(index:integer):TJvChartHorizontalBar; // new 2009 - function GetVerticalBar(index:integer):TJvChartVerticalBar; // new 2009 - - { Right Side Legend showing Pen Names, and/or Data Descriptors } - procedure GraphXAxisLegendMarker(ACanvas: TCanvas; MarkerKind: TJvChartPenMarkerKind; X, Y: Integer); - procedure GraphXAxisLegend; - procedure MyHeader(ACanvas: TCanvas; StrText: string); - procedure MyXHeader(ACanvas: TCanvas; StrText: string); - procedure MyYHeader(ACanvas: TCanvas; StrText: string); // NEW - procedure MyHeaderFont(ACanvas: TCanvas); - procedure MyAxisFont(ACanvas: TCanvas); - procedure MyAxisTitleFont(ACanvas: TCanvas; Vertical: Boolean); - procedure MySmallGraphFont(ACanvas: TCanvas); - function MyTextHeight(ACanvas: TCanvas; StrText: string): Longint; - { TEXTOUT stuff } - 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 MyLeftTextOut(ACanvas: TCanvas; X, Y: Integer; const AText: string; Vertical: Boolean = false); // LEFT ALIGN TEXT - - // Use HintColor: - procedure MyLeftTextOutHint(ACanvas: TCanvas; X, Y: Integer; const AText: string); - - { line, curve, rectangle stuff } - procedure MyPenLineTo(ACanvas: TCanvas; X, Y: Integer); - procedure MyAxisLineTo(ACanvas: TCanvas; X, Y: Integer); - procedure MyRectangle(ACanvas: TCanvas; X, Y, X2, Y2: Integer); - procedure MyColorRectangle(ACanvas: TCanvas; Pen: Integer; X, Y, X2, Y2: Integer); - procedure MyPie(ACanvas: TCanvas; X1, Y1, X2, Y2, X3, Y3, X4, Y4: Longint); { pie chart segment } - // procedure MyArc(X1, Y1, X2, Y2, X3, Y3, X4, Y4: Integer); { arc } // not used (ahuser) - - // procedure MyEllipse(X1, Y1, X2, Y2: Integer); // not used (ahuser) - procedure MyDrawLine(ACanvas: TCanvas; X1, Y1, X2, Y2: Integer); // not used (ahuser) - procedure MyDrawAxisMark(ACanvas: TCanvas; X1, Y1, X2, Y2: Integer); // solid line as a tick on an axis. - procedure MyDrawDotLine(ACanvas: TCanvas; X1, Y1, X2, Y2: Integer); - - procedure EditXHeader; - procedure EditYScale; - procedure EditHeader; - - procedure SetSolidLines(ACanvas: TCanvas); - procedure SetDotLines(ACanvas: TCanvas); - - procedure SetLineColor(ACanvas: TCanvas; Pen: Integer); - procedure SetRectangleColor(ACanvas: TCanvas; Pen: Integer); - procedure SetFontColor(ACanvas: TCanvas; Pen: Integer); - procedure CountGraphAverage; - procedure DrawPenColorBox(ACanvas: TCanvas; NColor, W, H, X, Y: Integer); - { function GetDefaultColorString(nIndex: Integer): string;}// (rom) not used - procedure MyPiePercentage(X1, Y1, W: Longint; NPercentage: Double); - procedure GraphPieChart(NPen: Integer); - procedure GraphDeltaAverage; - procedure MyPieLegend(NPen: Integer); - procedure ShowMouseMessage(X, Y: Integer); - // marker symbols: - procedure MyPolygon(ACanvas: TCanvas; Points: array of TPoint); - procedure PlotCross(ACanvas: TCanvas; X, Y: Integer); - procedure PlotDiamond(ACanvas: TCanvas; X, Y: Integer); - procedure PlotFilledDiamond(ACanvas: TCanvas; X, Y: Integer); - procedure PlotCircle(ACanvas: TCanvas; X, Y: Integer); - procedure PlotSquare(ACanvas: TCanvas; X, Y: Integer); - - procedure PlotMarker(ACanvas: TCanvas; MarkerKind: TJvChartPenMarkerKind; X, Y: Integer); - // Calls one of the Plot<Shape> functions. - - procedure ClearScreen; - // internal graphics methods - procedure GraphSetup; // These set up variables used for all the rest of the plotting functions - procedure GraphXAxis; - procedure GraphYAxis; - procedure GraphYAxisDivisionMarkers; - 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 - - function GetChartCanvas(isFloating:Boolean): TCanvas; // Get Picture.Bitmap Canvas. - function GetChartCanvasWidth: Integer; //WP NEW 2007 - function GetChartCanvasHeight: Integer; //WP NEW 2007 - - function DestRect: TRect; // from TImage - procedure DesignModePaint; virtual; // Invoked by Paint method when we're in design mode. - procedure Paint; override; // from TImage - procedure Resize; override; // from TControl - procedure Loaded; override; - { draw dummy data for design mode} - procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; - procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; - procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; - - procedure PrimaryYAxisLabels; // Put contents into Options.PrimaryYAxis.YLegends - procedure NotifyOptionsChange; {NEW} - - procedure InternalPlotGraph; { internal version of _PlotGraph that doesn't call Invalidate. } - - { internal drawing properties, valid during Paint method invocations only } - property XOrigin: Double read FXOrigin; {was in TJvChart.PlotGraph} - property YOrigin: Double read FYOrigin; {was in TJvChart.PlotGraph} - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - - // Get the X and Y Value for a particular Mouse location: - function MouseToXValue(X: Integer): Integer; - // convert X pixel mouse position to data index, ie Data.Values[..,<INDEX>]. - function MouseToYValue(Y: Integer): Double; - // convert Y pixel mouse position to value in range Options.PrimaryYAxis.Min to Options.PrimaryYAxis.mAx - - {General procedures for the graph...} - procedure ResetGraphModule; {Call this before totally new values and Pen} - //procedure AutoFormatGraph; {XXX BAD CODE. TO BE DELETED. MAY BE REPLACED LATER BY NEW AutoRange FUNCTION!} - - procedure PlotGraph; {Update screen / draw graph to screen. calls Invalidate. Don't call from inside Paint code!} - - procedure PlotPicture( picture : TPicture; fontScaling:Double ); - - procedure PrintGraph; {Send picture to printer; all printing done by component} - procedure AddGraphToOpenPrintCanvas(XStartPos, YStartPos, GraphWidth, GraphHeight: Longint); - {adds the graph to the "OPEN" printer canvas} - {printing control=outside this component; add other text etc} - procedure GraphToClipboard; {Puts picture on clipboard} - procedure ResizeChartCanvas; {Call this after screen resize and after start up} - procedure PivotData; { Pivot Table. Switches the x values with Pen! Resets AverageLine} - procedure AutoHint; // Make the automatic hint message showing all pens and their values. - procedure SetCursorPosition(Pos: Integer); - procedure DisplayBars; // NEW 2007 - - // FLOATING MARKERS: NEW JAN 2005. -WP - function AddFloatingMarker: TJvChartFloatingMarker; // NEW Jan 2005! - - property FloatingMarker[Index: Integer]: TJvChartFloatingMarker read GetFloatingMarker; // NEW Jan 2005! - property HorizontalBar[Index:Integer]:TJvChartHorizontalBar read GetHorizontalBar; // new 2009 - property VerticalBar[Index:Integer]:TJvChartVerticalBar read GetVerticalBar; // new 2009 - - procedure DeleteFloatingMarker(Index: Integer); // NEW Jan 2005! - - // --NEW 2007 METHOD-- - - procedure DeleteFloatingMarkerObj(Marker: TJvChartFloatingMarker); // NEW 2007 - procedure CopyFloatingMarkers(Source: TJvChart); - procedure ClearFloatingMarkers; - function FloatingMarkerCount: Integer; // NEW 2007 - - function AddHorizontalBar: TJvChartHorizontalBar; // NEW 2007 - procedure ClearHorizontalBars; // NEW 2007 - function HorizontalBarsCount: Integer; // NEW 2007 - - function AddVerticalBar: TJvChartVerticalBar; // NEW 2007 - procedure ClearVerticalBars; // NEW 2007 - function VerticalBarsCount: Integer; // NEW 2007 - - // -- END NEW 2007 METHOD-- - - property Data: TJvChartData read FData; - property AverageData: TJvChartData read FAverageData; - public - {runtime only helper properties} - { TImage-like stuff } - property Picture: TPicture read FPicture; // write SetPicture; - // NEW: Ability to highlight a particular sample by setting the Cursor position! - property CursorPosition: Integer read FCursorPosition write SetCursorPosition; - // procedure DataTests; // TESTING. WAP. - published - { Standard TControl Stuff} - //property Color default clWindow; - property Font; - property Align; - property Anchors; - property BorderSpacing; - property Constraints; - property OnDblClick; { TNotifyEvent from TControl } - property AutoSize; - property DragCursor; - property DragKind; - //property OnKeyDown; // Tried to add this, but it was too hard. -WP APril 2004. - property DragMode; - property Enabled; - property ParentShowHint; - property PopupMenu; - property ShowHint; - property Visible; - { chart options} - property Options: TJvChartOptions read FOptions write FOptions; - { chart events} - - property OnChartClick: TJvChartClickEvent read FOnChartClick write FOnChartClick; - - property OnChartPaint: TJvChartPaintEvent read FOnPaint write FOnPaint; // Chart paint event fixed Sept 2009 - // After chart bitmap is painted onto control surface we can "decorate" it with owner-drawn extras. - - { Drag and Drop of Floating Marker Events - NEW Jan 2005 -WP} - property OnBeginFloatingMarkerDrag: TJvChartFloatingMarkerDragEvent read FOnBeginFloatingMarkerDrag write - FOnBeginFloatingMarkerDrag; // Drag/drop of floating markers beginning. - property OnEndFloatingMarkerDrag: TJvChartFloatingMarkerDragEvent read FOnEndFloatingMarkerDrag write - FOnEndFloatingMarkerDrag; // Drag/drop of floating markers ending. - - { - Chart Margin Click Events - you can click on the four - 'margin' areas (left,right,top,bottom) around the main chart - area. The left and top margins have default behaviours - which you can disable by turning off Options.MouseEdit. - The other 2 margin areas are entirely up to the user to define. - Clicking bottom or right margins does nothing by default. - } - property OnYAxisClick: TJvChartEvent read FOnYAxisClick write FOnYAxisClick; - // When user clicks on Y axis, they can enter a new Y Scale value. - property OnXAxisClick: TJvChartEvent read FOnXAxisClick write FOnXAxisClick; - // Also allow user to define some optional action for clicking on the X axis. - property OnAltYAxisClick: TJvChartEvent read FOnAltYAxisClick write FOnAltYAxisClick; - // Right margin click (Secondary Y Axis labels) - property OnTitleClick: TJvChartEvent read FOnTitleClick write FOnTitleClick; // Top margin area (Title area) click. - end; - - -implementation - -uses - SysUtils, Forms, Dialogs, Printers, Clipbrd, - Math, // uses Ceil routine, also defines IsNaN on Delphi 6 and up. - JvJCLUtils, // StrToFloatDef - JvJVCLUtils, JvResources; - -const - {$IFDEF TJVCHART_ARRAY_OF_ARRAY} - CHART_SANITY_LIMIT = 60000; - {$ELSE} - CHART_SANITY_LIMIT = 12000000; - {$ENDIF TJVCHART_ARRAY_OF_ARRAY} - - // Any attempt to have more than CHART_SANITY_LIMIT elements in this - // graph will be treated as an internal failure on our part. This prevents - // ugly situations where we thrash because of excessive memory usage. - // Better to set this than to have the system pig out when we - // don't want it to. Set this very small when debugging, - // large when releasing component, and don't remove it unless - // you're absolutely sure. Increase it whenever necessary. - // Remember, it's a debugging tool, here on purpose to help keep you - // out of thrashing-virtual-memory-hell. You probably have a screen - // to view the chart that is a maximum of 1600x1200, so more than 1600 - // samples will mean the data should be reduced before charting. - - MAX_VALUES = 20000; - // Any attempt to exceed this values count will cause array size and performance problems, thus we limit it. - MAX_PEN = 100; - // Any attempt to exceed this pen count will cause array size and performance problems, thus we hardcode the pen limit to 100 pens. - DEFAULT_PEN_COUNT = 16; // By Default TJvChartData's internal data structures have room for up to 16 pens - MAX_X_LEGENDS = 50; - MAX_GRAPH_LEGEND_LEN = 9; - REALPREC = 7; - DEFAULT_MARKER_SIZE = 3; - DEFAULT_VALUE_COUNT = 100; - // By Default TJvChartData holds 100 values per pen. Grows autofragellisticexpialidociously. :-) - - X_TITLE_LABEL_DISTANCE = 4; - TITLE_MARGIN = 4; - -// NEW 2007: - - // HELPER FUNCTIONS - NEW 2007 -//-------------------Helper to draw a Gradient. Use it with TJvChartHorizontalBar, for example------------------------- - -procedure GradHorizontal(Canvas: TCanvas; Rect: TRect; FromColor, ToColor: TColor); // NEW 2007 -var - X: Integer; - dr, dg, DB: Extended; - C1, C2: TColor; - r1, r2, g1, g2, b1, b2: Byte; - R, G, B: Byte; - Cnt: Integer; - XDelta: Integer; -begin - C1 := FromColor; - R1 := GetRValue(C1); - G1 := GetGValue(C1); - B1 := GetBValue(C1); - - C2 := ToColor; - R2 := GetRValue(C2); - G2 := GetGValue(C2); - B2 := GetBValue(C2); - - XDelta := Rect.Right - Rect.Left; - if XDelta <= 0 then - Exit; - - dr := (R2 - R1) / XDelta; - dg := (G2 - G1) / XDelta; - DB := (B2 - B1) / XDelta; - - Cnt := 0; - for X := Rect.Left to Rect.Right - 1 do - begin - R := R1 + Ceil(dr * Cnt); // uses Math. - G := G1 + Ceil(dg * Cnt); - B := B1 + Ceil(DB * Cnt); - - Canvas.Pen.Color := RGB(R, G, B); - Canvas.MoveTo(X, Rect.Top); - Canvas.LineTo(X, Rect.Bottom); - Inc(Cnt); - end; -end; - -procedure GradVertical(Canvas: TCanvas; Rect: TRect; FromColor, ToColor: TColor); // NEW 2007 -var - Y: Integer; - dr, dg, DB: Extended; - C1, C2: TColor; - r1, r2, g1, g2, b1, b2: Byte; - R, G, B: Byte; - Cnt: Integer; - YDelta: Integer; -begin - C1 := FromColor; - R1 := GetRValue(C1); - G1 := GetGValue(C1); - B1 := GetBValue(C1); - - C2 := ToColor; - R2 := GetRValue(C2); - G2 := GetGValue(C2); - B2 := GetBValue(C2); - - YDelta := Rect.Bottom - Rect.Top; - if YDelta <= 0 then - Exit; - dr := (R2 - R1) / YDelta; - dg := (G2 - G1) / YDelta; - DB := (B2 - B1) / YDelta; - - Cnt := 0; - for Y := Rect.Top to Rect.Bottom - 1 do - begin - R := R1 + Ceil(dr * Cnt); - G := G1 + Ceil(dg * Cnt); - B := B1 + Ceil(DB * Cnt); - - Canvas.Pen.Color := RGB(R, G, B); - Canvas.MoveTo(Rect.Left, Y); - Canvas.LineTo(Rect.Right, Y); - Inc(Cnt); - end; -end; - -//=== { TJvChartGradientBar } ================================================ - -constructor TJvChartGradientBar.Create(Owner: TJvChart); -begin - inherited Create; - FOwner := Owner; - FVisible := false; - FColor := clWhite; - FGradDirection := grNone; - FGradColor := FColor; - FPenStyle := psClear; - FPenColor := clNone; -end; - -procedure TJvChartGradientBar.SetVisible(AVisible: Boolean); -begin - if AVisible <> FVisible then - begin - FVisible := AVisible; - if Assigned(FOwner) and not FOwner.FUpdating then - FOwner.Invalidate; - end -end; - -procedure TJvChartGradientBar.SetColor(AColor: TColor); -begin - if AColor <> FColor then - begin - FColor := AColor; - if Assigned(FOwner) and not FOwner.FUpdating then - FOwner.Invalidate; - end -end; - -procedure TJvChartGradientBar.SetGradientColor(AColor: TColor); -begin - if AColor <> FGradColor then - begin - FGradColor := AColor; - if Assigned(FOwner) and not FOwner.FUpdating then - FOwner.Invalidate; - end -end; - -procedure TJvChartGradientBar.SetGradientType(AType: TJvChartGradientDirection); -begin - if AType <> FGradDirection then - begin - FGradDirection := AType; - if Assigned(FOwner) and not FOwner.FUpdating then - FOwner.Invalidate; - end -end; - -//=== { TJvChartHorizontalBar } ============================================== - -constructor TJvChartHorizontalBar.Create(Owner: TJvChart); -begin - inherited Create(Owner); - FYTop := 0; - FYBottom := 0; -end; - -//=== { TJvChartVerticalBar } ================================================ - -constructor TJvChartVerticalBar.Create(Owner: TJvChart); -begin - inherited Create(Owner); - FXLeft := 0; - FXRight := 0; -end; - -//=== {TJvChartFloatingMarker} =============================================== - -constructor TJvChartFloatingMarker.Create(Owner: TJvChart); -begin - inherited Create; - FOwner := Owner; - FVisible := False; // NOT visible by default. - FIndex := -1; // not yet set. - FLineToMarker := -1; // Don't draw a line to connect to another marker. - //FYPositionToPen := -1; // Don't copy FYPosition from the pen values. - FMarkerColor := clRed; - FMarker := pmkDiamond; // default is diamond marker. - FLineStyle := psDot; - FLineColor := clBlue; - //FCaptionBorderStyle := psClear; - FXDragMin := -1; // no limit. - FXDragMax := -1; // no limit. - FRawXPosition := -1; - FRawYPosition := -1; - FLineWidth := 1; - //FXPosition := 0; - //FYPosition := 0.0; -end; - -procedure TJvChartFloatingMarker.Assign(Source: TPersistent); // NEW 2007. -var - Src: TJvChartFloatingMarker; -begin - // don't assign FOwner, FIndex, etc. - //FRawXPosition {don't copy} - //FRawYPosition {don't copy} - if Source is TJvChartFloatingMarker then - begin - Src := TJvChartFloatingMarker(Source); - - FCaption := Src.Caption; - FTag := Src.Tag; - - //FYPositionToPen := Src.YPositionToPen; - FMarkerColor := Src.MarkerColor; - FMarker := Src.Marker; - FLineStyle := Src.LineStyle; - FLineColor := Src.LineColor; - //FCaptionBorderStyle := psClear; - FXDragMin := Src.XDragMin; - FXDragMax := Src.XDragMax; - - FLineWidth := Src.LineWidth; - FLineToMarker := Src.LineToMarker; - FLineVertical := Src.LineVertical; - - FCaptionColor := Src.CaptionColor; - FCaptionPosition := Src.CaptionPosition; - FCaptionBoxed := Src.CaptionBoxed; - - {don't use internal property set for these:} - XPosition := Src.XPosition; - YPosition := Src.YPosition; - Visible := Src.Visible; - end; -end; - -procedure TJvChartFloatingMarker.SetCaption(ACaption: string); -begin - if ACaption <> FCaption then - begin - FCaption := ACaption; - if Assigned(FOwner) and FVisible then - if not FOwner.FUpdating then - FOwner.Invalidate; - end; -end; - -procedure TJvChartFloatingMarker.SetCaptionColor(const Value: TColor); -begin - FCaptionColor := Value; -end; - -procedure TJvChartFloatingMarker.SetXPosition(XPos: Integer); // should invalidate the chart (FOwner) if changed. -begin - if XPos <> FXPosition then - begin - FXPosition := XPos; - if Assigned(FOwner) and FVisible then - if not FOwner.FUpdating then - FOwner.Invalidate; - end -end; - -procedure TJvChartFloatingMarker.SetYPosition(YPos: Double); // should invalidate the chart (FOwner) if changed. -begin - if YPos <> FYPosition then - begin - FYPosition := YPos; - if Assigned(FOwner) and FVisible then - if not FOwner.FUpdating then - FOwner.Invalidate; - end -end; - -procedure TJvChartFloatingMarker.SetVisible(AVisible: Boolean); -begin - if AVisible <> FVisible then - begin - FVisible := AVisible; - if Assigned(FOwner) then - if not FOwner.FUpdating then - FOwner.Invalidate; - end -end; - -//=== { TJvChartData } ======================================================= - -constructor TJvChartData.Create; -{$IFDEF TJVCHART_ARRAY_OF_ARRAY} -var - I: Integer; -{$ENDIF TJVCHART_ARRAY_OF_ARRAY} -begin - inherited Create; - FPenCount := DEFAULT_PEN_COUNT; // Can never set less than one inside TJvChartData! - {$IFDEF TJVCHART_ARRAY_OF_ARRAY} - // FPenCount must be valid here: - for I := 0 to DEFAULT_PEN_COUNT do - Grow(I, DEFAULT_VALUE_COUNT); - {$ELSE} - Grow(DEFAULT_PEN_COUNT, DEFAULT_VALUE_COUNT); - {$ENDIF TJVCHART_ARRAY_OF_ARRAY} -end; - -destructor TJvChartData.Destroy; -{$IFDEF TJVCHART_ARRAY_OF_ARRAY} -var - I: Integer; -{$ENDIF TJVCHART_ARRAY_OF_ARRAY} -begin - {$IFDEF TJVCHART_ARRAY_OF_ARRAY} - for I := 0 to FDataAlloc - 1 do - Finalize(FData[I]); - {$ENDIF TJVCHART_ARRAY_OF_ARRAY} - Finalize(FData); // Free array. - inherited Destroy; -end; - -function TJvChartData.GetValue(Pen, ValueIndex: Integer): Double; -{$IFDEF TJVCHART_ARRAY_OF_ARRAY} -begin - Assert(ValueIndex >= 0); - Grow(Pen, ValueIndex); - Result := FData[ValueIndex, Pen]; // This will raise EInvalidOP for NaN values. -end; -{$ELSE} -var - Idx: Integer; -begin - // Grow base array - if (Pen < 0) or (Pen >= FPenCount) then - Result := NaN - else - begin - Assert(FPenCount > 0); - Idx := (ValueIndex * FPenCount) + Pen; - - if (Idx < 0) or (Idx > CHART_SANITY_LIMIT) then // Sanity check! - raise ERangeError.CreateRes(@RsEDataIndexTooLargeProbablyAnInternal); - - if Idx >= Length(FData) then - Grow(Pen, ValueIndex); - Result := FData[Idx]; - end; -end; -{$ENDIF TJVCHART_ARRAY_OF_ARRAY} - -procedure TJvChartData.SetValue(Pen, ValueIndex: Integer; NewValue: Double); -{$IFDEF TJVCHART_ARRAY_OF_ARRAY} -begin - // Grow base array - Grow(Pen, ValueIndex); - FData[ValueIndex, Pen] := NewValue; - if ValueIndex >= FValueCount then - begin - Grow(Pen, ValueIndex + 1); - FData[ValueIndex + 1, Pen] := NewValue; // Workaround for a graphical bug. Sorry. - FValueCount := ValueIndex + 1; - end; -end; -{$ELSE} -var - Idx: Integer; -begin - Assert(FPenCount > 0); - - // Grow base array - if (Pen < 0) or (Pen >= FPenCount) then - raise ERangeError.CreateRes(@RsEPenIndexInvalid); - - Idx := (ValueIndex * FPenCount) + Pen; - - if (Idx < 0) or (Idx > CHART_SANITY_LIMIT) then // Sanity check! - raise ERangeError.CreateRes(@RsEDataIndexTooLargeProbablyAnInternal); - - if Idx >= Length(FData) then - Grow(Pen, ValueIndex); - FData[Idx] := NewValue; - - if ValueIndex >= FValueCount then - FValueCount := ValueIndex + 1; -end; -{$ENDIF TJVCHART_ARRAY_OF_ARRAY} - -function TJvChartData.GetTimestamp(ValueIndex: Integer): TDateTime; -begin - if (ValueIndex < 0) or (ValueIndex >= Length(FTimeStamp)) then - Result := 0.0 // null datetime - else - Result := FTimeStamp[ValueIndex]; -end; - -procedure TJvChartData.SetEndDateTime(const Value: TDateTime); -begin - FEndDateTime := Value; -end; - -procedure TJvChartData.SetStartDateTime(const Value: TDateTime); -begin - FStartDateTime := Value; -end; - -procedure TJvChartData.SetTimestamp(ValueIndex: Integer; AValue: TDateTime); -begin - if ValueIndex < 0 then - Exit; - if ValueIndex >= Length(FTimeStamp) then - SetLength(FTimeStamp, ValueIndex + 1); - FTimeStamp[ValueIndex] := AValue; -end; - -procedure TJvChartData.Scroll; -{$IFDEF TJVCHART_ARRAY_OF_ARRAY} -var - I, J: Integer; -begin - if FValueCount < 2 then - begin - Clear; - Exit; - end; - { ULTRA SLOW BUT NON-CRASHING Version } - for I := 0 to FValueCount - 1 do - begin - for J := 0 to Length(FData[I]) - 1 do - FData[I, J] := FData[I + 1, J]; - SetTimestamp(I, GetTimestamp(I + 1)); - end; - FTimeStamp[FValueCount - 1] := 0; - // Check we didn't Break the heap: -end; -{$ELSE} -var - T: Integer; - Idx: Integer; -begin - if FValueCount > FPenCount then - begin - Assert(FPenCount > 0); - Idx := FValueCount * FPenCount; - - // Yeah, I wish: - //System.Move( {Source} FData[FPenCount], {Dest} FData[0], Idx-FPenCount); - for T := 0 to Idx - FPenCount do - FData[T] := FData[T + FPenCount]; - - for T := Idx - FPenCount to Idx - 1 do - begin - if T > Length(FData) then - Break; - FData[T] := FClearToValue; - end; - //Dec(FValueCount,FPenCount); - end - else - begin - FPenCount := 0; - Clear; - end; -end; -{$ENDIF TJVCHART_ARRAY_OF_ARRAY} - -procedure TJvChartData.PreGrow(Pen, ValueIndex: Integer); -{$IFDEF TJVCHART_ARRAY_OF_ARRAY} -var - T: Integer; -begin - if Length(FData) < ValueIndex then - SetLength(FData, ValueIndex); - for T := 0 to ValueIndex - 1 do - SetLength(FData[T], Pen); - FDataAlloc := ValueIndex; -end; -{$ELSE} -begin - if Pen > FPenCount then - FPenCount := Pen; - Grow(Pen, ValueIndex); - FDataAlloc := ValueIndex; -end; -{$ENDIF TJVCHART_ARRAY_OF_ARRAY} - -{$IFDEF TJVCHART_ARRAY_OF_ARRAY} -procedure TJvChartData.Grow(Pen, ValueIndex: Integer); -var - I, J, OldLength: Integer; -begin - if (Pen < 0) or (ValueIndex < 0) then - raise ERangeError.CreateRes(@RsEDataIndexCannotBeNegative); - if (Pen > CHART_SANITY_LIMIT) or (ValueIndex > CHART_SANITY_LIMIT) then - raise ERangeError.CreateRes(@RsEDataIndexTooLargeProbablyAnInternal); - - if ValueIndex >= FDataAlloc then - begin - //-------------------------------------------------------- - // Performance tweak: Uses more memory but makes JvChart - // much faster! - // We Double our allocation unit size - // until we start to get Really Huge, then grow in chunks! - //-------------------------------------------------------- - if ValueIndex < 640000 then - FDataAlloc := ValueIndex * 2 // Double in size - else - FDataAlloc := ValueIndex + 64000; - - OldLength := Length(FData); - SetLength(FData, FDataAlloc); - - // new: If we set FClearToValue to NaN, special handling in growing arrays: - if IsNaN(FClearToValue) then - for I := OldLength to FDataAlloc - 1 do - for J := 0 to Length(FData[I]) - 1 do - FData[I][J] := FClearToValue; // XXX Debug me! - - end; - if Pen >= Length(FData[ValueIndex]) then - begin - OldLength := Length(FData[ValueIndex]); - SetLength(FData[ValueIndex], Pen + 1); - if IsNaN(FClearToValue) then - begin - for I := OldLength to FDataAlloc - 1 do - begin - Assert(Length(FData) > ValueIndex); - if (Length(FData[ValueIndex]) < FDataAlloc) then - SetLength(FData[ValueIndex], FDataAlloc); // Safety code! - FData[ValueIndex][I] := FClearToValue; // XXX Debug me! - end; - end; - end; -end; -{$ELSE} -procedure TJvChartData.Grow(Pen, ValueIndex: Integer); -var - N, Idx: Integer; - OldLen: Integer; -begin - Assert(Assigned(Self)); - Assert(FPenCount > 0); - Idx := (ValueIndex + 1) * FPenCount; - OldLen := Length(FData); - if Idx >= OldLen then - begin - Idx := Idx + 1024; // Add 1024 floats (8k) headroom. - SetLength(FData, Idx + 1); - for N := OldLen to Idx do - FData[N] := FClearToValue; - end; - FDataAlloc := Length(FData); -end; -{$ENDIF TJVCHART_ARRAY_OF_ARRAY} - -function TJvChartData.DebugStr(ValueIndex: Integer): string; // dump all pens for particular valueindex, as string. -var - S: string; - I: Integer; - LValue: Double; -begin - if (ValueIndex < 0) or (ValueIndex >= FDataAlloc) then - Exit; - - if Timestamp[ValueIndex] > 0.0 then - S := FormatDateTime('hh:nn:ss ', Timestamp[ValueIndex]); - for I := 0 to FPenCount - 1 do - begin - LValue := GetValue(I, ValueIndex); - if IsNaN(LValue) then - S := S + '-' - else - S := S + Format('%5.2f', [LValue]); - - if I < FPenCount - 1 then - S := S + ', ' - end; - Result := S; -end; - -procedure TJvChartData.Clear; // Resets FValuesCount/FPenCount to zero. Zeroes everything too, just for good luck. -{$IFDEF TJVCHART_ARRAY_OF_ARRAY} -var - I, J: Integer; -begin - for I := 0 to FDataAlloc - 1 do - for J := 0 to Length(FData[I]) - 1 do - FData[I, J] := FClearToValue; - FValueCount := 0; -end; -{$ELSE} -var - I: Integer; -begin - for I := 0 to Length(FData) - 1 do - FData[I] := FClearToValue; -end; -{$ENDIF TJVCHART_ARRAY_OF_ARRAY} - -procedure TJvChartData.ClearPenValues; // Clears all pen values to NaN but does not reset pen definitions etc. -{$IFDEF TJVCHART_ARRAY_OF_ARRAY} -var - I, J: Integer; -begin - for I := 0 to FDataAlloc - 1 do - for J := 0 to Length(FData[I]) - 1 do - FData[I, J] := ClearToValue; // 0.0; -end; -{$ELSE} -begin - Clear; -end; -{$ENDIF TJVCHART_ARRAY_OF_ARRAY} - -//=== { TJvChartYAxisOptions } =============================================== - -constructor TJvChartYAxisOptions.Create(Owner: TJvChartOptions); -begin - inherited Create; - FOwner := Owner; - - FMarkerValueDecimals := -1; // -1 = default (automatic decimals) - - FYLegends := TStringList.Create; - FMaxYDivisions := 20; - FMinYDivisions := 5; - FYDivisions := 10; - FDefaultYLegends := JvDefaultYLegends; -end; - -destructor TJvChartYAxisOptions.Destroy; -begin - FYLegends.Free; - inherited Destroy; -end; - -procedure TJvChartYAxisOptions.Clear; -begin - YDivisions := DefaultYLegends; - YLegends.Clear; - Normalize; -end; - - -procedure TJvChartYAxisOptions.Assign(Source:TPersistent);// Warren added sept 2009 -var - src:TJvChartYAxisOptions; -begin - //inherited Assign(Source); //raises exception! - if Source is TJvChartYAxisOptions then begin - src := TJvChartYAxisOptions(Source); - FYLegends.Assign(src.YLegends); - - FMarkerValueDecimals := src.MarkerValueDecimals; - FYDivisions := src.YDivisions; - FMaxYDivisions := src.MaxYDivisions; - FMinYDivisions := src.MinYDivisions; - FYLegendDecimalPlaces:= src.YLegendDecimalPlaces; - FDefaultYLegends := src.DefaultYLegends; - - //FYGap : not copied! - //FYGap1 : not copied! - //FYPixelGap: not copied! - YMin := src.YMin; // always first! - YMax := src.YMax; // property set method calls Normalize! - // Always set YMax last! - - end; -end; - -procedure TJvChartYAxisOptions.Normalize; -var - // CheckYDivisions: Integer; - VC: Integer; -begin - if FYMax - FYMin < 0.00001 then // make sure that there is some difference here! - FYMax := FYMin + 10; - - if (DefaultYLegends > 0) and (YDivisions = 0) then - YDivisions := DefaultYLegends; - - // DON'T KNOW WHY WE NEEDED THIS. REMOVED IT. - (* -if (YGap>0.0) then -begin - CheckYDivisions := Round((YMax + (YGap - 1)) / YGap); - if CheckYDivisions<>YDivisions then - YDivisions :=CheckYDivisions; -end;*) - - VC := YDivisions; - if VC < 1 then - VC := 1; - FYGap := (YMax - YMin) / VC; - FYGap1 := ((YMax - YMin) + 1) / VC; - - YPixelGap := (FOwner.YEnd - 1) / VC; // Vertical Pixels Per Value Division counter. - - (*CheckYDivisions := Round(((YMax-YMin) + (YGap - 1)) / YGap); - if CheckYDivisions <> YDivisions then - YDivisions := CheckYDivisions; *) - - //--------------------------------------------------------------------- - // Here's the normalization section: - // !!!The 10 and 20 here should be properties settable by the user!!! - //--------------------------------------------------------------------- - if YDivisions < MinYDivisions then - begin - YDivisions := MinYDivisions; - FYGap := (YMax - YMin) / YDivisions; - end - else - if YDivisions > MaxYDivisions then - begin - YDivisions := MaxYDivisions; - FYGap := (YMax - YMin) / YDivisions; - end; -end; - -procedure TJvChartYAxisOptions.SetYMin(NewYMin: Double); -begin - if IsNaN(NewYMin) then - Exit; - - try - if NewYMin = FYMin then - Exit; - except - {$IFDEF DEBUGINFO_ON} - OutputDebugString('TJvChartYAxisOptions.SetYMin-WTF?'); - {$ENDIF DEBUGINFO_ON} - Exit; - end; - - FYMin := NewYMin; - - if not Assigned(FOwner) then - Exit; - if not Assigned(FOwner.FOwner) then - Exit; - if csLoading in FOwner.FOwner.ComponentState then - Exit; - - // Rework other values around new YMin: - Normalize; - FOwner.NotifyOptionsChange; - {NEW: Auto-Regenerate Y Axis Labels} - if Assigned(FYLegends) then - if FYLegends.Count > 0 then - begin - FYLegends.Clear; - FOwner.FOwner.PrimaryYAxisLabels; - end; -end; - -procedure TJvChartYAxisOptions.SetYMax(NewYMax: Double); -begin - if IsNaN(NewYMax) then - Exit; - - if NewYMax = FYMax then - Exit; - - FYMax := NewYMax; - - if not Assigned(FOwner) then - Exit; - if not Assigned(FOwner.FOwner) then - Exit; - if csLoading in FOwner.FOwner.ComponentState then - Exit; - - // Rework other values around new YMax: - Normalize; - FOwner.NotifyOptionsChange; - - {NEW: Auto-Regenerate Y Axis Labels} - if Assigned(FYLegends) then - if FYLegends.Count > 0 then - begin - FYLegends.Clear; - FOwner.FOwner.PrimaryYAxisLabels; - end; -end; - -(*procedure TJvChartYAxisOptions.SetYGap(newYgap: Double); -begin - if (FYGap < 5.0) and (YMax>100) then - begin - OutputDebugString('Bug'); - end; - - FYGap := newYGap; - // TODO: Fire event, and cause a refresh, recalculate other - // dependant fields that are calculated from the YGap. - FOwner.NotifyOptionsChange; // Fire event before we auto-format graph. Allows some customization to occur here. -end; - *) - -function TJvChartYAxisOptions.GetYLegends: TStrings; -begin - Result := TStrings(FYLegends); -end; - -procedure TJvChartYAxisOptions.SetYLegends(Value: TStrings); -begin - FYLegends.Assign(Value); - if Assigned(FOwner) then - FOwner.NotifyOptionsChange; // Fire event before we auto-format graph. Allows some customization to occur here. -end; - -procedure TJvChartYAxisOptions.SetYDivisions(AValue: Integer); -begin - FYDivisions := AValue; - - if not Assigned(FOwner) then - Exit; - if not Assigned(FOwner.FOwner) then - Exit; - if csLoading in FOwner.FOwner.ComponentState then - Exit; - - // Rework other values around new YMax: - Normalize; - FOwner.NotifyOptionsChange; -end; - -procedure TJvchartYAxisOptions.SetYPixelGap(AValue: Double); -begin - if FYPixelGap = AValue then exit; - FYPixelGap := AValue; - FOwner.NotifyOptionsChange; -end; - - -//=== { TJvChartOptions } ==================================================== - -constructor TJvChartOptions.Create(Owner: TJvChart); -begin - inherited Create; - FOwner := Owner; - - FAutoUpdateGraph := True; - - FPrimaryYAxis := TJvChartYAxisOptions.Create(Self); - FSecondaryYAxis := TJvChartYAxisOptions.Create(Self); - - FXAxisDivisionMarkers := True; //default property. - FYAxisDivisionMarkers := True; //default property. - - SetLength(FPenColors, 12); - FPenColors[0] := clLime; - FPenColors[1] := clRed; - FPenColors[2] := clBlue; - FPenColors[3] := clYellow; - FPenColors[4] := clMaroon; - FPenColors[5] := clGreen; - FPenColors[6] := clOlive; - FPenColors[7] := clNavy; - FPenColors[8] := clPurple; - FPenColors[9] := clTeal; - FPenColors[10] := clFuchsia; - FPenColors[11] := clAqua; - - FChartKind := ckChartLine; - - FPenCount := 1; - - FLegend := clChartLegendNone; //default Legend is None. - - // Create TStringList property objects - FXLegends := TStringList.Create; - FPenLegends := TStringList.Create; - FPenUnit := TStringList.Create; - // dynamic array setup - SetLength(FAverageValue, DEFAULT_VALUE_COUNT); - - // Defaults for Graph Options: - - FMarkerSize := JvChartDefaultMarkerSize; - FXStartOffset := 45; {DEFAULT} - FYStartOffset := 10; - FTitle := ''; - // FXAxisHeader := 'X'; - // FYAxisHeader := 'Y'; - - FPaperColor := clWhite; - FAxisLineColor := clBlack; - FAverageLineColor := JvDefaultAvgLineColor; - FDivisionLineColor := JvDefaultDivisionLineColor; // NEW! - FShadowColor := JvDefaultShadowColor; //NEW! - FPaperColor := JvDefaultPaperColor; - FHintColor := JvDefaultHintColor; - - FHeaderFont := TFont.Create; - FLegendFont := TFont.Create; - FAxisFont := TFont.Create; - FAxisTitleFont := TFont.Create; - - //FShowLegend := True; - FMouseEdit := True; - FMouseInfo := True; - FLegendWidth := 150; - FPenLineWidth := 1; - FAxisLineWidth := 2; - - FXValueCount := 10; - - FXAxisLegendSkipBy := 1; - FXLegendHoriz := 0; - -end; - -destructor TJvChartOptions.Destroy; -begin - FreeAndNil(FPrimaryYAxis); //memory leak fix SEPT 21, 2004.WAP. - FreeAndNil(FSecondaryYAxis); //memory leak fix SEPT 21, 2004. WAP. - - FreeAndNil(FXLegends); - FreeAndNil(FPenLegends); - FreeAndNil(FPenUnit); - - FreeAndNil(FHeaderFont); - FreeAndNil(FLegendFont); - FreeAndNil(FAxisFont); - FreeAndNil(FAxisTitleFont); - - inherited Destroy; -end; - - -procedure TJvChartOptions.Assign(Source: TPersistent); // Warren added sept 2009 -var - src:TJvChartOptions; - t:Integer; -begin -// inherited Assign(Source); {raises exception!} - if (Source is TJvChartOptions) then begin - src := Source as TJvChartOptions; - - FLegend := src.Legend; - FHeaderFont.Assign(src.HeaderFont); - FLegendFont.Assign(src.LegendFont); - FAxisFont.Assign(src.AxisFont); - FAxisTitleFont.Assign(src.AxisTitleFont); - FPenLegends.Assign(src.PenLegends); - FPenUnit.Assign(src.PenUnit); - FXLegends.Assign(src.XLegends); - - FChartKind := src.ChartKind; - FTitle := src.Title; - FNoDataMessage := src.NoDataMessage; - FYAxisHeader := src.YAxisHeader; - FYAxisDivisionMarkers := src.YAxisDivisionMarkers; - FXAxisDivisionMarkers := src.XAxisDivisionMarkers; - FXAxisHeader := src.XAxisHeader; - - FXLegendMaxTextWidth := src.XLegendMaxTextWidth; - FXAxisValuesPerDivision:= src.XAxisValuesPerDivision; - FXAxisLegendSkipBy := src.XAxisLegendSkipBy; - FXLegendHoriz := src.FXLegendHoriz; - FXAxisLabelAlignment := src.XAxisLabelAlignment; - FXAxisDateTimeMode := src.XAxisDateTimeMode; - FXAxisDateTimeFormat := src.XAxisDateTimeFormat; - FXAxisDateTimeDivision := src.XAxisDateTimeDivision; - FDateTimeFormat := src.DateTimeFormat; - FXValueCount := src.XValueCount; - FPenCount := src.PenCount; - - // Array copies - SetLength(FPenColors, Length(src.FPenColors)); - for t := 0 to Length(FPenColors)-1 do - FPenColors[t] := src.FPenColors[t]; - - SetLength(FPenStyles, Length(src.FPenStyles)); - for t := 0 to Length(FPenStyles)-1 do - FPenStyles[t] := src.FPenStyles[t]; - - SetLength(FPenMarkerKind, Length(src.FPenMarkerKind)); - for t := 0 to Length(FPenMarkerKind)-1 do - FPenMarkerKind[t] := src.FPenMarkerKind[t]; - - SetLength(FPenSecondaryAxisFlag, Length(src.FPenSecondaryAxisFlag)); - for t := 0 to Length(FPenSecondaryAxisFlag)-1 do - FPenSecondaryAxisFlag[t] := src.FPenSecondaryAxisFlag[t]; - - SetLength(FPenValueLabels, Length(src.FPenValueLabels)); - for t := 0 to Length(FPenValueLabels)-1 do - FPenValueLabels[t] := src.FPenValueLabels[t]; - - //SetLength(FAverageValue,Length(src.FAverageValue)); - // no copy of averages! - - FXOrigin := src.XOrigin; - FYOrigin := src.YOrigin; - FXStartOffset := src.XStartOffset; - FYStartOffset := src.YStartOffset; - FXEnd := src.XEnd; - FYEnd := src.YEnd; - FMarkerSize := src.MarkerSize; - { more design time } - FLegendWidth := src.LegendWidth; - FLegendRowCount := src.LegendRowCount; - FAutoUpdateGraph := src.AutoUpdateGraph; - FMouseEdit := src.MouseEdit; - FMouseDragObjects := src.MouseDragObjects; - FMouseInfo := src.MouseInfo; - - FPenLineWidth := src.PenLineWidth; - FAxisLineWidth := src.AxisLineWidth; - - //COLORS: - FPaperColor := src.PaperColor; - FDivisionLineColor := src.DivisionLineColor; - FShadowColor := src.ShadowColor; - FAxisLineColor := src.AxisLineColor; - FHintColor := src.HintColor; - FAverageLineColor := src.AverageLineColor; - FCursorColor := src.CursorColor; - - FCursorStyle := src.CursorStyle; - FGradientColor := src.GradientColor; - FGradientDirection := src.GradientDirection; - - // more internal dynamically calculated stuff: - //FXAxisDateTimeFirstMarker not copied - //FXAxisDateTimeSkipBy not copied - //FXAxisDateTimeLines not copied - //FXGap,FYGap: not copied. - - - - // Second last: - FSecondaryYAxis.Assign(src.SecondaryYAxis); - - // Last! - FPrimaryYAxis.Assign(src.PrimaryYAxis); - - // re-plot chart: - NotifyOptionsChange; - end; - -end; -procedure TJvChartOptions.NotifyOptionsChange; -begin - if Assigned(FOwner) then - FOwner.NotifyOptionsChange; -end; - -// Each pen can be associated with either the primary or secondary axis, -// this function decides which axis to return depending on the pen configuration: - -function TJvChartOptions.GetPenAxis(Index: Integer): TJvChartYAxisOptions; -begin - if (Index < 0) or (Index >= Length(FPenSecondaryAxisFlag)) then - Result := FPrimaryYAxis // default - else - if FPenSecondaryAxisFlag[Index] then - Result := FSecondaryYAxis // alternate! - else - Result := FPrimaryYAxis; // default -end; - -function TJvChartOptions.GetPenMarkerKind(Index: Integer): TJvChartPenMarkerKind; -begin - if (Index >= 0) and (Index < Length(FPenMarkerKind)) then - Result := FPenMarkerKind[Index] - else - Result := pmkNone; -end; - -function TJvChartOptions.GetPenColor(Index: Integer): TColor; -begin - // Don't check for out of range values, since we use that on purpose in this - // function. Okay, ugly, but it works. -WP. - case Index of - jvChartAverageLineColorIndex: - Result := FAverageLineColor; - jvChartDivisionLineColorIndex: // horizontal and vertical division line color - Result := FDivisionLineColor; - jvChartShadowColorIndex: // legend shadow (light gray) - Result := FShadowColor; - jvChartAxisColorIndex: - Result := FAxisLineColor; // get property. - jvChartHintColorIndex: - Result := FHintColor; // Get property. - jvChartPaperColorIndex: - Result := FPaperColor; // Get property. - else - if Index < jvChartAverageLineColorIndex then - Result := clBtnFace - else - if Index >= 0 then - Result := FPenColors[Index] - else - Result := clNone; // I hope clNone is a good unknown value (ahuser). {{Good enough. -WP.}} - end; -end; - -function TJvChartOptions.GetPenStyle(Index: Integer): TPenStyle; -begin - if (Index >= 0) and (Index < Length(FPenStyles)) then - Result := FPenStyles[Index] - else - Result := psSolid; -end; - -function TJvChartOptions.GetAverageValue(Index: Integer): Double; -begin - if Index < 0 then - raise ERangeError.CreateRes(@RsEGetAverageValueIndexNegative); - if Index >= Length(FAverageValue) then - Result := 0.0 - else - Result := FAverageValue[Index]; -end; - -procedure TJvChartOptions.SetAverageValue(Index: Integer; AValue: Double); -begin - if Index < 0 then - raise ERangeError.CreateRes(@RsESetAverageValueIndexNegative); - if Index >= Length(FAverageValue) then - SetLength(FAverageValue, Index + 1); - FAverageValue[Index] := AValue; -end; - -function TJvChartOptions.GetPenSecondaryAxisFlag(Index: Integer): Boolean; -begin - if (Index < 0) or (Index >= Length(FPenSecondaryAxisFlag)) then - Result := False - else - Result := FPenSecondaryAxisFlag[Index]; -end; - -procedure TJvChartOptions.SetPenSecondaryAxisFlag(Index: Integer; NewValue: Boolean); -begin - if (Index < 0) or (Index >= MAX_PEN) then - raise ERangeError.CreateRes(@RsEChartOptionsPenCountPenCountOutOf); - if Index >= Length(FPenSecondaryAxisFlag) then - SetLength(FPenSecondaryAxisFlag, Index + 1); - FPenSecondaryAxisFlag[Index] := NewValue; - NotifyOptionsChange; -end; - -function TJvChartOptions.GetPenValueLabels(Index: Integer): Boolean; -begin - if (Index < 0) or (Index >= Length(FPenValueLabels)) then - Result := False - else - Result := FPenValueLabels[Index]; -end; - -procedure TJvChartOptions.SetPenValueLabels(Index: Integer; NewValue: Boolean); -begin - if (Index < 0) or (Index >= MAX_PEN) then - raise ERangeError.CreateRes(@RsEChartOptionsPenCountPenCountOutOf); - - if Index >= Length(FPenValueLabels) then - SetLength(FPenValueLabels, Index + 1); - FPenValueLabels[Index] := NewValue; -end; - -procedure TJvChartOptions.SetPenCount(Count: Integer); -begin - if (Count < 0) or (Count >= MAX_PEN) then - raise ERangeError.CreateRes(@RsEChartOptionsPenCountPenCountOutOf); - FPenCount := Count; - SetLength(FPenSecondaryAxisFlag, FPenCount + 1); - // notify data object: - NotifyOptionsChange; -end; - -function TJvChartOptions.GetPenLegends: TStrings; -begin - Result := TStrings(FPenLegends); -end; - -function TJvChartOptions.GetPenUnit: TStrings; -begin - Result := TStrings(FPenUnit); -end; - -procedure TJvChartOptions.SetPenUnit(Value: TStrings); -begin - FPenUnit.Assign(Value); -end; - -function TJvChartOptions.GetXLegends: TStrings; -begin - Result := TStrings(FXLegends); -end; - -procedure TJvChartOptions.SetAxisLineWidth(const Value: Integer); -begin - if FAxisLineWidth <> Value then - begin - FAxisLineWidth := Value; - NotifyOptionsChange; - end; -end; - -procedure TJvChartOptions.SetAxisTitleFont(const Value: TFont); -begin - FAxisTitleFont.Assign(Value); - NotifyOptionsChange; -end; - -procedure TJvChartOptions.SetChartKind(AKind: TJvChartKind); -begin - if AKind <> FChartKind then - begin - FChartKind := AKind; - NotifyOptionsChange; - end; -end; - -procedure TJvChartOptions.SetDivisionLinecolor(const AColor: TColor); -begin - if FDivisionLineColor <> AColor then - begin - FDivisionLineColor := AColor; - NotifyOptionsChange; - end; -end; - -procedure TJvChartOptions.SetFillUnderLine(const AValue: Boolean); -begin - if FFillUnderLine <> AValue then - begin - FFillUnderLine := AValue; - NotifyOptionsChange; - end; -end; - -procedure TJvChartOptions.SetLegend(const ALegend: TJvChartLegend); -begin - if FLegend <> ALegend then - begin - FLegend := ALegend; - NotifyOptionsChange; - end; -end; - -procedure TJvChartOptions.SetMarkerSize(const Value: Integer); -begin - if FMarkerSize <> Value then - begin - FMarkerSize := Value; - NotifyOptionsChange; - end; -end; - -procedure TJvChartOptions.SetPaperColor(const AColor: TColor); -begin - if AColor <> FPaperColor then - begin - FPaperColor := AColor; - NotifyOptionsChange; - end; -end; - -procedure TJvChartOptions.SetPenColor(Index: Integer; AColor: TColor); -begin - if (Index < 0) or (Index >= MAX_PEN) then - raise ERangeError.CreateRes(@RsEChartOptionsPenCountPenCountOutOf); - - if Index >= Length(FPenColors) then - SetLength(FPenColors, Index + 1); - - FPenColors[Index] := AColor; - NotifyOptionsChange; -end; - -procedure TJvChartOptions.SetPenLegends(Value: TStrings); -begin - FPenLegends.Assign(Value); - NotifyOptionsChange; -end; - -procedure TJvChartOptions.SetPenLineWidth(const Value: Integer); -begin - if FPenLineWidth <> Value then - begin - FPenLineWidth := Value; - NotifyOptionsChange; - end; -end; - -procedure TJvChartOptions.SetPenMarkerKind(Index: Integer; AMarkKind: TJvChartPenMarkerKind); -begin - if Index >= 0 then - begin - if Index >= Length(FPenMarkerKind) then - SetLength(FPenMarkerKind, Index + 1); - FPenMarkerKind[Index] := AMarkKind; - NotifyOptionsChange; - end; -end; - -procedure TJvChartOptions.SetPenStyle(Index: Integer; APenStyle: TPenStyle); -begin - if (Index < 0) or (Index >= MAX_PEN) then - raise ERangeError.CreateRes(@RsEChartOptionsPenCountPenCountOutOf); - - if Index >= Length(FPenStyles) then - SetLength(FPenStyles, Index + 1); - FPenStyles[Index] := APenStyle; - NotifyOptionsChange; -end; - -procedure TJvChartOptions.SetShadowColor(const AColor: TColor); -begin - if FShadowColor <> AColor then - begin - FShadowColor := AColor; - NotifyOptionsChange; - end; -end; - -procedure TJvchartOptions.SetTitle(const Value: String); -begin - if FTitle <> Value then - begin - FTitle := Value; - NotifyOptionsChange; - end; -end; - -procedure TJvChartOptions.SetXAxisDateTimeDivision(const Value: Double); -begin - FXAxisDateTimeDivision := Value; -end; - -procedure TJvChartOptions.SetXAxisHeader(const Value: String); -begin - if FXAxisHeader <> Value then - begin - FXAxisHeader := Value; - NotifyOptionsChange; - end; -end; - -procedure TJvChartOptions.SetXLegends(Value: TStrings); -begin - FXLegends.Assign(Value); -end; - -procedure TJvChartOptions.SetYAxisHeader(const Value: String); -begin - if FYAxisHeader <> Value then - begin - FYAxisHeader := Value; - NotifyOptionsChange; - end; -end; - -procedure TJvChartOptions.SetHeaderFont(AFont: TFont); -begin - FHeaderFont.Assign(AFont); -end; - -procedure TJvChartOptions.SetLegendFont(AFont: TFont); -begin - FLegendFont.Assign(AFont); -end; - -procedure TJvChartOptions.SetAxisFont(AFont: TFont); -begin - FAxisFont.Assign(AFont); -end; - -procedure TJvChartOptions.SetPrimaryYAxis(AssignFrom: TJvChartYAxisOptions); -begin - FPrimaryYAxis.Assign(AssignFrom); -end; - -procedure TJvChartOptions.SetSecondaryYAxis(AssignFrom: TJvChartYAxisOptions); -begin - FSecondaryYAxis.Assign(AssignFrom); -end; - -procedure TJvChartOptions.SetXStartOffset(Offset: Integer); -begin - if FXStartOffset <> Offset then - begin - FXStartOffset := Offset; - NotifyOptionsChange; - end; -end; - -procedure TJvChartOptions.SetYStartOffset(Offset: Integer); -begin - if FYStartOffset <> Offset then - begin - FYStartOffset := Offset; - if Assigned(FOwner) then FOwner.CalcYEnd; - NotifyOptionsChange; - end; -end; - - -//=== { TJvChart } =========================================================== - -{ GRAPH } -{**************************************************************************} -{ call this function : NEVER! } -{**************************************************************************} - -constructor TJvChart.Create(AOwner: TComponent); -begin - inherited Create(AOwner); {by TImage...} - - ControlStyle := ControlStyle + [csOpaque]; - // XXX FLICKER REDUCTION: Set ControlStyle properly. -WP. APRIL 2004. - - FPicture := TPicture.Create; - - FCursorPosition := -1; // Invisible until CursorPosition is set >=0 to make it visible. - - FMouseDownHintStrs := TStringList.Create; - - { logical font used for rotating text to show vertical labels } - - FData := TJvChartData.Create; - FAverageData := TJvChartData.Create; - - FFloatingMarker := TObjectList.Create; // NEW: collection of TJvChartFloatingMarker objects. - FFloatingMarker.OwnsObjects := True; - - FHorizontalBars := TObjectList.Create; // NEW: collection of TJvChartFloatingMarker objects. - FHorizontalBars.OwnsObjects := True; - - FVerticalBars := TObjectList.Create; // NEW: collection of TJvChartFloatingMarker objects. - FVerticalBars.OwnsObjects := True; - - FOptions := TJvChartOptions.Create(Self); - CalcYEnd; - - PrintInSession := False; - - FOldYGap := 1; - FOldYOrigin := 0; - FStartDrag := False; - FMouseLegend := False; - FContainsNegative := False; - FMouseValue := 0; - FMousePen := 0; - - {Set default values for component fields...} - - if csDesigning in ComponentState then - begin - // default height and width - if not Assigned(Parent) then - begin - Width := 300; - Height := 300; - end; - end; -end; - -{**************************************************************************} -{ call this function : NEVER! } -{**************************************************************************} - -destructor TJvChart.Destroy; -begin - {Add code for destroying my own data...here} - FBitmap.Free; - { - if Ord(FYFontHandle) <> 0 then - DeleteObject(FYFontHandle); // vertical font object - FreeAndNil(FYFont); - } - FreeAndNil(FPicture); - FreeAndNil(FAverageData); - FreeAndNil(FOptions); - FreeAndNil(FData); - - FreeAndNil(FFloatingMarker); // Destroy collection of TJvChartFloatingMarker objects. Destroys contained objects also. - FreeAndNil(FHorizontalBars); // NEW 2007 - FreeAndNil(FVerticalBars); // NEW 2007 - - FreeAndNil(FMouseDownHintStrs); //new. - - inherited Destroy; -end; - -{Paint helper} - -function TJvChart.DestRect: TRect; -begin - Result.Left := 0; - Result.Top := 0; - Result.Right := GetChartCanvasWidth; - Result.Bottom := GetChartCanvasHeight; -end; - -procedure TJvChart.Loaded; -begin - inherited Loaded; - ResizeChartCanvas; -end; - -procedure TJvChart.Resize; -begin - inherited Resize; - ResizeChartCanvas; - // Invalidate already happens in ResizeChartCanvas. -end; - -{ PAINT } - -procedure TJvChart.DesignModePaint; -var - DesignStr: string; - TW, TH: Integer; - LCanvas: TCanvas; -begin - LCanvas := GetChartCanvas(false); - - LCanvas.Brush.Color := Options.PaperColor; - LCanvas.Rectangle(0, 0, Width, Height); - - DesignStr := ClassName + RsChartDesigntimeLabel; - - if Options.PrimaryYAxis.YMin >= Options.PrimaryYAxis.YMax then - begin - if Options.PrimaryYAxis.YMax > 0 then - Options.PrimaryYAxis.YMin := 0.0; - end; - - if (Abs(Options.PrimaryYAxis.YMax) < 0.000001) and (Abs(Options.PrimaryYAxis.YMin) < 0.000001) then - Options.PrimaryYAxis.YMax := 10.0; // Reasonable non-zero default, so that charting works! - - Options.PrimaryYAxis.Normalize; - Options.SecondaryYAxis.Normalize; - GraphSetup; - - DrawGradient; - DisplayBars; - - PrimaryYAxisLabels; - GraphXAxis; - GraphXAxisDivisionMarkers; - GraphYAxis; - GraphYAxisDivisionMarkers; - - { designtime component label } - TW := LCanvas.TextWidth(DesignStr); - TH := LCanvas.TextHeight(DesignStr); - - LCanvas.Brush.Color := Options.PaperColor; - LCanvas.Pen.Color := Color; - - //ACanvas.Pen.Style := psDot; - //ACanvas.Rectangle( (width div 2) - (TW div 2), (height div 2) - (TH div 2), TW, TH); - if (TW < Width) and (TH < Height) then - LCanvas.TextOut((Width div 2) - (TW div 2), (Height div 2) - (TH div 2), DesignStr); -end; - -procedure TJvChart.Paint; { based on TImage.Paint } -begin - if csDesigning in ComponentState then - begin - DesignModePaint; - Exit; - end; - - if Options.AutoUpdateGraph and not FAutoPlotDone then - begin - FAutoPlotDone := True; - PlotGraph; // Makes sure something is visible in the TPicture. - end; - - Assert(Assigned(FPicture)); - //inherited ACanvas.Lock; - inherited Canvas.StretchDraw(DestRect, Picture.Graphic); - - // New: Draw custom moveable markers on TOP of base data pen layer: - DrawFloatingMarkers; - - // Draw cursor (vertical dotted line) if present: - if (FCursorPosition >= 0) and (FCursorPosition <= Options.XValueCount) then - PaintCursor; - - // Allow end-user to custom paint on the Chart chanvas: - if Assigned(FOnPaint) then - FOnPaint(Self, Canvas); -end; - -// Draw an oscilliscope-like cursor over the place where the current sample is in the chart. -// This is very handy when you want to associate your table, grid, or other data source, -// with the chart, and highlight one row in the chart. - -procedure TJvChart.PaintCursor; -var - X: Integer; - XPixelGap: Double; -begin - with inherited Canvas do - begin - Pen.Color := Options.CursorColor; - Pen.Style := Options.CursorStyle; - - XPixelGap := ((Options.XEnd - 2) - Options.XStartOffset) / (Options.XValueCount - 1); - - X := Round(Options.XStartOffset + XPixelGap * FCursorPosition); - - // Vertical line along X position: - MoveTo(X, Options.YStartOffset); - LineTo(X, FXAxisPosition - 1); - end; -end; - -{device independent functions... no checking for printer / screen needed} - -{**************************************************************************} -{ call this function : } -{ a) before setting totally new values to the graph } -{ b) note that any custom strings in the PrimaryYAxis.Legends or } -{ SecondaryYAxis.Legends are CLEARED by this function. } -{**************************************************************************} - -procedure TJvChart.ResetGraphModule; -begin - Data.Clear; - - FPlotGraphCalled := False; - FContainsNegative := False; - Options.Title := ''; - Options.PenCount := 1; - Options.XValueCount := 0; - - Options.PrimaryYAxis.Clear; - Options.SecondaryYAxis.Clear; - - Options.XOrigin := 0; - Options.YOrigin := 0; - Options.XGap := 1; - - Options.PenLegends.Clear; - - (* for I := 0 to MAX_VALUES-1 do - begin - Options.AverageValue[I] := 0; - end; *) - - Data.Clear; - AverageData.Clear; - - Options.XLegends.Clear; -end; - -procedure TJvChart.PrimaryYAxisLabels; -var - I, J: Integer; - YDivision: Double; - FormatStr, YDivisionStr, PrevYDivisionStr: string; - // left hand side, vertically ascending labels for scale of Y values. - Decimals: Integer; - Unique: Boolean; -begin - Decimals := Options.PrimaryYAxis.YLegendDecimalPlaces; - Unique := False; { Add Decimals until we get unique values } - while not Unique do - begin - Unique := True; - PrevYDivisionStr := ''; - Options.PrimaryYAxis.YLegends.Clear; - FormatStr := '0.0'; - for J := 2 to Decimals do - FormatStr := FormatStr + '0'; - for I := 0 to Options.PrimaryYAxis.YDivisions do // NOTE! Don't make this YDivisions-1 That'd be bad! !!!! - begin - YDivision := Options.PrimaryYAxis.YMin + (I * Options.PrimaryYAxis.YGap); - if Decimals <= 0 then - YDivisionStr := IntToStr(Round(YDivision)) // Whole Numbers Only. - else - YDivisionStr := FormatFloat(FormatStr, YDivision); // Variable Decimals - if (PrevYDivisionStr = YDivisionStr) and (Decimals < 5) then - begin - Inc(Decimals); - Unique := False; // Force repeat - Break; // Exit for loop. - end; - Options.PrimaryYAxis.YLegends.Add(YDivisionStr); - PrevYDivisionStr := YDivisionStr; - end; - end; -end; - -{ Setup Graph Formatting Properties - - *** AutoFormatGraph CONSIDERED HARMFUL. REMOVED. *** - This procedure does nothing helpful, and will be removed from CVS soon. - What it *does* do is wildly screw up plotting of graphs with negative - values in it. - -Wpostma. -} - -(* XXXX BAD CODE. TO BE DELETED SOON. Wpostma. -procedure TJvChart.AutoFormatGraph; -var - V, NYMax, NYMin: Double; -// NPen: Longint; - I, J: Integer; -// calcYGap: Double; // not used (ahuser) - ATextWidth, SkipBy, MaxFit: Integer; -begin - // nMaxXValue := 0; - // NPen := 0; - Options.PrimaryYAxis.Normalize; - Options.SecondaryYAxis.Normalize; - - {Set graph type according to component property} - - if Options.PrimaryYAxis.YMax <= Options.PrimaryYAxis.YMin then - begin - {Analyse graph for max and min values...} - NYMax := Low(Integer); - NYMin := High(Integer); - for I := 0 to Data.ValueCount - 1 do - begin - for J := 0 to Options.PenCount - 1 do - begin - if Options.PenAxis[J] <> Options.PrimaryYAxis then - Continue; // XXX !!! AUTO SCALING ONLY ON PRIMARY AXIS, FOR NOW. !!! - - V := FData.Value[J, I]; - - if IsNaN(V) then - Continue; - if NYMin > V then - NYMin := V; - //if (I>nMaxXValue) and (FData.Value[J,I]<>0) then - //nMaxXValue := I; - //if (J>NPen) and (FData.Value[J,I]<>0) then - // NPen := J; - if NYMax < FData.Value[J, I] then - NYMax := FData.Value[J, I]; - end; - if (NYMin > 0) and (Options.PrimaryYAxis.YMin = 0) then - NYMin := 0; - end; - // Round up YMax so it's got some zeros after it: - if NYMax > 5000 then - NYMax := Trunc(Trunc(NYMax + 499) / 500) * 500 - else - if NYMax > 1000 then - NYMax := Trunc(Trunc(NYMax + 99) / 100) * 100 - else - if NYMax > 10 then - NYMax := Trunc(Trunc(NYMax + 9) / 10) * 10; - - // And now the really bad hack: - Options.PrimaryYAxis.SetYMax(0); - Options.PrimaryYAxis.SetYMax(NYMax); - end - else - begin - // !!!!!!!!!!!!! WARNING WARNING WARNING !!!!!!!!!!!!!!!!!!!! - // The following line has been commented out because it triggers - // a warning because NYMax is not used anywhere after the - // setting of its value - //NYMax := Options.PrimaryYAxis.YMax; - - NYMin := Options.PrimaryYAxis.YMin; - end; - - // And some negative handling crap. - FContainsNegative := False; - if NYMin < 0 then - begin - FContainsNegative := True; - -// if Options.PrimaryYAxis.DefaultYLegends>0 then -// Options.PrimaryYAxis.Normalize -// else -// Options.PrimaryYAxis.YGap := 1; - -// if Options.PrimaryYAxis.YGap <= 0 then {* XXX WORKAROUND A BUG. Better to have bad looking data than divide by zero exceptions. XXX *} -// Options.PrimaryYAxis.YGap := 0.00001; - - Options.ChartKind := ckChartLine; - Options.YOrigin := Round(-NYMin / Options.PrimaryYAxis.YGap); - end; - - if Options.PrimaryYAxis.YDivisions = 0 then - Options.PrimaryYAxis.YDivisions := 1; - - //Options.PenCount := NPen; - if Options.XValueCount < Data.ValueCount then - Options.XValueCount := Data.ValueCount; - -//XXX if Options.PrimaryYAxis.YDivisions < 3 then -// Options.PrimaryYAxis.YDivisions := 3; // some labels - - // Primary Y Axis Labels. This version only supports 0,1,2 decimal places. - PrimaryYAxisLabels; - - // XXX TODO: Draw secondary Y Axis labels, if enabled! - - // if we put too many labels on the bottom X axis, they crowd or overlap, - // so this prevents that: - - for I := 0 to Options.XLegends.Count - 1 do - begin - ATextWidth := ChartCanvas.TextWidth(Options.XLegends[I]) + 10; - - if ATextWidth > Options.XLegendMaxTextWidth then - Options.XLegendMaxTextWidth := ATextWidth; - end; - if Options.XLegendMaxTextWidth < 20 then - Options.XLegendMaxTextWidth := 20; - - MaxFit := ((Width - (Options.XStartOffset * 2)) div - (Options.XLegendMaxTextWidth + (Options.XLegendMaxTextWidth div 4))); - if MaxFit < 1 then - MaxFit := 1; - - SkipBy := Data.ValueCount div MaxFit; - if SkipBy < 1 then - SkipBy := 1; - //if SkipBy > Options.XAxisLegendSkipBy then - Options.XAxisLegendSkipBy := SkipBy; - - // Now do the graphing. - CountGraphAverage; - - PlotGraph; -end; - XXX BAD CODE. READ WARNING ABOVE. -*) - -procedure TJvChart.CountGraphAverage; -var - I, J: Integer; -begin - if Options.ChartKind = ckChartLine then - Exit; // no average needed. - - for I := 0 to Data.ValueCount - 1 do - begin - Options.AverageValue[I] := 0; - for J := 0 to MAX_PEN - 1 do - Options.AverageValue[I] := Options.AverageValue[I] + FData.Value[J, I]; - if Options.PenCount = 0 then - Options.AverageValue[I] := 0 - else - Options.AverageValue[I] := Options.AverageValue[I] / Options.PenCount; - end; -end; - -// These set up variables used for all the rest of the plotting functions. - -procedure TJvChart.GraphSetup; -var - X1, X2, Y1, Y2, PYVC, VC: Integer; - ACanvas: TCanvas; -begin - ACanvas := GetChartCanvas(false); - - ACanvas.Brush.Style := bsSolid; - if FData.ValueCount > 0 then - Options.XValueCount := FData.ValueCount; - - { Get X value count } - VC := Options.XValueCount; - if VC < 1 then - VC := 1; - - { Get Y value count. First normalize. } - Options.PrimaryYAxis.Normalize; - Options.SecondaryYAxis.Normalize; - PYVC := Options.PrimaryYAxis.YDivisions; - if PYVC < 1 then - PYVC := 1; - - Options.XPixelGap := ((Options.XEnd - 1) - Options.XStartOffset) / VC; - - FXOrigin := Options.XStartOffset + Options.XPixelGap * (Options.XOrigin); - FYOrigin := Options.YStartOffset + Round(Options.PrimaryYAxis.YPixelGap * PYVC); - - ACanvas.Brush.Style := bsClear; - - { NEW: Box around entire chart area. } - if Options.AxisLineWidth <> 0 then - begin - X1 := Round(XOrigin); - X2 := Round(Options.XStartOffset + Options.XPixelGap * VC); - Y1 := Options.YStartOffset - 1; - Y2 := Round(YOrigin) + 1; // was YTempOrigin - - if Y2 > Height then - begin - // I suspect that the value of YPixelGap is too large in some cases. - Options.PrimaryYAxis.Normalize; - //OutputDebugString( PChar('Y2 is bogus. PYVC='+IntToStr(PYVC)) ); - end; - MyRectangle(ACanvas, X1, Y1, X2, Y2); - end; - - ACanvas.Brush.Style := bsSolid; -end; - -// internal methods - -procedure TJvChart.GraphYAxis; -var - ACanvas: TCanvas; -begin - if Options.AxisLineWidth = 0 then - Exit; - - ACanvas := GetChartCanvas(false); - ACanvas.Pen.Style := psSolid; - ACanvas.Pen.Color := Options.AxisLineColor; - ACanvas.MoveTo(Round(XOrigin), Options.YStartOffset); - MyAxisLineTo(ACanvas, Round(XOrigin), - Round((Options.YStartOffset - 1) + - Options.PrimaryYAxis.YPixelGap * (Options.PrimaryYAxis.YDivisions))); -end; - -// internal methods - -procedure TJvChart.GraphXAxis; -var - LCanvas: TCanvas; -begin - if Options.AxisLineWidth = 0 then - Exit; - - LCanvas := GetChartCanvas(false); - LCanvas.Pen.Style := psSolid; - LCanvas.Pen.Color := Options.AxisLineColor; - LCanvas.Pen.Width := Options.AxisLineWidth; // was missing. Added Feb 2005. -WPostma. - FXAxisPosition := Options.YStartOffset + Round(Options.PrimaryYAxis.YPixelGap * (Options.PrimaryYAxis.YDivisions)); - - {Draw X-axis} - LCanvas.MoveTo(Options.XStartOffset, FXAxisPosition); - MyAxisLineTo(LCanvas, Round(Options.XStartOffset + Options.XPixelGap * Options.XValueCount), FXAxisPosition); -end; - -procedure TJvChart.GraphXAxisDivisionMarkers; // new. -var - I, X: Integer; - Lines: Integer; - LCanvas: TCanvas; - // these are used only in special XAxisDateTimeMode: - TimePerXValue: Double; - ElapsedTime: Double; -begin - if not Enabled then - Exit; - if Options.XValueCount <= 0 then // NOT VISIBLE WHEN NO VALUES TO SHOW. NEW 2007 - Exit; - if Options.XStartOffset <= 0 then // NOT VISIBLE WHEN NO ROOM TO SHOW IT. NEW 2007 - Exit; - - LCanvas := GetChartCanvas(false); - - if not Options.XAxisDivisionMarkers then - Exit; - if Options.XAxisValuesPerDivision <= 0 then - Exit; - - //XAxisDateTimeMode: [NEW 2007] - // Make charts with XAxis divisions synchronized - // to some regular time division such as hourly periods. - // - // new mode! when looking at date/time charts - // it's useful to be able to force the divisions to be - // shown at hourly intervals, or if you're looking at a month of data - // perhaps you might want to plot a division marker at midnight - // or at weekly intervals. - // - if (Options.XAxisDateTimeMode) and - (Options.XAxisDateTimeDivision > 0.000000001) and - (FData.EndDateTime > FData.StartDateTime) then - begin - - // How much time goes by in this chart? ( 1.0 = one day) - ElapsedTime := FData.EndDateTime - FData.StartDateTime; - - // How far apart the bars are spaced is determined by - // XAxisDateTimeDivision. - // if we plot one day of values, and we want a marker every - // hour, we want XAxisDateTimeDivision=(1.0/24). - - // Given the elapsed time in this chart, how many divisions - // should we be showing? - Options.FXAxisDateTimeLines := Round(ElapsedTime / Options.XAxisDateTimeDivision); - if (Options.FXAxisDateTimeLines < 0) or (Options.FXAxisDateTimeLines > 10000) then // sanity check! - Exit; - - // this value is to help us figure out how much time goes by - // for each time we go from one X value to the next one. - TimePerXValue := ElapsedTime / Options.XValueCount; - - // figure out how many divisions to move over for firstMarker - // given TimePerXValue (1.0=one day) and StartDateTime and - // XAxisDateTimeDivision. - Options.FXAxisDateTimeFirstMarker := 0; - // If XAxisDateTimeDivion=1.0, and TimePerXValue=0.25, then - // we want a division marker for every 4th value - Options.FXaxisDateTimeSkipBy := Round(Options.XAxisDateTimeDivision / TimePerXValue); - - for I := 0 to Options.FXAxisDateTimeLines - 1 do - begin - X := Round(Options.XStartOffset + (Options.XPixelGap * I * Options.FXaxisDateTimeSkipBy)) + - Options.FXAxisDateTimeFirstMarker; - if X > Options.XEnd then - Break; - // don't draw dotted line right at X Axis. - if X <> Options.XStartOffset then - begin - LCanvas.Pen.Color := Options.GetPenColor(jvChartDivisionLineColorIndex); - MyDrawDotLine(LCanvas, X, Options.YStartOffset + 1, X, FXAxisPosition - 1); - end; - end; - - // Note: datetime labels aren't drawn yet, they are drawn later, - // see local procedure XAxisDateTimeModeLabels2 inside - // GraphXAxisLegend, for the printing of the datetime labels! - - Exit; // done! - end; // END OF NEW CODE IN 2007 FOR THIS METHOD. -WP- - - Lines := (((Options.XValueCount + (Options.XAxisValuesPerDivision div 2)) div Options.XAxisValuesPerDivision)) - 1; - - for I := 1 to Lines do - begin - X := Round(Options.XStartOffset + Options.XPixelGap * I * Options.XAxisValuesPerDivision); - LCanvas.Pen.Color := Options.GetPenColor(jvChartDivisionLineColorIndex); - MyDrawDotLine(LCanvas, X, Options.YStartOffset + 1, X, FXAxisPosition - 1); - end; -end; - -procedure TJvChart.GraphYAxisDivisionMarkers; -var - I, Y: Integer; - LCanvas: TCanvas; -begin - Assert(Assigned(Self)); - Assert(Assigned(Options)); - Assert(Assigned(Options.PrimaryYAxis)); - Assert(Options.PrimaryYAxis.YPixelGap > 0); - LCanvas := GetChartCanvas(false); - - LCanvas.Font := Options.AxisFont; - - for I := 0 to Options.PrimaryYAxis.YDivisions do - begin - Y := Round(YOrigin - (Options.PrimaryYAxis.YPixelGap * ((I) - Options.YOrigin))); - - if I < Options.PrimaryYAxis.YLegends.Count then - MyRightTextOut(LCanvas, Round(XOrigin - 3), Y, Options.PrimaryYAxis.YLegends[I]); - - Y := Round(YOrigin - (Options.PrimaryYAxis.YPixelGap * ((I) - Options.YOrigin))); - if (I > 0) and (I < (Options.PrimaryYAxis.YDivisions)) and Options.YAxisDivisionMarkers then - begin - LCanvas.Pen.Color := Options.GetPenColor(jvChartDivisionLineColorIndex); - MyDrawDotLine(LCanvas, Options.XStartOffset, Y, - Round(Options.XStartOffset + Options.XPixelGap * Options.XValueCount) - 1, Y); - end; - if I > 0 then - if Options.PrimaryYAxis.YPixelGap > 20 then - begin // more than 20 pixels per major division? - LCanvas.Pen.Color := Options.GetPenColor(jvChartAxisColorIndex); - - Y := Round(Y + (Options.PrimaryYAxis.YPixelGap / 2)); - MyDrawAxisMark(LCanvas, Options.XStartOffset, Y, - Options.XStartOffset - 4, // Tick at halfway between major marks. - Y); - end; - end; -end; - -procedure TJvChart.PlotMarker(ACanvas: TCanvas; MarkerKind: TJvChartPenMarkerKind; X, Y: Integer); -begin - // Note: each drawing function below uses chart - // Options.MarkerSize property to determine the - // size of the markers! Future Idea: More flexible marker sizing - // might be useful especially in the case of floating markers. - case MarkerKind of - pmkDiamond: - PlotFilledDiamond(ACanvas, X, Y); - pmkCircle: - begin - ACanvas.Brush.Style := bsClear; - PlotCircle(ACanvas, X, Y); - ACanvas.Brush.Style := bsSolid; - end; - pmkSquare: - begin - ACanvas.Brush.Style := bsClear; - PlotSquare(ACanvas, X, Y); - ACanvas.Brush.Style := bsSolid; - end; - pmkCross: - PlotCross(ACanvas, X, Y); - end; -end; - - -{ PlotPicture: - New helper method helps us to print a prettier JvChart or save to disk, - with higher resolution and larger fonts than the ones we can show on - the on-screen form. - } -procedure TJvChart.PlotPicture(picture:TPicture; fontScaling:Double); -var -// oldfontsize:Integer; - oldhdrfontsize:Integer; - oldlgdfontsize:Integer; - oldaxisfontsize:Integer; - oldystartoffset:Integer; - oldxstartoffset:Integer; -begin - if picture.Graphic=nil then begin - raise Exception.Create('JvChart.PlotToPicture: You must initialize picture.Graphic.Bitmap first'); - end; - - if not (picture.Graphic is TBitmap) then begin - raise Exception.Create('JvChart.PlotToPicture: picture.Graphic.Bitmap must be type TBitmap.'); - end; - - - //oldfontsize := Self.Font.Size; - //Self.Font.Size := Self.Font.Size * fontScaling; - - oldystartoffset := Options.YStartOffset; - Options.YStartOffset := Round(Options.YStartOffset * fontScaling); - - oldxstartoffset := Options.XStartOffset; - Options.XStartOffset := Round(Options.XStartOffset * fontScaling); - - - oldhdrfontsize := Options.HeaderFont.Size; - Options.HeaderFont.Size := Round(Options.HeaderFont.Size * fontScaling); - - oldlgdfontsize := Options.LegendFont.Size; - Options.LegendFont.Size := Round(Options.LegendFont.Size * fontScaling); - - oldaxisfontsize := Options.AxisFont.Size; - Options.AxisFont.Size := Round(Options.AxisFont.Size * fontScaling); - - FExtPicture := picture; - try - ResizeChartCanvas; // Recovery. This shouldn't happen. - PlotGraph; - DrawFloatingMarkers; - - finally - FExtPicture := nil; - - Options.YStartOffset := oldystartoffset; - Options.XStartOffset := oldxstartoffset; - Options.HeaderFont.Size := oldhdrfontsize; - Options.LegendFont.Size := oldlgdfontsize; - Options.AxisFont.Size := oldaxisfontsize; - - end; - ResizeChartCanvas; // reset everything. - Invalidate; // repaint. - -end; - -{**************************************************************************} -{ call this function : } -{ a) you want to show the graph stored in memory } -{ b) you have changed single graph value (call AutoFormatGraph if all new)} -{ c) you have changed the settings of the graph and if you do not use } -{ FAutoUpdateGraph option } -{**************************************************************************} - -procedure TJvChart.PlotGraph; -begin - Assert(Assigned(Options)); - - // Sanity check on YEnd/XEnd: - if (Options.YEnd <= 0) or (Options.XEnd <= 0) or - (Options.YEnd > Height) or (Options.XEnd > Width) then - begin - FInPlotGraph := True; // recursion blocker. - ResizeChartCanvas; // Recovery. This shouldn't happen. - FInPlotGraph := False; - end; - - InternalPlotGraph; - Invalidate; // Force repaint. -end; - -procedure TJvChart.InternalPlotGraph; -var - ACanvas: TCanvas; - nStackGap: Integer; - n100Sum: Double; - // nOldY: Longint; - YOldOrigin: Integer; - nMaxTextHeight: Integer; - // Rectangle plotting: - X, Y, X2, Y2: Integer; - - //aWidth:Integer; - //aHeight:Integer; - { Here be lots of local functions } - - { Draw symbol markers and text labels on a chart... } - - procedure PlotGraphChartMarkers; - var - TW, TH, VC, I, J: Integer; - PenAxisOpt: TJvChartYAxisOptions; - V: Double; - MaxV, MinV: array of Double; - LineXPixelGap: Double; - LastX, LastY: Integer; - MinIndex, MaxIndex: array of Integer; - Decimals: Integer; - begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - - ACanvas.Brush.Color := Options.PaperColor; - ACanvas.Pen.Style := psSolid; - ACanvas.Pen.Color := Options.AxisLineColor; - ACanvas.Brush.Style := bsSolid; - - VC := Options.XValueCount; - LastX := Round(XOrigin); - LastY := 0; - - if VC < 2 then - VC := 2; - LineXPixelGap := ((Options.XEnd - 2) - Options.XStartOffset) / (VC - 1); - - SetLength(MaxV, Options.PenCount); - SetLength(MinV, Options.PenCount); - SetLength(MinIndex, Options.PenCount); - SetLength(MaxIndex, Options.PenCount); - - for I := 0 to Options.PenCount - 1 do - begin - if Options.PenMarkerKind[I] = pmkNone then - Continue; - PenAxisOpt := Options.PenAxis[I]; // Get whether this pen is plotted using the lefthand or righthand Y axis. - MaxV[I] := PenAxisOpt.YMin; - MinV[I] := PenAxisOpt.YMax; - MinIndex[I] := -1; - MaxIndex[I] := -1; - - for J := 0 to Options.XValueCount - 1 do - begin - V := FData.Value[I, J]; - if IsNaN(V) then - Continue; - //MaxFlag := False; - //MinFlag := False; - if V > MaxV[I] then - begin - MaxV[I] := V; - MaxIndex[I] := J; - end; - - if V < MinV[I] then - begin - MinV[I] := V; - MinIndex[I] := J; - end; - - // Calculate Marker position: - X := Round(XOrigin + J * LineXPixelGap); - - //old:Y := Round(YOrigin - ((V / PenAxisOpt.YGap1) * PenAxisOpt.YPixelGap)); - Y := Round(YOrigin - (((V - PenAxisOpt.YMin) / PenAxisOpt.YGap) * PenAxisOpt.YPixelGap)); - SetLineColor(ACanvas, I); - if Y < Options.YStartOffset then - Y := Options.YStartOffset; // constrain Y to stay on chart. - - (* - if MinFlag or MaxFlag then // local min/max markers! - ACanvas.Pen.Width := 2 - else - ACanvas.Pen.Width := 1; - *) - - // Now plot the right kind of marker: - PlotMarker(ACanvas, Options.PenMarkerKind[I], X, Y); - end; - end; - - { Now plot labels After all the markers. Looks nicer than doing - it all together } - for I := 0 to Options.PenCount - 1 do - begin - if not Options.PenValueLabels[I] then - Continue; - PenAxisOpt := Options.PenAxis[I]; // Get whether this pen is plotted using the lefthand or righthand Y axis. - for J := 0 to Options.XValueCount - 1 do - begin - V := FData.Value[I, J]; - if IsNaN(V) then - Continue; - // Calculate Marker position: - X := Round(XOrigin + J * LineXPixelGap); - Y := Round(YOrigin - ((V / PenAxisOpt.YGap1) * PenAxisOpt.YPixelGap)); - if Y < (Options.YStartOffset + 10) then - Y := (Options.YStartOffset + 10); // constrain Y to stay on chart. - - // Format with fixed number of decimal places (avoid screen clutter) - Decimals := Options.PenAxis[I].MarkerValueDecimals; - if Decimals < 0 then // auto - if V < 100.0 then - Decimals := 1 // handy automatic percentage mode. - else - Decimals := 0; - Text := FloatToStrF(V, ffFixed, 16, Decimals); - - if Options.PenUnit.Count >= I then - Text := Text + Options.PenUnit[I]; - - TW := ACanvas.TextWidth(Text); - TH := ACanvas.TextHeight(Text); - - if Options.GetPenValueLabels(I) and - ((X > (LastX + (TW div 2))) or // Show if it's not going to collide - ((Abs(Y - LastY) > (TH * 2)) and - (X > LastX)) or - ((J = MinIndex[I]) or (J = MaxIndex[I]))) then // Always show max/mins - begin - // TODO: EVENT FOR END-USER-CUSTOMIZED OR FORMATTED LABELS - //if Assigned(FOnGetValueLabel) then - // FOnGetValueLabel(Sender, {Pen}I, {Sample#}J, {Value}V, {var}Text ); - if Length(Text) > 0 then - begin - Dec(Y, 2); - // nifty little bit to draw a box around min/max values. - if (J = MinIndex[I]) or (J = MaxIndex[I]) then - begin - ACanvas.Pen.Style := psClear; //was psDot - ACanvas.Brush.Color := Options.PaperColor; //was HintColor - MyPolygon(ACanvas, [Point(X - ((TW div 2) + 2), Y - (TH + Options.MarkerSize + 2)), - Point(X - ((TW div 2) + 2), Y - Options.MarkerSize), - Point(X + (TW div 2) + 2, Y - Options.MarkerSize), - Point(X + (TW div 2) + 2, Y - (TH + Options.MarkerSize + 2))]); - ACanvas.Pen.Style := psSolid; - end; - - if Y >= Options.YStartOffset + 20 then - begin - ACanvas.Brush.Style := bsSolid; - MyCenterTextOut(ACanvas, X + 1, (Y - (Options.MarkerSize + TH)) - 1, Text); - ACanvas.Brush.Color := Options.PaperColor; - LastX := X + TW; - LastY := Y; - end; - end; - end; - end; - end; - end; - - procedure PlotGraphStackedBar; - var - I, J: Integer; - begin - for J := 0 to Options.XValueCount - 1 do - begin - YOldOrigin := 0; - for I := 0 to Options.PenCount - 1 do - begin - if Options.PenStyle[I] <> psClear then - begin - if Options.XPixelGap < 3.0 then - ACanvas.Pen.Color := Options.PenColor[I] // greek-out the borders - else - ACanvas.Pen.Color := clBlack; - MyColorRectangle(ACanvas, I, - Round((XOrigin + J * Options.XPixelGap) + (Options.XPixelGap / 6)), - Round(YOrigin - YOldOrigin), - Round(XOrigin + (J + 1) * Options.XPixelGap - nStackGap), - Round((YOrigin - YOldOrigin) - - ((FData.Value[I, J] / Options.PenAxis[I].YGap) * Options.PrimaryYAxis.YPixelGap))); - YOldOrigin := Round(YOldOrigin + - ((FData.Value[I, J] / Options.PenAxis[I].YGap) * Options.PrimaryYAxis.YPixelGap)); - end; - end; - end; - end; - - procedure PlotGraphBar; - var - I, J, N: Integer; - BarCount: Double; - V, BarGap: Double; - YTempOrigin: Integer; - - function BarXPosition(Index: Integer): Integer; - begin - Result := Round(XOrigin + (Index * BarGap)); - end; - - begin - YTempOrigin := Options.YStartOffset + Round(Options.PrimaryYAxis.YPixelGap * (Options.PrimaryYAxis.YDivisions)); - - BarCount := Options.PenCount * Options.XValueCount; - BarGap := (((Options.XEnd - 1) - Options.XStartOffset) / BarCount); - - for I := 0 to Options.PenCount - 1 do - begin - if Options.PenAxis[I].YGap = 0 then - Continue; // Can't plot this one. - for J := 0 to Options.XValueCount - 1 do - begin - N := (J * Options.PenCount) + I; // Which Bar Number!? - // Plot a rectangle for each Bar in our bar chart... - X := BarXPosition(N) + 1; - // Make a space between groups, 4 pixels per XValue Index: - //Dec(X,4); - //Inc(X, 2*J); - Y := YTempOrigin; -// Assert(Y < aHeight); - Assert(Y > 0); - Assert(X > 0); - //if (X>=aWidth) then - // OutputDebugString('foo!'); -// Assert(X < aWidth); - X2 := BarXPosition(N + 1) - 3; - // Make a space between groups, 4 pixels per XValue Index: - //Dec(X2,4); - //Inc(X2, 2*J); - V := FData.Value[I, J]; - if IsNaN(V) then - Continue; - Y2 := Round(YOrigin - ((V / Options.PenAxis[I].YGap) * Options.PrimaryYAxis.YPixelGap)); - //Assert(Y2 < aHeight); - if Y2 < 0 then - Y2 := -1; //clip extreme negatives. - if Y2 >= Y then - Y2 := Y - 1; - Assert(Y2 < Y); - Assert(X2 > 0); - //if (X2<aWidth) then - // OutputDebugString('foo!'); - //Assert(X2<aWidth); - //Assert(X2>X); - if Options.PenCount > 1 then - if X2 > X then - Dec(X2); // Additional 1 pixel gap - if Options.PenStyle[I] <> psClear then - begin - if (X2 - X) < 4 then // don't draw black line around bar if it is a very narrow bar. - ACanvas.Pen.Style := psClear - else - ACanvas.Pen.Style := Options.PenStyle[I]; - MyColorRectangle(ACanvas, I, X, Y, X2, Y2); - end; - end; - end; - {add average line for the type...} - if Options.ChartKind = ckChartBarAverage then - begin - SetLineColor(ACanvas, jvChartAverageLineColorIndex); - ACanvas.MoveTo(Round(XOrigin + 1 * Options.XPixelGap), - Round(YOrigin - ((Options.AverageValue[1] / Options.PrimaryYAxis.YGap) * Options.PrimaryYAxis.YPixelGap))); - for J := 0 to Options.XValueCount do - MyPenLineTo(ACanvas, Round(XOrigin + J * Options.XPixelGap), - Round(YOrigin - ((Options.AverageValue[J] / Options.PrimaryYAxis.YGap) * Options.PrimaryYAxis.YPixelGap))); - SetLineColor(ACanvas, jvChartAxisColorIndex); - end; - // NEW: Add markers to bar chart: - PlotGraphChartMarkers; - end; - - // Keep Y in visible chart range: - - function GraphConstrainedLineY(Pen, Sample: Integer): Double; - var - V: Double; - PenAxisOpt: TJvChartYAxisOptions; - begin - V := FData.Value[Pen, Sample]; - PenAxisOpt := Options.PenAxis[Pen]; - if IsNaN(V) then - begin - Result := NaN; // blank placeholder value in chart! - Exit; - end; - if PenAxisOpt.YGap < 0.0000001 then - begin - Result := 0.0; // can't chart! YGap is near zero, zero, or negative. - Exit; - end; - Result := YOrigin - (((V - PenAxisOpt.YMin) / PenAxisOpt.YGap) * PenAxisOpt.YPixelGap); - if Result >= YOrigin - 1 then - Result := Round(YOrigin) - 1 // hit the top of the chart - else - if Result < Options.YStartOffset - 2 then - Result := Options.YStartOffset - 2; // Not quite good enough, but better than before. - end; - - function GetUnderLineFillColor(const A, B: TColor) : TColor; - const - Lerp = 0.85; // 0-1, where 0 is fully A and 1 is fully B. This value seems good - var - AR, AG, AB, BR, BG, BB: Byte; - begin - AR := GetRValue(A); - AG := GetGValue(A); - AB := GetBValue(A); - BR := GetRValue(B); - BG := GetGValue(B); - BB := GetBValue(B); - - Result := RGB( - Round(AR + Lerp * (BR - AR)), - Round(AG + Lerp * (BG - AG)), - Round(AB + Lerp * (BB - AB)) - ); - end; - - procedure PlotGraphChartLine; - var - I, I2, J, Y1: Integer; - V, LineXPixelGap: Double; - NanFlag: Boolean; - VC: Integer; - // PenAxisOpt: TJvChartYAxisOptions; - begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - - VC := Options.XValueCount; - if VC < 2 then - VC := 2; - LineXPixelGap := ((Options.XEnd - 2) - Options.XStartOffset) / (VC - 1); - - ACanvas.Pen.Style := psSolid; - for I := 0 to Options.PenCount - 1 do - begin - // PenAxisOpt := Options.PenAxis[I]; - // No line types? - if Options.PenStyle[I] = psClear then - Continue; - SetLineColor(ACanvas, I); - J := 0; - V := GraphConstrainedLineY(I, J); - NanFlag := IsNaN(V); - if not NanFlag then - begin - Y := Round(V); - ACanvas.MoveTo(Round(XOrigin), Y); - end; - - for J := 1 to Options.XValueCount - 1 do - begin - V := GraphConstrainedLineY(I, J); - if IsNaN(V) then - begin - NanFlag := True; // skip. - ACanvas.MoveTo(Round(XOrigin + J * LineXPixelGap), 200); //DEBUG! - end - else - begin - if NanFlag then - begin // resume, valid value. - NanFlag := False; - Y := Round(V); - // pick up the pen and slide forward - ACanvas.MoveTo(Round(XOrigin + J * LineXPixelGap), Y); - end - else - begin - Y := Round(V); - ACanvas.Pen.Style := Options.PenStyle[I]; - if I > 0 then - begin - for I2 := 0 to I - 1 do - begin - V := GraphConstrainedLineY(I2, J); - if IsNaN(V) then - Continue; - Y1 := Round(V); - if Y1 = Y then - begin - Dec(Y); // Prevent line-overlap. Show dotted line above other line. - if ACanvas.Pen.Style = psSolid then - ACanvas.Pen.Style := psDot; - end; - end; - end; - MyPenLineTo(ACanvas, Round(XOrigin + J * LineXPixelGap), Y); - //OldV := V; // keep track of last valid value, for handling gaps. - end; - end; - end; - end; - PlotGraphChartMarkers; - // MARKERS: - SetLineColor(ACanvas, jvChartAxisColorIndex); - end; - - procedure PlotGraphChartLineFill; - var - I, I2, J: Integer; - V, LineXPixelGap: Double; - NanFlag: Boolean; - VC: Integer; - FillPoints : array of TPoint; - FillPolyIndex : Integer; - begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - - SetLength(FillPoints, 0); // Not set to 0 by compiler - try - VC := Options.XValueCount; - if VC < 2 then - VC := 2; - LineXPixelGap := ((Options.XEnd - 2) - Options.XStartOffset) / (VC - 1); - - for I := 0 to Options.PenCount - 1 do - begin - // No line types? - if Options.PenStyle[I] = psClear then - Continue; - - SetLength(FillPoints, FData.ValueCount + 2 {start and end points}); - FillPolyIndex := 0; - - J := 0; - V := GraphConstrainedLineY(I, J); - NanFlag := IsNaN(V); - if not NanFlag then - begin - Y := Round(V); - FillPoints[FillPolyIndex] := Point(Round(XOrigin)+1, Round(YOrigin)); // start at origin - Inc(FillPolyIndex); - FillPoints[FillPolyIndex] := Point(Round(XOrigin)+1, Y); // add first point - Inc(FillPolyIndex); - end; - - for J := 1 to Options.XValueCount - 1 do - begin - V := GraphConstrainedLineY(I, J); - if IsNaN(V) then - begin - NanFlag := True; // skip. - FillPoints[FillPolyIndex] := Point(Round(XOrigin + J * LineXPixelGap), Round(YOrigin)); // !!! DEBUG - Inc(FillPolyIndex); - end - else - begin - if NanFlag then - begin // resume, valid value. - NanFlag := False; - Y := Round(V); - // pick up the pen and slide forward - FillPoints[FillPolyIndex] := Point(Round(XOrigin + J * LineXPixelGap), Y); - Inc(FillPolyIndex); - end - else - begin - Y := Round(V); - if I > 0 then - begin - for I2 := 0 to I - 1 do - begin - V := GraphConstrainedLineY(I2, J); - if IsNaN(V) then - Continue; - end; - end; - - FillPoints[FillPolyIndex] := Point(Round(XOrigin + J * LineXPixelGap), Y); // add next point - Inc(FillPolyIndex); - end; - end; - end; - - // Add a final point which is the same as the last, but at the bottom - if FillPolyIndex > 0 then begin - FillPoints[FillPolyIndex] := Point(FillPoints[FillPolyIndex-1].X, Round(YOrigin)); - Inc(FillPolyIndex); - SetLength(FillPoints, FillPolyIndex); // Trim to the actual usage - - // First draw the fill - ACanvas.Pen.Style := psClear; - ACanvas.Brush.Color := GetUnderLineFillColor(Options.PenColor[I], - Options.PenColor[jvChartPaperColorIndex]); - ACanvas.Brush.Style := bsSolid; - ACanvas.Polygon(FillPoints); - end; - end; - finally - SetLength(FillPoints, 0); - end; - end; - - procedure PlotGraphStackedBarAverage; - var - I, J: Integer; - begin - for J := 0 to Options.XValueCount - 1 do - begin - n100Sum := 0; - for I := 0 to Options.PenCount - 1 do - n100Sum := n100Sum + FData.Value[I, J]; - - for I := 0 to Options.PenCount - 1 do - if n100Sum <> 0 then - AverageData.Value[I, J] := (FData.Value[I, J] / n100Sum) * 100 - else - AverageData.Value[I, J] := 0; - end; - - for J := 0 to Options.XValueCount - 1 do - begin - YOldOrigin := 0; - for I := 0 to Options.PenCount - 1 do - begin - if I = Options.PenCount then {last one; draw it always to the top line} - MyColorRectangle(ACanvas, I, - Round(XOrigin + J * Options.XPixelGap + (Options.XPixelGap / 2)), - Round(YOrigin - YOldOrigin), - Round(XOrigin + (J + 1) * Options.XPixelGap + (Options.XPixelGap / 2) - nStackGap), - Options.YStartOffset) - else - begin - MyColorRectangle(ACanvas, I, - Round(XOrigin + J * Options.XPixelGap + (Options.XPixelGap / 2)), - Round(YOrigin - YOldOrigin), - Round(XOrigin + (J + 1) * Options.XPixelGap + (Options.XPixelGap / 2) - nStackGap), - Round((YOrigin - YOldOrigin) - - ((AverageData.Value[I, J] / Options.PenAxis[I].YGap) * Options.PrimaryYAxis.YPixelGap))); - YOldOrigin := YOldOrigin + Round((AverageData.Value[I, J] / Options.PenAxis[I].YGap) * - Options.PrimaryYAxis.YPixelGap); - end; - end; - end; - end; - - procedure CheckYAxisFlags; - var - I: Integer; - begin - Options.PrimaryYAxis.FActive := True; - Options.SecondaryYAxis.FActive := False; - for I := 0 to Options.PenCount - 1 do - if Options.PenSecondaryAxisFlag[I] then - begin - Options.SecondaryYAxis.FActive := True; - Break; - end; - end; - -begin { Enough local functions for ya? -WP } - ACanvas := GetChartCanvas(false); - //aWidth := GetChartCanvasWidth; - //aHeight:= GetChartCanvasHeight; - - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - Assert(Assigned(ACanvas.Pen)); - - FPlotGraphCalled := True; - - // refuse to refresh under these conditions: - if not (Enabled and Visible) then - Exit; - if csDesigning in ComponentState then - begin - if not Assigned(Self.Parent) then - Exit; - if Self.Name = '' then - Exit; - end; - - // safety before we paint. - Assert(Assigned(Self)); - Assert(Assigned(Data)); - Assert(Assigned(Options)); - Assert(Assigned(Options.PrimaryYAxis)); - Assert(Assigned(Options.SecondaryYAxis)); - Assert(Assigned(AverageData)); - - // NEW: Primary Y axis is always shown, but secondary is only shown - // if a pen is set up to plot on the secondary Y Axis scale. - CheckYAxisFlags; - - ClearScreen; - - if Options.XValueCount > MAX_VALUES then - Options.XValueCount := MAX_VALUES; - if Options.PenCount > MAX_PEN then - Options.PenCount := MAX_PEN; - (* - if Options.PrimaryYAxis.YGap = 0 then - Options.PrimaryYAxis.YGap := 1; - if Options.SecondaryYAxis.YGap = 0 then - Options.SecondaryYAxis.YGap := 1; - *) - - PrimaryYAxisLabels; // Make sure there are Y Axis labels! - - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - - { Resize Header area according to HeaderFont size } - if (not PrintInSession) and (Length(Options.XAxisHeader) > 0) then - begin - MyHeaderFont(ACanvas); - // nOldY := Options.YStartOffset; - nMaxTextHeight := CanvasMaxTextHeight(ACanvas) + 2 * TITLE_MARGIN; - // Bump bottom margins if the fonts don't fit! - if Options.YStartOffset < nMaxTextHeight then - begin - Options.YStartOffset := nMaxTextHeight; - //Options.YEnd := Options.YEnd + (nOldY - Options.YStartOffset); - CalcYEnd; - Options.PrimaryYAxis.Normalize; - Options.SecondaryYAxis.Normalize; - end; - end; - - if (Options.ChartKind = ckChartStackedBar) or - (Options.ChartKind = ckChartStackedBarAverage) then - begin - FOldYOrigin := Options.YOrigin; - Options.YOrigin := 0; - end - else - FOldYOrigin := Options.YOrigin; - if Options.ChartKind = ckChartStackedBarAverage then - FOldYGap := Options.PrimaryYAxis.YGap - else - FOldYGap := Options.PrimaryYAxis.YGap; - - { This effects only graph type: JvChartStackedBar(_100) } - nStackGap := 1; - if Options.XEnd > 200 then - nStackGap := 3; - - MyAxisFont(ACanvas); - - YOldOrigin := Trunc(YOrigin); - - {Draw header and other stuff...} - GraphSetup; - - // If FData.ValueCount is zero we can preview the visual appearance of the chart, - // but there is no plotting of pens that can occur, so stop now... - if FData.ValueCount = 0 then // EMPTY! - begin - { draw a blank chart. Component shouldn't just be a white square, it makes - users think we're broken, when we're not, they just haven't given us any - data.} - Options.PrimaryYAxis.Normalize; - Options.SecondaryYAxis.Normalize; - GraphSetup; - - GraphXAxis; - GraphXAxisDivisionMarkers; - GraphYAxis; - GraphYAxisDivisionMarkers; - - ACanvas.Font.Color := clRed; - if Length(Options.NoDataMessage) = 0 then - MyLeftTextOut(ACanvas, Round(XOrigin), Round(YOrigin) + 4, RsNoData) - else - MyLeftTextOut(ACanvas, Round(XOrigin), Round(YOrigin) + 4, Options.NoDataMessage); // NEW! NOV 2004. WP. - - Exit; - end; - - DrawGradient; // NEW 2007 - DisplayBars; // NEW 2007 - - {Y Axis} - GraphYAxis; - GraphYAxisDivisionMarkers; // dotted lines making graph-paper across graph - - {X Axis} - GraphXAxis; - GraphXAxisDivisionMarkers; // new. - - {X-axis legends...} - GraphXAxisLegend; - - {Main Header} - if Options.Title <> '' then - MyHeader(ACanvas, Options.Title); - - {X axis header} - if Options.XAxisHeader <> '' then - MyXHeader(ACanvas, Options.XAxisHeader); - - {Create the actual graph...} - case Options.ChartKind of - ckChartBar, ckChartBarAverage: - PlotGraphBar; - ckChartStackedBar: - PlotGraphStackedBar; - ckChartLine: //, ckChartLineWithMarkers: - begin - if Options.FillUnderLine then - PlotGraphChartLineFill; // Do this before drawing lines, so lines are always visible - PlotGraphChartLine; - end; - ckChartMarkers: - PlotGraphChartMarkers; - ckChartStackedBarAverage: - PlotGraphStackedBarAverage; - ckChartPieChart: - GraphPieChart(1); { special types} - ckChartDeltaAverage: - GraphDeltaAverage; { special types} - end; - {Y axis header} - MyYHeader(ACanvas, Options.YAxisHeader); // vertical text out on Y axis -end; - - - -procedure TJvChart.DrawChartLegendBelow(ACanvas: TCanvas); {accidentally deleted during Jedi_new to Jedi_2009 branch. Restored by WP June 2009} -var - I,Y,nTextHeight:Integer; - BoxWidth:Integer; - LLabel:String; -begin - if (Options.Legend <> clChartLegendBelow) then exit; - - if (Options.YStartOffset<=0) or (Options.XStartOffset<=0) then exit; - - // space-saving pen-legend below chart - MySmallGraphFont(ACanvas); - nTextHeight := CanvasMaxTextHeight(ACanvas); - - //BoxHeight := nTextHeight - 2; - - Options.FXLegendHoriz := Options.XStartOffset; - for I := 0 to Options.PenCount - 1 do - begin - if Options.PenStyle[I] = psClear then - if Options.GetPenMarkerKind(I) = pmkNone then - Continue; // Skip invisible pens. - - Y := Options.YStartOffset + Options.YEnd + X_TITLE_LABEL_DISTANCE; //(nTextHeight div 2); - - // If chart has X legends: - if (Options.XLegends.Count > 0) or Options.XAxisDateTimeMode then - Y := Y + nTextHeight; - - if Options.PenStyle[I] = psClear then - begin - // For markers, draw marker: - ACanvas.Pen.Color := Options.GetPenColor(I); - GraphXAxisLegendMarker(ACanvas, Options.GetPenMarkerKind(I), - Options.FXLegendHoriz, (Y + 8) - (Options.MarkerSize div 2)); - BoxWidth := Options.MarkerSize + 2; - end - else - begin - // For lines, draw a pen color box: - BoxWidth := ACanvas.TextWidth('X') * 2 - 2; - DrawPenColorBox(ACanvas, I, {pen#} - BoxWidth - 2, {width} - nTextHeight - 2, {height} - Options.FXLegendHoriz, {X=} - Y + 2); {Y=} - end; - - //SetFontColor(ACanvas, jvChartAxisColorIndex); XXX - ACanvas.Font.Color := Options.AxisFont.Color; - - // Draw the Pen Legend (WAP :add unit to legend. ) - if Options.PenLegends.Count > I then - LLabel := Options.PenLegends[I] - else - LLabel := IntToStr(I + 1); - - // Put units in pen legends - // - // if ( Options.PenUnit.Count > I ) - // and ( Length( Options.PenUnit[I] ) > 0 ) then - // myLabel := myLabel + ' ('+Options.PenUnit[I]+')'; - - - MyLeftTextOut(ACanvas, Options.FXLegendHoriz + BoxWidth + 3, Y, LLabel); - Inc(Options.FXLegendHoriz, BoxWidth + ACanvas.TextWidth( LLabel) + 14); - //Inc(VisiblePenCount); - //end; - end; -end;{procedure} - - - - -procedure TJvChart.GraphXAxisLegendMarker(ACanvas: TCanvas; MarkerKind: TJvChartPenMarkerKind; X, Y: Integer); -begin - case MarkerKind of - pmkDiamond: - PlotFilledDiamond(ACanvas, X, Y); - pmkCircle: - PlotCircle(ACanvas, X, Y); - pmkSquare: - PlotSquare(ACanvas, X, Y); - pmkCross: - PlotCross(ACanvas, X, Y); - end; -end; - -procedure TJvChart.GraphXAxisLegend; // reworked in 2007. -var - I: Integer; - Timestamp: TDateTime; - TimestampStr: string; - XOverlap: Integer; - ACanvas: TCanvas; - - { draw x axis text at various alignments:} - function LeftXAxisText: Boolean; - var - Y: Integer; - begin - Result := True; - // Don't exceed right margin - causes some undesirable clipping. removed. -wpostma. - {if I < Options.XLegends.Count then - if ACanvas.TextWidth(Options.XLegends[I]) + Options.FXLegendHoriz > (Width XEnd+10) then begin - Result := False; - Exit; - end;} - - // Label X axis above or below? - if FContainsNegative then - begin - if I < Options.XLegends.Count then - begin // fix exception. June 23, 2004- WPostma. - if Options.FXLegendHoriz < XOverlap then - Exit; // would overlap, don't draw it. - MyLeftTextOut(ACanvas, Options.FXLegendHoriz, Options.YEnd + 3, Options.XLegends[I]); - XOverlap := Options.FXLegendHoriz + ACanvas.TextWidth(Options.XLegends[I]); - end; - end - else - if I < Options.XLegends.Count then - begin - if Options.FXLegendHoriz < XOverlap then - Exit; // would overlap, don't draw it. - Y := FXAxisPosition + Options.AxisLineWidth div 2; - MyLeftTextOut(ACanvas, Options.FXLegendHoriz, Y, Options.XLegends[I]); - XOverlap := Options.FXLegendHoriz + ACanvas.TextWidth(Options.XLegends[I]); - end - else - Result := False; - end; - - function RightXAxisText: Boolean; - var - Y: Integer; - begin - Result := True; - // Label X axis above or below? - if FContainsNegative then - begin - if I < Options.XLegends.Count then // fix exception. June 23, 2004- WPostma. - MyRightTextOut(ACanvas, Options.FXLegendHoriz, Options.YEnd + 3, Options.XLegends[I]) - end else - if I < Options.XLegends.Count then - begin - Y := FXAxisPosition + Options.AxisLineWidth div 2; - MyRightTextOut(ACanvas, Options.FXLegendHoriz, Y, Options.XLegends[I]); - end else - Result := False; - end; - - function CenterXAxisText: Boolean; - var - Y: Integer; - begin - Result := True; - // Label X axis above or below? - if FContainsNegative then - begin - if I < Options.XLegends.Count then // fix exception. June 23, 2004- WPostma. - MyCenterTextOut(ACanvas, Options.FXLegendHoriz, Options.YEnd + 3, Options.XLegends[I]) - end - else - if I < Options.XLegends.Count then - begin - Y := FXAxisPosition + Options.AxisLineWidth div 2; - MyCenterTextOut(ACanvas, Options.FXLegendHoriz, Y, Options.XLegends[I]); - end else - Result := False; - end; - - procedure XAxisDateTimeModeLabels1; // Classic mode [REFACTORED 2007] - var - L: Integer; - Y: Integer; - begin - // classic JvChart XAxisDateTime mode labels painting code. - - // if not Options.XAxisDivisionMarkers then Exit; - if Options.XAxisValuesPerDivision <= 0 then - Exit; - if Options.XStartOffset <= 0 then - Exit; - - for L := 1 to Options.XValueCount div Options.XAxisValuesPerDivision - 1 do - begin - Options.FXLegendHoriz := Round(Options.XStartOffset + Options.XPixelGap * L * Options.XAxisValuesPerDivision); - - Timestamp := FData.Timestamp[L * Options.XAxisValuesPerDivision - 1]; - if Timestamp < 0.0000001 then - Continue; - - if Length(Options.FXAxisDateTimeFormat) = 0 then // not specified, means use Locale defaults - TimestampStr := TimeToStr(Timestamp) - else - TimestampStr := FormatDateTime(Options.FXAxisDateTimeFormat, Timestamp); - - // Check if writing this label would collide with previous label, if not, plot it - if (Options.FXLegendHoriz - (ACanvas.TextWidth(TimestampStr) div 2)) > XOverlap then - begin - Y := FXAxisPosition + Options.AxisLineWidth div 2; - MyCenterTextOut(ACanvas, Options.FXLegendHoriz, Y, TimeStampStr); - - // 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. - ACanvas.Pen.Width := 1; - ACanvas.MoveTo(Options.FXLegendHoriz, FXAxisPosition); - ACanvas.LineTo(Options.FXLegendHoriz, FXAxisPosition + Options.AxisLineWidth + 2); - - XOverlap := Options.FXLegendHoriz + ACanvas.TextWidth(TimestampStr); - end; - end; - - end; - - //XAxisDateTimeModeLabels2: [NEW 2007] - // make text labels line up with new division line drawing code - // in GraphXAxisDivisionMarkers: - - procedure XAxisDateTimeModeLabels2; // [NEW 2007] - var - L: Integer; - X, Y: Integer; - DivPixels: Integer; - TextWidth: Integer; - Modn: Integer; - begin - Assert(Options.FXAxisDateTimeSkipBy > 0); - - DivPixels := Round(Options.XPixelGap * Options.FXaxisDateTimeSkipBy); - - for L := 0 to FOptions.FXAxisDateTimeLines - 1 do - begin - Timestamp := FData.Timestamp[(L * Options.FXaxisDateTimeSkipBy)] + Options.FXAxisDateTimeFirstMarker; - - if Timestamp < 0.0000001 then - Continue; - - if Length(Options.FXAxisDateTimeFormat) = 0 then // not specified, means use Locale defaults - TimestampStr := TimeToStr(Timestamp) - else - TimestampStr := FormatDateTime(Options.FXAxisDateTimeFormat, Timestamp); - - TextWidth := ACanvas.TextWidth(TimeStampStr); - if DivPixels > 0 then - begin - Modn := Trunc(TextWidth / DivPixels) + 1; - if Modn > 1 then - begin - if (L mod Modn) <> 0 then - Continue; // skip labels if they are too densely spaced. - end; - end; - - X := Round(Options.XStartOffset + (Options.XPixelGap * L * Options.FXaxisDateTimeSkipBy)) + - Options.FXAxisDateTimeFirstMarker; - if X > Options.XEnd then - Break; - if X = Options.XStartOffset then - Continue; // don't draw dotted line right at X Axis. - - Y := FXAxisPosition + Options.AxisLineWidth div 2; - MyCenterTextOut(ACanvas, X, Y, TimeStampStr); - - ACanvas.Pen.Color := Options.GetPenColor(jvChartDivisionLineColorIndex); - MyDrawDotLine(ACanvas, X, Options.YStartOffset + 1, X, FXAxisPosition - 1); - end; - end; - - procedure DefaultXAxisLegendMode; - var - count: Integer; - K: Integer; - begin - {default X axis legend mode: use text legends} - if Options.FXAxisLegendSkipBy < 1 then - Options.FXAxisLegendSkipBy := 1; - - Count := (Options.XValueCount + (Options.FXAxisLegendSkipBy - 1)) div Options.FXAxisLegendSkipBy; - // Skip the first (Index 0) Axis Label, for visual reasons. - for K := 0 to Count - 1 do - begin - I := K * Options.FXAxisLegendSkipBy; - //Options.FXLegendHoriz := Round(Options.XStartOffset + (Options.XPixelGap * I)); - Options.FXLegendHoriz := Round(Options.XStartOffset + Options.XPixelGap * I ); - - case Options.FXAxisLabelAlignment of - taLeftJustify: if not leftXAxisText then break; - taRightJustify: if not rightXAxisText then break; - taCenter: if not centerXAxisText then break; - end; - end; {for K} - end; {default mode} - -begin - {X-LEGEND: ...} - if (Options.XStartOffset = 0) and (Options.YStartOffset = 0) then - Exit; - ACanvas := GetChartCanvas(false); - - XOverlap := 0; // XAxis Label Overlap protection checking variable. - - {Count how many characters to show in the separate legend} - - SetLineColor(ACanvas, jvChartAxisColorIndex); - MyAxisFont(ACanvas); - - { datetime mode for X axis legends : follow the time division markers } - if Options.XAxisDateTimeMode then - begin { if DateTime mode then legends are painted where the division markers are painted } - if (Data.EndDateTime > Data.StartDateTime) and (Options.XAxisDateTimeDivision > 0.00001) then - XAxisDateTimeModeLabels2 // new mode! align division markers to even hour/day/etc boundaries! - else - XAxisDateTimeModeLabels1; // classic mode! let the labels displayed be any old time. - end else - if Options.XValueCount > 0 then // is there data to plot? - begin - DefaultXAxisLegendMode; - end; - DrawChartLegendBelow(ACanvas); -end; - -procedure TJvChart.DrawPenColorBox(ACanvas: TCanvas; NColor, W, H, X, Y: Integer); -begin - MyColorRectangle(ACanvas, NColor, X, Y, X + W, Y + H); - SetRectangleColor(ACanvas, jvChartPaperColorIndex); -end; - - -{**************************************************************************} -{ call this function : } -{ a) when you want to print the graph to Windows default printer } -{**************************************************************************} - -procedure TJvChart.PrintGraph; -var - nXEnd, nYEnd: Longint; - nXStart, nYStart: Longint; - nLegendWidth: Longint; -begin - {Save display values...} - nXEnd := Options.XEnd; - nYEnd := Options.YEnd; - nXStart := Options.XStartOffset; - nYStart := Options.YStartOffset; - nLegendWidth := Options.LegendWidth; - {Calculate new values for printer....} - Options.LegendWidth := Round((Options.LegendWidth / (nXEnd + Options.LegendWidth)) * Printer.PageWidth); - Options.XStartOffset := Round(Printer.PageWidth * 0.08); {8%} - Options.YStartOffset := Round(Printer.PageHeight * 0.1); {10%} - Options.XEnd := Round(Printer.PageWidth - (1.2 * Options.LegendWidth)) - Options.XStartOffset; - Options.YEnd := Round(Printer.PageHeight * 0.75); - if Options.YEnd > Options.XEnd then - Options.YEnd := Options.XEnd; - {Begin printing...} - PrintInSession := True; - Printer.BeginDoc; - PlotGraph; {Here it goes!} - Printer.EndDoc; - PrintInSession := False; - {Restore display values...} - Options.XStartOffset := nXStart; {margin} - Options.YStartOffset := nYStart; - Options.XEnd := nXEnd; - Options.YEnd := nYEnd; - Options.LegendWidth := nLegendWidth; -end; - -{**************************************************************************} -{ call this function : } -{ a) when you want to print the graph to Windows default printer } -{ AND you add something else on the same paper. This function } -{ will just add the chart to the OPEN printer canvas at given position } -{**************************************************************************} - -// (rom) XStartPos, YStartPos unused - -procedure TJvChart.AddGraphToOpenPrintCanvas(XStartPos, YStartPos, GraphWidth, GraphHeight: Longint); -var - nXEnd, nYEnd: Longint; - nXStart, nYStart: Longint; - nLegendWidth: Longint; -begin - {Save display values...} - nXEnd := Options.XEnd; - nYEnd := Options.YEnd; - nXStart := Options.XStartOffset; - nYStart := Options.YStartOffset; - nLegendWidth := Options.LegendWidth; - {Set new values for printing the graph at EXISTING print canvas....} - Options.LegendWidth := Round((Options.LegendWidth / (nXEnd + Options.LegendWidth)) * GraphWidth); - Options.XStartOffset := Round(GraphWidth * 0.08); {8%} - Options.YStartOffset := Round(GraphHeight * 0.1); {10%} - Options.XEnd := Round(GraphWidth - (1.2 * Options.LegendWidth)) - Options.XStartOffset; - Options.YEnd := Round(GraphHeight * 0.75); - {Begin printing...NOTICE BeginDoc And EndDoc must be done OUTSIDE this procedure call} - PrintInSession := True; - PlotGraph; {Here it goes!} - PrintInSession := False; - {Restore display values...} - Options.XStartOffset := nXStart; {margin} - Options.YStartOffset := nYStart; - Options.XEnd := nXEnd; - Options.YEnd := nYEnd; - Options.LegendWidth := nLegendWidth; -end; - -{NEW} -{ when the user clicks the chart and changes the axis, we need a notification - so we can save the new settings. } - -procedure TJvChart.NotifyOptionsChange; -begin - if FUpdating then - Exit; - if csDesigning in ComponentState then - begin - Invalidate; - Exit; - end; - if csLoading in ComponentState then - Exit; // Component properties being set at runtime. - - if Options.PenCount <> Self.Data.FPenCount then - begin - if Options.PenCount > 0 then { never set Data.FPenCount to zero internally! } - Data.FPenCount := Options.PenCount; - end; - - // Event fire: - if Assigned(FOnOptionsChangeEvent) then - FOnOptionsChangeEvent(Self); - if Options.AutoUpdateGraph then - begin - FAutoPlotDone := False; // Next paint will also call PlotGraph - Invalidate; - end; -end; - -{ Warren implemented TImage related code directly into TJvChart, to remove TImage as base class.} -// (rom) simplified by returning the Printer ACanvas when printing - -function TJvChart.GetChartCanvas(isFloating:Boolean): TCanvas; -var - Bitmap: TBitmap; -begin - { designtime - draw directly to screen } - if csDesigning in ComponentState then - begin - Result := Self.Canvas; - Assert(Assigned(Result)); - Assert(Assigned(Result.Brush)); - Exit; - end; - - // external picture mode? - if Assigned(FExtPicture) and Assigned(FExtPicture.Graphic) then begin - if FExtPicture.Graphic is TBitmap then begin - Result := TBitmap(FExtPicture.Graphic).Canvas; - exit; - end else begin - raise EInvalidOperation.Create(RsEUnableToGetCanvas); - end; - end; - - { printer canvas } - if PrintInSession then - begin - Result := Printer.Canvas; - Assert(Assigned(Result)); - Assert(Assigned(Result.Brush)); - Exit; - end; - - { Floating marker draw but not external picture mode:} - if isFloating then begin - Result := Self.Canvas; - exit; - end; - - { FPicture.Graphic -bitmap canvas - normal display method. } - if FPicture.Graphic = nil then - begin - Bitmap := TBitmap.Create; - try - Bitmap.Width := Width; - Bitmap.Height := Height; - FPicture.Graphic := Bitmap; - finally - Bitmap.Free; - end; - end; - if FPicture.Graphic is TBitmap then - begin - Result := TBitmap(FPicture.Graphic).Canvas; - Assert(Assigned(Result)); - Assert(Assigned(Result.Brush)); - end - else - raise EInvalidOperation.CreateRes(@RsEUnableToGetCanvas); -end; - -function TJvChart.GetChartCanvasWidth: Integer; // WP NEW 2007 -begin - { designtime - draw directly to screen } - if csDesigning in ComponentState then - begin - Result := Width; - Exit; - end; - - if Assigned(FExtPicture) then begin - result := FExtPicture.Graphic.Width; - exit; - end; - - if PrintInSession then - begin - Result := Printer.PageWidth; - Exit; - end; - - if Assigned(FPicture) then - Result := FPicture.Width - else - Result := Width; -end; - -function TJvChart.GetChartCanvasHeight: Integer; // WP NEW 2007 -begin - { designtime - draw directly to screen } - if csDesigning in ComponentState then - begin - Result := Self.Height; - Exit; - end; - - if Assigned(FExtPicture) then begin - result := FExtPicture.Graphic.Height; - exit; - end; - - { printer canvas } - if PrintInSession then - begin - Result := Printer.PageHeight; - Exit; - end; - - { FPicture.Graphic -bitmap canvas - normal display method. } - if Assigned(FPicture) then - Result := FPicture.Height - else - Result := Self.Height; -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; -var - aHeight: Integer; -begin - if Assigned(FExtPicture) then begin - aHeight := FExtPicture.Bitmap.Height; - end else begin - if not Assigned(FBitmap) then exit; - aHeight := FBitmap.Height; - end; - -// Options.YEnd := aHeight - 2 * Options.YStartOffset; {canvas size, excluding margin} - Options.YEnd := aHeight - Options.YStartOffset - CalcXAxisTextHeight; -end; - - -{**************************************************************************} -{ call this function : } -{ a) when you resize the canvas for the AABsoftGraph } -{ b) at program startup before drawing the first graph } -{**************************************************************************} -// ResizeChartCanvas/PlotGraph endless recursion loop fixed. --WP -procedure TJvChart.ResizeChartCanvas; -var - awidth:Integer; -begin - {Add code for my own data...here} - if Assigned(FExtPicture) then begin - awidth := FExtPicture.Graphic.Width; - end else begin - if not Assigned(FBitmap) then - begin - FBitmap := TBitmap.Create; - FBitmap.Height := Height; - FBitmap.Width := Width; - FPicture.Graphic := FBitmap; - end - else - begin - FBitmap.Width := Width; - FBitmap.Height := Height; - FPicture.Graphic := FBitmap; - end; - awidth := Width; - end; - - CalcYEnd; // YEnd depends on YStartOffset. - - if Options.Legend = clChartLegendRight then - Options.XEnd := Round(((awidth - 2) - 1.5 * Options.XStartOffset) - Options.LegendWidth) - else - Options.XEnd := Round((awidth - 2) - 0.5 * Options.XStartOffset); - - if Options.XEnd < 10 then - Options.XEnd := 10; - if Options.YEnd < 10 then - Options.YEnd := 10; - - if not Assigned(Data) then - Exit; //safety. - // if Data.ValueCount = 0 then - // Exit; // no use, there's no data yet. - - Options.PrimaryYAxis.Normalize; - Options.SecondaryYAxis.Normalize; - - if (not FInPlotGraph) and Visible {and (Data.ValueCount>0)} then // endless recursion protection. - if Options.AutoUpdateGraph or FPlotGraphCalled then - begin - FInPlotGraph := True; // recursion blocker. - InternalPlotGraph; { must not call Invalidate here, causes exceptions in some cases. } - FInPlotGraph := False; - end; -end; - -{This procedure is called when user clicks on the main header} -procedure TJvChart.EditHeader; -var - StrString: string; -begin - StrString := Options.Title; - if InputQuery(RsGraphHeader, Format(RsCurrentHeaders, [Options.Title]), StrString) then - Options.Title := StrString; - InternalPlotGraph; - Invalidate; - if Assigned(FOnTitleClick) then - FOnTitleClick(Self); -end; - -{This procedure is called when user clicks on the X-axis header} -procedure TJvChart.EditXHeader; -var - StrString: string; -begin - StrString := Options.XAxisHeader; - if InputQuery(RsGraphHeader, Format(RsXAxisHeaders, [Options.XAxisHeader]), StrString) then - Options.XAxisHeader := StrString; - InternalPlotGraph; - Invalidate; -end; - -procedure TJvChart.EditYScale; -var - StrString: string; -begin - StrString := FloatToStr(Options.PrimaryYAxis.YMax); - - // NOTE: StrToFloatDefIgnoreInvalidCharacters now called JvSafeStrToFloatDef: - - if InputQuery(RsGraphScale, Format(RsYAxisScales, [FloatToStr(Options.PrimaryYAxis.YMax)]), StrString) then - Options.PrimaryYAxis.YMax := JvSafeStrToFloatDef(StrString, Options.PrimaryYAxis.YMax) - else - Exit; - - // Fire event so the application can save this new Options.PrimaryYAxis.YMax value - if Assigned(FOnYAxisClick) then - FOnYAxisClick(Self); - - //XXX AutoFormatGraph; BAD CODE REMOVED. Wpostma. Call PlotGraph instead. - InternalPlotGraph; - Invalidate; -end; - -// NEW: X Axis Header has to move to make room if there is a horizontal -// X axis legend: -procedure TJvChart.MyXHeader(ACanvas: TCanvas; StrText: string); -var - X, Y, H: Integer; -begin - if StrText = '' then - exit; - - MyAxisFont(ACanvas); - 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 - begin - { left aligned X Axis Title, right after the legend itself} - X := Options.FXLegendHoriz + 32; - MyLeftTextOut(ACanvas, X, Y, StrText); - end - else - begin - { center title within range covered by x axis } - X := (Options.XStartOffset + Options.XEnd) div 2; - MyCenterTextOut(ACanvas, X, Y, StrText); - end; -end; - -procedure TJvChart.MyYHeader(ACanvas: TCanvas; StrText: string); -var - WD, Vert, Horiz: Integer; -begin - if Length(StrText) = 0 then - Exit; - - ACanvas.Brush.Color := Color; - MyAxisTitleFont(ACanvas, true); - - if Options.XStartOffset > 10 then - begin - WD := ACanvas.TextWidth(StrText); - //Vert := Options.YStartOffset + WD; // top-aligned - Vert := Max(0, Options.YStartOffset + (Options.YEnd + WD) div 2); // centered - Horiz := 2; - MyLeftTextOut(ACanvas, Horiz, Vert, StrText, true); - end; -// MyAxisFont(ACanvas); -end; - - -{***************************************************************************} -{ MOUSE FUNCTIONS AND PROCEDURES } -{***************************************************************************} - -function TJvChart.MouseToXValue(X: Integer): Integer; -var - XPixelGap: Double; -begin - XPixelGap := ((Options.XEnd - Options.XStartOffset) / Options.XValueCount); - if XPixelGap > 0.001 then - begin - Result := Round(((X - 1) - Options.XStartOffset) / (XPixelGap)); - if (Result >= Data.ValueCount - 1) then - Result := Data.ValueCount - 1 - else - if Result < 0 then - Result := 0; - end - else - Result := 0; // can't figure it out. -end; - -function TJvChart.MouseToYValue(Y: Integer): Double; -begin - with FOptions.PrimaryYAxis do - begin - //Y = (YOrigin - (((Result - YMin) / YGap) * YPixelGap)) - - Result := -1 * (((Y / YPixelGap) * YGap) - ((YOrigin / YPixelGap) * YGap) - YMin); - - if Result < YMin then - Result := YMin - else - if Result > YMax then - Result := YMax; - end; -end; - -procedure TJvChart.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); -begin - Screen.Cursor := crDefault; - inherited MouseUp(Button, Shift, X, Y); - - if Options.MouseDragObjects then - begin - if Assigned(FDragFloatingMarker) then - begin - FDragFloatingMarker.FDragging := False; - // Solve for X Position etc. - FDragFloatingMarker.XPosition := MouseToXValue(X); - - FDragFloatingMarker.YPosition := MouseToYValue(Y); - //OutputDebugString(PChar( 'End Mouse Drag Floating Object at '+InTToStr(FDragFloatingMarker.XPosition)+','+FloatToStr(FDragFloatingMarker.YPosition)) ); - if Assigned(FOnEndFloatingMarkerDrag) then - FOnEndFloatingMarkerDrag(Self, FDragFloatingMarker); - - FDragFloatingMarker := nil; - Invalidate; - Exit; - end; - end; - - if FStartDrag then - begin - Options.LegendWidth := Options.LegendWidth + (FMouseDownX - X); - Options.XEnd := Options.XEnd - (FMouseDownX - X); - InternalPlotGraph; - end; - if FMouseLegend then - begin - InternalPlotGraph; - FMouseLegend := False; - end; - FStartDrag := False; - Invalidate; -end; - -procedure TJvChart.MouseMove(Shift: TShiftState; X, Y: Integer); //override; -begin - inherited MouseMove(Shift, X, Y); - if Assigned(FDragFloatingMarker) then - begin - if FDragFloatingMarker.XDraggable then - begin - if X < Options.XStartOffset then - X := Options.XStartOffset; - if X > Options.XEnd then - X := Options.XEnd; - FDragFloatingMarker.FRawXPosition := X; - end; - if FDragFloatingMarker.YDraggable then - if Y > FXAxisPosition then - Y := FXAxisPosition; - - if Y < Options.YStartOffset then - Y := Options.YStartOffset; - - FDragFloatingMarker.FRawYPosition := Y; - - Self.Invalidate; // Repaint control LATER ! .. like a PostMessage(WM_PAINT) - //Self.Repaint; // much more CPU intensive, but smoother. - end; - -end; - -procedure TJvChart.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); -var - XPixelGap: Double; - I: Integer; - // YPixelGap: Double; // not used (ahuser) - Marker: TJvChartFloatingMarker; -begin - inherited MouseDown(Button, Shift, X, Y); - - if Options.MouseDragObjects then - begin - if not Assigned(FDragFloatingMarker) then - begin - for I := 0 to FFloatingMarker.Count - 1 do - begin - Marker := GetFloatingMarker(I); - if not Marker.Visible then - Continue; - if not (Marker.XDraggable or Marker.YDraggable) then - Continue; - if (Abs(X - Marker.FRawXPosition) < (Options.MarkerSize * 2)) and - ((Marker.Marker = pmkNone) or (Abs(Y - Marker.FRawYPosition) < Options.MarkerSize * 2)) then - begin - FDragFloatingMarker := Marker; - FDragFloatingMarker.FDragging := True; - //OutputDebugString('Begin Mouse Drag Floating Object'); - if Assigned(FOnBeginFloatingMarkerDrag) then - FOnBeginFloatingMarkerDrag(Self, FDragFloatingMarker); - Exit; - end; - end; - end; - - end; - - if Options.MouseEdit then - begin - if X < Options.XStartOffset then - begin - EditYScale; - Exit; - end - else - // New: Don't let end user mess with title, if we - // provide our own way to set the title or title options, - // however, if Options.MouseEdit is on, they can still set the - // scale via mouse clicking. - if (Y < Options.YStartOffset) and not Assigned(FOnTitleClick) then - begin - EditHeader; - Exit; - end; - - if (Y > Options.YStartOffset + Options.YEnd) and not Assigned(FOnXAxisClick) then - begin - EditXHeader; - Exit; - end; - end; - - if X < Options.XStartOffset then - begin - // Just fire the Y axis clicked event, don't popup the editor - if Assigned(FOnYAxisClick) then - begin - FOnYAxisClick(Self); - Exit; - end; - end - else - if Y < Options.YStartOffset then - if Assigned(FOnTitleClick) then - FOnTitleClick(Self); - // New: Click on bottom area of chart (X Axis) can be defined by - // user of the component to do something. - if Assigned(FOnXAxisClick) then - if (Y > Options.YEnd) and (X > Options.XStartOffset) then - begin - FOnXAxisClick(Self); - Exit; - end; - if Assigned(FOnAltYAxisClick) then - if (Y < Options.YEnd) and (X > Options.XEnd) then - FOnAltYAxisClick(Self); - - if Options.MouseInfo then - begin - FStartDrag := False; - FMouseDownX := X; - FMouseDownY := Y; - if (Y > Options.YStartOffset) and - (Y < Options.YStartOffset + Options.YEnd) and - (X > Options.XStartOffset) and - (X < Options.XStartOffset + Options.XEnd + 10) then - begin - {Legend resize...} - if X > (Options.XStartOffset + Options.XEnd) - 5 then - begin - FStartDrag := True; - Screen.Cursor := crSizeWE; - end; - {Inside the actual graph...} - if (X <= (Options.XStartOffset + Options.XEnd) - 5) and - (Options.ChartKind <> ckChartPieChart) and - (Options.ChartKind <> ckChartDeltaAverage) then - begin - XPixelGap := ((Options.XEnd - Options.XStartOffset) / (Options.XValueCount + 1)); - //if XPixelGap <1 then - // XPixelGal := 1; - if XPixelGap > 0.001 then - FMouseValue := Round((X - Options.XStartOffset) / (XPixelGap)) - else - FMouseValue := 0; // can't figure it out. - - case Options.ChartKind of - ckChartBar, ckChartBarAverage: - if Options.PenCount = 1 then {check for Pen count} - FMousePen := Round(((X + (XPixelGap / 2)) - - (Options.XStartOffset + - Options.XOrigin * XPixelGap + - XPixelGap * FMouseValue)) / - Round(XPixelGap / (Options.PenCount + 0.1)) + 0.1) - else - FMousePen := Round(((X + (XPixelGap / 2)) - - (Options.XStartOffset + - Options.XOrigin * XPixelGap + - XPixelGap * FMouseValue)) / - Round(XPixelGap / (Options.PenCount + 0.5)) + 0.5); - ckChartStackedBar, ckChartLine, ckChartStackedBarAverage: - FMousePen := 0; - end; - if (FMouseValue > Options.XValueCount) or (FMouseValue < 0) then - FMouseValue := 0; - if FMousePen > Options.PrimaryYAxis.YDivisions then - FMousePen := 0; - - // New: Allow user to do custom hints, or else do other things - // when a chart is clicked. - if Assigned(FOnChartClick) then - begin - FMouseDownShowHint := False; - FMouseDownHintBold := False; - // This event can handle chart clicks on data area only. - if X <= Options.XEnd then - FOnChartClick(Self, Button, Shift, X, Y, FMouseValue, - FMousePen, FMouseDownShowHint, - FMouseDownHintBold, FMouseDownHintStrs); - end - else - begin - if Button = mbLeft then - begin - FMouseDownShowHint := True; - FMouseDownHintBold := True; - AutoHint; - end - else - FMouseDownShowHint := False; { don't show } - end; - - if (FMouseDownHintStrs.Count > 0) and FMouseDownShowHint then - ShowMouseMessage(X, Y); - end; - end; - end; -end; - -procedure TJvChart.SetCursorPosition(Pos: Integer); -begin - FCursorPosition := Pos; - Invalidate; // repaint! -end; - -procedure TJvChart.DisplayBars; // NEW 2007! -begin - DrawHorizontalBars; - DrawVerticalBars; -end; - -{ make list of 'PenName=Value' strings for each pen.. } - -procedure TJvChart.AutoHint; // Make the automatic hint message showing all pens and their values. -var - I: Integer; - Str: string; - Val: Double; -begin - FMouseDownHintStrs.Clear; - - if Options.XAxisDateTimeMode then - begin - if Length(Options.DateTimeFormat) = 0 then - Str := DateTimeToStr(FData.GetTimestamp(FMouseValue)) - else - Str := FormatDateTime(Options.DateTimeFormat, FData.GetTimestamp(FMouseValue)); - - FMouseDownHintStrs.Add(Str); - end - else - if Options.XLegends.Count > FMouseValue then - FMouseDownHintStrs.Add(Options.XLegends[FMouseValue]); - - for I := 0 to Options.PenCount - 1 do - begin - if Options.PenLegends.Count <= I then - Break; // Exception fixed. WP - Str := Options.PenLegends[I]; - Val := FData.Value[I, FMouseValue]; - if Length(Str) = 0 then - Str := IntToStr(I + 1); - Str := Str + ' : '; - if IsNaN(Val) then - Str := Str + RsNA - else - begin - Str := Str + FloatToStrF(Val, ffFixed, REALPREC, 3); - if Options.PenUnit.Count > I then - Str := Str + ' ' + Options.PenUnit[I]; - end; - - FMouseDownHintStrs.Add(Str); - {$IFDEF DEBUGINFO_ON} - OutputDebugString(PChar('TJvChart.AutoHint: ' + Str)); - {$ENDIF DEBUGINFO_ON} - end; -end; - -(* orphaned - - {We will show some Double values...} -if FMousePen = 0 then -begin -{show all values in the Pen...} -nLineCount := Options.PenCount; -nHeight := nLineH * (nLineCount + 2); -if Options.XLegends.Count > FMouseValue then -strMessage1 := Options.XLegends[FMouseValue] -else -strMessage1 := ''; -strMessage2 := '-'; -if nWidth < ChartCanvas.TextWidth(strMessage1) then -nWidth := ChartCanvas.TextWidth(strMessage1); -end -else -begin -nLineCount := 1; -nHeight := nLineH * (nLineCount + 2); -strMessage1 := Options.XLegends[FMouseValue]; -if nWidth < ChartCanvas.TextWidth(strMessage1) then -nWidth := ChartCanvas.TextWidth(strMessage1); -if FMousePen > 0 then -strMessage2 := Options.PenLegends[FMousePen]; -if ChartCanvas.TextWidth(strMessage2) > nWidth then -nWidth := ChartCanvas.TextWidth(strMessage2); -strMessage3 := FloatToStrF(FData.Value[FMousePen, FMouseValue], ffFixed, REALPREC, 3); -end; - -*) - -{ ShowMouseMessage can invoke an OnChartClick event, and/or -shows hint boxes, etc. } - -procedure TJvChart.ShowMouseMessage(X, Y: Integer); -var - nWidth: Integer; - nHeight: Integer; - nLineH: Integer; - nLineCount: Integer; - I: Integer; - StrWidth, StrHeight: Integer; - ACanvas: TCanvas; -begin - ACanvas := GetChartCanvas({floating}true); - ACanvas.Font.Color := Font.Color; // March 2004 Fixed. - - // scan and set nWidth,nLineH - nWidth := 100; // minimum 100 pixel hint box width. - nLineH := 8; // minimum 8 pixel line height for hints. - nLineCount := FMouseDownHintStrs.Count; - - for I := 0 to nLineCount - 1 do - begin - StrWidth := ACanvas.TextWidth(FMouseDownHintStrs[I]); - if StrWidth > nWidth then - nWidth := StrWidth; - StrHeight := ACanvas.TextHeight(FMouseDownHintStrs[I]); - if StrHeight > nLineH then - nLineH := StrHeight; - end; - - // bump height of text in hint box, - // leaving a little extra pixel space between rows. - nLineH := Round(nLineH * 1.07) + 1; - - {RsNoValuesHere} - if FMouseDownHintStrs.Count = 0 then - begin - StrWidth := ACanvas.TextWidth(RsNoValuesHere); - if StrWidth > nWidth then - nWidth := StrWidth; - MyColorRectangle(ACanvas, jvChartShadowColorIndex, X + 3, Y + 3, X + nWidth + 3, Y + nLineH + 3); - MyColorRectangle(ACanvas, jvChartHintColorIndex, X, Y, X + nWidth, Y + nLineH); - ACanvas.Font.Color := Self.Font.Color; - MyLeftTextOutHint(ACanvas, X + 2, Y, RsNoValuesHere); - FMouseLegend := True; - Exit; - end; - - // Get hint box height/width, size to contents: - nWidth := nWidth + 25; - nHeight := nLineH * nLineCount + 8; - - // keep hint from clipping at bottom and right. - if (Y + nHeight) > Self.Height then - Y := (Self.Height - nHeight); - if (X + nWidth) > Self.Width then - X := (Self.Width - nWidth); - - // Draw hint box: - MyColorRectangle(ACanvas, jvChartShadowColorIndex, X + 3, Y + 3, X + nWidth + 3, Y + nHeight + 3); - MyColorRectangle(ACanvas, jvChartHintColorIndex, X, Y, X + nWidth, Y + nHeight); - - //MyLeftTextOut( ACanvas, X + 3, Y + 3, 'Foo'); - - // Draw text inside the hint box: - ACanvas.Font.Color := Self.Font.Color; - //ACanvas.Font.Style := - - if FMouseDownHintBold then - ACanvas.Font.Style := [fsBold]; - - for I := 0 to nLineCount - 1 do - begin - if (I = 1) and FMouseDownHintBold then - ACanvas.Font.Style := []; - MyLeftTextOutHint(ACanvas, X + 2, 4 + Y + (I * nLineH), FMouseDownHintStrs[I]); // draw text for each line. - end; - - FMouseLegend := True; - - //Invalidate; //removed to solve painting glitch. - //ResizeChartCanvas; // removed to solve painting glitch. -end; - -{***************************************************************************} -{ PIE FUNCTIONS AND PROCEDURES } -{***************************************************************************} - -procedure TJvChart.GraphPieChart(NPen: Integer); -var - nSize: Integer; - I: Integer; - nLast: Integer; - nXExtra: Integer; - nSum: Double; - n100Sum: Double; - nP: Double; - ACanvas: TCanvas; -begin - ACanvas := GetChartCanvas(false); - ClearScreen; - - {Main Header} - MyHeader(ACanvas, Options.Title); - MyPieLegend(NPen); - if Options.XEnd < Options.YEnd then - begin - nSize := Options.XEnd; - nXExtra := 0; - end - else - begin - nSize := Options.YEnd; - nXExtra := Round((Options.XEnd - Options.YEnd) / 2); - end; - {Count total sum...} - n100Sum := 0; - for I := 1 to MAX_VALUES do - n100Sum := n100Sum + FData.Value[NPen, I]; - {Show background pie....} - SetRectangleColor(ACanvas, jvChartAxisColorIndex); {black...} - MyPiePercentage(Options.XStartOffset + nXExtra + 2, - Options.YStartOffset + 2, nSize, 100); - {Show pie if not zero...} - if n100Sum <> 0 then - begin - nSum := n100Sum; - nLast := Options.XValueCount + 1; - if nLast > MAX_VALUES then - nLast := MAX_VALUES; - for I := nLast downto 2 do - begin - nSum := nSum - FData.Value[NPen, I]; - nP := 100 * (nSum / n100Sum); - SetRectangleColor(ACanvas, I - 1); - MyPiePercentage(Options.XStartOffset + nXExtra, - Options.YStartOffset, nSize, nP); - end; - end; -end; - -procedure TJvChart.MyPiePercentage(X1, Y1, W: Longint; NPercentage: Double); -var - nOriginX, nOriginY: Longint; - nGrade: Double; - nStartGrade: Double; - X, Y: Double; - nLen: Double; -begin - nOriginX := Round((W - 1.01) / 2) + X1; - nOriginY := Round((W - 1.01) / 2) + Y1; - nGrade := (NPercentage / 100) * 2 * Pi; - nStartGrade := (2 / 8) * 2 * Pi; - nLen := Round((W - 1) / 2); - X := Cos(nStartGrade + nGrade) * nLen; - Y := Sin(nStartGrade + nGrade) * nLen; - MyPie(GetChartCanvas(false), X1, Y1, X1 + W, Y1 + W, - nOriginX, Y1, nOriginX + Round(X), nOriginY - Round(Y)); -end; - -procedure TJvChart.MyPieLegend(NPen: Integer); -var - I: Integer; - nTextHeight: Longint; - {nChars: Integer;}// not used (ahuser) - XLegendStr: string; - ACanvas: TCanvas; -begin - ACanvas := GetChartCanvas(false); - {Count how many characters to show in the separate legend} - {nChars := Round(Options.LegendWidth / ChartCanvas.TextWidth('1'));}// not used (ahuser) - {Decrease the value due to the color box shown} - {if (nChars>4) then nChars := nChars-4;}// not used (ahuser) - - MySmallGraphFont(ACanvas); - nTextHeight := Round(CanvasMaxTextHeight(ACanvas) * 1.2); - - // Pie Chart Right Side Legend. - if Options.Legend = clChartLegendRight then - begin - MyColorRectangle(ACanvas, 0, - Options.XStartOffset + Options.XEnd + 6, - Options.YStartOffset + 1 * nTextHeight + 6 + 4, - Options.XStartOffset + Options.XEnd + Options.LegendWidth + 6, - Options.YStartOffset + (Options.XValueCount + 1) * nTextHeight + 6 + 4); - MyColorRectangle(ACanvas, jvChartPaperColorIndex, - Options.XStartOffset + Options.XEnd + 3, - Options.YStartOffset + 1 * nTextHeight + 3 + 4, - Options.XStartOffset + Options.XEnd + Options.LegendWidth + 3, - Options.YStartOffset + (Options.XValueCount + 1) * nTextHeight + 3 + 4); - for I := 1 to Options.XValueCount do - begin - DrawPenColorBox(ACanvas, I, ACanvas.TextWidth('12') - 2, nTextHeight - 4, - Options.XStartOffset + Options.XEnd + 7, - Options.YStartOffset + I * nTextHeight + 9); - SetFontColor(ACanvas, jvChartAxisColorIndex); - if I - 1 < Options.XLegends.Count then - XLegendStr := Options.XLegends[I - 1] - else - XLegendStr := IntToStr(I); - MyLeftTextOut(ACanvas, Options.XStartOffset + Options.XEnd + 7 + ACanvas.TextWidth('12'), - Options.YStartOffset + I * nTextHeight + 7, - XLegendStr); - end; - end; -end; - -// Used in line charting as a Marker kind: - -procedure TJvChart.PlotSquare(ACanvas: TCanvas; X, Y: Integer); -begin - MyPolygon(ACanvas, [Point(X - Options.MarkerSize, Y - Options.MarkerSize), - Point(X + Options.MarkerSize, Y - Options.MarkerSize), - Point(X + Options.MarkerSize, Y + Options.MarkerSize), - Point(X - Options.MarkerSize, Y + Options.MarkerSize)]); -end; - -// Used in line charting as a Marker kind: - -procedure TJvChart.PlotDiamond(ACanvas: TCanvas; X, Y: Integer); -begin - MyPolygon(ACanvas, [Point(X, Y - Options.MarkerSize), - Point(X + Options.MarkerSize, Y), - Point(X, Y + Options.MarkerSize), - Point(X - Options.MarkerSize, Y)]); -end; - -procedure TJvChart.PlotFilledDiamond(ACanvas: TCanvas; X, Y: Integer); -begin - with ACanvas.Brush do - begin - Style := bsSolid; - Color := ACanvas.Pen.Color; - PlotDiamond(ACanvas, X, Y); - Style := bsClear; - end; -end; - -// Used in line charting as a Marker kind: - -procedure TJvChart.PlotCircle(ACanvas: TCanvas; X, Y: Integer); -begin - ACanvas.Pen.Style := psSolid; - ACanvas.Ellipse(X - Options.MarkerSize, - Y - Options.MarkerSize, - X + Options.MarkerSize, - Y + Options.MarkerSize); // Marker Circle radius 3. -end; - -// Used in line charting as a Marker kind: - -procedure TJvChart.PlotCross(ACanvas: TCanvas; X, Y: Integer); -begin - MyDrawLine(ACanvas, X - Options.MarkerSize, Y, X + Options.MarkerSize, Y); - MyDrawLine(ACanvas, X, Y - Options.MarkerSize, X, Y + Options.MarkerSize); -end; - -procedure TJvChart.ClearScreen; -var - ACanvas: TCanvas; -begin - ACanvas := GetChartCanvas(false); - {Clear screen} - SetLineColor(ACanvas, jvChartPaperColorIndex); - // Fishy: - MyColorRectangle(ACanvas, jvChartPaperColorIndex, 0, 0, - // XXX The point here is to exceed the edges, wipe it all, thus the 3* and 5* multipliers. - 3 * Options.XStartOffset + Options.XEnd + Options.LegendWidth, - 5 * Options.YStartOffset + Options.YEnd); - SetRectangleColor(ACanvas, jvChartAxisColorIndex); - SetLineColor(ACanvas, jvChartAxisColorIndex); -end; - -{NEW chart type!!!} - -procedure TJvChart.GraphDeltaAverage; -var - XPixelGap: Longint; - YPixelGap: Longint; - lXOrigin: Longint; - lYOrigin: Longint; - I, J: Longint; - TempYOrigin: Longint; - ACanvas: TCanvas; -begin - ACanvas := GetChartCanvas(false); - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - - {new type of chart...} - ClearScreen; - - {Check graph values and correct if wrong. Actually not needed if there are no bugs} -// if (Options.PrimaryYAxis.YDivisions>MAX_Y_LEGENDS) then -// Options.PrimaryYAxis.YDivisions := MAX_Y_LEGENDS; - if Options.PrimaryYAxis.YDivisions = 0 then - Options.PrimaryYAxis.YDivisions := 1; - if Options.XValueCount > MAX_VALUES then - Options.XValueCount := MAX_VALUES; - if Options.XValueCount = 0 then - Options.XValueCount := 1; - if Options.PenCount > MAX_PEN then - Options.PenCount := MAX_PEN; - // if Options.PrimaryYAxis.YGap = 0 then - // Options.PrimaryYAxis.YGap := 1; - - XPixelGap := Round((Options.YEnd - Options.YStartOffset) / - (Options.XValueCount)); - YPixelGap := Round((Options.XEnd - Options.XStartOffset) / - (Options.PrimaryYAxis.YDivisions + 1)); // SPECIALIZED. - - TempYOrigin := Options.YOrigin; - Options.YOrigin := Options.PrimaryYAxis.YDivisions div 2; - - lYOrigin := Options.XStartOffset + (YPixelGap * Options.YOrigin); - lXOrigin := Options.YStartOffset; - - {Create texts for Y-axis} -// Options.PrimaryYAxis.YLegends.Clear; -// for I := 0 to MAX_Y_LEGENDS-1 do - // Options.PrimaryYAxis.YLegends.Add( IntToStr(Round(((I-1)-Options.YOrigin)*Options.PrimaryYAxis.YGap)) ); - - {Y-axis legends and lines...} - MyAxisFont(ACanvas); - for I := 1 to Options.PrimaryYAxis.YDivisions + 1 do - begin - if I >= Options.PrimaryYAxis.YLegends.Count then - Exit; - MyLeftTextOut(ACanvas, - lYOrigin + (YPixelGap * ((I - 1) - Options.YOrigin)), - lXOrigin + XPixelGap * Options.XValueCount + 2, - Options.PrimaryYAxis.YLegends[I]); - MyDrawDotLine(ACanvas, - lYOrigin - (YPixelGap * ((I - 1) - Options.YOrigin)), - lXOrigin, - lYOrigin - (YPixelGap * ((I - 1) - Options.YOrigin)), - lXOrigin + (XPixelGap * (Options.XValueCount))); - end; - - {Draw Y-axis} - ACanvas.MoveTo(Options.XStartOffset, lXOrigin); - MyAxisLineTo(ACanvas, Options.XEnd, lXOrigin); - {Draw second Y-axis} - ACanvas.MoveTo(Options.XStartOffset, lXOrigin + XPixelGap * Options.XValueCount + 1); - MyAxisLineTo(ACanvas, Options.XEnd, lXOrigin + XPixelGap * Options.XValueCount + 1); - {Draw X-axis} - ACanvas.MoveTo(lYOrigin, lXOrigin); - MyAxisLineTo(ACanvas, lYOrigin, lXOrigin + XPixelGap * Options.XValueCount + 1); - - {X-axis legends...} - GraphXAxisLegend; - - {Main Header} - MyHeader(ACanvas, Options.Title); - - {X axis header} - MyXHeader(ACanvas, Options.XAxisHeader); - - // Now draw the delta average... - for I := 0 to Options.PenCount - 1 do - for J := 0 to Options.XValueCount - 1 do - if Options.PenCount = 1 then - MyColorRectangle(ACanvas, I, - lYOrigin, - lXOrigin + J * XPixelGap + (I) * Round(XPixelGap / (Options.PenCount + 0.1)) - XPixelGap, - lYOrigin + Round(((FData.Value[I, J] - Options.AverageValue[J]) / - Options.PrimaryYAxis.YGap) * YPixelGap), - lXOrigin + J * XPixelGap + (I + 1) * Round(XPixelGap / (Options.PenCount + 0.1)) - XPixelGap) - else - MyColorRectangle(ACanvas, I, - lYOrigin, - lXOrigin + J * XPixelGap + (I) * Round(XPixelGap / (Options.PenCount + 0.5)) - XPixelGap, - lYOrigin + Round(((FData.Value[I, J] - Options.AverageValue[J]) / - Options.PrimaryYAxis.YGap) * YPixelGap), - lXOrigin + J * XPixelGap + (I + 1) * Round(XPixelGap / (Options.PenCount + 0.5)) - XPixelGap); - Options.YOrigin := TempYOrigin; -end; - -{****************************************************************************} -{ Device dependent functions for the rest of this module...check for printer } -{ or check for metafile output! } -{****************************************************************************} - - (* -{ !!warning: uses Win32 only font-handle stuff!!} -procedure TJvChart.MakeVerticalFont; -begin - if Ord(FYFontHandle) <> 0 then - DeleteObject(FYFontHandle); // delete old object - // Clear the contents of FLogFont - FillChar(FYLogFont, SizeOf(TLogFont), 0); - // Set the TLOGFONT's fields - Win32 Logical Font Details. - with FYLogFont do - begin - lfHeight := Abs(Font.Height) + 2; - lfWidth := 0; //Font.Width; - lfEscapement := 900; // 90 degree vertical rotation - lfOrientation := 900; // not used. - lfWeight := FW_BOLD; //FW_HEAVY; // bold, etc - lfItalic := 1; // no - lfUnderline := 0; // no - lfStrikeOut := 0; // no - lfCharSet := ANSI_CHARSET; // or DEFAULT_CHARSET - lfOutPrecision := OUT_TT_ONLY_PRECIS; //Require TrueType! - // OUT_DEFAULT_PRECIS; - // OUT_STRING_PRECIS, OUT_CHARACTER_PRECIS, OUT_STROKE_PRECIS, - // OUT_TT_PRECIS, OUT_DEVICE_PRECIS, OUT_RASTER_PRECIS, - // OUT_TT_ONLY_PRECIS - - lfClipPrecision := CLIP_DEFAULT_PRECIS; - lfQuality := DEFAULT_QUALITY; - lfPitchAndFamily := DEFAULT_PITCH or FF_DONTCARE; - StrPCopy(lfFaceName, Font.Name); - end; - - // Retrieve the requested font - FYFontHandle := CreateFontIndirect(FYLogFont); - Assert(Ord(FYFontHandle) <> 0); - // Assign to the Font.Handle - //Font.Handle := FYFont; // XXX DEBUG - //pbxFont.Refresh; - FYFont := TFont.Create; - FYFont.Assign(Font); - FYFont.Color := Options.AxisFont.Color; - FYFont.Handle := FYFontHandle; -end; -*) - - -procedure TJvChart.MyHeader(ACanvas: TCanvas; StrText: string); -begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - - MyHeaderFont(ACanvas); - MyCenterTextOut(ACanvas, - (Options.XStartOffset + Round(Options.XEnd)) div 2, - TITLE_MARGIN, - StrText - ); - MyAxisFont(ACanvas); -end; - -procedure TJvChart.MySmallGraphFont(ACanvas: TCanvas); -begin - ACanvas.Brush.Color := Options.PaperColor; // was hard coded to clWhite. - ACanvas.Font.Assign(Options.LegendFont); -end; - -procedure TJvChart.MyAxisFont(ACanvas: TCanvas); -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.AxisFont); -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!!} -procedure TJvChart.MyGraphVertFont(ACanvas: TCanvas); -begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - - if Ord(FYFontHandle) = 0 then - MakeVerticalFont; - ACanvas.Font.Assign(FYFont); //Handle := FYFontHnd; - if not PrintInSession then - Assert(ACanvas.Font.Handle = FYFontHandle); -end; -*) - -procedure TJvChart.MyHeaderFont(ACanvas: TCanvas); -begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - Assert(Assigned(Options)); - ACanvas.Brush.Color := Options.PaperColor; //was clWhite; - ACanvas.Font.Assign(Options.HeaderFont); -end; - -procedure TJvChart.MyPenLineTo(ACanvas: TCanvas; X, Y: Integer); -begin - ACanvas.Pen.Width := Options.PenLineWidth; - ACanvas.LineTo(X, Y); - ACanvas.Pen.Width := 1; -end; - -procedure TJvChart.MyAxisLineTo(ACanvas: TCanvas; X, Y: Integer); -begin - if Options.AxisLineWidth = 0 then - Exit; - - ACanvas.Pen.Width := Options.AxisLineWidth; - ACanvas.LineTo(X, Y); - ACanvas.Pen.Width := 1; -end; - -function TJvChart.MyTextHeight(ACanvas: TCanvas; StrText: string): Longint; -begin - Result := ACanvas.TextHeight(StrText); -end; - -{ Text Left Aligned to X,Y boundary } - -procedure TJvChart.MyLeftTextOut(ACanvas: TCanvas; X, Y: Integer; - const AText: string; Vertical: Boolean = false); -begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - 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); -end; - -procedure TJvChart.MyLeftTextOutHint(ACanvas: TCanvas; X, Y: Integer; const AText: string); -begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - 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); -end; - -procedure TJvChart.MyCenterTextOut(ACanvas: TCanvas; X, Y: Integer; const AText: string); -begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - ACanvas.Brush.Color := Options.PaperColor; // non default paper color. - 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; - -procedure TJvChart.MyRightTextOut(ACanvas: TCanvas; X, Y: Integer; const AText: string); -begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - ACanvas.Brush.Color := Options.PaperColor; // non default paper color. - X := X - ACanvas.TextWidth(AText); - Y := Y - ACanvas.TextHeight(AText) div 2; - {$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; - -procedure TJvChart.MyRectangle(ACanvas: TCanvas; X, Y, X2, Y2: Integer); -begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - ACanvas.Rectangle(X, Y, X2, Y2); -end; - -(*Procedure TJvChart.MyShadowRectangle(Pen : Integer; X, Y, X2, Y2: Integer); -begin - SetRectangleColor(Shadow); - ACanvas.Rectangle(X, Y, X2, Y2); -end;*) - -procedure TJvChart.MyColorRectangle(ACanvas: TCanvas; Pen: Integer; X, Y, X2, Y2: Integer); -begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - SetRectangleColor(ACanvas, Pen); - //OutputDebugString(PChar('MyColorRectangle X='+IntToStr(X)+' Y='+IntToStr(Y)+ ' X2='+IntToStr(X2)+ ' Y2='+IntToStr(Y2) )); - ACanvas.Rectangle(X, Y, X2, Y2); -end; - -procedure TJvChart.MyPie(ACanvas: TCanvas; X1, Y1, X2, Y2, X3, Y3, X4, Y4: Longint); -begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - ACanvas.Pie(X1, Y1, X2, Y2, X3, Y3, X4, Y4); -end; - -{Procedure TJvChart.MyArc(X1, Y1, X2, Y2, X3, Y3, X4, Y4: Integer); -begin - ACanvas.Arc(X1, Y1, X2, Y2, X3, Y3, X4, Y4); -end;}// not used (ahuser) - -procedure TJvChart.MyPolygon(ACanvas: TCanvas; Points: array of TPoint); -begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - ACanvas.Polygon(Points); -end; - -{Procedure TJvChart.MyEllipse(X1, Y1, X2, Y2: Integer); -begin - ACanvas.Ellipse(X1, Y1, X2, Y2); -end;} - -procedure TJvChart.MyDrawLine(ACanvas: TCanvas; X1, Y1, X2, Y2: Integer); -begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - ACanvas.MoveTo(X1, Y1); - ACanvas.LineTo(X2, Y2); -end; - -procedure TJvChart.MyDrawAxisMark(ACanvas: TCanvas; X1, Y1, X2, Y2: Integer); -begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - SetSolidLines(ACanvas); - ACanvas.Pen.Width := 1; // always width 1 - ACanvas.MoveTo(X1, Y1); - ACanvas.LineTo(X2, Y2); -end; - -procedure TJvChart.MyDrawDotLine(ACanvas: TCanvas; X1, Y1, X2, Y2: Integer); -begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - SetDotLines(ACanvas); - ACanvas.MoveTo(X1, Y1); - ACanvas.LineTo(X2, Y2); - SetSolidLines(ACanvas); -end; - -{ (rom) not used -function TJvChart.GetDefaultColorString(nIndex: Integer): string; -begin - if nIndex <= 10 then - case nIndex of - -2: - Result := 'clWhite'; // MouseDownBox - -1: - Result := 'clWhite'; - 0: - Result := 'clBlack'; - 1: - Result := 'clLime'; - 2: - Result := 'clBlue'; - 3: - Result := 'clRed'; - 4: - Result := 'clGreen'; - 5: - Result := 'clMaroon'; - 6: - Result := 'clOlive'; - 7: - Result := 'clSilver'; - 8: - Result := 'clTeal'; - 9: - Result := 'clBlack'; - 10: - Result := 'clAqua'; - end - else - Result := '$00888888'; -end; -} - -procedure TJvChart.SetFontColor(ACanvas: TCanvas; Pen: Integer); -begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - ACanvas.Font.Color := Options.PenColor[Pen]; -end; - -procedure TJvChart.SetRectangleColor(ACanvas: TCanvas; Pen: Integer); -begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - ACanvas.Brush.Color := Options.PenColor[Pen]; -end; - -procedure TJvChart.SetLineColor(ACanvas: TCanvas; Pen: Integer); -begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - Assert(Assigned(ACanvas.Pen)); - ACanvas.Pen.Color := Options.PenColor[Pen]; -end; - -procedure TJvChart.SetDotLines(ACanvas: TCanvas); -begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - Assert(Assigned(ACanvas.Pen)); - ACanvas.Pen.Style := psDot; -end; - -procedure TJvChart.SetSolidLines(ACanvas: TCanvas); -begin - Assert(Assigned(ACanvas)); - Assert(Assigned(ACanvas.Brush)); - Assert(Assigned(ACanvas.Pen)); - ACanvas.Pen.Style := psSolid; -end; - -procedure TJvChart.GraphToClipboard; -begin - {This works with bitmaps at least...how to do it as a metafile?} - Clipboard.Assign(FPicture); -end; - -{ PivotData: Pivot Data in Table. Formerly ChangeXValuesWithPen } - -procedure TJvChart.PivotData; -var - I, J: Integer; - PenCount, XValueCount: Integer; - TempData: TJvChartData; - TempStrings: TStringList; -begin - TempData := TJvChartData.Create; - PenCount := Options.PenCount; - XValueCount := Options.XValueCount; - try - { Move data to temp } - for I := 0 to PenCount - 1 do - for J := 0 to XValueCount - 1 do - TempData.Value[I, J] := FData.Value[I, J]; - FData.Clear; - { copy back, pivot X/Y axis } - for I := 0 to PenCount - 1 do - for J := 0 to XValueCount - 1 do - TempData.Value[I, J] := FData.Value[J, I]; - - {swap labels} - TempStrings := Options.FXLegends; - Options.FXLegends := Options.FPenLegends; - Options.FPenLegends := TempStrings; - - Options.XValueCount := PenCount; - Options.PenCount := XValueCount; - - {recalc average} - CountGraphAverage; - InternalPlotGraph; - Invalidate; - finally - TempData.Free; - end; -end; - -{FLOATING MARKERS: new Jan 2005 by WP } - -procedure TJvChart.DrawFloatingMarkers; { called from TJvChart.Paint! } -var - Marker, Marker2: TJvChartFloatingMarker; - LineXPixelGap: Double; - CaptionYPosition, TextWidth, TextHeight, VC, I: Integer; - ACanvas: TCanvas; -begin - if csDesigning in ComponentState then - Exit; - if FFloatingMarker.Count = 0 then - Exit; - ACanvas := Self.GetChartCanvas({isFloating}true); - - VC := Options.XValueCount; - if (VC < 2) then - VC := 2; - LineXPixelGap := ((Options.XEnd - 2) - Options.XStartOffset) / (VC - 1); - - {-- First loop through all and update their Raw X and Y Positions --} - for I := 0 to FFloatingMarker.Count - 1 do - begin - Marker := GetFloatingMarker(I); - if not Marker.Visible then - Continue; - if (Marker.XPosition < 0) or (Marker.XPosition >= VC) then - Continue; // out of visible X range. - - // if following a pen, get the updated pen value: - //if Marker.YPositionToPen>=0 then begin - // Marker.YPosition := Self.Data.Value[Marker.YPositionToPen, Marker.XPosition]; - //end; - - // find Raw X,Y co-ordinates: - if not Marker.FDragging then - begin - with FOptions.PrimaryYAxis do - Marker.FRawYPosition := Trunc((YOrigin - (((Marker.YPosition - YMin) / YGap) * YPixelGap))); - Marker.FRawXPosition := Round(XOrigin + Marker.XPosition * LineXPixelGap); - end; - end; - - {-- Now draw any connecting lines or vertical lines --} - for I := 0 to FFloatingMarker.Count - 1 do - begin - Marker := GetFloatingMarker(I); - if not Marker.Visible then - Continue; - if (Marker.XPosition < 0) or (Marker.XPosition >= VC) then - Continue; // out of visible X range. - - // Draw connecting (rubberband) line: - if (Marker.LineToMarker >= 0) and (Marker.FLineStyle <> psClear) then - begin - Marker2 := GetFloatingMarker(Marker.LineToMarker); - ACanvas.Pen.Style := Marker.FLineStyle; - ACanvas.Pen.Color := Marker.FLineColor; - ACanvas.Pen.Width := Marker.FLineWidth; - ACanvas.MoveTo(Marker.FRawXPosition, Marker.FRawYPosition); - ACanvas.LineTo(Marker2.FRawXPosition, Marker2.FRawYPosition); - end - else - if Marker.FLineVertical then - begin - // Vertical line along X position: - ACanvas.Pen.Style := Marker.FLineStyle; - ACanvas.Pen.Color := Marker.FLineColor; - ACanvas.Pen.Width := Marker.FLineWidth; - ACanvas.MoveTo(Marker.FRawXPosition, Options.YStartOffset); - ACanvas.LineTo(Marker.FRawXPosition, FXAxisPosition - 1); - end; - end; - - {-- Now draw the markers themselves, we draw them LAST so they are ON TOP. --} - MySmallGraphFont(ACanvas); - for I := 0 to FFloatingMarker.Count - 1 do - begin - Marker := GetFloatingMarker(I); - if not Marker.Visible then - Continue; - if (Marker.XPosition < 0) or (Marker.XPosition >= VC) then - Continue; // out of visible X range. - if Marker.Marker <> pmkNone then - begin - // Draw Marker: - ACanvas.Pen.Color := Marker.FMarkerColor; - PlotMarker(ACanvas, Marker.Marker, Marker.FRawXPosition, Marker.FRawYPosition); - end; - - if Marker.Caption <> '' then - begin - TextHeight := ACanvas.TextHeight(Marker.Caption); - - CaptionYPosition := 0; // not used. - case Marker.CaptionPosition of - cpMarker: - CaptionYPosition := Marker.FRawYPosition - Round(TextHeight * 1.4); - cpXAxisBottom: - CaptionYPosition := Options.YStartOffset + Options.YEnd + Round(TextHeight * 1.4); - cpXAxisTop: - CaptionYPosition := Trunc(XOrigin - Round(TextHeight * 1.4)); - cpTitleArea: - CaptionYPosition := (Options.YStartOffset div 2) - (TextHeight div 2); - end; - - if Marker.CaptionBoxed then - begin - TextWidth := ACanvas.TextWidth(Marker.Caption) + 10; - - ACanvas.Pen.Color := Marker.LineColor; - ACanvas.Pen.Width := 1; - ACanvas.Pen.Style := Marker.LineStyle; - MyRectangle(ACanvas, - Marker.FRawXPosition - TextWidth div 2, - CaptionYPosition, - Marker.FRawXPosition + TextWidth div 2, - CaptionYPosition + TextHeight + TextHeight div 4); - ACanvas.Pen.Style := psSolid; - //MySmallGraphFont(ACanvas); <-redundant. - //MyCenterTextOut(ACanvas, Marker.FRawXPosition, Options.FYStartOffset + Round(TextHeight / 4), - // Marker.Caption); - end; - - MyCenterTextOut(ACanvas, Marker.FRawXPosition, CaptionYPosition, Marker.Caption); - end; - end; -end; - -function TJvChart.AddFloatingMarker: TJvChartFloatingMarker; -begin - Assert(Assigned(FFloatingMarker)); - Result := TJvChartFloatingMarker.Create(Self); - Result.FIndex := FFloatingMarker.Count; - FFloatingMarker.Add(Result); -end; - -procedure TJvChart.DeleteFloatingMarker(Index: Integer); -var - I: Integer; -begin - Assert(Assigned(FFloatingMarker)); - if Assigned(FDragFloatingMarker) then - FDragFloatingMarker := nil; - - FFloatingMarker.Delete(Index); - for I := Index to FFloatingMarker.Count - 1 do - with GetFloatingMarker(I) do - begin - FIndex := I; // update index. - if LineToMarker = Index then - LineToMarker := -1 // Disconnected now. - else - if LineToMarker > Index then - LineToMarker := LineToMarker - 1; // Index changed. - end; - Invalidate; -end; - -procedure TJvChart.DeleteFloatingMarkerObj(Marker: TJvChartFloatingMarker); // NEW 2007 -var - I: Integer; -begin - for I := 0 to FFloatingMarker.Count - 1 do - begin - if TJvChartFloatingMarker(FFloatingMarker[I]) = Marker then - begin - DeletefloatingMarker(I); - Exit; - end; - end; -end; - -procedure TJvChart.CopyFloatingMarkers(Source: TJvChart); -var - I: Integer; - NewMarker: TJvChartFloatingMarker; -begin - ClearFloatingMarkers; - for I := 0 to Source.FloatingMarkerCount - 1 do - begin - NewMarker := Self.AddFloatingMarker; - NewMarker.Assign(Source.GetFloatingMarker(I)); - end; - Invalidate; // repaint! -end; - -procedure TJvChart.ClearFloatingMarkers; -begin - if Assigned(FDragFloatingMarker) then - FDragFloatingMarker := nil; - FFloatingMarker.Clear; -end; - -function TJvChart.GetFloatingMarker(Index: Integer): TJvChartFloatingMarker; -begin - Assert(Assigned(FFloatingMarker)); - Result := TJvChartFloatingMarker(FFloatingMarker[Index]); -end; - -function TJvChart.GetHorizontalBar(index: integer): TJvChartHorizontalBar; -begin - // new 2009 - Assert(Assigned(FHorizontalBars)); - Result := TJvChartHorizontalBar(FHorizontalBars[Index]); - -end; - -function TJvChart.GetVerticalBar(index: integer): TJvChartVerticalBar; -begin -// new 2009 - Assert(Assigned(FVerticalBars)); - Result := TJvChartVerticalBar(FVerticalBars[Index]); -end; - -function TJvChart.FloatingMarkerCount: Integer; -begin - Assert(Assigned(FFloatingMarker)); - Result := FFloatingMarker.Count; -end; - -// NEW HORIZONTAL BAR AND VERTICAL BAR AND GRADIENT PAINTING METHODS (2007) - W.Postma. - -procedure TJvChart.DrawGradient; // new 2007 -var - ACanvas: TCanvas; - RawRect: TRect; - VC: Integer; -begin - if csDesigning in ComponentState then - Exit; - if (Options.FGradientDirection = grNone) or (Options.PaperColor = Options.FGradientColor) then - Exit; - ACanvas := GetChartCanvas(false); - VC := Max(1, Options.XValueCount); - RawRect.Top := FOptions.YStartOffset; - RawRect.Bottom := Trunc(YOrigin); - RawRect.Left := Round(XOrigin); - RawRect.Right := Round(Options.XStartOffset + Options.XPixelGap * VC) - 1; - case Options.FGradientDirection of - //grNone: - // ; - grUp: - GradVertical(ACanvas, RawRect, Options.FGradientColor, Options.PaperColor); - grDown: - GradVertical(ACanvas, RawRect, Options.PaperColor, Options.FGradientColor); - grLeft: - GradHorizontal(ACanvas, RawRect, Options.PaperColor, Options.FGradientColor); - grRight: - GradHorizontal(ACanvas, RawRect, Options.FGradientColor, Options.PaperColor); - end; -end; - -{ Gradient bars - indicators on background of various vertical subranges } - -procedure TJvChart.DrawHorizontalBars; // new 2007 -var - HB: TJvChartHorizontalBar; - J: Integer; - ACanvas: TCanvas; - VC: Integer; - RawRect: TRect; - procedure CalcRawRect; // new april 2009 -begin - with FOptions.PrimaryYAxis do - if (YGap <> 0) then - begin - if IsNaN(HB.FYTop) then - RawRect.Top := FOptions.YStartOffset - else - begin - RawRect.Top := Trunc((YOrigin - (((HB.FYTop - YMin) / YGap) * YPixelGap))); - if RawRect.Top < 0 then - RawRect.Top := FOptions.YStartOffset; - end; - - if IsNaN(HB.FYBottom) then - RawRect.Bottom := Trunc(YOrigin) - else - begin - RawRect.Bottom := Trunc((YOrigin - (((HB.FYBottom - YMin) / YGap) * YPixelGap))); - if (RawRect.Bottom < 0) or (RawRect.Bottom > YOrigin) then - RawRect.Bottom := Trunc(YOrigin); - end; - - RawRect.Left := Round(XOrigin); - RawRect.Right := Round(Options.XStartOffset + Options.XPixelGap * VC) - 1; - end; - end; -begin - if csDesigning in ComponentState then - Exit; - if FHorizontalBars.Count = 0 then - Exit; - ACanvas := GetChartCanvas(false); - VC := Options.XValueCount; - if VC < 1 then - VC := 1; - - for J := 0 to FHorizontalBars.Count - 1 do - begin - HB := TJvChartHorizontalBar(FHorizontalBars[J]); - if not HB.FVisible then - Continue; - - CalcRawRect; - - ACanvas.Brush.Color := HB.FColor; - ACanvas.Brush.Style := bsSolid; - ACanvas.FillRect(RawRect); - if HB.FColor <> HB.FGradColor then - case HB.FGradDirection of - //grNone: - // ; - grUp: - GradVertical(ACanvas, RawRect, HB.FGradColor, HB.FColor); - grDown: - GradVertical(ACanvas, RawRect, HB.FColor, HB.FGradColor); - end; - end; - - {now draw outlines } - // new april 2009 - for J := 0 to FHorizontalBars.Count - 1 do - begin - HB := TJvChartHorizontalBar(FHorizontalBars[J]); - if not HB.FVisible then - Continue; - if HB.PenStyle<>psClear then begin - CalcRawRect; - ACanvas.Brush.Style := bsClear; - ACanvas.Pen.Style := HB.PenStyle; - ACAnvas.Pen.Color := HB.PenColor; - ACanvas.Rectangle(RawRect); - end; - end; - - -end; - -procedure TJvChart.DrawVerticalBars; // new 2007 -var - VB: TJvChartVerticalBar; - J: Integer; - ACanvas: TCanvas; - VC: Integer; - RawRect: TRect; - procedure CalcRawRect; - begin - RawRect.Top := FOptions.YStartOffset; - RawRect.Bottom := Trunc(YOrigin); - RawRect.Left := Round(Options.XStartOffset + Options.XPixelGap * VB.FXLeft); - if RawRect.Left <= 0 then - RawRect.Left := Round(XOrigin); - RawRect.Right := Round(Options.XStartOffset + Options.XPixelGap * VB.FXRight); - VC := Round(Options.XStartOffset + Options.XPixelGap * Options.XValueCount); - if RawRect.Right > VC then - RawRect.Right := VC; - end; - -begin - if csDesigning in ComponentState then - Exit; - if FVerticalBars.Count = 0 then - Exit; - ACanvas := GetChartCanvas(false); - {VC :=Options.XValueCount; - if VC<1 then VC:=1;} - - for J := 0 to FVerticalBars.Count - 1 do - begin - VB := TJvChartVerticalBar(FVerticalBars[J]); - if not VB.FVisible then - Continue; - - CalcRawRect; - - ACanvas.Brush.Color := VB.FColor; - ACanvas.Brush.Style := bsSolid; - ACanvas.FillRect(RawRect); - if VB.FColor <> VB.FGradColor then - case VB.FGradDirection of - //grNone: - // ; - grUp: - GradVertical(ACanvas, RawRect, VB.FGradColor, VB.FColor); - grDown: - GradVertical(ACanvas, RawRect, VB.FColor, VB.FGradColor); - grLeft: - GradHorizontal(ACanvas, RawRect, VB.FColor, VB.FGradColor); - grRight: - GradHorizontal(ACanvas, RawRect, VB.FGradColor, VB.FColor); - end; - end; - - - {now draw outlines. these are done last so we can properly paint overlaps } - // new april 2009 - for J := 0 to FVerticalBars.Count - 1 do - begin - VB := TJvChartVerticalBar(FVerticalBars[J]); - if not VB.FVisible then - Continue; - if VB.PenStyle<>psClear then begin - CalcRawRect; - ACanvas.Brush.Style := bsClear; - ACanvas.Pen.Style := VB.PenStyle; - ACAnvas.Pen.Color := VB.PenColor; - ACanvas.Rectangle(RawRect); - end; - end; - -end; - -function TJvChart.AddHorizontalBar: TJvChartHorizontalBar; // NEW 2007 -begin - Assert(Assigned(FHorizontalBars)); - Result := TJvChartHorizontalBar.Create(Self); - Result.FIndex := FHorizontalBars.Count; - FHorizontalBars.Add(Result); -end; - -function TJvChart.AddVerticalBar: TJvChartVerticalBar; // NEW 2007 -begin - Assert(Assigned(FVerticalBars)); - Result := TJvChartVerticalBar.Create(Self); - Result.FIndex := FVerticalBars.Count; - FVerticalBars.Add(Result); -end; - -procedure TJvChart.ClearHorizontalBars; // NEW 2007 -begin - FHorizontalBars.Clear; -end; - -procedure TJvChart.ClearVerticalBars; // NEW 2007 -begin - FVerticalBars.Clear; -end; - -function TJvChart.HorizontalBarsCount: Integer; // NEW 2007 -begin - Result := FHorizontalBars.Count; -end; - -function TJvChart.VerticalBarsCount: Integer; // NEW 2007 -begin - Result := FVerticalBars.Count; -end; - -end.