*-------------------------------------------------------------------------------------------------------------------------------------------------------- * (EN) AUTOGENERATED - ATTENTION!! - NOT INTENDED FOR EXECUTION!! USE ONLY FOR MERGING CHANGES AND STORING WITH SCM TOOLS!! *-------------------------------------------------------------------------------------------------------------------------------------------------------- *< FOXBIN2PRG: Version="1.21" SourceFile="foxcharts.vcx" CPID="1252" /> (Solo para binarios VFP 9 / Only for VFP 9 binaries) * * DEFINE CLASS _chartcanvas AS imgcanvas OF "gdiplusx.vcx" && Internal use. Not to be used directly ! *< CLASSDATA: Baseclass="image" Timestamp="" Scale="Pixels" Uniqueid="" /> * Name = "_chartcanvas" * PROCEDURE Init * Check if using Windows7 and not SP2 IF (OS(3) = "6") AND ;&& (same as Vista) (OS(4) = "1") AND ; &&(Vista = 0) (VERSION(4) < "09.00.0000.5411") && VFP 9.0 SP2 This.RenderMode = 1 && File BMP - slower performance ENDIF DODEFAULT() ENDPROC ENDDEFINE DEFINE CLASS _legend AS label && Internal use. Not to be used directly ! *< CLASSDATA: Baseclass="label" Timestamp="" Scale="Pixels" Uniqueid="" /> * *m: caption_assign *m: reset && Resets the legend GDI+ objects *m: rotation_assign *m: _drawstring *m: _setup *m: _updatemeasures *m: _value_assign *p: backcoloralpha *p: forecoloralpha *p: format && Specifies the input and output formatting of a control's Value property. *p: format2 *p: isparent *p: ogfx *p: rotationcenter *p: _forceformat *p: _height *p: _initialized *p: _memberdata && XML Metadata for customizable properties *p: _obrush *p: _ofont *p: _orectangle *p: _ostringformat *p: _transfcaption *p: _value *p: _vartype *p: _width * HIDDEN AddProperty,Anchor,AutoSize,BackStyle,BorderStyle,Click,CloneObject,ColorScheme,ColorSource,Comment,DblClick,Destroy,DisabledBackColor,DisabledForeColor,DragDrop,DragIcon,DragMode,DragOver,Drag,Error,FontCondense,FontExtend,FontOutline,FontShadow,GotFocus,HelpContextID,Init,LostFocus,MiddleClick,MouseDown,MouseEnter,MouseIcon,MouseLeave,MouseMove,MousePointer,MouseUp,MouseWheel,Move,OLECompleteDrag,OLEDragDrop,OLEDragMode,OLEDragOver,OLEDragPicture,OLEDrag,OLEDropEffects,OLEDropHasData,OLEDropMode,OLEGiveFeedback,OLESetData,OLEStartDrag,ParentClass,Parent,ReadExpression,ReadMethod,Refresh,ResetToDefault,RightClick,RightToLeft,SaveAsClass,ShowWhatsThis,StatusBarText,Style,TabIndex,TabStop,Tag,ToolTipText,UIEnable,WhatsThisHelpID,WordWrap,WriteExpression,WriteMethod,ZOrder * AutoSize = .T. backcoloralpha = 0 Caption = "Legend" DragIcon = ..\ forecoloralpha = 255 format = format2 = Height = 17 isparent = .F. Name = "_legend" ogfx = .F. OLEDragPicture = ..\ rotationcenter = 0 Width = 44 _forceformat = _height = 0 _initialized = .F. _memberdata = _obrush = _ofont = _orectangle = _ostringformat = _transfcaption = _value = _vartype = _width = 0 * HIDDEN PROCEDURE caption_assign LPARAMETERS tuCaption LOCAL lcType m.lcType = VARTYPE(m.tuCaption) IF m.lcType $ "DLTN" && Logical, Date, DateTime, Numeric m.tuCaption = TRANSFORM(m.tuCaption) ENDIF This.Caption = m.tuCaption This._UpdateMeasures(.F.) && Character passed *!* C Character, Memo, Varchar, Varchar (Binary) *!* D Date *!* G General *!* L Logical *!* N Numeric, Float, Double, or Integer *!* O Object *!* Q Blob, Varbinary *!* T DateTime *!* U Unknown or variable does not exist *!* X Null *!* Y Currency ENDPROC HIDDEN PROCEDURE Init THIS.IsParent = TYPE('this.Parent.Name')='C' IF THIS.IsParent AND VARTYPE(THIS.PARENT.oGfx)='O' THIS.oGfx = THIS.PARENT.oGfx ENDIF ENDPROC PROCEDURE reset && Resets the legend GDI+ objects This._Setup() This._UpdateMeasures() ENDPROC PROCEDURE rotation_assign LPARAMETERS tnRotation IF tnRotation < 0 tnRotation = tnRotation + 360 ENDIF THIS.Rotation = tnRotation ENDPROC PROCEDURE _drawstring LPARAMETERS tnX, tnY, tnWidth, tnHeight, tlVertical LOCAL x1, y1, lnAlign, lnMode, xBack, llBar llBar = IIF(This.Parent.Name = "ShapeLegend",.T., .F.) lnMode = 0 && 0 = x,y Coordinates ; 1 = xfcRectangle coordinates lnAlign = This.Alignment * 0 = Left 1 = Right 2 = Center LOCAL loGfx as xfcGraphics loGfx = This.Parent.oGfx WITH _Screen.System.Drawing DO CASE CASE VARTYPE(tnWidth) + VARTYPE(tnHeight) = "NN" lnMode = 1 * Create a STRINGFORMAT object in order to draw the string centered in the image LOCAL loStringFmt as xfcStringFormat LOCAL lnGdipAlign loStringFmt = .StringFormat.New() DO CASE CASE lnAlign = 2 && Center lnGdipAlign = .StringAlignment.Center CASE lnAlign = 1 lnGdipAlign = .StringAlignment.Far OTHERWISE lnGdipAlign = .StringAlignment.Near ENDCASE loStringFmt.Alignment = lnGdipAlign IF tlVertical loStringFmt.FormatFlags = .StringFormatFlags.DirectionVertical loStringFmt.LineAlignment = .StringAlignment.Center ENDIF LOCAL loSize as xfcSize IF tlVertical loSize = .Size.New(This.Parent.Width, This.Parent.Height) ELSE loSize = .Size.New(tnWidth, tnHeight) ENDIF loSize = loGfx.MeasureString(; This._TransfCaption, This._oFont, loSize, loStringFmt) This._Height = CEILING(loSize.Height) This._Width = CEILING(loSize.Width) LOCAL loRect as xfcRectangle loRect = .Rectangle.New(tnX, tnY, tnWidth, This._Height) x1 = tnX y1 = tnY IF tlVertical xBack = tnX + tnWidth / 2 - (This._Width / 2) DO CASE CASE lnAlign = 0 && Left y1 = tnY CASE lnAlign = 1 && Right y1 = tnY + tnHeight - This._Height CASE lnAlign = 2 && Center y1 = tnY + (tnHeight / 2) - (This._Height / 2) ENDCASE ELSE DO CASE CASE lnAlign = 0 && Left xBack = tnX CASE lnAlign = 1 && Right xBack = tnX + tnWidth - This._Width CASE lnAlign = 2 && Center xBack = tnX + (tnWidth - This._Width) / 2 ENDCASE ENDIF CASE lnAlign = 0 && Left STORE tnX TO x1, xBack y1 = tnY CASE lnAlign = 1 && Right x1 = tnX - This._Width xBack = x1 y1 = tnY CASE lnAlign = 2 && Center x1 = tnX - (This._Width / 2) xBack = x1 y1 = tnY ENDCASE LOCAL lnRotation lnRotation = This.Rotation IF lnRotation <> 0 WITH _SCREEN.System.Drawing LOCAL loPointF as xfcPointF LOCAL loMatrix as xfcMatrix loMatrix = .Drawing2D.Matrix.New() IF lnMode = 1 loPointF = .PointF.New(tnX, tnY) && this is the point of rotation ELSE DO CASE CASE lnAlign = 0 && Left loPointF = .PointF.New(x1 + 5, y1 + This._Height / 2) && this is the point of rotation CASE lnAlign = 1 && Right loPointF = .PointF.New(x1 + This._Width - 5, y1 + This._Height / 2) && this is the point of rotation CASE lnAlign = 2 && Center loPointF = .PointF.New(x1 + This._Width / 2, y1 + This._Height / 2) && this is the point of rotation ENDCASE ENDIF loMatrix.RotateAt(lnRotation, loPointF) loGfx.MultiplyTransform(loMatrix) ENDWITH ENDIF lnRotationCenter = This.RotationCenter * Center Rotation IF lnRotationCenter <> 0 WITH _SCREEN.System.Drawing LOCAL loPointFC as xfcPointF LOCAL loMatrixC as xfcMatrix loMatrixC = .Drawing2D.Matrix.New() * loPointFC = .PointF.New(x1 + This._Width / 2, y1 + This._Height / 2) && this is the point of rotation loPointFC = .PointF.New(xBack + This._Width / 2, y1 + This._Height / 2) && this is the point of rotation loMatrixC.RotateAt(lnRotationCenter, loPointFC) loGfx.MultiplyTransform(loMatrixC) ENDWITH ENDIF IF This.BackColorAlpha > 0 * Draw the BackGround Rectangle WITH _Screen.System.Drawing IF lnMode = 0 && default loGfx.FillRectangle( ; .SolidBrush.New(.Color.FromARGB(This.BackColorAlpha, This.BackColor)), ; x1, y1, This._Width, This._Height) ELSE loGfx.FillRectangle( ; .SolidBrush.New(.Color.FromARGB(This.BackColorAlpha, This.BackColor)), ; xBack, y1, This._Width, This._Height) ENDIF ENDWITH ENDIF * Draw the Text IF lnMode = 0 loGfx.DrawString(This._TransfCaption, This._oFont, This._oBrush, x1, y1) ELSE IF tlVertical loRect = .Rectangle.New(xBack, y1, This._Width, This._Height) loGfx.DrawString(This._TransfCaption, This._oFont, This._oBrush, loRect, loStringFmt) ELSE loGfx.DrawString(This._TransfCaption, This._oFont, This._oBrush, loRect, loStringFmt) ENDIF ENDIF IF lnRotation <> 0 OR lnRotationCenter <> 0 loGfx.ResetTransform() ENDIF ENDWITH RETURN ENDPROC PROCEDURE _setup * Update the FONT object LOCAL liStyle liStyle = 0 && Regular IF This.FontBold liStyle = liStyle + 1 ENDIF IF This.FontItalic liStyle = liStyle + 2 ENDIF IF This.FontStrikethru liStyle = liStyle + 8 ENDIF IF This.FontUnderline liStyle = liStyle + 4 ENDIF * Prepare the font object LOCAL lcFont lcFont = IIF(EMPTY(This.FontName), This.Parent.FontName, This.FontName) * If no font was selected, then take the _Screen one! IF EMPTY(lcFont) lcFont = _Screen.FontName ENDIF IF EMPTY(lcFont) lcFont = "Arial" ENDIF WITH _Screen.System.Drawing LOCAL loFont as xfcFont loFont = .Font.New(lcFont, This.FontSize, liStyle) This._oFont = loFont * Update the BRUSH object LOCAL loColor as xfcColor LOCAL lnColor lnColor = IIF(This.Parent.BrushType = 3, 0, This.ForeColor) loColor = .Color.FromArgb(This.ForeColorAlpha, lnColor) LOCAL loBrush as xfcSolidBrush loBrush = .SolidBrush.New(loColor) This._oBrush = loBrush ENDWITH This._initialized = .T. ENDPROC PROCEDURE _updatemeasures LPARAMETERS tlNumeric IF VARTYPE(THIS.oGfx)#'O' AND THIS.IsParent THIS.oGfx = THIS.PARENT.oGfx ENDIF IF VARTYPE(THIS.oGfx) <> "O" RETURN ENDIF * Measure the Legend height IF VARTYPE(THIS._oBrush) + VARTYPE(THIS._oFont) <> "OO" OR NOT THIS._initialized THIS._Setup() ENDIF LOCAL lcCaption, lcFormat * _ForceFormat is a forced formatting managed directly from FoxCharts lcFormat = IIF(EMPTY(ALLTRIM(THIS._ForceFormat)), THIS.FORMAT, ALLTRIM(THIS._ForceFormat)) IF tlNumeric IF VARTYPE(THIS._Value) = "C" lcCaption = THIS._Value ELSE IF this.IsParent and EMPTY(lcFormat) lcFormat = "999,999,999,999" + ; IIF(THIS.PARENT._ValueDecimals > 0, ; "." + REPLICATE("9", THIS.PARENT._ValueDecimals), "") ENDIF lcCaption = ALLTRIM(TRANSFORM(THIS._Value, lcFormat)) IF this.IsParent and THIS.PARENT._ValueDecimals>0 lcCaption=RTRIM(RTRIM(lcCaption,'0'),'.') ENDIF ENDIF ELSE lcCaption = STRTRAN(THIS.CAPTION,[CHR(13)+CHR(10)], CHR(13)+CHR(10),-1,-1,1) lcCaption = ALLTRIM(textmerge(lcCaption)) ENDIF LOCAL loSize AS xfcSize loSize = THIS.oGfx.MeasureString(lcCaption, THIS._oFont) &&, This._oStringFormat) THIS._Height = loSize.HEIGHT THIS._Width = CEILING(loSize.WIDTH) THIS._TransfCaption = lcCaption ENDPROC PROCEDURE _value_assign lparameters tuNewValue This._Value = tuNewValue This._UpdateMeasures(.T.) && Value passed ENDPROC ENDDEFINE DEFINE CLASS _tooltip AS label && Internal use. Not to be used directly ! *< CLASSDATA: Baseclass="label" Timestamp="" Scale="Pixels" Uniqueid="" /> * *m: caption_assign * * Caption = "ToolTip" Height = 17 Name = "_tooltip" Width = 40 * PROCEDURE caption_assign LPARAMETERS vNewVal *To do: Modify this routine for the Assign method THIS.Caption = m.vNewVal ENDPROC ENDDEFINE DEFINE CLASS foxcharts AS container && This is the main FoxCharts class. Just drop it to a form and start charting ! *< CLASSDATA: Baseclass="container" Timestamp="" Scale="Pixels" Uniqueid="" ProjectClassIcon="chart.ico" ClassIcon="chart.ico" /> *-- OBJECTDATA items order determines ZOrder / El orden de los items OBJECTDATA determina el ZOrder *< OBJECTDATA: ObjPath="Title" UniqueID="" Timestamp="" /> *< OBJECTDATA: ObjPath="SubTitle" UniqueID="" Timestamp="" /> *< OBJECTDATA: ObjPath="XAxis" UniqueID="" Timestamp="" /> *< OBJECTDATA: ObjPath="YAxis" UniqueID="" Timestamp="" /> *< OBJECTDATA: ObjPath="ScaleLegend" UniqueID="" Timestamp="" /> *< OBJECTDATA: ObjPath="AxisLegend2" UniqueID="" Timestamp="" /> *< OBJECTDATA: ObjPath="ShapeLegend" UniqueID="" Timestamp="" /> *< OBJECTDATA: ObjPath="SideLegend" UniqueID="" Timestamp="" /> *< OBJECTDATA: ObjPath="ChartCanvas" UniqueID="" Timestamp="" /> *< OBJECTDATA: ObjPath="Fields" UniqueID="" Timestamp="" /> *< OBJECTDATA: ObjPath="ToolTip" UniqueID="" Timestamp="" /> *< OBJECTDATA: ObjPath="YAxis2" UniqueID="" Timestamp="" /> * *m: afterchart && Event that occurs immediately after the chart is drawn, but still before the image object is updated. *m: axiscolor_access *m: backcolor2_access *m: brushtype_assign *m: changecolor && Method that returns a darker or brighter version of the original color. Most recommended to obtain some destination gradient values. *m: chartscount_assign *m: charttype_assign *m: color1_access *m: colortype_assign *m: currcolumn_access *m: currlegend_access *m: currobjtype_access *m: currrecno_access *m: currvalue_access *m: drawchart && Draws and updates the current chart image. DrawChart is the last method to be called after you setup all the chart properties. *m: drawreport && Returns the FULLPATH() of physical copy of an image from the current chart drawn using the EMF encoder. *m: fontname_assign *m: getchartproperties && Returns the chart user defined properties for the current chart *m: getscalelegend && Returns legends to be used in vertical scale *m: getscalevalue && Returns values to be used in vertical scale *m: mousepointer_access *m: mousepointer_assign *m: savechartproperties && Saves current list of properties so that incremental property list can be returned by GetChartProperties() *m: savetofile && Saves the current chart to a file in the image format compatible with Gdi+: Bmp, Png, Jpeg, Gif, Tiff and Emf. *m: scalebackcolor_access *m: scalelinecolor_access *m: selectedshapecolor_access *m: shapelegendexpression_access *m: shapemouseenter && Event that occurs when a user moves the mouse over a shape object from the chart. *m: shapemouseleave && Event that occurs when a user moves the mouse out of a shape object from the chart. *m: shapemousemove && Event that occurs when a user moves the mouse into a shape object of the chart. *m: shapetooltip && Event that occurs immediately before the default tooltip of FoxCharts is exibited. Use this event in order to customize the text that is to be shown in the tooltips. *m: sourcealias_assign *m: _adjuststartsweep *m: _beforedraw *m: _calculatescale *m: _centerpath *m: _checkmouseposition *m: _checkparams *m: _detachclickedslice *m: _drawaxis *m: _drawbar *m: _drawbarchart *m: _drawcylinder *m: _drawdoughnutslice *m: _drawlegendinbar *m: _drawlinechart *m: _drawpiechart *m: _drawscale *m: _drawshape *m: _drawshapelegend *m: _drawsidelegends *m: _drawslice *m: _drawsliceexternal *m: _drawstackedareachart *m: _drawtrianglebar *m: _drawverticallineback *m: _drawxaxislegend *m: _drawyaxis *m: _drawyaxislegend *m: _getadjustedangle *m: _getbasiccolor *m: _getcenterpoint *m: _getchartprop *m: _getchartproperties *m: _getchartscript && Returns a complete script to reproduce the current chart in a separate PRG. *m: _getcursorpos *m: _getfieldtype *m: _getgradientcolor *m: _getpalettecolor *m: _getrandomcolor *m: _getrelativepositions *m: _getrgb *m: _getshapepath *m: _getvalue *m: _getylegendsize *m: _initchart *m: _initpalettes *m: _newfield *m: _objtoclientex *m: _preparebackground *m: _preparebrushes *m: _preparecolors *m: _preparedata *m: _preparelegend *m: _preparelegendinslice *m: _preparesidelegend *m: _preparetitle *m: _preparetooltip *m: _preparevariables *m: _ps *m: _setfieldscount *m: _spellproperty *m: _str *m: _updatechartinfo *m: _updatecoordinates *m: _updatequality *p: alphachannel && Numeric, 0-255 Determines the level of the transparency level; 255 = Opaque; 0 = Transparent ***Spinner0,255 *p: area3dtop && Logical, when true, a line will be drawn on the top of the 3D Area chat *p: areadrawborders && Logical, draws borders around each Area piece *p: axisalpha && Numeric, Determines the Alpha (transparency) for the Y and X axis and the background lines. Useful when the background contains colors. ***Spinner0,255 *p: axiscolor && Numeric, the RGB value for the Axis main color. ***COLOR *p: backcolor2 && Numeric or logical, specifies the secondary RGB color for the background of the current chart. .F. means that this property will be ignored, and the background color will be solid, determined by the property "BackColor". *p: backcoloralpha && Numeric (0-255), the transparency level of the background of the chart. ***Spinner0,255 *p: backgradientmode && Numeric, if gradient background (having BackColor2 specified). *** 0 = Horizontal, 1 = Vertical, 2 = Diagonal 1 , 3 = Diagonal 2 *p: barlegenddirection && Integer (0-2), the direction from the legend that stays inside the bars shapes. ***0 = Horizontal, 1 = Vertical (top to bottom), 2 = Vertical (bottom to top) *p: barlegendtype && Integer, specifies the how the legend text inside bars shapes will be displayed.*** 0 = Default; 1 = Text is aligned at the center of the shape (old behavior) *p: barsperscale && Integer, number of horizontal bars per scale legend. ***Spinner0,255 *p: barsspacebetween && Numeric, for bars chart - the distance between bars in pixels. ***Spinner0,500 *p: bartype && Integer (0-2), the bar type ***0 = Rectangular ; 1 = Cylinder ; 2 = Triangle *p: brushtype && Numeric, Type of brush used to fill the chart: ***1 = Solid Colors; 2 = Gradient Colors; 3 = Monochrome Hatch brush *p: changecoloronmouse && Logical, determines if a shape color will be changed when the mouse is passed over it. *p: chartrow && Numeric, only for Pie, Doughnut and SingleBars charts, determines which row will be used to create the chart, for the case when more than one sequence of data is passed. *p: chartscount && Numeric, the number of data series. *p: chartsum && Numeric, ReadOnly, For Pie, Doughnut and SingleBars charts, returns the sum for the current column of data when the readonly SingleData property is true. *p: charttype && Num, type of chart: ***1=Pie;2=Donut;3=Full-Stacked bars;4=Point;5=Line;6=Area;7=Bars;8=MultiBars;9=Stacked Bars; 10=Stacked Area;11=3D Bars;12= Hor Bars;13=Hor MultiBars;14=Hor Stacked Bars;15=Hor Full-Stacked Bars;16=Full-Stacked Area;17=Paired Bars *p: charttype1 *p: color1 && Numeric, the RGB value of the color from the first chart. For backwards compatibility - use Fields.Color instead *p: colortype && Numeric, the type of colors: 0 = Basic Colors 1 = Custom (default) 2 = Random 3 = Scale of Gradients *p: currcolumn && Numeric, ReadOnly, the column number from the Source alias cursor. To be used when controlling mouse events. *p: currindex && Numeric, ReadOnly, the index number to be used in the aCoord property index to obtain more info about the current shape. If no shape was selected, the value of this property is 0 (zero). To be used when controlling mouse events. *p: currlegend && Character, ReadOnly, The current associated legend. To be used when controlling mouse events. *p: currobjtype && Character, ReadOnly, the type of object - "Pie", "Rect" or "Legend". To be used when controlling mouse events. *p: currrecno && Numeric, ReadOnly, the RECNO(), the row value from the Source alias cursor. To be used when controlling mouse events. *p: currvalue && ReadOnly, the value of the current shape. To be used when controlling mouse events. *p: debug && logical, determines the creation of a log file when an error occurs. The file "FOXCHARTS.LOG" will contain general error info, and you can send it to vfpimaging@hotmail.com, with some other detailed information about the error. *p: depth && Numeric, the depth in pixels, simulating a 3D effect (0 = plain) ***Spinner0,50 *p: donutratio && For Doughnut chart - Numeric, the width of the donut related to its size ( 0.01 = full slice ; 0.99 = thin). *p: fieldaxis2 && Character, the name of the field that contains the text to be drawn in the axis opposite to the scale. *p: fieldcolor && Character, the field name of the cursor that contains the RGB values of the custom colors for the chart *p: fielddetachslice && Character, the field name of the cursor that contains the logical values that tell if the slice of the Pie or Donut chart will be detached or not *p: fieldhideslice && Character, the field name of the cursor that contains the logical values that tell if the slice of the Pie or Donut chart will be hidden or not *p: fieldlegend && Character, the field name of the cursor that contains the character values that contain the main legends of the Pie or Donut charts *p: fieldvalue1 && Character, the field name from the data cursor that contains the numeric values that will create the chart. For backwards compatibility - use Fields(n).FieldValue instead *p: fieldxaxis && For backwards compatibility - use FieldAxis2 instead *p: fontname && Character, the name of the font used to display text. *p: gradientinvertcolors && Logical, determines if the gradient start and destination colors will be inverted. *p: gradientlevel && Numeric, for gradient brush mode (-10 = destination black; 0 = solid color; +10 destination white). ***Spinner -10,10 *p: gradientposition && Numeric (0-1), specifies where, along any radial from the center of the path to the path's boundary, the center color will be at its highest intensity. A value of 1 places the highest intensity at the center of the path. ***Spinner0,1,0.1 *p: gradientshapedirection && Integer, (0-3) determines the gradient direction for gradient brush charts: *** 0 = Horizontal; 1 = Vertical; 2 = Diagonal1 ; 3 = Diagonal 2 *p: gradienttype && Integer, Gradient type 0 = SigmaBell - The transition from one color to another is based on a bell-shaped curve; 1 = Triangular - gradient with a center color and a linear falloff to each surrounding color. ***0 = SigmaBell; 1 = Triangular *p: legend1 && The legend for the first column of chart. For backwards compatibility - use Fields.Color instead *p: legendhidewhennull && Logical, For Pies, Doughnuts and Simple horizontal and vertical bars, will hide the legends associated when the source value s NULL. *p: legendposition && Num, position where side legend will be drawn*** 0=No Legend;1=Vert TopLeft;2=Vert BotLeft;3=Vert TopRight;4=Vert BotRight;5=Hor TopLeft;6=Hor TopCenter;7=Hor TopRight;8=Hor BotLeft;9=Hor BotCenter;10=Hor BotRight;11=Vert CentLeft;\n12=Vert CentRight\n *p: linecaps && Logical, for the case of plain line chart, shows rounded caps in each point. *p: linecapsshape && Integer, the value of the shape to be used in the lines intersections for the line charts *p: lineignorenulls *p: margin && Numeric, Specifies the margin width created in the text portion of the control. *p: marginbottom && Numeric, Specifies the bottom margin left without any drawing in the FoxCharts control. *p: marginleft && Numeric, Specifies the left margin left without any drawing in the FoxCharts control. *p: marginright && Numeric, Specifies the right margin left without any drawing in the FoxCharts control. *p: margintop && Numeric, Specifies the top margin left without any drawing in the FoxCharts control. *p: maxvalue && If numeric, maximum value plotted along Y-Axis. Otherwise ignored (maximum value will be calculated). *p: minnumberscalelegends && Numeric, Determines the minimum number of scales legends along the Y-Axis *p: minvalue && If numeric, minimum value plotted along Y-Axis. Otherwise ignored (minimum value will be calculated). *p: multichart && Logical, determines if more than one kind of chart will run at the same time *p: multichartmargin && Logical, Determines if there will be a margin at the beginning and at the end of the chart, when using the Multichart mode. To be used when a Bar chart is not present, in order to obtain a better effect. \n *p: obmp && Object, ReadOnly, The GDI+ Bitmap object for the Chart Canvas. For GdiPlusX users, allow direct manipulation of the charts canvas. *p: ogfx && Object, ReadOnly, The GDI+ Graphics object for the Chart Canvas. For GdiPlusX users, allow direct manipulation of the charts canvas. *p: oldstyleproperties && Logical, determines if the legacy style using enumerated properties will be used. Disrecommended use ! *p: piecompensateangles && Logical, recalculates the needed angles, adjusting for a better visualisation when the pie has an important difference between width and height. Set this to false to force circular shapes. *p: piedetachanimationsteps && Numeric, the quantity of steps that a slice of a pie or doughnut will take till full detachment *p: piedetachpixels && Numeric, for Pie and Doughnut charts, the quantity of pixels to detach from center *p: piedetachsliceonclick && Logical, allows detachment of pie or doughnut slices on mouse click. *p: piedetachsliceonlegendclick && Logical, allows detachment of pie or doughnut slices on mouse click over the associated side legend *p: piedirection && Integer (0-1), determines the direction that the slices will be drawn in Pie or Doughnut charts *** 0 = Clockwise, 1 = Anticlockwise *p: pieenhanceddrawing && Logical, For Pie and Doughnut charts. Enables the enhancing drawing mode, with all edges separately, providing a better effect. *p: pieforcecircle && logical, for Pie and Doughnut charts, determines if the shape will be a circle with the same width and height. *p: piegradcenterangle && Numeric, the angle that the desired Center Point for the gradient brush will be applied (0-360). Use together with "PieGradCenterDistance" *p: piegradcenterdistance && Numeric, the distance from the center that the desired Center Point for the gradient brush will be applied (-2, +2). Use together with "PieGradCenterAngle" *p: pielegenddistance && Numeric (0.01-2), the distance in percentage starting from the center of the pie or doughnut. 0=Center of the pie; 1=external border of the pie. ***Spinner 0.01,2.00,0.01 *p: pieshowpercent && Logical, shows the percentage of the slice in the tooltip. *p: pointshapewidth && Numeric, for Point chart, determines the width of the pen that will draw the shapes. ***Spinner1,10,1 *p: qualitycompositing && Specifies the quality level to use during compositing. *** 0 = Default; 1 = HighSpeed; 2 = HighQuality; 3 = GammaCorrected; 4 = AssumeLinear *p: qualitysmoothing && Specifies whether smoothing (antialiasing) is applied to lines and curves and the edges of filled areas. *** 0 = Default; 1 = HighSpeed Specifies no antialiasing; 2 = HighQuality; 3 = None Specifies no antialiasing; 4 = AntiAlias *p: qualitytextrenderinghint && Specifies the quality of text rendering. *** 0 = SystemDefault; 1 = SingleBitPerPixelGridFit; 2 = SingleBitPerPixel; 3 = AntiAliasGridFit; 4 = AntiAlias; 5 = ClearTypeGridFit *p: scale && Numeric, determines the scale value for the Y axys; 0 = Automatic scale *p: scaleautoformat && Logical, determines if the Scales formatting from "ScaleLegend.Format" will be automatically configured. *p: scalebackalpha && Numeric (0-255), Determines the level of the transparency level; 255 = Opaque; 0 = Transparent. ***Spinner0,255 *p: scalebackbarstype && Integer (0-3), the background scale type; *** 0 = None; 1 = Horizontal lines; 2 = Vertical lines; 3 = Both *p: scalebackcolor && Numeric, the RGB value for the bar background scale color. ***Color *p: scalebacklinesdash && Numeric, The Dash style of the GDI+ pen used to draw the background scale ***0 = Solid line;1 = Line consisting of dashes; 2 = Line consisting of dots; 3 = Line consisting of a repeating pattern of dash-dot; 4 = DashDotDot (a pattern of dash-dot-dot) *p: scalebacklinestype && Integer (0-3), the background scale type; *** 0 = None; 1 = Horizontal lines; 2 = Vertical lines; 3 = Both *p: scalebacklineswidth && Numeric, Width in pixels of the GDI+ pen used to draw the background scale *p: scaledivider && Numeric, the value that the scales must be divided. Useful when the scale values are very big. *p: scalelinecolor && Numeric, RGB value for the line Background color. ***Color *p: scalelinezerocolor && Numeric, the RGB value for the color of the line of the zero scale. ***COLOR *p: selectedshapecolor && Numeric, the RGB values for the selected shape color when property 'ChangeColoronMouse' is true ***COLOR *p: shadow && Logical, determines if shadows will be drawn under the shapes. The deepness is defined by the "depth" property. *p: shape1 *p: shapelegendexpression && Character, an expression that replaces the default ShapeLegend text. A valid expression to fully customize the text to be "drawn" in the chart shapes. Use the "Curr" properties to get detailed info about the current shape and build your expression. *p: shapemousepointer && Numeric, Specifies the shape of the mouse pointer when the mouse is over a shape of the chart at run time *p: showaxis && Logical, for Line, Area or Point charts - defines if the X and Y axys will be drawn *p: showaxis2tics && Logical, determines if the legend axis (axis2) will show tic marks on each legend. *p: showlinezero && Logical, determines if the background line for the zero scale will be shown or not. *p: showpercentages && Logical, for full-stacked charts, determines if the default ShapeLegend and Tooltip text will show as Percentage\ninstead of values \nValid for the chart types: 3, 7, 8, 12, 13, 15, 16 *p: showscale && Logical, determines if the scale in the Y axys will be shown *p: showsidelegend && Logical, Shows the side legends *p: showtips && Logical, specifies if ToolTips are shown for the controls on the specified Form object or the specified ToolBar object. *p: showvaluesonshape1 *p: showvaluesonshapes && Logical, determines if the values will be drawn inside the shapes of the chart *p: showvaluezero && Logical, If True, ensures that a value of zero will appear in Y-Axis. If False, calculated range may be entirely above or entirely below zero. *p: singledata && Logical, ReadOnly, tells if the current chart is based on single data, eg. Pie, Doughnut, Single Bars *p: sourcealias && Character, The name of the alias that contains the needed fields that will create the chart *p: ticlength && Integer, the length in pixels of the tic marks used in the scales and in the legend axis. ***Spinner0,30 *p: version && Numeric, the current version number of FoxCharts class. *p: versiona && Character, the detailed version of FoxCharts class, in alphanumeric format. *a: acolors[1,0] && ReadOnly, Array that contains information about the current colors for the chart. Useful when working with random colors. *a: acoord[1,0] && Array that stores information about the object that is under the mouse, like X, Y, Width, Height, Value, Legend, Start, Sweep, CHartIndex, RECNO(), ObjType. See HELP for detailed information about the available info. *a: apalettecolors[1,0] *a: _acolors[1,0] *a: _apoints[1,2] *a: _ashapes[1,0] *a: _asidelegends[1,2] *p: _3d && Numeric, the quantity of pixels that create the 3D effect. For backwards compatibility - use the property "Depth" instead. *p: _absolutescalevalues *p: _allowaxis *p: _anchor *p: _axis2scalewidth *p: _bottomoffset *p: _chartindex *p: _charty0 *p: _charty1 *p: _currentrow *p: _datacursor *p: _deepchart *p: _drawing *p: _firstactivate *p: _generaltype *p: _hasnegatives *p: _inlegend *p: _inreport *p: _insideform *p: _leftoffset *p: _legendexternalmargin *p: _legendheight && Internal Use *p: _legendpixheight *p: _legendwidth && Internal use *p: _maxscale *p: _maxscale2 *p: _memberdata && XML Metadata for customizable properties *p: _minscale *p: _minscale2 *p: _minvalue *p: _ncolor && Internal Use *p: _nindex *p: _nmouseonshape *p: _nmouseover *p: _nrecords && Internal use, the total of records in the main cursor *p: _o3dbrush && Internal Use, GDI+ Brush object for drawing the 3D effects *p: _oblackpen *p: _oborderpen && Internal Use, Gdi+ Pen for drawing borders *p: _oclrblack *p: _oclrmatrix && Internal Use, GDI+ ColorMatrix object for drawing the transparent shapes *p: _oclrwhite *p: _omainbrush && Internal Use, GDI+ Brush object for drawing the main shapes *p: _orientation *p: _origmousepointer *p: _otempbmp && Internal Use, GDI+ Bitmap object for drawing the transparent shapes *p: _palettecolors *p: _pie1stdetached *p: _pieanimatedrec *p: _pieanimationpix *p: _piex0 *p: _piey0 *p: _redraw *p: _rightoffset *p: _savedchartproperties *p: _scale *p: _scale2 *p: _scaleadjust *p: _scaleadjust2 *p: _scaleh *p: _scaleh2 *p: _scaleinpercent *p: _scalelegaxis1forceformat *p: _scalelegaxis2forceformat *p: _scalelegend2forceformat *p: _scalerange *p: _scalerange2 *p: _scalew *p: _scalew2 *p: _skippreparedata *p: _spellinglist *p: _stacked *p: _started *p: _sumrow *p: _tippixels *p: _titleheight && Internal use *p: _topoffset *p: _updaterandomcolors *p: _useaxis *p: _using3d *p: _valuedecimals *p: _valueformat *p: _valuetype *p: _xaxisheight *p: _xrelative *p: _yaxiswidth *p: _yaxiswidth2 *p: _yrelative * * alphachannel = 255 Anchor = 0 area3dtop = .T. areadrawborders = .T. axisalpha = 200 axiscolor = 15790320 backcolor2 = .F. backcoloralpha = 255 backgradientmode = 0 barlegenddirection = 0 barlegendtype = 0 barsperscale = 2 barsspacebetween = 15 bartype = 0 brushtype = 1 changecoloronmouse = .F. chartrow = 1 chartscount = 1 chartsum = 0 charttype = 1 charttype1 = 0 color1 = 0 colortype = 1 currcolumn = 0 currindex = 0 currlegend = currobjtype = currrecno = 0 currvalue = 0 depth = 20 donutratio = 0.50 fieldaxis2 = fieldcolor = fielddetachslice = fieldhideslice = fieldlegend = fieldvalue1 = fieldxaxis = fontname = gradientinvertcolors = .F. gradientlevel = 5 gradientposition = 0.6 gradientshapedirection = 0 gradienttype = 0 Height = 264 legend1 = legendhidewhennull = .T. legendposition = 3 linecaps = .T. lineignorenulls = .F. margin = 4 marginbottom = 0 marginleft = 0 marginright = 0 margintop = 0 maxvalue = .F. minnumberscalelegends = 5 minvalue = .F. MouseIcon = ..\..\..\gradobjects\gradobjects_foxite\gradobjects\ multichart = .F. multichartmargin = .T. Name = "foxcharts" obmp = NULL ogfx = NULL oldstyleproperties = .F. piecompensateangles = .T. piedetachanimationsteps = 3 piedetachpixels = 30 piedetachsliceonclick = .T. piedetachsliceonlegendclick = .F. piedirection = 0 pieenhanceddrawing = .T. pieforcecircle = .F. piegradcenterangle = 0 piegradcenterdistance = 0 pielegenddistance = 0.75 pieshowpercent = .T. pointshapewidth = 2 qualitycompositing = 2 qualitysmoothing = 4 qualitytextrenderinghint = 4 scale = 0 scaleautoformat = .T. scalebackalpha = 128 scalebackbarstype = 1 scalebackcolor = 16118000 scalebacklinesdash = 0 scalebacklinestype = 1 scalebacklineswidth = 1 scaledivider = 1 scalelinecolor = 0 scalelinezerocolor = 255 selectedshapecolor = 8421504 shadow = .F. shape1 = 0 shapelegendexpression = shapemousepointer = 15 showaxis = .T. showaxis2tics = .T. showlinezero = .T. showpercentages = .F. showscale = .T. showsidelegend = .T. showtips = .T. showvaluesonshape1 = .T. showvaluesonshapes = .F. showvaluezero = .T. singledata = .F. sourcealias = StatusBarText = "" ticlength = 5 version = 1.37 versiona = FoxCharts v1.37b ALPHA Width = 360 _3d = .F. _absolutescalevalues = .F. _allowaxis = _anchor = 0 _axis2scalewidth = 0 _bottomoffset = 0 _chartindex = 0 _charty0 = 0 _charty1 = 0 _currentrow = 0 _datacursor = _deepchart = .F. _firstactivate = .F. _generaltype = _hasnegatives = .F. _inlegend = .F. _inreport = .F. _insideform = .T. _leftoffset = _legendexternalmargin = 19 _legendheight = 0 _legendpixheight = 0 _legendwidth = 0 _maxscale = 0 _maxscale2 = 0 _memberdata = _minscale = 0 _minscale2 = 0 _minvalue = 0 _ncolor = 0 _nindex = 0 _nmouseonshape = 0 _nmouseover = 0 _nrecords = 0 _o3dbrush = _oborderpen = _oclrblack = _oclrmatrix = _oclrwhite = _omainbrush = _orientation = 1 _origmousepointer = 0 _otempbmp = _palettecolors = 184 _pie1stdetached = .F. _pieanimatedrec = 0 _pieanimationpix = 0 _piex0 = 0 _piey0 = 0 _rightoffset = _savedchartproperties = .NULL. _scale = 0 _scale2 = 0 _scaleadjust = _scaleadjust2 = 0 _scaleh = .F. _scaleh2 = 0 _scaleinpercent = .F. _scalelegaxis1forceformat = _scalelegaxis2forceformat = _scalelegend2forceformat = _scalerange = _scalerange2 = 0 _scalew = .F. _scalew2 = 0 _skippreparedata = .F. _spellinglist = _started = .F. _sumrow = 0 _tippixels = 16 _titleheight = 0 _topoffset = 0 _updaterandomcolors = .T. _useaxis = .T. _using3d = .F. _valuedecimals = 0 _valueformat = _valuetype = _xaxisheight = 0 _xrelative = 0 _yaxiswidth = 0 _yaxiswidth2 = 0 _yrelative = 0 * ADD OBJECT 'AxisLegend2' AS _legend WITH ; Alignment = 2, ; Caption = "AxisLegend2", ; FontBold = .F., ; FontSize = 9, ; FontUnderline = .F., ; Left = 108, ; Name = "AxisLegend2", ; Top = 130, ; Visible = .F. *< END OBJECT: ClassLib="foxcharts.vcx" BaseClass="label" /> ADD OBJECT 'ChartCanvas' AS _chartcanvas WITH ; drawwheninvisible = .T., ; Height = 60, ; Left = 0, ; Name = "ChartCanvas", ; Top = 0, ; Width = 72, ; _usesmooth = .T. *< END OBJECT: ClassLib="foxcharts.vcx" BaseClass="image" /> ADD OBJECT 'Fields' AS collection WITH ; Left = 0, ; Name = "Fields", ; Top = 0 *< END OBJECT: BaseClass="collection" /> ADD OBJECT 'ScaleLegend' AS _legend WITH ; Alignment = 2, ; Caption = "ScaleLegend", ; FontBold = .F., ; FontSize = 7, ; FontUnderline = .F., ; Left = 108, ; Name = "ScaleLegend", ; Top = 60, ; Visible = .F. *< END OBJECT: ClassLib="foxcharts.vcx" BaseClass="label" /> ADD OBJECT 'ShapeLegend' AS _legend WITH ; Alignment = 2, ; Caption = "ShapeLegend", ; FontSize = 9, ; Left = 108, ; Name = "ShapeLegend", ; Top = 80, ; Visible = .F. *< END OBJECT: ClassLib="foxcharts.vcx" BaseClass="label" /> ADD OBJECT 'SideLegend' AS _legend WITH ; Alignment = 0, ; Caption = "SideLegend", ; FontBold = .F., ; FontSize = 9, ; FontUnderline = .F., ; Left = 216, ; Name = "SideLegend", ; Top = 46, ; Visible = .F. *< END OBJECT: ClassLib="foxcharts.vcx" BaseClass="label" /> ADD OBJECT 'SubTitle' AS _legend WITH ; Alignment = 2, ; Caption = "SubTitle", ; FontBold = .T., ; FontSize = 11, ; Left = 108, ; Name = "SubTitle", ; Top = 36, ; Visible = .F. *< END OBJECT: ClassLib="foxcharts.vcx" BaseClass="label" /> ADD OBJECT 'Title' AS _legend WITH ; Alignment = 2, ; Caption = "Title", ; FontBold = .T., ; FontSize = 16, ; ForeColor = 0,128,255, ; Left = 108, ; Name = "Title", ; Top = 8, ; Visible = .F. *< END OBJECT: ClassLib="foxcharts.vcx" BaseClass="label" /> ADD OBJECT 'ToolTip' AS _tooltip WITH ; Alignment = 2, ; AutoSize = .T., ; BackColor = 255,255,164, ; BackStyle = 1, ; BorderStyle = 1, ; Left = 216, ; Name = "ToolTip", ; Top = 12, ; Visible = .F., ; WordWrap = .T. *< END OBJECT: ClassLib="foxcharts.vcx" BaseClass="label" /> ADD OBJECT 'XAxis' AS _legend WITH ; Alignment = 2, ; Caption = "XAxis", ; FontBold = .T., ; FontSize = 10, ; FontUnderline = .F., ; Left = 108, ; Name = "XAxis", ; Top = 105, ; Visible = .F. *< END OBJECT: ClassLib="foxcharts.vcx" BaseClass="label" /> ADD OBJECT 'YAxis' AS _legend WITH ; Alignment = 2, ; Caption = "YAxis", ; FontBold = .T., ; FontSize = 10, ; FontUnderline = .F., ; Height = 144, ; Left = 24, ; Name = "YAxis", ; Rotation = 270, ; Top = 57, ; Visible = .F., ; Width = 24 *< END OBJECT: ClassLib="foxcharts.vcx" BaseClass="label" /> ADD OBJECT 'YAxis2' AS _legend WITH ; Alignment = 2, ; Caption = "YAxis2", ; FontBold = .T., ; FontSize = 10, ; FontUnderline = .F., ; Height = 144, ; Left = 312, ; Name = "YAxis2", ; Rotation = 270, ; Top = 57, ; Visible = .F., ; Width = 24 *< END OBJECT: ClassLib="foxcharts.vcx" BaseClass="label" /> PROCEDURE afterchart && Event that occurs immediately after the chart is drawn, but still before the image object is updated. ENDPROC PROCEDURE axiscolor_access RETURN This._GetRGB(This.AxisColor) ENDPROC PROCEDURE backcolor2_access LOCAL luBackColor2 m.luBackColor2 = This.BackColor2 IF VARTYPE(m.luBackColor2) = "L" RETURN This.BackColor2 ELSE RETURN This._GetRGB(This.BackColor2) ENDIF ENDPROC PROCEDURE brushtype_assign LPARAMETERS tnBrushType This.BrushType = m.tnBrushType This._UpdateRandomColors = .T. ENDPROC PROCEDURE changecolor && Method that returns a darker or brighter version of the original color. Most recommended to obtain some destination gradient values. LPARAMETERS tnRGB, tnLevel IF VARTYPE(m.tnRGB) + VARTYPE(m.tnLevel) <> "NN" RETURN 0 ENDIF IF m.tnLevel = 0 RETURN m.tnRGB ENDIF m.tnLevel = m.tnLevel / 100 LOCAL lnRed, lnGreen, lnBlue m.lnRed = BITAND(m.tnRGB, 0x000000FF) m.lnGreen = BITRSHIFT(BITAND(m.tnRGB, 0x0000FF00), 8) m.lnBlue = BITRSHIFT(BITAND(m.tnRGB, 0x00FF0000), 16) IF m.tnLevel > 0 RETURN RGB( ; m.lnRed + ((255 - m.lnRed) * m.tnLevel) , ; m.lnGreen + ((255 - m.lnGreen) * m.tnLevel) , ; m.lnBlue + ((255 - m.lnBlue) * m.tnLevel) ) ELSE RETURN RGB( ; m.lnRed + (m.lnRed * m.tnLevel) , ; m.lnGreen + (m.lnGreen * m.tnLevel) , ; m.lnBlue + (m.lnBlue * m.tnLevel) ) ENDIF ENDPROC PROCEDURE chartscount_assign LPARAMETERS tnCount This.ChartsCount = m.tnCount * Prepare the Enumerated properties IF This.OldStyleProperties LOCAL n, lcIndex FOR m.n = 1 TO m.tnCount m.lcIndex = This._Str(m.n) IF m.n > 1 && The enum properties #1 already exists - no need to recreate This.AddProperty("ChartType" + m.lcIndex, 0) This.AddProperty("FieldValue" + m.lcIndex, "") This.AddProperty("Legend" + m.lcIndex, "") This.AddProperty("Color" + m.lcIndex, "") This.AddProperty("Shape" + m.lcIndex, 0) This.AddProperty("ShowValuesOnShape" + m.lcIndex, .T.) This.AddProperty("AxisIndex" + m.lcIndex, 1) ENDIF ENDFOR ENDIF * Prepare the Fields collection This._SetFieldsCount(m.tnCount) ENDPROC PROCEDURE charttype_assign LPARAMETERS tnChartType This.ChartType = tnChartType This._UpdateRandomColors = .T. This._SkipPrepareData = .F. ENDPROC PROCEDURE color1_access RETURN This._GetRGB(This.Color1) ENDPROC PROCEDURE colortype_assign LPARAMETERS tnColorType This.ColorType = m.tnColorType IF m.tnColorType = 2 && Random This._UpdateRandomColors = .T. ENDIF ENDPROC PROCEDURE currcolumn_access LOCAL lnIndex, lnColumn m.lnIndex = This.CurrIndex m.lnColumn = IIF(m.lnIndex = 0, 0, This.aCoord(m.lnIndex, 9)) RETURN m.lnColumn ENDPROC PROCEDURE currlegend_access LOCAL lnIndex, lcLegend m.lnIndex = This.CurrIndex m.lcLegend = IIF(m.lnIndex = 0, "", This.aCoord(m.lnIndex, 6)) RETURN m.lcLegend ENDPROC PROCEDURE currobjtype_access LOCAL lnIndex, lcObjType m.lnIndex = This.CurrIndex m.lcObjType = IIF(m.lnIndex = 0, "", This.aCoord(m.lnIndex, 11)) RETURN m.lcObjType ENDPROC PROCEDURE currrecno_access LOCAL lnIndex, lnRec m.lnIndex = This.CurrIndex m.lnRec = IIF(m.lnIndex = 0, 0, This.aCoord(m.lnIndex, 10)) RETURN m.lnRec ENDPROC PROCEDURE currvalue_access LOCAL lnIndex, lnValue m.lnIndex = This.CurrIndex m.lnValue = IIF(EMPTY(m.lnIndex), 0, This.aCoord(m.lnIndex, 5)) RETURN m.lnValue ENDPROC PROCEDURE drawchart && Draws and updates the current chart image. DrawChart is the last method to be called after you setup all the chart properties. * Some setups before drawing for the case of transparent background * When some Image Canvas settings are needed IF This.BackColorAlpha < 255 && Transparency active This.ChartCanvas.Clear(_Screen.System.Drawing.Color.Transparent) This.ChartCanvas.RenderMode = 4 && Memory PNG This.BackStyle = 0 && Transparent ENDIF IF NOT This._Started This._InitChart() ENDIF This.ChartCanvas.Draw() ENDPROC PROCEDURE drawreport && Returns the FULLPATH() of physical copy of an image from the current chart drawn using the EMF encoder. LPARAMETERS tnWidth, tnHeight This._SkipPrepareData = .T. This._InReport = .T. LOCAL ARRAY laBackup(1) ACOPY(This.aCoord, laBackup) LOCAL lcFile, lcAlias m.lcAlias = ALIAS() m.lcFile = This.ChartCanvas.DrawReport(m.tnWidth, m.tnHeight) ACOPY(laBackup, This.aCoord) This._InReport = .F. SELECT(m.lcAlias) RETURN m.lcFile ENDPROC PROCEDURE fontname_assign LPARAMETERS tcFontName This.FontName = m.tcFontName * Set all the legend types available This.SetAll("FontName", m.tcFontName, "_Legend") * Set the Tooltip fontname as well IF This._InsideForm This.ToolTip.FontName = m.tcFontName ENDIF ENDPROC PROCEDURE getchartproperties && Returns the chart user defined properties for the current chart ********************************************************************************************** * Method: GetChartProperties * Author: Jim R. Nelson * Returns the properties and values used to create the current chart * 2009-12-11 CChalom: added parameter #4, for getting the full script ********************************************************************************************** Lparameters tnType, tbWrapper, tlShowDescriptions * tnType = 1 for all properties * = 2 for non-default properties * = 3 for properties since last call to .SaveChartProperties * = 4 for returning a full script for recreating the chart * tbWrapper = .T. to include code around it ... WITH / ENDWITH Local lcResult, lcObjects, lcCollection, loPropertiesList, lcMember, lnType, laMembers(1), laObjMembers(1), lcObjMem, lcItem, lnI, lcTempResult, lnJ Local lcTabs, lnRow, lcDescription, loMember Local lcCRLF, lnTabSpaces, lcProperty m.lcCRLF = Chr(13) + Chr(10) m.lnTabSpaces = 4 m.lcTabs = Space(m.lnTabSpaces) Do Case Case Empty (m.tnType) m.lnType = 1 Case m.tnType = 3 And Isnull(This._savedchartproperties) * for tnType =2, you must have first invoked method SaveChartProperties ... * the result is then all properties modified after the call to SaveChartProperties m.lnType = 2 CASE m.tnType = 4 RETURN This._GetChartScript() Otherwise m.lnType = m.tnType Endcase m.lcResult = "" m.lcObjects = "" m.lcCollection = "" m.loPropertiesList = This._GetChartProperties() Amembers(laMembers, m.loPropertiesList, 3) *!* 2009-12-17 *!* CChalom: Changed order of appearance of the properties For m.lnI = 1 To Alen (m.laMembers, 1) m.lcMember = This._spellproperty (m.laMembers(m.lnI,1)) m.lcDescription = '' m.lnRow = Ascan (m.loPropertiesList._Descriptions, m.lcMember, -1, -1, 1, 9) If m.lnRow > 0 m.lcDescription = m.loPropertiesList._Descriptions(m.lnRow, 4) Endif Do Case Case Lower(m.lcMember) = '_descriptions' Case "O" # Type ("loPropertiesList." + m.lcMember) && simple properties m.lcResult = m.lcResult + This._GetChartProp(m.loPropertiesList, m.lcMember, m.lnType, This._savedchartproperties, m.lcDescription, m.tlShowDescriptions) Case "C" = Type ("loPropertiesList." + m.lcMember, 1) && collection container For m.lnJ = 1 To Evaluate ("loPropertiesList." + m.lcMember + ".Count") m.lcItem = m.lcMember + ".Item(" + Transform(m.lnJ) + ")" m.loMember = Evaluate ("loPropertiesList." + m.lcItem) Amembers (laObjMembers, m.loMember) m.lcTempResult = '' For Each m.lcObjMem In m.laObjMembers m.lcObjMem = This._spellproperty (m.lcObjMem) m.lcDescription = '' If m.tlShowDescriptions And Pemstatus(m.loMember, "_Descriptions", 5) m.lnRow = Ascan (m.loMember._Descriptions, m.lcObjMem, -1, -1, 1, 9) If m.lnRow > 0 m.lcDescription = m.loMember._Descriptions(m.lnRow, 4) Endif Endif m.lcProperty = This._GetChartProp(; m.loPropertiesList, m.lcItem + "." + m.lcObjMem, m.lnType, This._savedchartproperties, m.lcDescription, m.tlShowDescriptions) m.lcTempResult = m.lcTempResult + m.lcProperty Endfor If Not Empty (m.lcTempResult) m.lcCollection = m.lcCollection + ; "WITH ." + m.lcMember + "(" + Transform(m.lnJ) + ")" + m.lcCRLF + ; Strtran(m.lcTempResult, "." + m.lcItem, m.lcTabs)+ "ENDWITH" + m.lcCRLF Endif Endfor Otherwise && Legend objects m.loMember = Evaluate ("loPropertiesList." + m.lcMember) Amembers (laObjMembers, m.loMember) m.lcTempResult = '' For Each m.lcObjMem In m.laObjMembers m.lcObjMem = This._spellproperty (m.lcObjMem) m.lcDescription = '' If m.tlShowDescriptions And Pemstatus(m.loMember, "_Descriptions", 5) m.lnRow = Ascan (m.loMember._Descriptions, m.lcObjMem, -1, -1, 1, 9) If m.lnRow > 0 m.lcDescription = m.loMember._Descriptions(m.lnRow, 4) Endif Endif m.lcTempResult = m.lcTempResult + This._GetChartProp (; m.loPropertiesList, m.lcMember + "." + m.lcObjMem, m.lnType, This._savedchartproperties, m.lcDescription, m.tlShowDescriptions) Endfor If Not Empty (m.lcTempResult) m.lcObjects = m.lcObjects + "WITH ." + m.lcMember + m.lcCRLF + ; Strtran(m.lcTempResult, "." + m.lcMember, m.lcTabs) + ; "ENDWITH" + m.lcCRLF Endif Endcase Endfor * Merge all types m.lcResult = m.lcResult + m.lcObjects + m.lcCollection *!* 2009-02-21 *!* CChalom: Fixed insertion of With/Endwith If m.tbWrapper Local lcCommand, laLines(1), N m.lcCommand = "" For m.N = 1 To Alines(laLines, m.lcResult) m.lcCommand = m.lcCommand + Space(3) + m.laLines(m.N) + m.lcCRLF Endfor TEXT TO m.lcResult NOSHOW TEXTMERGE LOCAL loChart as FoxCharts OF "FoxCharts.vcx" m.loChart = CREATEOBJECT("FoxCharts") WITH loChart <> <>loChart.DrawChart() ENDWITH ENDTEXT Endif Return m.lcResult ENDPROC PROCEDURE getscalelegend && Returns legends to be used in vertical scale Lparameters tnScaleNumber, tnValue **************************************************************** * Jim Nelson 10/10/08 * Returns the Value for the N-th scale legend on the vertical axis. * tnScaleNumber = 0 corresponds to the highest scale legend * * for tnScaleNumber = -1, returns the value to be used in determining the width of the scale legends. * * Return value may be numeric (usual) or character (e.g., substituting "zero" for 0) Do Case * -1 means the default (maximum) used to determine width Case (m.tnScaleNumber <> -1) AND (0 # m.tnScaleNumber % This.BarsPerScale) Return [] Case m.tnScaleNumber = -1 RETURN This._MaxScale *!* Case m.tnScaleNumber = -1 And Not Empty (This.ScaleLegend._ForceFormat) *!* Return This.ScaleLegend._ForceFormat *!* Case m.tnScaleNumber = -1 And Empty (This.ScaleLegend._ForceFormat) *!* RETURN This._MaxScale Otherwise Return m.tnValue Endcase ENDPROC PROCEDURE getscalevalue && Returns values to be used in vertical scale Lparameters tnScaleNumber, tnIndex m.tnIndex = EVL(m.tnIndex, 1) **************************************************************** * Jim Nelson 10/10/08 * Returns the Value for the N-th scale on the vertical axis. * tnScaleNumber = 0 corresponds to the highest scale * * Returns .F. for values of lnScaleNumber that are beyond the lowest scale. * This code assumes that the increment between successive scale values is constant. * There is not need for that to be true. * For instance, it could return the values in the first column here, where the second column is the grade * (and Method GetScaleLegend could return the character grades) * * 100 A+ * 90 A * 80 B * 65 C * 50 D * 0 F Local lnResult IF m.tnIndex = 1 m.lnResult = This._MaxScale - m.tnScaleNumber * This._Scale If m.lnResult >= This._MinScale - This._Scale / 100 Return m.lnResult Else Return .F. ENDIF ELSE m.lnResult = This._MaxScale2 - m.tnScaleNumber * This._Scale2 If m.lnResult >= This._MinScale2 - This._Scale2 / 100 Return m.lnResult Else Return .F. ENDIF ENDIF ENDPROC PROCEDURE Init This._InitChart() ENDPROC PROCEDURE MouseMove LPARAMETERS nButton, nShift, nXCoord, nYCoord, tnValue, tcLegend, tnCoordIndex, tcObjType ENDPROC PROCEDURE mousepointer_access RETURN This.ChartCanvas.MousePointer ENDPROC PROCEDURE mousepointer_assign LPARAMETERS nMousePointer This.ChartCanvas.MousePointer = m.nMousePointer This.MousePointer = m.nMousePointer ENDPROC PROCEDURE MouseUp LPARAMETERS nButton, nShift, nXCoord, nYCoord, tnValue, tcLegend, tnCoordIndex, tcObjType ENDPROC PROCEDURE Moved This._GetRelativePositions() ENDPROC PROCEDURE Resize IF This._InsideForm IF Thisform.Visible = .F. OR This.Visible = .F. This.ChartCanvas.lRedrawNow = .F. This.ChartCanvas.Width = This.Width This.ChartCanvas.Height = This.Height RETURN ENDIF ENDIF IF This._FirstActivate && AND Thisform.Visible This._FirstActivate = .F. RETURN ENDIF This._UpdateRandomColors = .F. This.ChartCanvas.lRedrawNow = .F. This.ChartCanvas.Width = This.Width This.ChartCanvas.Height = This.Height This._SkipPrepareData = .T. IF This._Started This.ChartCanvas.lRedrawNow = .T. ENDIF RETURN ENDPROC PROCEDURE savechartproperties && Saves current list of properties so that incremental property list can be returned by GetChartProperties() **************************************************************** * Jim Nelson 10/20/2008 * modified 06/30/2009 * Save current settings of Chart Properties so that later comparisons * can determine which properties have changed Lparameters tlSkipIfAlreadySaved If tlSkipIfAlreadySaved And "O" = Vartype(This._SavedChartProperties) Return Endif This._SavedChartProperties = This._GetChartProperties() ENDPROC PROCEDURE savetofile && Saves the current chart to a file in the image format compatible with Gdi+: Bmp, Png, Jpeg, Gif, Tiff and Emf. LPARAMETERS tcFile, tnQuality IF EMPTY(m.tcFile) && Invalid File Name RETURN .F. ENDIF LOCAL lcImgFormatTypes, lcFile, lcExt LOCAL loImgFormat as xfcImageFormat LOCAL loQualityEncoder AS xfcEncoderParameter LOCAL loEncoderParameters AS xfcEncoderParameters m.loEncoderParameters = .F. m.lcExt = LOWER(JUSTEXT(m.tcFile)) IF EMPTY(m.lcExt) m.lcExt = "png" ENDIF DO CASE CASE m.lcExt = "bmp" OR m.lcExt = "bitmap" m.loImgFormat = _Screen.System.Drawing.Imaging.ImageFormat.Bmp CASE m.lcExt = "jpg" OR m.lcExt = "jpeg" m.loImgFormat = _Screen.System.Drawing.Imaging.ImageFormat.Jpeg IF VARTYPE(m.tnQuality) = "N" && set the quality encoder if the parameter was passed && otherwise, the default 75% for Gdi+ will be used. && Create an EncoderParameters object. && An EncoderParameters object has an array of EncoderParameter && objects. In this case, there is only one && EncoderParameter object in the array. m.loEncoderParameters = _Screen.System.Drawing.Imaging.EncoderParameters.New(1) && Save the bitmap as a JPEG file with quality level. m.loQualityEncoder = _Screen.System.Drawing.Imaging.EncoderParameter.New(_Screen.System.Drawing.Imaging.Encoder.Quality, m.tnQuality) m.loEncoderParameters.Param.Add(m.loQualityEncoder) ENDIF CASE m.lcExt = "gif" m.loImgFormat = _Screen.System.Drawing.Imaging.ImageFormat.Gif CASE m.lcExt = "png" m.loImgFormat = _Screen.System.Drawing.Imaging.ImageFormat.Png CASE m.lcExt = "tif" OR m.lcExt = "tiff" m.loImgFormat = _Screen.System.Drawing.Imaging.ImageFormat.Tiff CASE m.lcExt = "emf" LOCAL lcTempFile m.lcTempFile = This.DrawReport() IF FILE(m.lcTempFile) COPY FILE (m.lcTempFile) TO (m.tcFile) ENDIF RETURN OTHERWISE RETURN .F. ENDCASE TRY This.oBmp.Save(m.tcFile, m.loImgFormat, m.loEncoderParameters) CATCH ENDTRY ENDPROC PROCEDURE scalebackcolor_access RETURN This._GetRGB(This.ScaleBackColor) ENDPROC PROCEDURE scalelinecolor_access RETURN This._GetRGB(This.ScaleLineColor) ENDPROC PROCEDURE selectedshapecolor_access RETURN This._GetRGB(This.SelectedShapeColor) ENDPROC PROCEDURE shapelegendexpression_access RETURN This.ShapeLegendExpression ENDPROC PROCEDURE shapemouseenter && Event that occurs when a user moves the mouse over a shape object from the chart. LPARAMETERS nButton, nShift, nXCoord, nYCoord, tnValue, tcLegend, tnCoordIndex ENDPROC PROCEDURE shapemouseleave && Event that occurs when a user moves the mouse out of a shape object from the chart. LPARAMETERS nButton, nShift, nXCoord, nYCoord, tnValue, tcLegend, tnCoordIndex ENDPROC PROCEDURE shapemousemove && Event that occurs when a user moves the mouse into a shape object of the chart. LPARAMETERS nButton, nShift, nXCoord, nYCoord, tnValue, tcLegend, tnCoordIndex ENDPROC PROCEDURE shapetooltip && Event that occurs immediately before the default tooltip of FoxCharts is exibited. Use this event in order to customize the text that is to be shown in the tooltips. LPARAMETERS nButton, nShift, nXCoord, nYCoord, tnValue, tcLegend, tnCoordIndex, tcObjType WITH This LOCAL lcCaption, lcFormat, lnDecimals, lcDecHelp, i IF m.tcObjType = "Legend" m.lcCaption = "" ELSE * 2013-02-24 CChalom - Update to calculate the decimals for the current object m.lcDecHelp = TRANSFORM(ABS(INT(tnValue) - tnValue)) m.lcDecHelp = SUBSTR(m.lcDecHelp, 3) FOR i = 1 TO LEN(m.lcDecHelp) IF RIGHT(m.lcDecHelp,1) = "0" m.lcDecHelp = LEFT(m.lcDecHelp, LEN(m.lcDecHelp) - 1) ELSE EXIT ENDIF ENDFOR m.lnDecimals = LEN(m.lcDecHelp) * - m.lcFormat = .ShapeLegend.Format IF EMPTY(m.lcFormat) && AND NOT EMPTY(This.ShapeLegendExpression) * m.lcFormat = "999,999,999,999" + ; IIF(This._ValueDecimals > 0, "." + REPLICATE("9", This._ValueDecimals), "") m.lcFormat = "999,999,999,999" + ; IIF(m.lnDecimals > 0, "." + REPLICATE("9", m.lnDecimals), "") ENDIF m.lcCaption = ALLTRIM(ALLTRIM(TRANSFORM(m.tnValue, m.lcFormat)) + ; IIF(EMPTY(m.tcLegend),"", CHR(13) + m.tcLegend) + ; IIF(m.tcObjType = "Pie", CHR(13) + TRANSFORM(INT((m.tnValue / .ChartSum)*100)) + "%","")) ENDIF .ToolTip.Caption = m.lcCaption .MousePointer = .ShapeMousePointer IF NOT EMPTY(m.lcCaption) AND ; Thisform.FoxChartsToolTip.Width = 0 Thisform.FoxChartsToolTip.Width = 10 ENDIF ENDWITH RETURN ENDPROC PROCEDURE sourcealias_assign LPARAMETERS tcNewAlias This.SourceAlias = m.tcNewAlias IF NOT EMPTY(This._DataCursor) AND USED(This._DataCursor) USE IN (This._DataCursor) ENDIF This._DataCursor = "" ENDPROC PROCEDURE _adjuststartsweep LPARAMETERS tnStart, tnSweep, tnWidth, tnHeight LOCAL lnDrawStart, lnDrawSweep, lnDestAngle IF This.PieCompensateAngles m.lnDrawStart = This._GetAdjustedAngle(m.tnStart, m.tnWidth, m.tnHeight) m.lnDestAngle = This._GetAdjustedAngle(m.tnStart + m.tnSweep, m.tnWidth, m.tnHeight) IF m.lnDestAngle < m.lnDrawStart m.lnDestAngle = m.lnDestAngle + 360 ENDIF m.lnDrawSweep = m.lnDestAngle - m.lnDrawStart m.tnStart = m.lnDrawStart m.tnSweep = m.lnDrawSweep ELSE IF m.tnStart < 0 m.tnStart = m.tnStart + 360 ENDIF ENDIF ENDPROC PROCEDURE _beforedraw Local loException as Object TRY This._Drawing = .T. * Store the current selected table / cursor LOCAL lnSelect m.lnSelect = SELECT() * Initial Settings LOCAL loChart as FoxCharts OF FoxCharts.Vcx m.loChart = This m.loChart.oGfx = This.ChartCanvas.oGfx m.loChart.oBmp = This.ChartCanvas.oBmp * Update quality settings This._UpdateQuality() * Check if the FoxCharts object was created * This is for the case when the user does not create the chart cursor before the form is initialized. IF EMPTY(This.SourceAlias) m.loChart._PrepareBackGround() EXIT ENDIF * Check for the minimum dimensions IF This.ChartCanvas.Width < 30 OR ; This.ChartCanvas.Height < 30 EXIT ENDIF m.loChart._CheckParams() m.loChart._UpdateChartInfo() IF NOT m.loChart._SkipPrepareData OR NOT USED(This._DataCursor) * Check if empty cursor IF NOT m.loChart._PrepareData() m.loChart._PrepareBackGround() m.loChart._PrepareTitle() EXIT ENDIF * Make sure to clear some properties to avoid issues if changing the chart type * having the Chart active This._ScaleLegAxis1ForceFormat = "" This._ScaleLegAxis2ForceFormat = "" This.ScaleLegend._ForceFormat = "" m.loChart._PrepareVariables() m.loChart._PrepareColors() ELSE SELECT (This._DataCursor) GO TOP ENDIF * m.loChart._PrepareColors() m.loChart._PrepareBackGround() m.loChart._PrepareTitle() m.loChart._PrepareSideLegend() m.loChart._PrepareLegend() m.loChart._DrawAxis() m.loChart._PrepareTooltip IF m.loChart.ShowValuesOnShapes m.loChart.ShapeLegend._Setup() ENDIF LOCAL lnChartType m.lnChartType = m.loChart.ChartType IF INLIST(m.lnChartType, 6, 9, 14, 11, 10) AND This._HasNegatives MESSAGEBOX("The selected Chart type does not support negative values" + CHR(13) + "The chart will not be drawn", 48, "Invalid Data") ELSE DO CASE *!* Chart Type Values: *!* 1 = Pie ; 2 = Donut ; *!* 3 = Unspecified ; *!* 4 = Point ; 5 = Line ; 6 = Area ; *!* 7 = Simple Bar ; 8 = Multiple Bars ; 9 = Stacked Bars ; 11 = 3D Bars *!* 10 = Stacked Area *!* 12 = Horizontal Bars ; 13 = Horizontal multiple bars ; 14 = Horizontal Stacked Bars CASE This._GeneralType = "Pie" && Pie or Donut Chart m.loChart._DrawPieChart() CASE This._GeneralType = "Bar" && Bar Chart m.loChart._DrawBarChart() CASE INLIST(m.lnChartType, 4, 5, 6, 18) && Line or Area Chart m.loChart._DrawLineChart() CASE INLIST(m.lnChartType, 10, 16) && Stacked Area Chart m.loChart._DrawStackedAreaChart() ENDCASE ENDIF m.loChart._DrawSideLegends() m.loChart.AfterChart() m.loChart._FirstActivate = .F. m.loChart._SkipPrepareData = .F. m.loChart._yAxisWidth = 0 m.loChart._yAxisWidth2 = 0 * Restore the original selected alias SELECT (m.lnSelect) This._GetRelativePositions() CATCH TO m.loException IF This.Debug * Send the error to a file LOCAL lcVersion, lcError, lcErrFile, lcCRLF, lcLine m.lcCRLF = CHR(13) + CHR(10) m.lcLine = m.lcCRLF + REPLICATE("=", 60) + m.lcCRLF m.lcErrFile = "FoxCharts.log" m.lcError = "FoxCharts Error" + ; m.lcLine + ; TRANSFORM(DATETIME()) + m.lcLine + ; [Error: ] + STR(m.loException.ERRORNO) + m.lcCRLF + ; [Line : ] + STR(m.loException.LINENO) + m.lcCRLF + ; [Message: ] + m.loException.MESSAGE + m.lcCRLF + ; [Procedure: ] + m.loException.PROCEDURE + m.lcCRLF + ; [Details: ] + m.loException.DETAILS + m.lcCRLF + ; [StackLevel: ] + STR(m.loException.STACKLEVEL) + m.lcCRLF + ; [LineContents: ] + m.loException.LINECONTENTS + m.lcCRLF + ; [UserValue: ] + m.loException.USERVALUE + m.lcLine + m.lcCRLF * Code from Christof Wollenhaupt LOCAL lcDir, lcMemory, lcStatus m.lcDir = ADDBS(GETENV("TEMP")) IF FILE(m.lcDir + "mem.txt") ERASE (m.lcDir + "mem.txt") ENDIF LIST MEMORY LIKE * TO (m.lcDir + "mem.txt") NOCONSOLE IF FILE(m.lcDir + "List_status.txt") ERASE (m.lcDir + "List_status.txt") ENDIF LIST STATUS TO (m.lcDir + "list_status.txt") NOCONSOLE m.lcMemory = FILETOSTR(m.lcDir + "mem.txt") m.lcStatus = FILETOSTR(m.lcDir + "List_Status.txt") ERASE (m.lcDir + "mem.txt") ERASE (m.lcDir + "List_status.txt") *------------------------------------------------------ * Assemble the calling hierarchy *------------------------------------------------------ LOCAL lcHierarchy, lnLevel, lcProcedure, laStack[1] m.lcHierarchy = "PROCEDURE HIERARCHY" + m.lcLine FOR m.lnLevel = ASTACKINFO(laStack) - 1 TO 1 STEP - 1 m.lcProcedure = SUBSTR(SYS(16, m.lnLevel), AT(" ", ; SYS(16, m.lnLevel), 1) + 1) m.lcHierarchy = m.lcHierarchy + ; " " + PROPER(ALLTRIM(LEFT(m.lcProcedure, ; AT(" ", m.lcProcedure)))) + " in " + ; JUSTSTEM(SUBSTR(SYS(16, m.lnLevel), ; AT(" ", SYS(16, m.lnLevel), 2) + 1)) + ; ", " + TRANSFORM(m.laStack[m.lnLevel, 5]) + ; CHR(13) + CHR(10) ENDFOR * GdiPlusX version check LOCAL lnVersion m.lnVersion = 0 IF pemstatus(_Screen.System, "Version", 5) m.lnVersion = _Screen.System.Version ENDIF m.lcVersion = "Visual FoxPro " + TRANSFORM(VERSION(4)) + m.lcCRLF + ; "System: " + TRANSFORM(OS(1)) + " - " + TRANSFORM(OS(7)) + m.lcCRLF + ; "GdiPlusX Version: " + TRANSFORM(m.lnVersion) + m.lcCRLF + ; "FoxCharts Version: #" + TRANSFORM(This.Version) + " - " + TRANSFORM(This.VersionA) + ; m.lcLine + m.lcCRLF * Retrieve Chart properties LOCAL lcChartProps TRY m.lcChartProps = This.GetChartProperties() m.lcChartProps = STRTRAN(m.lcChartProps, CHR(13), m.lcCRLF) CATCH m.lcChartProps = "Not Available" ENDTRY m.lcChartProps = "Chart Properties" + m.lcCRLF + m.lcLine + m.lcCRLF + m.lcChartProps IF FILE(m.lcErrFile) ERASE (m.lcErrFile) ENDIF * Save error file to disk STRTOFILE(m.lcVersion + m.lcError + m.lcLine + ; m.lcChartProps + m.lcLine + ; m.lcHierarchy + m.lcLine + m.lcMemory + m.lcLine + m.lcStatus, m.lcErrFile) MESSAGEBOX("A Log file containing info about this error and your environment details was created: " + m.lcCRLF + m.lcCRLF + ; FULLPATH(m.lcErrFile) + m.lcCRLF + m.lcCRLF + ; "Please send it to: vfpimaging@hotmail.com to help us fixing it." + m.lcCRLF + m.lcCRLF + ; m.lcError + m.lcCRLF + m.lcCRLF + ; "Sorry for the inconvenience", 16, "FoxCharts Error") ELSE IF _VFP.StartMode = 0 LOCAL lcVersion, lcError, lcErrFile, lcCRLF, lcLine m.lcCRLF = CHR(13) + CHR(10) m.lcLine = m.lcCRLF + REPLICATE("=", 30) + m.lcCRLF m.lcError = "FoxCharts Error" + ; m.lcLine + ; TRANSFORM(DATETIME()) + m.lcLine + ; [Error: ] + STR(m.loException.ERRORNO) + m.lcCRLF + ; [Line : ] + STR(m.loException.LINENO) + m.lcCRLF + ; [Message: ] + m.loException.MESSAGE + m.lcCRLF + ; [Procedure: ] + m.loException.PROCEDURE + m.lcCRLF + ; [Details: ] + m.loException.DETAILS + m.lcCRLF + ; [StackLevel: ] + STR(m.loException.STACKLEVEL) + m.lcCRLF + ; [LineContents: ] + m.loException.LINECONTENTS + m.lcCRLF + ; [UserValue: ] + m.loException.USERVALUE + m.lcLine + m.lcCRLF MESSAGEBOX(m.lcError, 16, "FoxCharts error") THROW m.loException ENDIF ENDIF This._Drawing = .F. IF This._Redraw = .T. This._Redraw = .F. This.DrawChart() ENDIF ENDTRY RETURN ENDPROC PROCEDURE _calculatescale LPARAMETERS tnMaxValue, tnMinValue, tnAxis m.tnAxis = EVL(m.tnAxis, 1) * 2009-12-12 CChalom - if working with full-stacked charts, use fixed values IF This._ScaleInPercent This._MinScale = 0 This._MaxScale = 100 This._ScaleRange = 100 This._Scale = IIF(This.Scale > 0, MIN(This.Scale, 100), 20) This._ScaleAdjust = 0 RETURN ENDIF * By Jim Nelson * Determines the maximum and minimum values plotted along the Y-Axis, and the increment between the legends. * Arguments: * tnMaxValue = Maximum value in the data being plotted * tnMinValue = Minimum value in the data being plotted * Properties referenced: * .Scale = Increment between legends along the axis. If empty, will be calculated. * .MaxValue = If numeric, the value of the top legend along the axis. Otherwise calculated. * .MinValue = If numeric, the value of the bottom legend along the axis. Otherwise calculated. * .ShowValueZero = If True, insures that a value of zero will appear along the Y-Axis. Otherwise, * the calculated range may be entirely above or below zero. * .MinNumberScaleLegends = The minimum number of scale legends to be drawn along the axis. * (The actual number is dependent on the data; the maximum will be one less * than twice this number.) * .BarsPerScale = The number of horizontal background bars (alternating colors) for each * scale legend. * Note that the values for Scale, MaxValue, and MinValue are normally left at their default values, so that * "nice" (that is, visually attractive) values can be determined. * Not all combinations of these properties make sense: for instance, setting MaxValue and/or MinValue * can make ShowValueZero irrelevant; setting Scale makes MinNumberScaleLegends irrelevant Local lnMax, lnMin, lnScale, lnMaxScale, lnMinScale, lnRange, lnLegendHeight, lnDigits, lnScaling IF m.tnAxis = 1 m.lnMax = Icase( ; "N" = Vartype (This.MaxValue), This.MaxValue, ; This.ShowValueZero, Max (0, m.tnMaxValue) , ; m.tnMaxValue) m.lnMin = Icase( ; "N" = Vartype (This.MinValue), This.MinValue, ; This.ShowValueZero, Min (0, m.tnMinValue), ; m.tnMinValue) m.lnScale = This.Scale ELSE m.lnMax = m.tnMaxValue m.lnMin = m.tnMinValue m.lnScale = 0 ENDIF * 20081006 - JNelson fixed range calculation m.lnRange = m.lnMax - m.lnMin * Calculate the scale, if none supplied Do Case Case Not Empty (m.lnScale) m.lnMaxScale = m.lnScale * Ceiling (m.lnMax / m.lnScale) m.lnMinScale = m.lnScale * Floor (m.lnMin / m.lnScale) *** JRN 07/01/09 : Insure legend on both top and bottom of Y-Axis If This.BarsPerScale > 1 m.lnLegendHeight = m.lnScale * This.BarsPerScale m.lnMaxScale = m.lnLegendHeight * Ceiling( (m.lnMaxScale - m.lnMinScale) / m.lnLegendHeight) Endif If This.ScaleAutoFormat m.lnDigits = Ceiling (Log10(Max (10, Abs( m.lnMaxScale / This.ScaleDivider ), Abs (m.lnMinScale / This.ScaleDivider)))) This.ScaleLegend._ForceFormat = " " + Right ("999,999,999,999,999", m.lnDigits + Floor((m.lnDigits + 3) / 3)+1) Else This.ScaleLegend._ForceFormat = "" Endif Case m.lnRange = 0 m.lnScale = 10 m.lnMaxScale = 1 m.lnMinScale = 0 Otherwise * choose "nice" steps sizes -- 10, 20, 25, or 50 times some power of ten. Local laSteps(4) m.laSteps(1) = 1 m.laSteps(2) = 2 m.laSteps(3) = 2.5 m.laSteps(4) = 5 Local lnMult, lnCurrentNSteps, lnStep, lnSteps, lnNiceStep, lnPowerof10, lnExponent m.lnExponent = Floor ( Log10 (m.lnRange)) - 3 && scale range to be between 1,000 and 9,999 m.lnCurrentNSteps = 9999 For Each m.lnNiceStep In m.laSteps For m.lnPowerof10 = 0 To 3 m.lnStep = (m.lnNiceStep / Evl (This.BarsPerScale, 1)) * 10 ^ (m.lnExponent + m.lnPowerof10) m.lnSteps = Ceiling (m.lnMax / m.lnStep) - Floor (m.lnMin / m.lnStep) *** JRN 07/01/09 : Insure legend on both top and bottom oy Y-Axis If This.BarsPerScale > 1 m.lnSteps = This.BarsPerScale * Ceiling( m.lnSteps / This.BarsPerScale) Endif If Between (m.lnSteps, This.MinNumberScaleLegends, m.lnCurrentNSteps) m.lnScale = m.lnStep / 1 m.lnMaxScale = m.lnStep * Ceiling (m.lnMax / m.lnStep) m.lnMinScale = m.lnStep * Floor (m.lnMin / m.lnStep) m.lnCurrentNSteps = m.lnSteps m.lnScaling = m.lnExponent + m.lnPowerof10 + Iif (0 = m.lnNiceStep % 1, 1, 0) *** JRN 07/01/09 : Insure legend on both top and bottom oy Y-Axis If This.BarsPerScale > 1 m.lnLegendHeight = m.lnScale * This.BarsPerScale m.lnMaxScale = m.lnLegendHeight * Ceiling( (m.lnMaxScale - m.lnMinScale) / m.lnLegendHeight) Endif Endif Next m.lnPowerof10 Endfor m.lnDigits = Ceiling (Log10(Max (10, Abs( m.lnMaxScale / This.ScaleDivider ), Abs (m.lnMinScale / This.ScaleDivider)))) If This.ScaleAutoFormat This.ScaleLegend._ForceFormat = " " + Right ("999,999,999,999,999", m.lnDigits + Floor((m.lnDigits + 3) / 3)) If m.lnScaling < 1 This.ScaleLegend._ForceFormat = This.ScaleLegend._ForceFormat + "." + Replicate ("9", 1 - m.lnScaling) Endif Else This.ScaleLegend._ForceFormat = "" Endif Endcase **************************************************************** * Save WITH This IF m.tnAxis = 1 ._Scale = m.lnScale ._ScaleRange = m.lnMaxScale && - m.lnMinScale ._ScaleAdjust = - m.lnMinScale ._MinScale = m.lnMinScale ._MaxScale = m.lnMaxScale + m.lnMinScale IF This.ChartType = 17 ._ScaleRange = m.lnMaxScale * 2 && - m.lnMinScale ._MinScale = - ._MaxScale ENDIF ELSE ._Scale2 = m.lnScale ._ScaleRange2 = m.lnMaxScale && - m.lnMinScale ._ScaleAdjust2 = - m.lnMinScale ._MinScale2 = m.lnMinScale ._MaxScale2 = m.lnMaxScale + m.lnMinScale ENDIF ENDWITH ENDPROC PROCEDURE _centerpath LPARAMETERS toPath as xfcGraphicsPath, tlScale, tnWidth, tnHeight LOCAL loMatrix as xfcMatrix, ; loRect as xfcRectangle, ; lnWidth, lnHeight, x1, y1 m.loRect = m.toPath.GetBounds() m.lnWidth = m.loRect.Width m.lnHeight = m.loRect.Height m.loMatrix = _Screen.System.Drawing.Drawing2D.Matrix.New() && lnWidth /2, lnHeight /2) IF m.tlScale m.loMatrix.Scale(1+This.PointShapeWidth /10, 1+This.PointShapeWidth /10) m.toPath.Transform(m.loMatrix) m.loRect = m.toPath.GetBounds() m.lnWidth = m.loRect.Width m.lnHeight = m.loRect.Height m.x1 = m.loRect.X m.y1 = m.loRect.Y m.loMatrix.Translate(-m.x1 -m.lnWidth/2, -m.y1 -m.lnHeight/2) ELSE m.x1 = m.loRect.X m.y1 = m.loRect.Y m.loMatrix.Translate(-m.x1 -m.lnWidth /(2 * This.PointShapeWidth), ; -m.y1 -m.lnHeight /(2 * This.PointShapeWidth)) ENDIF m.toPath.Transform(m.loMatrix) RETURN m.toPath ENDPROC PROCEDURE _checkmouseposition LPARAMETERS nButton, nShift, nXCoord, nYCoord, lnValue, lcLegend, lnCoordIndex, lcObjType * Passed by reference: lnValue, lcLegend IF VARTYPE(m.lcLegend) = "L" m.lcLegend = "" ENDIF m.lcObjType = "" IF VARTYPE(This.aCoord(1,1)) <> "N" OR m.nYCoord < 0 OR m.nXCoord <0 This.MouseMove(m.nButton, m.nShift, m.nXCoord, m.nYCoord, 0, "", 0, "") RETURN ENDIF WITH This LOCAL n, lnValue, lnStart, lnSweep, lnLeft, lnTop m.lnLeft = This._xRelative &&+ .Left m.lnTop = This._yRelative &&+ .Top * 1st step is to check if we are over the side legends IF This.ShowSideLegend AND ; BETWEEN(m.nXCoord - m.lnLeft,; This.SideLegend.Left, ; This.SideLegend.Left + This.SideLegend.Width) AND ; BETWEEN(m.nYCoord - m.lnTop, ; This.SideLegend.Top , ; This.SideLegend.Top + This.SideLegend.Height) m.lcObjType = "Legend" ENDIF ENDWITH *!* This.aCoord(n,1) = tnX *!* This.aCoord(n,2) = tnY *!* This.aCoord(n,3) = tnWidth *!* This.aCoord(n,4) = tnHeight DO CASE CASE This._GeneralType = "Bar" OR This._GeneralType = "Point" OR m.lcObjType = "Legend" FOR m.n = ALEN(This.aCoord,1) TO 1 STEP -1 && Reverse in order to catch the first drawing IF BETWEEN(m.nXCoord - m.lnLeft,; This.aCoord(m.n,1), ; This.aCoord(m.n,1) + This.aCoord(m.n,3)) ; AND ; BETWEEN(m.nYCoord - m.lnTop, ; This.aCoord(m.n,2) , ; This.aCoord(m.n,2) + This.aCoord(m.n,4)) m.lnValue = This.aCoord(m.n, 5) m.lcLegend = This.aCoord(m.n, 6) m.lnCoordIndex = m.n m.lcObjType = This.aCoord(m.n,11) IF m.lcObjType = "Legend" This._nMouseOnShape = 0 RETURN ENDIF IF This._nMouseOnShape = 0 This._nMouseOnShape = m.n IF This.ChangeColoronMouse This._SkipPrepareData = .T. This.DrawChart() ENDIF This.ShapeMouseEnter(m.nButton, m.nShift, m.nXCoord, m.nYCoord, m.lnValue, m.lcLegend, m.lnCoordIndex) ELSE IF This._nMouseOnShape <> m.n This._nMouseOnShape = m.n IF This.ChangeColoronMouse This._SkipPrepareData = .T. This.DrawChart() ENDIF This.ShapeMouseEnter(m.nButton, m.nShift, m.nXCoord, m.nYCoord, m.lnValue, m.lcLegend, m.lnCoordIndex) ELSE && Mouse over the shape This.ShapeMouseMove(m.nButton, m.nShift, m.nXCoord, m.nYCoord, m.lnValue, m.lcLegend, m.lnCoordIndex) ENDIF ENDIF RETURN ELSE ENDIF NEXT IF This._nMouseOnShape <> 0 This._nMouseOnShape = 0 This.ShapeMouseLeave(m.nButton, m.nShift, m.nXCoord, m.nYCoord, m.lnValue, m.lcLegend, m.lnCoordIndex) ENDIF CASE This._GeneralType = "Pie" *!* This.aCoord(n,1) = tnX *!* This.aCoord(n,2) = tnY *!* This.aCoord(n,3) = tnWidth *!* This.aCoord(n,4) = tnHeight *!* This.aCoord(n,5) = tnValue *!* This.aCoord(n,7) = tnStart *!* This.aCoord(n,8) = tnSweep *!* This.aCoord(n,9) = This._ChartIndex *!* This.aCoord(n,10) = RECNO() * Adapted code from Luis Maria Guayan - VFP MVP from Argentina LOCAL lnX1, lnX2, lnX3, lnY1, lnY2, lnY3, lnStart, lnSweep, lnValue, m.lcLegend, lnAngle * Center of Ellipse m.lnX1 = This.aCoord(1,3) / 2 m.lnY1 = This.aCoord(1,4) / 2 * Coordinates inside the Shape IF This._Pie1stDetached m.lnX2 = (m.nXCoord - m.lnLeft - m.lnX1 - This._PieX0) m.lnY2 = ((m.nYCoord - m.lnTop - m.lnY1 - This._PieY0) * (-1)) ELSE m.lnX2 = (m.nXCoord - m.lnLeft - m.lnX1 - This.aCoord(1,1)) m.lnY2 = ((m.nYCoord - m.lnTop - m.lnY1 - This.aCoord(1,2)) * (-1)) ENDIF * Angle in degrees [0°..360°] m.lnAngle = RTOD(ATAN(m.lnY2/m.lnX2)) DO CASE CASE m.lnX2 < 0 m.lnAngle = 180 + m.lnAngle CASE m.lnY2 < 0 m.lnAngle = 360 + m.lnAngle OTHERWISE ENDCASE m.lnAngle = 360 - m.lnAngle LOCAL lnFoundShape, n m.lnFoundShape = 0 * Now we need to find the shape FOR m.n = 1 TO ALEN(This.aCoord,1) m.lnStart = EVL(This.aCoord(m.n,7), 0) IF VARTYPE(m.lnStart) <> "N" EXIT ENDIF m.lnSweep = EVL(This.aCoord(m.n,8), 0) IF BETWEEN(m.lnAngle, m.lnStart, m.lnStart + m.lnSweep) OR ; BETWEEN(m.lnAngle + 360, m.lnStart, m.lnStart + m.lnSweep) m.lnFoundShape = m.n EXIT ENDIF ENDFOR IF m.lnFoundShape = 0 RETURN ENDIF * Now we can know exactly the positions in the screen * for the case of detached slices * So, we restart, using the correct information * Center of Shape m.lnX1 = This.aCoord(m.lnFoundShape,3) / 2 m.lnY1 = This.aCoord(m.lnFoundShape,4) / 2 * Coordinates inside the Shape m.lnX2 = m.nXCoord - m.lnLeft - m.lnX1 - This.aCoord(m.lnFoundShape, 1) m.lnY2 = -(m.nYCoord - m.lnTop - m.lnY1 - This.aCoord(m.lnFoundShape, 2)) * Percentage in the ellipse m.lnX3 = m.lnX2 / m.lnX1 m.lnY3 = m.lnY2 / m.lnY1 *** NEW ANGLE * Angle in degrees [0°..360°] m.lnAngle = RTOD(ATAN(m.lnY2/m.lnX2)) DO CASE CASE m.lnX2 < 0 m.lnAngle = 180 + m.lnAngle CASE m.lnY2 < 0 m.lnAngle = 360 + m.lnAngle ENDCASE m.lnAngle = 360 - m.lnAngle IF BETWEEN(m.lnAngle, m.lnStart, m.lnStart + m.lnSweep) OR ; BETWEEN(m.lnAngle + 360, m.lnStart, m.lnStart + m.lnSweep) ELSE IF This._nMouseOnShape <> 0 This._nMouseOnShape = 0 IF This.ChangeColoronMouse This._SkipPrepareData = .T. This.DrawChart() ENDIF This.ShapeMouseLeave(m.nButton, m.nShift, m.nXCoord, m.nYCoord, m.lnValue, m.lcLegend, m.lnCoordIndex) ENDIF RETURN ENDIF *** NEW ANGLE LOCAL lnRatio m.lnRatio = m.lnY3^2 + m.lnX3^2 IF m.lnRatio > 1 OR ; This.ChartType = 2 AND m.lnRatio < This.DonutRatio / 2 && Doughnut IF This._nMouseOnShape <> 0 This._nMouseOnShape = 0 This.ShapeMouseLeave(m.nButton, m.nShift, m.nXCoord, m.nYCoord, m.lnValue, m.lcLegend, m.lnCoordIndex) IF This.ChangeColoronMouse This._SkipPrepareData = .T. This.DrawChart() ENDIF This.ShapeMouseLeave(m.nButton, m.nShift, m.nXCoord, m.nYCoord, m.lnValue, m.lcLegend, m.lnCoordIndex) ENDIF RETURN ENDIF m.lnValue = This.aCoord(m.lnFoundShape, 5) m.lcLegend = This.aCoord(m.lnFoundShape, 6) m.lnCoordIndex = m.lnFoundShape m.lcObjType = "Pie" IF This._nMouseOnShape = 0 This._nMouseOnShape = m.lnFoundShape IF This.ChangeColoronMouse This._SkipPrepareData = .T. This.DrawChart() ENDIF This.ShapeMouseEnter(m.nButton, m.nShift, m.nXCoord, m.nYCoord, m.lnValue, m.lcLegend, m.lnCoordIndex) ELSE IF This._nMouseOnShape <> m.lnFoundShape This._nMouseOnShape = m.lnFoundShape IF This.ChangeColoronMouse This._SkipPrepareData = .T. This.DrawChart() ENDIF This.ShapeMouseEnter(m.nButton, m.nShift, m.nXCoord, m.nYCoord, m.lnValue, m.lcLegend, m.lnCoordIndex) ELSE This.ShapeMouseMove(m.nButton, m.nShift, m.nXCoord, m.nYCoord, m.lnValue, m.lcLegend, m.lnCoordIndex) ENDIF ENDIF RETURN OTHERWISE ENDCASE ENDPROC PROCEDURE _checkparams ASSERT BETWEEN(This.AlphaChannel, 0, 255) MESSAGE "AlphaChannel must be between 0-255" ASSERT BETWEEN(This.AxisAlpha, 0, 255) MESSAGE "AxisAlpha must be between 0-255" ASSERT BETWEEN(This.BackGradientMode, 0, 3) MESSAGE "BackGradientMode not available (0-3)" ASSERT BETWEEN(This.BarType, 0, 2) MESSAGE "BarType not available (0-2)" ASSERT BETWEEN(This.BrushType, 1, 3) MESSAGE "BrushType not available (1-3)" ASSERT BETWEEN(This.ChartType, 1, 18) MESSAGE "ChartType not available (1-18)" ASSERT BETWEEN(This.ColorType, 0, 27) MESSAGE "ColorType not available (0-27)" ASSERT BETWEEN(This.DonutRatio, 0, 1) MESSAGE "DonutRatio must be between 0 and 1" ASSERT BETWEEN(This.GradientLevel, -10, +10) MESSAGE "GradientLevel not available (-10, +10)" ASSERT BETWEEN(This.ScaleBackAlpha, 0, 255) MESSAGE "ScaleBackAlpha must be between 0-255" ASSERT BETWEEN(This.ScaleBackBarsType, 0, 3) MESSAGE "ScaleBackBarsType not available (0-3)" ASSERT BETWEEN(This.ScaleBackLinesType, 0, 3) MESSAGE "ScaleBackLinesType not available (0-3)" ASSERT BETWEEN(This.ScaleBackLinesDash, 0, 4) MESSAGE "ScaleBackLinesDash must be between 0-4" ASSERT This.ScaleDivider > 0 MESSAGE "ScaleDivider must be greater than Zero" ASSERT This.BarsPerScale > 0 MESSAGE "BarsPerScale must be greater than Zero" ASSERT This.LegendPosition <=12 MESSAGE "LegendPosition must be between 0-12" ASSERT USED(This.SourceAlias) MESSAGE "The specified source alias - '" + ; This.SourceAlias + "' could not be found!" IF This.ColorType = 3 && Gradient ASSERT (VARTYPE(This.Fields(1).Color) = "N" OR VARTYPE(This.Color1) = "N") ; MESSAGE "You have to define the property .Fields(1).Color to determine the main starting gradient color" ENDIF * GdiPlusX version check LOCAL lnVersion m.lnVersion = 1.10 IF pemstatus(_Screen.System, "Version", 5) m.lnVersion = _Screen.System.Version ENDIF IF m.lnVersion < 1.20 ASSERT (This.ChartType <> 4) ; MESSAGE "Points ChartType #4 is not supported for GdiPlusX System.App versions prior to version 1.20" + CHR(13) + ; "Please make sure to be using at least version 1.20 to be able to use this type of chart" ENDIF ENDPROC PROCEDURE _detachclickedslice LPARAMETERS tnIndex LOCAL llOrigDetach as Boolean IF EMPTY(m.tnIndex) OR (VARTYPE(m.tnIndex) <> "N") RETURN ENDIF LOCAL lnRecno, lnChartIndex, llOriginalDetach *!* This.aCoord(n,1) = tnX *!* This.aCoord(n,2) = tnY *!* This.aCoord(n,3) = tnWidth *!* This.aCoord(n,4) = tnHeight *!* This.aCoord(n,5) = tnValue *!* This.aCoord(n,7) = tnStart *!* This.aCoord(n,8) = tnSweep *!* This.aCoord(n,9) = This._ChartIndex *!* This.aCoord(n,10) = RECNO() m.lnRecno = This.aCoord(m.tnIndex,10) m.lnChartIndex = This.aCoord(m.tnIndex,9) SELECT (This._DataCursor) GO m.lnRecno m.llOrigDetach = lDetach LOCAL lcCursor m.lcCursor = (This._DataCursor) REPLACE lDetach WITH NOT lDetach FOR RECNO() = m.lnRecno IN &lcCursor IF m.llOrigDetach This._SkipPrepareData = .T. This.DrawChart() ELSE This._PieAnimatedRec = m.lnRecno LOCAL lnDetachPixels, n, lnStep m.lnDetachPixels = This.PieDetachPixels m.lnStep = m.lnDetachPixels / MAX(1,This.PieDetachAnimationSteps) FOR m.n = m.lnStep TO m.lnDetachPixels STEP m.lnStep This._PieAnimationPix = m.n This._SkipPrepareData = .T. This.DrawChart() ENDFOR ENDIF This._PieAnimatedRec = 0 This._PieAnimationPix = 0 This._SkipPrepareData = .F. ENDPROC PROCEDURE _drawaxis LOCAL ln3D, lnMargin, lnYAxisHeight LOCAL lnHeight as Number m.lnMargin = This.Margin IF This._DeepChart && Point, Line or Area m.ln3D = This._3D * This.ChartsCount ELSE m.ln3D = This._3D ENDIF * Prepare the scale in the Y Axis, populating the ._ScaleW property This._GetyLegendSize() IF This.ChartType = 18 AND This.ShowScale && DoubleAxis This._GetyLegendSize(2) ENDIF m.lnYAxisHeight = 0 IF This.ShowAxis = .T. * Draw the main Y Axis caption LOCAL lcYText m.lcYText = This.YAxis.Caption IF NOT EMPTY(m.lcYText) This.YAxis.Reset() m.lnYaxisHeight = CEILING(This.YAxis._Height) ENDIF ENDIF * Leaving some extra space for the X Axis legends LOCAL lnMinLeft, lnLeftCaptionWidth IF NOT EMPTY(This.FieldAxis2) * Measure the legend width This.AxisLegend2._Setup() GO TOP && First Legend This.AxisLegend2.Caption = cAxis2 && Field text m.lnLeftCaptionWidth = This.AxisLegend2._Width m.lnMinLeft = m.lnLeftCaptionWidth / 2 ELSE m.lnMinLeft = 0 m.lnLeftCaptionWidth = 0 ENDIF LOCAL lnEstimatedX, lnXBetween m.lnEstimatedX = This.Width - ; (This._Rightoffset + This._Scalew + m.lnYaxisHeight + m.ln3D) m.lnXBetween = m.lnEstimatedX / This._nRecords IF m.lnXBetween > (m.lnLeftCaptionWidth / 2) m.lnMinLeft = (m.lnLeftCaptionWidth / 2) && - lnXBetween ENDIF IF (NOT This.ShowAxis) OR (NOT This._AllowAxis) IF This._Orientation = 1 && Vertical This._yAxisWidth = 0 + m.lnMinLeft ELSE && Horizontal This._yAxisWidth = MAX(m.lnMinLeft, 0 + This._ScaleW) ENDIF This._XAxisHeight = This._XAxisHeight - This.XAxis._Height RETURN ENDIF LOCAL lnTickWidth m.lnTickWidth = 4 LOCAL loGfx as xfcGraphics m.loGfx = This.oGfx WITH _Screen.System.Drawing * Determining Colors, Brushes and Pens LOCAL lnAxisColor, lnAxisBorderColor IF This.BrushType = 3 && Monochrome m.lnAxisColor = RGB(255,255,255) && White m.lnAxisBorderColor = 0 && Black ELSE m.lnAxisColor = This.AxisColor m.lnAxisBorderColor = This.ChangeColor(m.lnAxisColor, -30) ENDIF LOCAL loAxisMainColor as xfcColor LOCAL loAxisBorderColor as xfcColor m.loAxisMainColor = .Color.FromARGB(This.AxisAlpha, m.lnAxisColor) m.loAxisBorderColor = .Color.FromARGB(This.AxisAlpha, m.lnAxisBorderColor) LOCAL loPen as xfcPen m.loPen = .Pen.New(m.loAxisBorderColor, 1) LOCAL loBrush as xfcSolidBrush m.loBrush = .SolidBrush.New(m.loAxisMainColor) ENDWITH This._DrawYAxis(m.ln3D, m.lnMinLeft, m.lnYAxisHeight, m.loBrush, m.loPen, 1) IF This.ChartType = 18 && DoubleAxis This._DrawYAxis(m.ln3D, m.lnMinLeft, m.lnYAxisHeight, m.loBrush, m.loPen, 2) IF This.ShowScale * This._DrawScale(m.loPen, 2) ENDIF ENDIF WITH _Screen.System.Drawing m.lnHeight = This.ChartCanvas.Height - This._XAxisHeight - This._TopOffSet - m.ln3D This._ChartY0 = This.ChartCanvas.Height - This._XAxisHeight - m.ln3D This._ChartY1 = This._ChartY0 - m.lnHeight * Draw the X Axis m.lnMargin = This._yAxisWidth + This._LeftOffset LOCAL x0, x1, y0 m.x0 = m.lnMargin m.x1 = This.ChartCanvas.Width - This._RightOffset - This._yAxisWidth2 m.y0 = ROUND(This.ChartCanvas.Height - This._XAxisHeight + 1,0) IF This.ShowAxis = .T. IF m.ln3D = 0 m.loGfx.DrawLine(m.loPen, m.x0, m.y0, m.x1, m.y0) ELSE LOCAL laPoints(4) m.laPoints(1) = .Point.New(m.x0, m.y0) m.laPoints(2) = .Point.New(m.x0 + m.ln3D, m.y0 - m.ln3D) m.laPoints(3) = .Point.New(m.x1, m.y0 - m.ln3D) m.laPoints(4) = .Point.New(m.x1 - m.ln3D, m.y0) m.loGfx.FillPolygon(m.loBrush, @m.laPoints) LOCAL laPointsB(6) m.laPointsB(1) = m.laPoints(1) m.laPointsB(2) = m.laPoints(4) m.laPointsB(3) = m.laPoints(3) m.laPointsB(4) = .Point.New(m.laPoints(3).x, m.y0 - m.ln3D + 3) m.laPointsB(5) = .Point.New(m.laPoints(4).x, m.y0 + 3) m.laPointsB(6) = .Point.New(m.laPoints(1).x, m.y0 + 3) m.loGfx.FillPolygon(m.loBrush, @m.laPointsB) m.loGfx.DrawPolygon(m.loPen, @m.laPointsB) m.loGfx.DrawLine(m.loPen, m.x0, m.y0, m.x0 + m.ln3D, m.y0 - m.ln3D) ENDIF ENDIF * Draw the main X Axis caption IF NOT EMPTY(This.XAxis.Caption) This.XAxis.Reset() LOCAL lnX, lnY, lnW, lnH m.lnX = m.lnMargin m.lnY = m.y0 + This._LegendPixHeight + 4 m.lnW = m.x1 - m.x0 m.lnH = This.XAxis._Height This.XAxis._DrawString(m.lnX, m.lnY, m.lnW, m.lnH) ENDIF IF This.ShowScale This._DrawScale(m.loPen) ENDIF IF This.ChartType = 18 && DoubleAxis * This._DrawYAxis(ln3D, lnMinLeft, lnYAxisHeight, loBrush, loPen, 2) IF This.ShowScale This._DrawScale(m.loPen, 2) ENDIF ENDIF ENDWITH ENDPROC PROCEDURE _drawbar LPARAMETERS tnX, tnY, tnWidth, tnHeight, tnValue m.tnHeight = ABS(m.tnHeight) LOCAL ln3D m.ln3D = This._3D DO CASE CASE This.BarType = 1 && Cylinder This._UpdateCoordinates("Rect", m.tnX + m.ln3D / 2, m.tnY, m.tnWidth, m.tnHeight, m.tnValue) This._DrawCylinder(m.tnX, m.tnY, m.tnWidth, m.tnHeight, m.tnValue) RETURN CASE This.BarType = 2 && Triangle This._UpdateCoordinates("Rect", m.tnX + m.ln3D / 2, m.tnY, m.tnWidth, m.tnHeight, m.tnValue) This._DrawTriangleBar(m.tnX, m.tnY, m.tnWidth, m.tnHeight, m.tnValue) RETURN OTHERWISE This._UpdateCoordinates("Rect", m.tnX, m.tnY, m.tnWidth, m.tnHeight, m.tnValue) ENDCASE This._PrepareBrushes(m.tnX, m.tnY, m.tnWidth, m.tnHeight, .F., IIF(This.SingleData, RECNO(),This._ChartIndex)) LOCAL loPen as xfcPen m.loPen = This._oBorderPen LOCAL loGfx as xfcGraphics m.loGfx = This.oGfx LOCAL loMainBrush as xfcBrush m.loMainBrush = This._oMainBrush LOCAL lo3dBrush as xfcBrush m.lo3DBrush = This._o3DBrush WITH _Screen.System.Drawing * Draw the 3D Bar using the 3DBrush IF m.ln3D > 0 && 3D IF This.Shadow = .F. * Prepare Array of points to draw the 3D part of the Bar LOCAL laPoints(4) m.laPoints(1) = .PointF.New(m.tnX + m.tnWidth, m.tnY) m.laPoints(2) = .PointF.New(m.tnX + m.tnWidth + m.ln3D, m.tnY - m.ln3D) m.laPoints(3) = .PointF.New(m.tnX + m.ln3D, m.tnY - m.ln3D) m.laPoints(4) = .PointF.New(m.tnX, m.tnY) m.loGfx.FillPolygon(m.lo3DBrush, @m.laPoints) m.loGfx.DrawPolygon(m.loPen, @m.laPoints) * Change only Points 3 and 4 m.laPoints(3) = .PointF.New(m.tnX + m.tnWidth + m.ln3D, m.tnY + m.tnHeight - m.ln3D) m.laPoints(4) = .PointF.New(m.tnX + m.tnWidth, m.tnY + m.tnHeight) m.loGfx.FillPolygon(m.lo3DBrush, @m.laPoints) m.loGfx.DrawPolygon(m.loPen, @m.laPoints) ELSE LOCAL loShadowBrush as xfcSolidBrush m.loShadowBrush = .SolidBrush.New(.Color.FromARGB(This.AlphaChannel,128,128,128)) m.loGfx.FillRectangle(m.loShadowBrush , m.tnX + m.ln3D, m.tnY + m.ln3D, m.tnWidth, m.tnHeight - m.ln3d - m.ln3d) LOCAL laPoints(4) m.laPoints(1) = .PointF.New(m.tnX , m.tnY + m.tnHeight) m.laPoints(2) = .PointF.New(m.tnX + m.tnWidth , m.tnY + m.tnHeight) m.laPoints(3) = .PointF.New(m.tnX + m.tnWidth + m.ln3D, m.tnY + m.tnHeight - m.ln3D) m.laPoints(4) = .PointF.New(m.tnX + m.ln3d, m.tnY + m.tnHeight - m.ln3D) m.loGfx.FillPolygon(m.loShadowBrush , @m.laPoints) ENDIF ENDIF m.loGfx.FillRectangle(m.loMainBrush, m.tnX, m.tnY, m.tnWidth, m.tnHeight) m.loGfx.DrawRectangle(m.loPen, m.tnX, m.tnY, m.tnWidth, m.tnHeight) IF This._GeneralType = "Bar" This._DrawLegendinBar(m.tnX, m.tnY, m.tnWidth, m.tnHeight, m.tnValue) ENDIF ENDWITH RETURN ENDPROC PROCEDURE _drawbarchart LOCAL lnWidth, lnHeight, x1, y1, n, lnValue, lnLeftMargin, ln3D, lnTopMargin LOCAL lnPointHeight as Number, ; lnYBase as Number SELECT(This._DataCursor) m.ln3D = This._3D m.lnWidth = This.ChartCanvas.Width - This._LeftOffset - This._RightOffset - m.ln3D - This._yAxisWidth m.lnHeight = This.ChartCanvas.Height - This._XAxisHeight - This._TopOffSet - m.ln3D IF (m.lnWidth <= 0) OR (m.lnHeight <= 0) RETURN ENDIF m.lnLeftMargin = This._yAxisWidth + This._LeftOffset m.lnTopMargin = This._TopOffSet + m.ln3D LOCAL lnBarWidth, lnBarHeight, lnBetween, lnMaxValue, lnAdjust, lnChartsCount m.lnBetween = This.BarsSpaceBetween m.lnMaxValue = This._ScaleRange m.lnChartsCount = This.ChartsCount * Prepare Points IF This._Orientation = 1 && Vertical IF This._DeepChart m.lnWidth = m.lnWidth - (m.ln3D * (m.lnChartsCount - 1)) ENDIF m.lnBetween = MIN(m.lnBetween, ; (m.lnWidth - This._nRecords) / This._nRecords) m.lnBarWidth = (m.lnWidth - (This._nRecords - 1) * m.lnBetween) / This._nRecords SCAN m.n = RECNO() m.x1 = m.lnLeftMargin + ((m.lnBarWidth + m.lnBetween) * (m.n - 1)) This._aPoints(m.n,1) = m.x1 + (m.lnBarWidth / 2) ENDSCAN ELSE && Horizontal m.lnBetween = MIN(m.lnBetween, ; (m.lnHeight - This._nRecords) / This._nRecords) m.lnBarHeight = (m.lnHeight - (This._nRecords - 1) * m.lnBetween) / This._nRecords SCAN m.n = RECNO() m.y1 = m.lnTopMargin + ((m.lnBarHeight + m.lnBetween) * (m.n - 1)) This._aPoints(m.n,2) = m.y1 + (m.lnBarHeight / 2) ENDSCAN This._DrawYAxisLegend() ENDIF This._DrawVerticalLineBack() DO CASE CASE This.ChartType = 7 && Simple Bar LOCAL lnZeroY, lnValue2, lnScaleAdjustment m.lnScaleAdjustment = This._ScaleAdjust / m.lnMaxValue * m.lnHeight m.lnZeroY = This._TopOffSet + m.ln3D + (This._MaxScale / m.lnMaxValue * m.lnHeight) IF This._MinScale > 0 m.lnZeroY = m.lnZeroY - (This._MinScale / m.lnMaxValue * m.lnHeight) ENDIF This._ChartIndex = This.ChartRow SCAN m.lnValue = This._GetValue(This.ChartRow, .T.) IF ISNULL(m.lnValue) OR m.lnValue < This._MinScale LOOP ENDIF IF m.lnValue < 0 m.lnBarHeight = (m.lnValue / m.lnMaxValue * m.lnHeight) m.y1 = m.lnZeroY ELSE m.lnBarHeight = (m.lnValue / m.lnMaxValue * m.lnHeight) + ; IIF(This._ScaleAdjust < 0, m.lnScaleAdjustment, 0) m.y1 = m.lnZeroY - m.lnBarHeight ENDIF m.x1 = m.lnLeftMargin + ((m.lnBarWidth + m.lnBetween) * (RECNO() - 1)) This._DrawBar(m.x1, m.y1, m.lnBarWidth, m.lnBarHeight, m.lnValue) ENDSCAN CASE This.ChartType = 8 && Multi Bars LOCAL i, lnOneBarWidth, lnZeroY, lnScaleAdjustment LOCAL lnTotRow LOCAL laValues(m.lnChartsCount) m.lnOneBarWidth = m.lnBarWidth / m.lnChartsCount m.lnZeroY = This._TopOffSet + m.ln3D + (This._MaxScale / m.lnMaxValue * m.lnHeight) IF This._MinScale > 0 m.lnZeroY = m.lnZeroY - (This._MinScale / m.lnMaxValue * m.lnHeight) ENDIF m.lnScaleAdjustment = This._ScaleAdjust / m.lnMaxValue * m.lnHeight SCAN m.n = RECNO() m.lnTotRow = 0 * Get the total for the current row FOR m.i = 1 TO m.lnChartsCount m.lnValue = This._GetValue(m.i, .T.) m.laValues(m.i) = m.lnValue m.lnTotRow = m.lnTotRow + NVL(m.lnValue, 0) ENDFOR FOR m.i = 1 TO m.lnChartsCount m.lnValue = m.laValues(m.i) IF ISNULL(m.lnValue) OR m.lnValue < This._MinScale LOOP ENDIF This._ChartIndex = m.i m.x1 = m.lnLeftMargin + ; ((m.lnBarWidth + m.lnBetween) * (m.n - 1)) + ; ((m.i-1 ) * m.lnOneBarWidth) IF m.lnValue < 0 m.lnBarHeight = (m.lnValue / m.lnMaxValue * m.lnHeight) m.y1 = m.lnZeroY ELSE m.lnBarHeight = (m.lnValue / m.lnMaxValue * m.lnHeight) + ; IIF(This._ScaleAdjust < 0, m.lnScaleAdjustment, 0) m.y1 = m.lnZeroY - m.lnBarHeight ENDIF This.ChartSum = m.lnTotRow This._DrawBar(m.x1, m.y1, m.lnOneBarWidth, m.lnBarHeight, m.lnValue) ENDFOR ENDSCAN This._ChartIndex = 1 CASE This.ChartType = 9 && Stacked Bars m.lnYBase = This._TopOffSet + m.ln3D + m.lnHeight SCAN m.y1 = m.lnYBase FOR m.i = 1 TO m.lnChartsCount This._ChartIndex = m.i m.lnValue = This._GetValue(m.i, .T.) IF ISNULL(m.lnValue) OR m.lnValue = 0 LOOP ENDIF m.lnBarHeight = m.lnValue / m.lnMaxValue * m.lnHeight m.x1 = m.lnLeftMargin + ; ((m.lnBarWidth + m.lnBetween) * (RECNO() - 1)) m.y1 = m.y1 - m.lnBarHeight This._DrawBar(m.x1, m.y1, m.lnBarWidth, m.lnBarHeight, m.lnValue) ENDFOR ENDSCAN This._ChartIndex = 1 CASE This.ChartType = 11 && 3D Bars * Calculate the maximum width of the chart m.lnHeight = m.lnHeight - (m.ln3D * (m.lnChartsCount - 1)) * Not needed any more, this is now calculated above, checking for _DeepChart * m.lnWidth = m.lnWidth - (m.ln3D * (m.lnChartsCount - 1)) * m.lnBarWidth = (m.lnWidth - (This._nRecords - 1) * m.lnBetween) / This._nRecords FOR m.i = 1 TO m.lnChartsCount This._ChartIndex = m.i m.lnAdjust = (m.ln3D * (m.lnChartsCount - m.i )) SCAN m.n = RECNO() m.lnValue = This._GetValue(m.i, .T.) m.x1 = m.lnLeftMargin + m.lnAdjust + ((m.lnBarWidth + m.lnBetween) * (RECNO() - 1)) IF m.i = m.lnChartsCount * Prepare Points This._aPoints(m.n,1) = m.x1 + (m.lnBarWidth / 2) ENDIF IF ISNULL(m.lnValue) LOOP ENDIF m.lnPointHeight = m.lnValue / m.lnMaxValue * m.lnHeight m.y1 = This._TopOffSet + (m.lnHeight - m.lnPointHeight) - m.lnAdjust + (m.ln3D * (m.lnChartsCount)) m.lnYBase = This.ChartCanvas.Height - This._xAxisHeight - m.lnAdjust m.lnBarHeight = m.lnYBase - m.y1 This._DrawBar(m.x1, m.y1, m.lnBarWidth, m.lnBarHeight, m.lnValue) ENDSCAN ENDFOR CASE This.ChartType = 12 && HORIZONTAL Simple Bar IF m.lnBetween >= m.lnHeight / (This._nRecords - 1) m.lnBarHeight = 1 m.lnBetween = (m.lnHeight - This._nRecords) / (This._nRecords - 1) ENDIF LOCAL lnZeroX, lnScaleAdjustment m.lnZeroX = m.lnLeftMargin + IIF(This._ScaleAdjust < 0 , 0, (This._ScaleAdjust / m.lnMaxValue * m.lnWidth)) m.lnScaleAdjustment = This._ScaleAdjust / m.lnMaxValue * m.lnWidth This._ChartIndex = This.ChartRow SET ORDER TO Revert SCAN m.lnValue = This._GetValue(This.ChartRow, .T.) IF ISNULL(m.lnValue) OR m.lnValue < This._MinScale LOOP ENDIF IF m.lnValue < 0 m.lnBarWidth = ABS(m.lnValue / m.lnMaxValue * m.lnWidth) m.x1 = m.lnZeroX - m.lnBarWidth ELSE m.lnBarWidth = (m.lnValue / m.lnMaxValue * m.lnWidth) + ; IIF(This._ScaleAdjust < 0, m.lnScaleAdjustment, 0) m.x1 = m.lnZeroX ENDIF m.y1 = This._TopOffSet + ((m.lnBarHeight + m.lnBetween) * (RECNO() - 1)) + m.ln3D This._DrawBar(m.x1, m.y1, m.lnBarWidth, m.lnBarHeight, m.lnValue) ENDSCAN SET ORDER TO CASE This.ChartType = 13 && HORIZONTAL Multi Bars IF m.lnBetween >= m.lnHeight / (This._nRecords - 1) m.lnBarHeight = 1 m.lnBetween = (m.lnHeight - This._nRecords) / (This._nRecords - 1) ENDIF m.lnBarHeight = (m.lnHeight - (This._nRecords - 1) * m.lnBetween) / This._nRecords LOCAL i, lnOneBarHeight m.lnOneBarHeight = m.lnBarHeight / m.lnChartsCount LOCAL lnZeroX, lnScaleAdjustment m.lnZeroX = m.lnLeftMargin + IIF(This._ScaleAdjust < 0 , 0, (This._ScaleAdjust / m.lnMaxValue * m.lnWidth)) m.lnScaleAdjustment = This._ScaleAdjust / m.lnMaxValue * m.lnWidth LOCAL lnTotRow LOCAL laValues(m.lnChartsCount) SET ORDER TO Revert SCAN m.n = RECNO() m.lnTotRow = 0 * Get the total for the current row FOR m.i = m.lnChartsCount TO 1 STEP -1 m.lnValue = This._GetValue(m.i, .T.) m.laValues(m.i) = m.lnValue m.lnTotRow = m.lnTotRow + NVL(m.lnValue, 0) ENDFOR FOR m.i = m.lnChartsCount TO 1 STEP -1 m.lnValue = m.laValues(m.i) IF ISNULL(m.lnValue) OR m.lnValue < This._MinScale LOOP ENDIF This._ChartIndex = m.i IF m.lnValue < 0 m.lnBarWidth = ABS(m.lnValue / m.lnMaxValue * m.lnWidth) m.x1 = m.lnZeroX - m.lnBarWidth ELSE m.lnBarWidth = (m.lnValue / m.lnMaxValue * m.lnWidth) + ; IIF(This._ScaleAdjust < 0, m.lnScaleAdjustment, 0) m.x1 = m.lnZeroX ENDIF m.y1 = This._TopOffSet + m.ln3D + ((m.lnBarHeight + m.lnBetween) * (m.n - 1)) + ; ((m.i-1 ) * m.lnOneBarHeight) This.ChartSum = m.lnTotRow This._DrawBar(m.x1, m.y1, m.lnBarWidth, m.lnOneBarHeight, m.lnValue) ENDFOR ENDSCAN SET ORDER TO This._ChartIndex = 1 CASE This.ChartType = 14 && HORIZONTAL Stacked Bars IF m.lnBetween >= m.lnHeight / (This._nRecords - 1) m.lnBarHeight = 1 m.lnBetween = (m.lnHeight - This._nRecords) / (This._nRecords - 1) ENDIF SET ORDER TO Revert SCAN m.x1 = m.lnLeftMargin FOR m.i = 1 TO m.lnChartsCount This._ChartIndex = m.i m.lnValue = This._GetValue(m.i, .T.) IF ISNULL(m.lnValue) LOOP ENDIF m.lnBarWidth = m.lnValue / m.lnMaxValue * m.lnWidth m.y1 = This._TopOffSet + ((m.lnBarHeight + m.lnBetween) * (RECNO() - 1)) + m.ln3D This._DrawBar(m.x1, m.y1, m.lnBarWidth, m.lnBarHeight, m.lnValue) m.x1 = m.x1 + m.lnBarWidth ENDFOR ENDSCAN SET ORDER TO This._ChartIndex = 1 CASE This.ChartType = 15 && HORIZONTAL Full-Stacked Bars IF m.lnBetween >= m.lnHeight / (This._nRecords - 1) m.lnBarHeight = 1 m.lnBetween = (m.lnHeight - This._nRecords) / (This._nRecords - 1) ENDIF SET ORDER TO Revert LOCAL lnTotRow LOCAL laValues(m.lnChartsCount) SCAN m.lnTotRow = 0 * Get the total for the current row FOR m.i = 1 TO m.lnChartsCount m.lnValue = NVL(This._GetValue(m.i, .T.),0) m.laValues(m.i) = m.lnValue m.lnTotRow = m.lnTotRow + m.lnValue ENDFOR m.x1 = m.lnLeftMargin FOR m.i = 1 TO m.lnChartsCount m.lnValue = m.laValues(m.i) IF m.lnValue = 0 LOOP ENDIF m.lnBarWidth = m.lnValue / m.lnTotRow * m.lnWidth m.y1 = This._TopOffSet + ((m.lnBarHeight + m.lnBetween) * (RECNO() - 1)) + m.ln3D This._ChartIndex = m.i This.ChartSum = m.lnTotRow This._DrawBar(m.x1, m.y1, m.lnBarWidth, m.lnBarHeight, m.lnValue) m.x1 = m.x1 + m.lnBarWidth ENDFOR ENDSCAN SET ORDER TO This._ChartIndex = 1 CASE This.ChartType = 3 && Full-Stacked Bars LOCAL lnTotRow LOCAL laValues(m.lnChartsCount) m.lnYBase = This._TopOffSet + m.ln3D + m.lnHeight SCAN m.y1 = m.lnYBase m.lnTotRow = 0 * Get the total for the current row FOR m.i = 1 TO m.lnChartsCount m.lnValue = NVL(This._GetValue(m.i, .T.),0) m.laValues(m.i) = m.lnValue m.lnTotRow = m.lnTotRow + m.lnValue ENDFOR FOR m.i = 1 TO m.lnChartsCount m.lnValue = m.laValues(m.i) IF m.lnValue = 0 LOOP ENDIF m.lnBarHeight = m.lnValue / m.lnTotRow * m.lnHeight m.x1 = m.lnLeftMargin + ; ((m.lnBarWidth + m.lnBetween) * (RECNO() - 1)) m.y1 = m.y1 - m.lnBarHeight This._ChartIndex = m.i This.ChartSum = m.lnTotRow This._DrawBar(m.x1, m.y1, m.lnBarWidth, m.lnBarHeight, m.lnValue) ENDFOR ENDSCAN This._ChartIndex = 1 CASE This.ChartType = 17 && PAIRED HORIZONTAL BARS LOCAL lnZeroX, lnScaleAdjustment, lnAlign m.lnZeroX = m.lnLeftMargin + (m.lnWidth / 2) SET ORDER TO Revert * Draw the left side of the chart m.lnAlign = This.ShapeLegend.Alignment DO CASE CASE m.lnAlign = 0 && Left This.ShapeLegend.Alignment = 1 && Right CASE m.lnAlign = 1 && Right This.ShapeLegend.Alignment = 0 && Left OTHERWISE ENDCASE This._ChartIndex = 1 SCAN m.lnValue = This._GetValue(1, .T.) && 1st column IF ISNULL(m.lnValue) OR (m.lnValue < 0) LOOP ENDIF m.lnBarWidth = ABS(m.lnValue / m.lnMaxValue * m.lnWidth) m.x1 = m.lnZeroX - m.lnBarWidth m.y1 = This._TopOffSet + ((m.lnBarHeight + m.lnBetween) * (RECNO() - 1)) + m.ln3D This._DrawBar(m.x1, m.y1, m.lnBarWidth, m.lnBarHeight, m.lnValue) ENDSCAN This.ShapeLegend.Alignment = m.lnAlign && Restore to the original setting IF m.lnChartsCount > 1 * Draw the right side of the chart This._ChartIndex = 2 SCAN m.lnValue = This._GetValue(2, .T.) && 2nd column IF ISNULL(m.lnValue) OR (m.lnValue < This._MinScale) OR (m.lnValue < 0) LOOP ENDIF m.lnBarWidth = (m.lnValue / m.lnMaxValue * m.lnWidth) m.x1 = m.lnZeroX m.y1 = This._TopOffSet + ((m.lnBarHeight + m.lnBetween) * (RECNO() - 1)) + m.ln3D This._DrawBar(m.x1, m.y1, m.lnBarWidth, m.lnBarHeight, m.lnValue) ENDSCAN ENDIF SET ORDER TO OTHERWISE ENDCASE * Draw Legends on X Axis for Vertical charts IF This._Orientation = 1 && Vertical IF This.BarType > 0 This._DrawXAxisLegend(m.ln3D/2) ELSE This._DrawXAxisLegend() ENDIF ENDIF RETURN ENDPROC PROCEDURE _drawcylinder LPARAMETERS tnX, tnY, tnWidth, tnHeight, tnValue This._PrepareBrushes(m.tnX, m.tnY, m.tnWidth, m.tnHeight, .F., IIF(This.SingleData, RECNO(),This._ChartIndex)) LOCAL loPen as xfcPen m.loPen = This._oBorderPen LOCAL loGfx as xfcGraphics m.loGfx = This.oGfx LOCAL lnAlpha, lnOrigAlpha m.lnOrigAlpha = This.AlphaChannel m.lnAlpha = MIN(255, (This.AlphaChannel * 1.25)) This.AlphaChannel = m.lnAlpha LOCAL loTopBrush as xfcBrush LOCAL loBotBrush as xfcBrush LOCAL xTopCyl WITH _Screen.System.Drawing DO CASE CASE This.BrushType = 1 && SolidColors m.loTopBrush = .SolidBrush.New(.Color.FromARGB(This.AlphaChannel, This.ChangeColor(This._nColor, - 20))) m.loBotBrush = .SolidBrush.New(.Color.FromARGB(This.AlphaChannel, This._nColor)) CASE This.BrushType = 2 && Gradient m.loTopBrush = .SolidBrush.New(.Color.FromARGB(This.AlphaChannel, This._nColor)) m.loBotBrush = m.loTopBrush OTHERWISE This._PrepareBrushes(m.tnX, m.tnY, m.tnWidth, m.tnHeight, .F., IIF(This.SingleData, RECNO(),This._ChartIndex)) m.loTopBrush = This._oMainBrush m.loBotBrush = m.loTopBrush ENDCASE This.AlphaChannel = m.lnOrigAlpha IF This._Orientation = 1 && Vertical LOCAL yRect, ln3D, x0, yTopCyl, yBotCyl m.ln3D = MAX(This._3d, 1) m.yRect = m.tnY - (m.ln3D / 2) m.yTopCyl = m.tnY - m.ln3D m.yBotCyl = m.tnY + m.tnHeight - m.ln3D m.x0 = m.tnX + m.ln3D / 2 * Draw the lower ellipse m.loGfx.FillEllipse(m.loBotBrush, m.x0, m.yBotCyl, m.tnWidth, m.ln3D) m.loGfx.FillEllipse(This._oMainBrush, m.x0, m.yBotCyl, m.tnWidth, m.ln3D) * Draw the front shape using a GraphicsPath object * Prepare the Main Path LOCAL loPath as xfcGraphicsPath m.loPath = .Drawing2D.GraphicsPath.New() m.loPath.StartFigure() * Bottom Arc m.loPath.AddArc(m.x0, m.yBotCyl, m.tnWidth, m.ln3D, 0, 180) m.loPath.Reverse() * Right Line m.loPath.AddLine(m.x0 + m.tnWidth, m.yRect + m.tnHeight, m.x0 + m.tnWidth, m.yRect) * Top Arc m.loPath.AddArc(m.x0, m.yTopCyl, m.tnWidth, m.ln3D, 0, 180) * Draw the path m.loGfx.FillPath(This._oMainBrush, m.loPath) m.loGfx.DrawPath(m.loPen, m.loPath) * Draw the upper ellipse m.loGfx.FillEllipse(m.loTopBrush, m.x0, m.yTopCyl, m.tnWidth, m.ln3D) m.loGfx.DrawEllipse(m.loPen , m.x0, m.yTopCyl, m.tnWidth, m.ln3D) This._DrawLegendinBar(m.X0, m.tnY, m.tnWidth, m.tnHeight, m.tnValue) ELSE &&_Orientation = 2 - Horizontal LOCAL xRect, ln3D, x0 m.ln3D = MAX(This._3d, 1) m.xRect = m.tnX && - (m.ln3D / 2) m.xTopCyl = m.tnX + m.tnWidth && - m.ln3D / 2 * Draw the front shape using a GraphicsPath object * Prepare the Main Path LOCAL loPath as xfcGraphicsPath m.loPath = .Drawing2D.GraphicsPath.New() m.loPath.StartFigure() * Bottom Arc m.loPath.AddArc(m.tnX, m.tnY, m.ln3D, m.tnHeight, 270, 180) * Bottom Line m.loPath.AddLine(m.tnX + m.ln3D / 2, m.tnY + m.tnHeight, m.xTopCyl + m.ln3D / 2, m.tnY + m.tnHeight) * Top Arc m.loPath.AddArc(m.xTopCyl, m.tnY, m.ln3D, m.tnHeight, 90, 180) * Top Line m.loPath.AddLine(m.xTopCyl + m.ln3D / 2, m.tnY, m.tnX + m.ln3D / 2, m.tnY) * Draw the path m.loGfx.FillPath(This._oMainBrush, m.loPath) m.loGfx.DrawPath(m.loPen, m.loPath) * Draw the upper ellipse m.loGfx.FillEllipse(m.loTopBrush, m.xTopCyl, m.tnY, m.ln3D, m.tnHeight) m.loGfx.DrawEllipse(m.loPen , m.xTopCyl, m.tnY, m.ln3D, m.tnHeight) * Draw the left-most ellipse m.loGfx.FillEllipse(m.loBotBrush , m.tnX, m.tnY, m.ln3D, m.tnHeight) m.loGfx.FillEllipse(This._oMainBrush, m.tnX, m.tnY, m.ln3D, m.tnHeight) This._DrawLegendinBar(m.tnX, m.tnY, m.tnWidth, m.tnHeight, m.tnValue) ENDIF ENDWITH ENDPROC PROCEDURE _drawdoughnutslice LPARAMETERS tnX, tnY, tnWidth, tnHeight, tnStart, tnSweep, tnValue Local laEndPoints[1], ; laPoints[1], ; laPointsB[1], ; laStartPoints[1], ; loPoint4 as Object, ; loPoint5 as Object, ; loPoint6 as Object IF m.tnWidth <= 0 OR m.tnHeight <= 0 RETURN ENDIF This._AdjustStartSweep(@m.tnStart, @m.tnSweep, m.tnWidth, m.tnHeight) This._UpdateCoordinates("Pie", m.tnX, m.tnY, m.tnWidth, m.tnHeight, m.tnValue, m.tnStart, m.tnSweep) LOCAL lnXBrush, lnYBrush IF This.PieEnhancedDrawing m.lnXBrush = m.tnX m.lnYBrush = m.tnY ELSE m.lnXBrush = 0 m.lnYBrush = 0 ENDIF This._PrepareBrushes(m.lnXBrush, m.lnYBrush, m.tnWidth, m.tnHeight, .F., RECNO()) LOCAL loPen as xfcPen m.loPen = This._oBorderPen LOCAL loGfx as xfcGraphics m.loGfx = This.oGfx LOCAL loMainBrush as xfcBrush m.loMainBrush = This._oMainBrush LOCAL lo3dBrush as xfcBrush m.lo3dBrush = This._o3DBrush LOCAL ln3d, lnFinalAngle m.ln3d = This._3D m.lnFinalAngle = m.tnStart + m.tnSweep IF m.lnFinalAngle > 360 m.lnFinalAngle = m.lnFinalAngle - 360 ENDIF IF This.PieEnhancedDrawing && New behavior for Doughnuts && Drawing all edges using the GraphicsPath class WITH _Screen.System.Drawing * Create a GraphicsPath object. LOCAL loMainPath as xfcGraphicsPath m.loMainPath = .Drawing2D.GraphicsPath.New() LOCAL loRect as xfcRectangle LOCAL loRect2 as xfcRectangle LOCAL lnRatio m.lnRatio = This.DonutRatio m.loRect = .Rectangle.New(m.tnX, m.tnY, m.tnWidth, m.tnHeight) m.loRect2 = .Rectangle.New( ; m.tnX + (m.tnWidth * (1 - m.lnRatio) / 2), ; m.tnY + (m.tnHeight * (1 - m.lnRatio) / 2), ; m.tnWidth * m.lnRatio, ; m.tnHeight * m.lnRatio) LOCAL lnXInt, lnYInt, lnHInt, lnWInt m.lnXInt = m.loRect2.X m.lnYInt = m.loRect2.Y m.lnWInt = m.loRect2.Width m.lnHInt = m.loRect2.Height LOCAL loPoint0 as xfcPointF LOCAL loPoint1 as xfcPointF LOCAL loPoint2 as xfcPointF LOCAL loPoint3 as xfcPointF * Obtaining the needed points m.loMainPath.AddArc(m.loRect, m.tnStart, 0.0001) m.loPoint0 = m.loMainPath.GetLastPoint() m.loMainPath.AddArc(m.loRect2, m.tnStart, 0.0001) m.loPoint3 = m.loMainPath.GetLastPoint() m.loMainPath.AddArc(m.loRect, m.tnStart, m.tnSweep) m.loPoint1 = m.loMainPath.GetLastPoint() m.loMainPath.AddArc(m.loRect2, m.tnStart, m.tnSweep) m.loPoint2 = m.loMainPath.GetLastPoint() m.loPoint4 = .Point.New(m.loPoint3.X, m.loPoint3.Y + m.ln3d) m.loPoint5 = .Point.New(m.loPoint0.X, m.loPoint0.Y + m.ln3d) m.loPoint6 = .Point.New(m.loPoint1.X, m.loPoint1.Y + m.ln3d) * Prepare the Main Path LOCAL loPath as xfcGraphicsPath m.loPath = .Drawing2D.GraphicsPath.New() m.loPath.StartFigure() m.loPath.AddArc(m.loRect2, m.tnStart, m.tnSweep) m.loPath.Reverse() m.loPath.AddLine(m.loPoint3.X, m.loPoint3.Y, m.loPoint0.X, m.loPoint0.Y) m.loPath.AddArc(m.loRect, m.tnStart, m.tnSweep) m.loPath.AddLine(m.loPoint1.X, m.loPoint1.Y, m.loPoint2.X, m.loPoint2.Y) ENDWITH IF m.ln3d = 0 OR This.Shadow * Draw shadow IF This.Shadow * Prepare the Shadow Path LOCAL loPath2 as xfcGraphicsPath m.loPath2 = _Screen.System.Drawing.Drawing2D.GraphicsPath.New() m.loPath2.StartFigure() m.loPath2.AddArc(m.loRect2.X, m.loRect2.Y + m.ln3d, m.loRect2.Width, m.loRect2.Height, m.tnStart, m.tnSweep) m.loPath2.Reverse() m.loPath2.AddLine(m.loPoint3.X, m.loPoint3.Y + m.ln3d, m.loPoint0.X, m.loPoint0.Y + m.ln3d) m.loPath2.AddArc(m.loRect.X, m.loRect.Y + m.ln3d, m.loRect.Width, m.loRect.Height, m.tnStart, m.tnSweep) m.loPath2.AddLine(m.loPoint1.X, m.loPoint1.Y + m.ln3d, m.loPoint2.X, m.loPoint2.Y + m.ln3d) * Prepare the shadow brush LOCAL loShadowBrush as xfcSolidBrush m.loShadowBrush = .SolidBrush.New(.Color.FromARGB(This.AlphaChannel, 128, 128, 128)) * Draw the shadow m.loGfx.FillPath(m.loShadowBrush, m.loPath2) ENDIF * Draw the Main doughnut slice (path) m.loGfx.FillPath(m.loMainBrush, m.loPath) m.loGfx.DrawPath(m.loPen, m.loPath) RETURN ENDIF * Continue Drawing, for 3D chart * Prepare the polygon points for the final part of the slice DIMENSION m.laEndPoints(4) m.laEndPoints(1) = m.loPoint1 m.laEndPoints(2) = m.loPoint2 m.laEndPoints(3) = _Screen.System.Drawing.Point.New(m.loPoint2.X, m.loPoint2.Y + m.ln3d) m.laEndPoints(4) = m.loPoint6 * Prepare the polygon points for the beginning part of the slice DIMENSION m.laStartPoints(4) m.laStartPoints(1) = m.loPoint0 m.laStartPoints(2) = m.loPoint5 m.laStartPoints(3) = m.loPoint4 m.laStartPoints(4) = m.loPoint3 * If the slice ends in the left side, draw the Ending polygon before the top face of the slice IF BETWEEN(m.lnFinalAngle, 90.001, 269.999) m.loGfx.DrawPolygon(m.loPen, @m.laEndPoints) m.loGfx.FillPolygon(m.lo3dBrush, @m.laEndPoints) ENDIF IF NOT (m.tnStart >= 90 AND m.tnStart <= 270) m.loGfx.DrawPolygon(m.loPen, @m.laStartPoints) m.loGfx.FillPolygon(m.lo3dBrush, @m.laStartPoints) ENDIF * Draw the external and internal paths LOCAL lnFinalAngle m.lnFinalAngle = m.tnStart + m.tnSweep IF m.lnFinalAngle > 360 m.lnFinalAngle = m.lnFinalAngle - 360 ENDIF LOCAL lnAdjStart, lnAdjSweep m.lnAdjStart = m.tnStart m.lnAdjSweep = m.tnSweep LOCAL loAdjPoint0 as xfcPoint, loAdjPoint1 as xfcPoint m.loAdjPoint0 = m.loPoint0 m.loAdjPoint1 = m.loPoint1 LOCAL loAdjPoint2 as xfcPoint, loAdjPoint3 as xfcPoint m.loAdjPoint2 = m.loPoint3 m.loAdjPoint3 = m.loPoint2 IF m.tnStart >= 270 AND ; m.tnStart < 360 AND ; BETWEEN(m.lnFinalAngle, 0, 270) LOCAL loTempPoint as xfcPoint m.loTempPoint = _Screen.System.Drawing.Point.New(m.tnX + m.tnWidth, m.tnY + m.tnHeight / 2) LOCAL loTempPoint2 as xfcPoint m.loTempPoint2 = _Screen.System.Drawing.Point.New(m.lnXInt + m.lnWInt, m.lnYInt + m.lnHInt / 2) * External part This._DrawSliceExternal(m.tnX, m.tnY, m.tnWidth, m.tnHeight, m.tnStart, 360 - m.tnStart, m.loPoint0, m.loTempPoint) * Internal part This._DrawSliceExternal(m.lnXInt, m.lnYInt, m.lnWInt, m.lnHInt, m.tnStart, 360 - m.tnStart, m.loPoint3, m.loTempPoint2) m.lnAdjStart = 0 m.lnAdjSweep = m.tnSweep - (360 - m.tnStart) m.loAdjPoint0 = m.loTempPoint m.loAdjPoint1 = m.loPoint1 * Internal m.loAdjPoint2 = m.loTempPoint2 m.loAdjPoint3 = m.loPoint2 ENDIF LOCAL llDrawExtAtEnd m.llDrawExtAtEnd = .F. IF (m.tnStart < 180 AND m.lnFinalAngle > 180) OR ; (m.tnStart >= 270 AND m.lnFinalAngle > 180 AND m.lnFinalAngle < 270.01) IF m.tnStart >= 270 m.lnAdjStart = 0 m.lnAdjSweep = 180 ELSE m.lnAdjStart = m.tnStart m.lnAdjSweep = 180 - m.tnStart ENDIF m.loAdjPoint1 = _Screen.System.Drawing.Point.New(m.tnX, m.tnY + m.tnHeight / 2) m.loAdjPoint3 = _Screen.System.Drawing.Point.New(m.lnXInt, m.lnYInt + m.lnHInt / 2) * External part m.llDrawExtAtEnd = .T. LOCAL lnStartB, lnSweepB, loPoint0B, loPoint1B m.lnStartB = m.lnAdjStart m.lnSweepB = m.lnAdjSweep m.loPoint0B = m.loAdjPoint0 m.loPoint1B = m.loAdjPoint1 * Internal part This._DrawSliceExternal(m.lnXInt, m.lnYInt, m.lnWInt, m.lnHInt, m.lnAdjStart, m.lnAdjSweep, m.loAdjPoint2, m.loAdjPoint3) m.loAdjPoint0 = m.loAdjPoint1 m.loAdjPoint2 = m.loAdjPoint3 m.lnAdjStart = 180 m.lnAdjSweep = m.lnFinalAngle - 180 ENDIF IF BETWEEN(m.lnFinalAngle, 0, 180) * Internal part This._DrawSliceExternal(m.lnXInt, m.lnYInt, m.lnWInt, m.lnHInt, m.lnAdjStart, m.lnAdjSweep, m.loAdjPoint2, m.loPoint2) * External part This._DrawSliceExternal(m.tnX, m.tnY, m.tnWidth, m.tnHeight, m.lnAdjStart, m.lnAdjSweep, m.loAdjPoint0, m.loPoint1) ELSE * External part This._DrawSliceExternal(m.tnX, m.tnY, m.tnWidth, m.tnHeight, m.lnAdjStart, m.lnAdjSweep, m.loAdjPoint0, m.loPoint1) * Internal part This._DrawSliceExternal(m.lnXInt, m.lnYInt, m.lnWInt, m.lnHInt, m.lnAdjStart, m.lnAdjSweep, m.loAdjPoint2, m.loPoint2) ENDIF IF m.llDrawExtAtEnd This._DrawSliceExternal(m.tnX, m.tnY, m.tnWidth, m.tnHeight, m.lnStartB, m.lnSweepB, m.loPoint0B, m.loPoint1B) ENDIF * Draw polygon at the beginning of the doughnut IF m.tnStart > 90 AND m.tnStart < 270 m.loGfx.DrawPolygon(m.loPen, @m.laStartPoints) m.loGfx.FillPolygon(m.lo3dBrush, @m.laStartPoints) ENDIF IF NOT BETWEEN(m.lnFinalAngle, 90, 270) m.loGfx.DrawPolygon(m.loPen, @m.laEndPoints) m.loGfx.FillPolygon(m.lo3dBrush, @m.laEndPoints) ENDIF * Draw the main path m.loGfx.FillPath(m.loMainBrush, m.loPath) m.loGfx.DrawPath(m.loPen, m.loPath) ELSE && This.PieEnhancedDrawing .F. - This is the old Behavior WITH _Screen.System.Drawing LOCAL loBmp as xfcBitmap m.loBmp = poTempBmp LOCAL loTempGfx as xfcGraphics m.loTempGfx = .Graphics.FromImage(m.loBmp) m.loTempGfx.Clear(.Color.Transparent) m.loTempGfx.SmoothingMode = .Drawing2D.SmoothingMode.AntiAlias * Create a GraphicsPath object. LOCAL loTempPath as xfcGraphicsPath m.loTempPath = .Drawing2D.GraphicsPath.New() LOCAL loRect as xfcRectangle LOCAL loRect2 as xfcRectangle LOCAL lnRatio m.lnRatio = This.DonutRatio m.loRect = .Rectangle.New(0, 0, m.tnWidth, m.tnHeight) m.loRect2 = .Rectangle.New( ; (m.tnWidth * (1 - m.lnRatio) / 2), ; (m.tnHeight * (1 - m.lnRatio) / 2), ; m.tnWidth * m.lnRatio, ; m.tnHeight * m.lnRatio) LOCAL loPoint0 as xfcPointF LOCAL loPoint1 as xfcPointF LOCAL loPoint2 as xfcPointF LOCAL loPoint3 as xfcPointF * Obtaining the needed points m.loTempPath.AddArc(m.loRect, m.tnStart, 0.0001) m.loPoint0 = m.loTempPath.GetLastPoint() m.loTempPath.AddArc(m.loRect2, m.tnStart, 0.0001) m.loPoint3 = m.loTempPath.GetLastPoint() m.loTempPath.AddArc(m.loRect, m.tnStart, m.tnSweep) m.loPoint1 = m.loTempPath.GetLastPoint() m.loTempPath.AddArc(m.loRect2, m.tnStart, m.tnSweep) m.loPoint2 = m.loTempPath.GetLastPoint() m.loPoint4 = .Point.New(m.loPoint3.X, m.loPoint3.Y + m.ln3d) m.loPoint5 = .Point.New(m.loPoint0.X, m.loPoint0.Y + m.ln3d) m.loPoint6 = .Point.New(m.loPoint1.X, m.loPoint1.Y + m.ln3d) * Prepare the Main Path LOCAL loPath as xfcGraphicsPath m.loPath = .Drawing2D.GraphicsPath.New() m.loPath.StartFigure() m.loPath.AddLine(m.loPoint0.X, m.loPoint0.Y, m.loPoint3.X, m.loPoint3.Y) m.loPath.AddArc(m.loRect2, m.tnStart, m.tnSweep) m.loPath.StartFigure() m.loPath.AddArc(m.loRect, m.tnStart, m.tnSweep) m.loPath.AddLine(m.loPoint1.X, m.loPoint1.Y, m.loPoint2.X, m.loPoint2.Y) IF m.ln3d > 0 * Create a new Path for the 3D LOCAL lo3DPath as xfcPath m.lo3DPath = m.loPath.Clone() LOCAL loMatrix as xfcMatrix m.loMatrix = .Drawing2D.Matrix.New() m.loMatrix.Translate(0, + 1) * Prepare the polygon points for the final part of the slice DIMENSION m.laPointsB(4) m.laPointsB(1) = m.loPoint1 m.laPointsB(2) = m.loPoint2 m.laPointsB(3) = .Point.New(m.loPoint2.X, m.loPoint2.Y + m.ln3d) m.laPointsB(4) = m.loPoint6 * If the slice ends in the left side, draw the polygon before the top face of the slice IF BETWEEN(m.lnFinalAngle, 90, 270) m.loTempGfx.DrawPolygon(m.loPen, @m.laPointsB) ENDIF LOCAL n FOR m.n = 1 TO m.ln3d - 1 m.lo3DPath.Transform(m.loMatrix) m.loTempGfx.FillPath(m.lo3dBrush, m.lo3DPath) ENDFOR * Draw the side Polygons * Draw polygon at the beginning of the donut IF m.tnStart > 90 AND m.tnStart < 270 DIMENSION m.laPoints(4) m.laPoints(1) = m.loPoint0 m.laPoints(2) = m.loPoint5 m.laPoints(3) = m.loPoint4 m.laPoints(4) = m.loPoint3 m.loTempGfx.DrawPolygon(m.loPen, @m.laPoints) ENDIF * Draw polygon at the end of the donut IF m.lnFinalAngle < 90 OR m.lnFinalAngle > 270 m.loTempGfx.DrawPolygon(m.loPen, @m.laPointsB) ENDIF ENDIF * Draw the path m.loTempGfx.FillPath(m.loMainBrush, m.loPath) m.loTempGfx.DrawPath(This._oBorderPen, m.loPath) m.loBmp.ApplyColorMatrix(poClrMatrix) m.loGfx.DrawImage(m.loBmp, m.tnX, m.tnY) ENDWITH ENDIF RETURN ENDPROC PROCEDURE _drawlegendinbar LPARAMETERS tnX, tnY, tnWidth, tnHeight, tnValue, tnIndex * Zero values in Stacked charts will not have space for drawing legends * so we'll ignore this case IF This._Stacked AND m.tnValue = 0 RETURN ENDIF This.CurrIndex = This._nIndex LOCAL lnLeftMargin m.lnLeftMargin = This._yAxisWidth + This._LeftOffset *!* Other available properties *!* This.CurrValue *!* This.CurrLegend *!* This.CurrObjType *!* This.CurrRecno *!* This.CurrColumn IF This.Fields(This._ChartIndex).ShowValuesOnShape AND This.ShowValuesOnShapes LOCAL lcExpr m.lcExpr = This.ShapeLegendExpression IF (VARTYPE(m.lcExpr) = "C") AND (NOT EMPTY(m.lcExpr)) This.ShapeLegend._Value = EVALUATE(m.lcExpr) ELSE IF This._SumRow AND This.ShowPercentages * Show percentages as values DO CASE CASE EMPTY(This.ShapeLegend.Format) AND EMPTY(This.ShapeLegendExpression) This.ShapeLegend._ForceFormat = ; This._GetFieldType(This.SourceAlias, EVALUATE("This.Fields(This.ChartRow).FieldValue"), .T.) + "%" CASE NOT "%" $ This.ShapeLegend.Format This.ShapeLegend._ForceFormat = This.ShapeLegend.Format + "%" ENDCASE LOCAL lnValue m.lnValue = ROUND(m.tnValue / This.ChartSum * 100,0) This.ShapeLegend._Value = m.lnValue ELSE This.ShapeLegend._Value = m.tnValue ENDIF ENDIF LOCAL lnAlign, lnDirection m.lnAlign = This.ShapeLegend.Alignment *!* IF This._InvertShapeLegendAlignment = .T. *!* DO CASE *!* CASE lnAlign = 0 && Left *!* lnAlign = 1 && Right *!* CASE lnAlign = 1 && Right *!* lnAlign = 0 && Left *!* OTHERWISE *!* ENDCASE *!* ENDIF m.lnDirection = This.BarLegendDirection IF m.lnDirection = 0 && Horizontal * Draw the Values inside the shapes IF This._Orientation = 1 && Vertical IF (m.tnHeight < This.ShapeLegend._Height) AND (NOT This._Stacked) LOCAL y0 m.y0 = This.ChartCanvas.Height - This._XAxisHeight + 1 m.tnY = m.y0 - This.ShapeLegend._Height ENDIF DO CASE CASE This.ShapeLegend.Rotation <> 0 AND This.BarLegendType = 1 m.tnY = m.tnY - This.ShapeLegend._Height - 2 This.ShapeLegend._DrawString(m.tnX + m.tnWidth / 2, m.tnY) CASE m.lnAlign = 0 && Left This.ShapeLegend._DrawString(m.tnX, m.tnY) CASE m.lnAlign = 1 && Right This.ShapeLegend._DrawString(m.tnX + m.tnWidth, m.tnY) CASE m.lnAlign = 2 && Center This.ShapeLegend._DrawString(m.tnX + m.tnWidth / 2, m.tnY) OTHERWISE ENDCASE ELSE && This._Orientation = 2 && Horizontal DO CASE CASE m.lnAlign = 2 && Center * This.ShapeLegend._DrawString(tnX + tnWidth / 2, tnY) IF This.ShapeLegend._Width > m.tnWidth && force left This.ShapeLegend.Alignment = 0 This.ShapeLegend._DrawString(m.tnX, m.tnY) This.ShapeLegend.Alignment = 2 ELSE This.ShapeLegend._DrawString(m.tnX + m.tnWidth / 2, m.tnY) ENDIF CASE m.lnAlign = 0 AND m.tnValue >= 0 && Left This.ShapeLegend._DrawString(m.tnX, m.tnY) CASE m.lnAlign = 1 AND m.tnValue >= 0 && Right IF This.ShapeLegend._Width > m.tnWidth && force left This.ShapeLegend.Alignment = 0 This.ShapeLegend._DrawString(m.tnX, m.tnY) This.ShapeLegend.Alignment = 1 ELSE This.ShapeLegend._DrawString(m.tnX + m.tnWidth, m.tnY) ENDIF CASE m.lnAlign = 1 AND m.tnValue < 0 && Force Left This.ShapeLegend.Alignment = 0 This.ShapeLegend._DrawString(m.tnX, m.tnY) This.ShapeLegend.Alignment = 1 CASE m.lnAlign = 0 AND m.tnValue < 0 && Force Right This.ShapeLegend.Alignment = 1 This.ShapeLegend._DrawString(m.tnX + m.tnWidth, m.tnY) This.ShapeLegend.Alignment = 0 OTHERWISE ENDCASE ENDIF ELSE && BarLegendDirection = 1 && Vertical IF m.lnDirection = 2 && Invert Direction LOCAL lnRotCenter m.lnRotCenter = This.ShapeLegend.RotationCenter This.ShapeLegend.RotationCenter = m.lnRotCenter + 180 ENDIF IF m.tnValue >= 0 OR m.lnAlign = 2 This.ShapeLegend._DrawString(m.tnX, m.tnY, m.tnWidth, m.tnHeight, .T.) ELSE IF m.lnAlign = 0 This.ShapeLegend.Alignment = 1 ELSE This.ShapeLegend.Alignment = 0 ENDIF This.ShapeLegend._DrawString(m.tnX, m.tnY, m.tnWidth, m.tnHeight, .T.) This.ShapeLegend.Alignment = m.lnAlign ENDIF IF m.lnDirection = 2 && Invert Direction This.ShapeLegend.RotationCenter = m.lnRotCenter ENDIF ENDIF ENDIF ENDPROC PROCEDURE _drawlinechart LOCAL laPoints[1], ; laPointsI[1], ; lcType as String, ; lnAdjust as Number, ; lnBarHeight as Number, ; lnBarWidth as Number SELECT(This._DataCursor) LOCAL lnLeftMargin, lnWidth, lnHeight, lnValue LOCAL lnBetween, lnBetween2, n, i, j, lnMaxValue, lnPointHeight, x1, y1, ln3D, lnChartsCount LOCAL llIsNull, lnYBase LOCAL lnTipPixels, lnType2, lnAlignment, lnRecs LOCAL lnMaxValue2 m.lnAlignment = This.ShapeLegend.Alignment m.lnRecs = This._nRecords m.lnTipPixels = This._TipPixels m.lnLeftMargin = This._YAxisWidth + This._LeftOffset m.ln3D = This._3D m.lnChartsCount = This.ChartsCount * Calculate the maximum width of the chart m.lnWidth = This.ChartCanvas.Width - This._YAxisWidth - This._LeftOffset - (m.ln3D * m.lnChartsCount) - This._RightOffset - THIS._yAxisWidth2 m.lnHeight = This.ChartCanvas.Height - This._XAxisHeight - This._TopOffSet - (m.ln3D * m.lnChartsCount) IF m.lnWidth < 10 OR m.lnHeight < 10 OR m.lnRecs < 1 RETURN ENDIF LOCAL loGfx as xfcGraphics m.loGfx = This.oGfx * Get the maximum value of the chart m.lnMaxValue = This._ScaleRange m.lnMaxValue2 = This._ScaleRange2 LOCAL loBrush as xfcBrush IF This.BrushType = 1 m.loBrush = "This._o3dbrush" ELSE m.loBrush = "This._oMainBrush" ENDIF * Prepare array of points * 1st column is the current point object * 2nd column is the global index number for the coordinates array LOCAL lnArrayLength IF INLIST(This.ChartType, 5, 18) && Line m.lnArrayLength = m.lnRecs ELSE && Area m.lnArrayLength = m.lnRecs + 3 ENDIF DIMENSION m.laPoints(m.lnArrayLength) DIMENSION m.laPointsI(m.lnArrayLength) WITH _Screen.System.Drawing FOR m.i = 1 TO m.lnChartsCount This._ChartIndex = m.i m.lnType2 = EVALUATE("This.Fields(i).ChartType") m.lnAdjust = (m.ln3D * (m.lnChartsCount - m.i )) m.lnYBase = This._TopOffSet + m.lnHeight - m.lnAdjust + (m.ln3D * m.lnChartsCount) * If MultiChart mode, the chart needs to start half a position further IF This.Multichart AND This.MultiChartMargin m.lnBetween = m.lnWidth / (m.lnRecs) ELSE m.lnBetween = m.lnWidth / (m.lnRecs - IIF(m.lnRecs = 1, 0, 1)) ENDIF m.lnBetween2 = m.lnBetween + m.lnAdjust && the X distance between the points to be used when drawing the legends in the X axis SCAN m.n = RECNO() m.x1 = m.lnLeftMargin + (m.lnBetween * (m.n - 1)) + ; m.lnAdjust + IIF(This.Multichart AND This.MultiChartMargin, ; (m.lnBetween / 2), 0) m.lnValue = This._GetValue(m.i, .T.) m.llIsNull = ISNULL(m.lnValue) IF m.llIsNull m.lnValue = 0 ENDIF IF This.Fields(m.i).AxisIndex = 2 AND This.ChartType = 18 m.lnValue = m.lnValue + This._ScaleAdjust2 m.lnPointHeight = m.lnValue / m.lnMaxValue2 * m.lnHeight m.y1 = m.lnYBase - m.lnPointHeight This._aPoints(m.n, 1) = m.x1 + m.ln3D This._aPoints(m.n, 2) = m.y1 This._aPoints(m.n, 3) = m.lnValue - This._ScaleAdjust2 && Restore the original value ELSE && This.Fields(i).AxisIndex = 1 IF m.llIsNull AND (m.n > 1) AND (This.LineIgnoreNULLs) && Special situation to Tamar Granor This._aPoints(m.n, 1) = This._aPoints(m.n - 1, 1) This._aPoints(m.n, 2) = This._aPoints(m.n - 1, 2) This._aPoints(m.n, 3) = This._aPoints(m.n - 1, 3) * Extra checking to avoid drawing a line if the starting values are NULLs IF VARTYPE(m.laPoints(m.n - 1)) = "L" m.laPoints(RECNO()) = .F. ELSE m.laPoints(RECNO()) = .Point.New(This._aPoints(m.n, 1) - m.ln3D, This._aPoints(m.n, 2)) ENDIF LOOP ENDIF m.lnValue = m.lnValue + This._ScaleAdjust m.lnPointHeight = m.lnValue / m.lnMaxValue * m.lnHeight m.y1 = m.lnYBase - m.lnPointHeight This._aPoints(m.n, 1) = m.x1 + m.ln3D This._aPoints(m.n, 2) = m.y1 This._aPoints(m.n, 3) = m.lnValue - This._ScaleAdjust && Restore the original value ENDIF m.laPoints(RECNO()) = IIF(m.llIsNull, .F., .Point.New(m.x1, m.y1)) ENDSCAN GO TOP * Draw the vertical line only for the first line IF m.i = 1 This._DrawVerticalLineBack() ENDIF DO CASE *-- 2010-11-26 *-- Fix by Paulo Henrique de Almeida (Casion) CASE m.lnType2 = 3 && Single Bar m.lnBarWidth = (m.lnWidth - (m.lnRecs - 1) * This.BarsSpaceBetween) / m.lnRecs FOR m.n = 1 TO m.lnRecs IF VARTYPE(m.laPoints(m.n)) <> "O" LOOP ENDIF * changed by paulo henrique m.x1 = This._aPoints(m.n, 1) - m.lnBarWidth / 2 - m.ln3D m.y1 = This.Height - ((0 - This._MinScale) / m.lnMaxValue * m.lnHeight) - This._XAxisHeight m.lnValue = This._aPoints(m.n, 3) m.lnBarHeight = m.y1 - This._aPoints(m.n, 2) m.y1 = min(m.y1, This._aPoints(m.n, 2)) * end - changed by paulo henrique This._CurrentRow = m.n This._DrawBar(m.x1, m.y1, m.lnBarWidth, m.lnBarHeight, m.lnValue) m.laPointsI(m.n) = This._nIndex ENDFOR *-- CASE This.ChartType = 4 OR m.lnType2 = 4 && Point / Secondary Point FOR m.n = 1 TO m.lnRecs IF VARTYPE(m.laPoints(m.n)) <> "O" LOOP ENDIF This._DrawShape(m.laPoints(m.n).X, m.laPoints(m.n).Y, This._aPoints(m.n, 3)) m.laPointsI(m.n) = This._nIndex This._CurrentRow = m.n ENDFOR OTHERWISE && ChartType <> 4 - Line or Area IF This.ChartType = 6 && Area This._PrepareBrushes(0, 0, This.ChartCanvas.Width, This.ChartCanvas.Height, .F., m.i) ENDIF LOCAL laPolygon(4) LOCAL laPolygonB(4) IF m.ln3D = 0 * Create pen. LOCAL loLinePen as xfcPen LOCAL lnColor IF This.BrushType = 3 && Monochrome m.lnColor = 0 m.loLinePen = .Pen.New(This._oClrBlack, 3) m.loLinePen.DashStyle = m.i - 1 && _Screen.System.Drawing.Drawing2D.DashStyle.Dash ELSE m.lnColor = This.aColors(m.i) m.loLinePen = .Pen.New(.Color.FromRGB(m.lnColor), 2) ENDIF FOR m.n = 1 TO m.lnRecs - 1 This._CurrentRow = m.n m.lcType = VARTYPE(m.laPoints(m.n)) + VARTYPE(m.laPoints(m.n + 1)) DO CASE CASE m.lcType = "LO" OR m.lcType = "LL" LOOP CASE m.lcType = "OL" m.loGfx.Drawline(m.loLinePen, m.laPoints(m.n).X, m.laPoints(m.n).Y, m.laPoints(m.n).X + 1, m.laPoints(m.n).Y + 1) This._UpdateCoordinates("Rect", m.laPoints(m.n).X - m.lnTipPixels / 2, m.laPoints(m.n).Y - m.lnTipPixels / 2, m.lnTipPixels, m.lnTipPixels, ; This._aPoints(m.n, 3), m.n) m.laPointsI(m.n) = This._nIndex LOOP OTHERWISE m.loGfx.Drawline(m.loLinePen, m.laPoints(m.n), m.laPoints(m.n + 1)) ENDCASE IF This.ChartType = 6 && Area * Draw the area m.laPolygonB(1) = m.laPoints(m.n) m.laPolygonB(2) = m.laPoints(m.n + 1) m.laPolygonB(3) = .Point.New(m.laPolygonB(2).X, m.lnYBase) m.laPolygonB(4) = .Point.New(m.laPolygonB(1).X, m.lnYBase) m.loGfx.FillPolygon(This._oMainBrush, @m.laPolygonB) IF This.AreaDrawBorders m.loGfx.DrawPolygon(This._oBorderPen, @m.laPolygonB) ENDIF ENDIF This._UpdateCoordinates("Rect", m.laPoints(m.n).X - m.lnTipPixels / 2, m.laPoints(m.n).Y - m.lnTipPixels / 2, m.lnTipPixels, m.lnTipPixels, ; This._aPoints(m.n, 3)) m.laPointsI(m.n) = This._nIndex ENDFOR IF VARTYPE(m.laPoints(m.n)) = "O" This._CurrentRow = m.n This._UpdateCoordinates( ; "Rect", m.laPoints(m.n).X - m.lnTipPixels / 2, m.laPoints(m.n).Y - m.lnTipPixels / 2, ; m.lnTipPixels, m.lnTipPixels, This._aPoints(m.n, 3)) m.laPointsI(m.n) = This._nIndex ENDIF * Draw the shapes after (over) the lines IF This.LineCaps = .T. AND INLIST(This.ChartType, 5, 18) && Line FOR m.j = 1 TO m.lnRecs IF VARTYPE(m.laPoints(m.j)) <> "O" OR ; VARTYPE(m.laPoints(m.j).X) + VARTYPE(m.laPoints(m.j).Y) <> "NN" LOOP ENDIF This._DrawShape(m.laPoints(m.j).X, m.laPoints(m.j).Y, This._aPoints(m.j, 3)) m.laPointsI(m.n) = This._nIndex This._CurrentRow = m.j ENDFOR ENDIF ELSE && m.ln3D <> 0 * Store a big area brush that will be used for the main area part of the shapes LOCAL loAreaBrush, llDrawPointLine m.loAreaBrush = This._oMainBrush FOR m.n = 1 TO m.lnRecs - 1 This._CurrentRow = m.n m.lcType = VARTYPE(m.laPoints(m.n)) + VARTYPE(m.laPoints(m.n + 1)) DO CASE CASE m.lcType = "LO" OR m.lcType = "LL" LOOP CASE m.lcType = "OL" m.llDrawPointLine = .T. OTHERWISE m.llDrawPointLine = .F. ENDCASE IF This.ChartType = 6 ; && Area AND "L" $ m.lcType IF m.lcType = "OL" This._UpdateCoordinates("Rect", m.laPoints(m.n).X - m.lnTipPixels / 2, m.laPoints(m.n).Y - m.lnTipPixels / 2, m.lnTipPixels, m.lnTipPixels, ; This._aPoints(m.n, 3)) m.laPointsI(m.n) = This._nIndex ENDIF LOOP ENDIF IF INLIST(This.ChartType, 5, 18) OR (This.ChartType = 6 AND This.Area3dTop) m.laPolygon(1) = m.laPoints(m.n) m.laPolygon(2) = .Point.New(m.laPoints(m.n).X + m.ln3D, m.laPoints(m.n).Y - m.ln3D) IF m.llDrawPointLine LOCAL lnColor, loLinePen as xfcPen m.lnColor = This.aColors(m.i) m.loLinePen = .Pen.New(.Color.FromRGB(m.lnColor), 2) m.loGfx.Drawline(m.loLinePen, m.laPolygon(1), m.laPolygon(2)) This._UpdateCoordinates("Rect", m.laPoints(m.n).X - m.lnTipPixels / 2, m.laPoints(m.n).Y - m.lnTipPixels / 2, m.lnTipPixels, m.lnTipPixels, ; This._aPoints(m.n, 3)) m.laPointsI(m.n) = This._nIndex LOOP ENDIF m.laPolygon(3) = .Point.New(m.laPoints(m.n + 1).X + m.ln3D, m.laPoints(m.n + 1).Y - m.ln3D) m.laPolygon(4) = m.laPoints(m.n + 1) This._PrepareBrushes(m.laPoints(m.n).X, m.laPoints(m.n).Y - m.ln3D, ; m.laPoints(m.n + 1).X + m.ln3D - m.laPoints(m.n).X, ; MAX(2, ABS(m.laPoints(m.n).Y - m.laPoints(m.n + 1).Y)), .F., m.i) m.loGfx.FillPolygon(This._oMainBrush, @m.laPolygon) m.loGfx.DrawPolygon(This._oBorderPen, @m.laPolygon) ENDIF IF This.ChartType = 6 && Area * Draw the area m.laPolygonB(1) = m.laPoints(m.n) m.laPolygonB(2) = m.laPoints(m.n + 1) m.laPolygonB(3) = .Point.New(m.laPolygonB(2).X, m.lnYBase) m.laPolygonB(4) = .Point.New(m.laPolygonB(1).X, m.lnYBase) m.loGfx.FillPolygon(m.loAreaBrush, @m.laPolygonB) IF This.AreaDrawBorders m.loGfx.DrawPolygon(This._oBorderPen, @m.laPolygonB) ENDIF * Draw the right 3d edge of the Area IF This.Area3dTop m.laPolygonB(1) = .Point.New(m.laPolygonB(2).X + m.ln3D, m.laPolygonB(2).Y - m.ln3D) m.laPolygonB(4) = .Point.New(m.laPolygonB(3).X + m.ln3D, m.laPolygonB(3).Y - m.ln3D) m.loGfx.FillPolygon(This._o3dbrush, @m.laPolygonB) m.loGfx.DrawPolygon(This._oBorderPen, @m.laPolygonB) ENDIF ENDIF && ChartType = 6 - Area This._UpdateCoordinates("Rect", m.laPoints(m.n).X - m.lnTipPixels / 2, m.laPoints(m.n).Y - m.lnTipPixels / 2, m.lnTipPixels, m.lnTipPixels, ; This._aPoints(m.n, 3)) m.laPointsI(m.n) = This._nIndex ENDFOR This._CurrentRow = m.n IF VARTYPE(m.laPoints(m.n)) = "O" This._UpdateCoordinates("Rect", m.laPoints(m.n).X - m.lnTipPixels / 2, m.laPoints(m.n).Y - m.lnTipPixels / 2, m.lnTipPixels, m.lnTipPixels, ; This._aPoints(m.n, 3)) m.laPointsI(m.n) = This._nIndex ENDIF ENDIF && m.ln3D = 0 ENDCASE * Reset Row counter This._CurrentRow = 0 * Adjust _aPoints Array to show the information in the correct position FOR m.n = 1 TO m.lnRecs This._aPoints(m.n, 1) = This._aPoints(m.n, 1) - m.ln3D ENDFOR IF This.ShowValuesOnShapes AND This.Fields(m.i).ShowValuesOnShape LOCAL lnIndex * Draw Legends above the points FOR m.n = 1 TO m.lnRecs * Adjust _aPoints Array to show the information in the correct position This._aPoints(m.n, 1) = This._aPoints(m.n, 1) - m.ln3D IF VARTYPE(m.laPoints(m.n)) = "L" LOOP ENDIF m.x1 = This._aPoints(m.n, 1) m.y1 = This._aPoints(m.n, 2) m.lnIndex = m.laPointsI(m.n) This._DrawShapeLegend(m.x1, m.y1, m.lnIndex) ENDFOR ENDIF ENDFOR This._DrawXAxisLegend(.F., m.lnBetween2) ENDWITH This.ShapeLegend.Alignment = m.lnAlignment RETURN ENDPROC PROCEDURE _drawpiechart LOCAL lnDetachAngle as Number, ; lnTempStart as Number, ; lnTempSweep as Number, x1, y1 SELECT(This._DataCursor) LOCAL lnDetachPixels, lnStart, lnSweep, lnAngle, ln3D, lnValue LOCAL lnWidth, lnHeight, lnX, lnY, lnTotal, lnMaxWidth, lnMaxHeight m.lnDetachPixels = This.PieDetachPixels m.lnMaxWidth = This.ChartCanvas.Width - This._LeftOffset - This._RightOffset - (lnDetachPixels * 2) m.lnMaxHeight = This.ChartCanvas.Height - (This.Margin * 2) - This.MarginBottom - ; This.MarginTop - This._TitleHeight - This._3d - ; (lnDetachPixels * 2) - ; IIF(This.LegendPosition > 4, This._LegendHeight, 0) m.lnWidth = MIN(lnMaxWidth, lnMaxHeight) m.lnHeight = m.lnWidth IF NOT This.PieForceCircle * Adjust the maximum width in order to ensure that the chart will retain LOCAL lnFactor m.lnFactor = 0.80 IF m.lnMaxWidth <= m.lnWidth / m.lnFactor m.lnWidth = lnMaxWidth ELSE m.lnWidth = m.lnWidth / m.lnFactor ENDIF ENDIF m.ln3D = This._3d IF This.PieCompensateAngles m.lnWidth = m.lnMaxWidth ELSE ENDIF IF m.lnWidth <= 10 OR ; lnHeight <= 10 OR ; lnHeight <= ln3D RETURN ENDIF * Calculate the chart basic positions lnX = lnDetachPixels + This.Margin + This._LeftOffset + ((lnMaxWidth - m.lnWidth) / 2) lnY = This.Margin + This._TopOffSet + ((lnMaxHeight - m.lnHeight) / 2) + lnDetachPixels lnTotal = This.ChartSum IF NOT This.PieEnhancedDrawing && Draws without taking care of slices edges * Prepare the Gdi+ objects WITH _Screen.System.Drawing PRIVATE poTempBmp as xfcBitmap PRIVATE poClrMatrix as xfcColorMatrix poTempBmp = .Bitmap.New(m.lnWidth + m.ln3D + 2, m.lnHeight + m.ln3D + 2) poClrMatrix = .Imaging.ColorMatrix.New() poClrMatrix.Matrix33 = This.AlphaChannel / 255 ENDWITH ENDIF LOCAL laLegends(This._nRecords + 1, 3) LOCAL lnRec, llHidden, llDrawLegend LOCAL lnPixelsOut llDrawLegend = This.ShowValuesonShapes lnRec = 1 This._ChartIndex = This.ChartRow This._Pie1stDetached = .F. IF This.PieDirection = 1 && Anticlockwise SET ORDER TO Revert ENDIF * Draw the pie * Draw the RIGHT side of the pie lnStart = 270 SCAN FOR lnStart < 450 x1 = lnX y1 = lnY * Calculate Start point and Sweep lnValue = This._GetValue(This.ChartRow) IF lnValue <= 0 LOOP ENDIF lnSweep = lnValue / lnTotal * 360 IF lnSweep > 359.99 lnSweep = 359.99 ENDIF llHidden = lSliceHidden IF lDetach = .T. IF lnRec = 1 This._Pie1stDetached = .T. This._PieX0 = x1 This._PieY0 = y1 ENDIF IF RECNO() = This._PieAnimatedRec lnPixelsOut = This._PieAnimationPix ELSE lnPixelsOut = lnDetachPixels ENDIF lnTempStart = lnStart lnTempSweep = lnSweep This._AdjustStartSweep(@lnTempStart, @lnTempSweep, m.lnWidth, m.lnHeight) lnDetachAngle = 360 - (lnTempStart + (lnTempSweep / 2)) x1 = lnX + (COS(DTOR(lnDetachAngle)) * lnPixelsOut) y1 = lnY - (SIN(DTOR(lnDetachAngle)) * lnPixelsOut) ELSE x1 = lnX y1 = lnY ENDIF IF lnStart + lnSweep > 450 EXIT ENDIF IF NOT llHidden IF This.ChartType = 1 && Pie This._DrawSlice(x1, y1, m.lnWidth, m.lnHeight, lnStart, lnSweep, lnValue) ELSE && 2 - Doughnut This._DrawDoughnutSlice(x1, y1, m.lnWidth, m.lnHeight, lnStart, lnSweep, lnValue) ENDIF IF llDrawLegend This._PrepareLegendinSlice(@x1, @y1, m.lnWidth, m.lnHeight, lnStart, lnSweep, lnValue) laLegends(lnRec, 1) = x1 laLegends(lnRec, 2) = y1 laLegends(lnRec, 3) = lnValue lnRec = lnRec + 1 ENDIF ENDIF lnStart = lnStart + lnSweep ENDSCAN * Draw the LEFT side of the pie GO BOTTOM lnStart = 270 DO WHILE lnStart >= 90 x1 = lnX y1 = lnY * Calculate Start point and Sweep lnValue = This._GetValue(This.ChartRow) IF lnValue <= 0 IF BOF() EXIT ENDIF SKIP -1 IF BOF() EXIT ENDIF LOOP ENDIF lnSweep = lnValue / lnTotal * 360 IF lnSweep > 359.99 lnSweep = 359.99 ENDIF lnStart = lnStart - lnSweep llHidden = lSliceHidden IF lDetach = .T. lnTempStart = lnStart lnTempSweep = lnSweep IF lnStart + lnSweep >= 269.9 This._Pie1stDetached = .T. This._PieX0 = x1 This._PieY0 = y1 ENDIF IF RECNO() = This._PieAnimatedRec lnPixelsOut = This._PieAnimationPix ELSE lnPixelsOut = lnDetachPixels ENDIF This._AdjustStartSweep(@lnTempStart, @lnTempSweep, m.lnWidth, m.lnHeight) lnDetachAngle = 360 - (lnTempStart + (lnTempSweep / 2)) x1 = lnX + (COS(DTOR(lnDetachAngle)) * lnPixelsOut) y1 = lnY - (SIN(DTOR(lnDetachAngle)) * lnPixelsOut) ENDIF IF NOT llHidden IF This.ChartType = 1 && Pie This._DrawSlice(x1, y1, m.lnWidth, m.lnHeight, lnStart, lnSweep, lnValue) ELSE && 2 - Doughnut This._DrawDoughnutSlice(x1, y1, m.lnWidth, m.lnHeight, lnStart, lnSweep, lnValue) ENDIF IF llDrawLegend This._PrepareLegendinSlice(@x1, @y1, m.lnWidth, m.lnHeight, lnStart, lnSweep, lnValue) laLegends(lnRec, 1) = x1 laLegends(lnRec, 2) = y1 laLegends(lnRec, 3) = lnValue lnRec = lnRec + 1 ENDIF ENDIF SKIP -1 IF BOF() EXIT ENDIF ENDDO * Draw the legends at the end of the process in order to avoid * a slice hiding a legend IF This.Fields(This._ChartIndex).ShowValuesOnShape IF llDrawLegend LOCAL lnOrigAlign, n lnOrigAlign = This.ShapeLegend.Alignment This.ShapeLegend.Alignment = 2 && Force Center FOR n = 1 TO lnRec - 1 TRY LOCAL lcExpr lcExpr = This.ShapeLegendExpression IF (VARTYPE(lcExpr) = "C") AND (NOT EMPTY(lcExpr)) *!* Other available properties *!* This.CurrValue *!* This.CurrLegend *!* This.CurrObjType *!* This.CurrRecno *!* This.CurrColumn This.CurrIndex = n lnValue = EVALUATE(lcExpr) ELSE IF This.PieShowPercent DO CASE CASE EMPTY(This.ShapeLegend.Format) AND EMPTY(lcExpr) This.ShapeLegend._ForceFormat = ; This._GetFieldType(This.SourceAlias, EVALUATE("This.Fields(This.ChartRow).FieldValue"), .T.) + "%" CASE NOT "%" $ This.ShapeLegend.Format This.ShapeLegend._ForceFormat = This.ShapeLegend.Format + "%" ENDCASE lnValue = (laLegends(n, 3) / lnTotal) * 100 ELSE lnValue = laLegends(n, 3) ENDIF ENDIF CATCH ERROR "Invalid Expression in 'ShapeLegendExpressionProperty' !" ENDTRY This.ShapeLegend._Value = lnValue x1 = laLegends(n, 1) IF VARTYPE(x1) <> "N" EXIT ENDIF y1 = laLegends(n, 2) * Draw the Text This.ShapeLegend._DrawString(x1, y1) ENDFOR This.ShapeLegend._ForceFormat = "" This.ShapeLegend.Alignment = lnOrigAlign ENDIF ENDIF IF This.PieDirection = 1 && Anticlockwise SET ORDER TO ENDIF ENDPROC PROCEDURE _drawscale LPARAMETERS toPen, tnAxisIndex LOCAL lnScaleNumber as Number, ; lnScaleWidth as Number, ; lnThisScale as Number, ; lnValue as Number, ; lnWidth as Number, x m.tnAxisIndex = EVL(m.tnAxisIndex, 1) * Draw the scale in the Y Axis Local ln3D, lnHeight, lnMargin, lnScaleValue, llShowLineZero IF This.ChartType = 17 && Paired m.llShowLineZero = .F. ELSE m.llShowLineZero = This.ShowLineZero ENDIF IF This._DeepChart && Point, Line or Area m.ln3D = This._3D * This.ChartsCount ELSE m.ln3D = This._3D ENDIF LOCAL lnMaxValue, lnScale, lnScaleAdjust, lnMinScale, lnMaxScale m.lnMaxValue = IIF(m.tnAxisIndex = 1, This._ScaleRange, This._ScaleRange2) m.lnScale = IIF(m.tnAxisIndex = 1, This._Scale, This._Scale2) m.lnScaleAdjust = IIF(m.tnAxisIndex = 1, This._ScaleAdjust, This._ScaleAdjust2) m.lnMinScale = IIF(m.tnAxisIndex = 1, This._MinScale, This._MinScale2) m.lnMaxScale = IIF(m.tnAxisIndex = 1, This._MaxScale, This._MaxScale2) LOCAL loGfx AS xfcGraphics m.loGfx = This.oGfx LOCAL loBackBrush AS xfcSolidBrush LOCAL loBackPen AS xfcPen LOCAL loBlackPen AS xfcPen LOCAL llDrawBack, lnOneScale, lnxWidth m.loBlackPen = This._oBlackPen m.llDrawBack = .T. This.ScaleLegend._Setup() If This._Orientation = 1 && Vertical Local lnRectColor, lnLineColor If This.BrushType = 3 && Monochrome m.lnRectColor = Rgb(255, 255, 255) && White m.lnLineColor = 0 && Black Else m.lnRectColor = This.ScaleBackColor m.lnLineColor = This.ScaleLineColor Endif With _Screen.System.Drawing m.loBackBrush = .SolidBrush.New(.Color.FromARGB(This.ScaleBackAlpha, m.lnRectColor)) This._oBlackPen = .Pen.New(.Color.FromARGB(This.AxisAlpha, m.lnLineColor), This.ScaleBackLinesWidth - 1) Endwith Local lnDashValue m.lnDashValue = This.ScaleBackLinesDash If m.lnDashValue > 0 This._oBlackPen.DashStyle = m.lnDashValue && _Screen.System.Drawing.Drawing2D.DashStyle.Dash Endif m.lnHeight = This.Height - This._XAxisHeight - This._TopOffSet - m.ln3D m.lnOneScale = m.lnScale / m.lnMaxValue * m.lnHeight m.lnxWidth = This.Width - This._LeftOffset - This._RightOffset - This._yAxisWidth - m.ln3D - This._yAxisWidth2 Local x0, x1, y0, y1, lnScaleHeight, N, Y m.y0 = This.Height - This._XAxisHeight m.x0 = IIF(m.tnAxisIndex = 1, ; This._yAxisWidth + This._LeftOffset, ; This.ChartCanvas.Width - This._RightOffset - m.ln3D + 2 + 2 - This._yAxisWidth2) **************************************************************** * Jim Nelson 10/10/08 * * Loop now calls method GetScaleValue (and its cousin GetScaleLegend) to get the * scale values and associated legends. lnScaleNumber = 0 returns highest scale * Save original Alignment settings LOCAL lnOrigAlignment, lcOrigScaleFormat m.lnOrigAlignment = This.ScaleLegend.Alignment m.lcOrigScaleFormat = This.ScaleLegend._ForceFormat * CCHALOM 2013-02-21 * Fix in getting a nice Scale legend format for both axes * New properties inserted: _ScaleLegAxis1ForceFormat , _ScaleLegAxis2ForceFormat This.ScaleLegend._ForceFormat = IIF(m.tnAxisIndex = 1, This._ScaleLegAxis1ForceFormat, This._ScaleLegAxis2ForceFormat) For m.lnScaleNumber = 0 To 1000 m.lnValue = This.GetScaleValue (m.lnScaleNumber, m.tnAxisIndex) If "N" # Vartype(m.lnValue) Exit Endif m.lnScaleHeight = (m.lnValue - m.lnMinScale) / m.lnMaxValue * m.lnHeight m.Y = This.Height - m.lnScaleHeight - This._XAxisHeight m.x1 = IIF(m.tnAxisIndex = 1, ; This._yAxisWidth + This._LeftOffset - 7, ; This.ChartCanvas.Width - This._RightOffset - m.ln3D + 6 - This._yAxisWidth2) m.y1 = m.Y - (This._ScaleH/2) m.lnScaleValue = m.lnValue - m.lnScaleAdjust * 2nd Y Axis IF m.tnAxisIndex = 1 This.ScaleLegend.Alignment = 1 && Force Right alignment ELSE This.ScaleLegend.Alignment = 0 && Force Left alignment ENDIF This.ScaleLegend._Value = This.GetScaleLegend(m.lnScaleNumber, (m.lnValue / This.ScaleDivider)) This.ScaleLegend._DrawString(m.x1, m.y1) * Draw the horizontal scale (tick) line in the Y Axis m.loGfx.DrawLine(m.toPen, m.x0, m.Y, m.x0 + m.ln3D, m.Y - m.ln3D) m.loGfx.DrawLine(m.loBlackPen, m.x0 - 0, m.Y, m.x0 - This.TicLength, m.Y) * Chack if finished drawing IF "N" # VARTYPE(This.GetScaleValue (m.lnScaleNumber + 1)) EXIT ENDIF * Draw the scale background Local x1Scale, y1Scale m.x1Scale = m.x0 + m.ln3D m.y1Scale = m.Y - m.ln3D If m.llDrawBack AND m.tnAxisIndex = 1 **************************************************************** * Jim Nelson 10/11/08 * * Calculate height to next scale m.lnThisScale = (This.GetScaleValue (m.lnScaleNumber) - This.GetScaleValue (m.lnScaleNumber+1)) / m.lnMaxValue * m.lnHeight IF INLIST(This.ScaleBackBarsType, 1, 3) && Horizontal, Both **************************************************************** * Jim Nelson 10/11/08 * * Calculate the height of this horizontal bar (allowing for case where not all bars are same height) * loGfx.FillRectangle(loBackBrush, x1Scale, y1Scale, lnxWidth, lnOneScale) m.loGfx.FillRectangle(m.loBackBrush, m.x1Scale, m.y1Scale, m.lnxWidth, m.lnThisScale) ENDIF IF INLIST(This.ScaleBackLinesType, 1, 3) && Horizontal, Both **************************************************************** * Jim Nelson 10/10/08 * * Do NOT draw the line if its the zero line (see below) IF NOT ( ; m.llShowLineZero ; AND ABS(m.lnValue) < m.lnScale / 100 ; AND m.lnMaxScale > 0 ; AND m.lnMinScale < 0 ; AND m.ln3D = 0 ; ) m.loGfx.DrawLine(This._oBlackPen, m.x1Scale, m.y1Scale, m.x1Scale + m.lnxWidth, m.y1Scale) m.loGfx.DrawLine(This._oBlackPen, m.x1Scale, m.y1Scale + m.lnThisScale, m.x1Scale + m.lnxWidth, m.y1Scale + m.lnThisScale) ENDIF ENDIF ENDIF m.llDrawBack = Not m.llDrawBack IF m.llShowLineZero AND m.tnAxisIndex = 1 * Draw the ZERO line IF ABS(m.lnValue) < m.lnScale / 100 And m.lnMaxScale > 0 And m.lnMinScale < 0 WITH _Screen.System.Drawing LOCAL loZeroPen As xfcPen m.loZeroPen = .Pen.New(.Color.FromARGB(This.AxisAlpha, This.ScaleLineZeroColor), 1) If m.ln3D = 0 m.loGfx.DrawLine(m.loZeroPen, ; m.x1Scale, m.y1Scale, m.x1Scale + m.lnxWidth, m.y1Scale) Else * Following line moved; does not apply to case m.ln3D = 0 m.y1Scale = m.y1Scale + 1 Local laPolygon(4) m.laPolygon(1) = .Point.New(m.x1Scale, m.y1Scale) m.laPolygon(2) = .Point.New(m.x1Scale + m.lnxWidth, m.y1Scale) m.laPolygon(3) = .Point.New(m.x1Scale + m.lnxWidth - m.ln3D, m.y1Scale + m.ln3D) m.laPolygon(4) = .Point.New(m.x1Scale - m.ln3D, m.y1Scale + m.ln3D) Local loZeroBrush As xfcSolidBrush m.loZeroBrush = .SolidBrush.New(.Color.FromARGB(64, This.ScaleLineZeroColor)) m.loGfx.FillPolygon(m.loZeroBrush, @m.laPolygon) m.loGfx.DrawPolygon(m.loZeroPen, @m.laPolygon) Endif Endwith Endif Endif Endfor This._ChartY0 = This.Height - This._XAxisHeight - m.ln3D This._ChartY1 = This._ChartY0 - m.lnHeight * Restore original Alignment settings This.ScaleLegend.Alignment = m.lnOrigAlignment This.ScaleLegend._ForceFormat = m.lcOrigScaleFormat Else && _Orientation = 2 HORIZONTAL Local x0, x1, y0, y1 m.lnMargin = This._yAxisWidth + This._LeftOffset m.y0 = This._TopOffSet m.y1 = This.Height - This._XAxisHeight + 6 m.x0 = m.lnMargin m.x1 = This.Width - This._RightOffset && This._LegendWidth m.lnWidth = This.Width - This._LeftOffset - This._RightOffset - This._yAxisWidth - m.ln3D Local llDrawBack, lnOneScale m.llDrawBack = .T. Local lnRectColor, lnLineColor If This.BrushType = 3 && Monochrome m.lnRectColor = Rgb(255, 255, 255) && White m.lnLineColor = 0 && Black Else m.lnRectColor = This.ScaleBackColor m.lnLineColor = This.ScaleLineColor Endif With _Screen.System.Drawing m.loBackBrush = .SolidBrush.New(.Color.FromARGB(This.ScaleBackAlpha, m.lnRectColor)) This._oBlackPen = .Pen.New(.Color.FromARGB(This.AxisAlpha, m.lnLineColor), This.ScaleBackLinesWidth - 1) Endwith Local lnDashValue m.lnDashValue = This.ScaleBackLinesDash If m.lnDashValue > 0 This._oBlackPen.DashStyle = m.lnDashValue && _Screen.System.Drawing.Drawing2D.DashStyle.Dash Endif m.lnOneScale = m.lnScale / m.lnMaxValue * m.lnWidth **************************************************************** * Jim Nelson 10/10/08 * * Loop now calls method GetScaleValue (and its cousin GetScaleLegend) to get the * scale values and associated legends. lnScaleNumber = 0 returns highest scale For m.lnScaleNumber = 0 To 1000 m.lnValue = This.GetScaleValue (m.lnScaleNumber) If "N" # Vartype( m.lnValue) Exit Endif m.lnScaleWidth = (m.lnValue - m.lnMinScale) / m.lnMaxValue * m.lnWidth m.x = m.x0 + m.lnScaleWidth m.lnScaleValue = This.GetScaleLegend (m.lnScaleNumber, m.lnValue) IF VARTYPE(m.lnScaleValue) = "C" This.ScaleLegend._Value = m.lnScaleValue ELSE This.ScaleLegend._Value = IIF(This._AbsoluteScaleValues, ABS(m.lnScaleValue), m.lnScaleValue) ENDIF If This.ScaleLegend.Rotation = 0 This.ScaleLegend._DrawString(m.x, m.y1, .T.) && Force Center Else This.ScaleLegend._DrawString(m.x, m.y1) Endif * Draw the horizontal scale line in the Y Axis m.loGfx.DrawLine(m.toPen, m.x, m.y1 - 5, m.x + m.ln3D, m.y1 - 5 - m.ln3D) m.loGfx.DrawLine(m.loBlackPen, m.x, m.y1, m.x, m.y1 - This.TicLength) * Draw the scale background Local x1Scale, y1Scale m.x1Scale = m.x + m.ln3D m.y1Scale = m.y1 - m.ln3D - 3 If m.llDrawBack and "N" = Vartype (This.GetScaleValue (m.lnScaleNumber+1)) **************************************************************** * Jim Nelson 10/11/08 * * Calculate width to next scale m.lnThisScale = (This.GetScaleValue (m.lnScaleNumber) - This.GetScaleValue (m.lnScaleNumber+1)) / m.lnMaxValue * m.lnWidth If Inlist(This.ScaleBackBarsType, 2, 3) && Vertical, Both **************************************************************** * Jim Nelson 10/11/08 * * Calculate the widtht of this horizontal bar (allowing for case where not all bars are same height) m.loGfx.FillRectangle(m.loBackBrush, m.x1Scale - m.lnThisScale, m.y0, m.lnThisScale, m.y1Scale - m.y0) Endif If Inlist(This.ScaleBackLinesType, 2, 3) && Vertical, Both **************************************************************** * Jim Nelson 10/10/08 * * Do NOT draw the line if its the zero line (see below) If Not ( ; m.llShowLineZero ; and Abs(m.lnValue) < m.lnScale / 100 ; And m.lnMaxScale > 0 ; And m.lnMinScale < 0 ; and m.ln3D = 0 ; ) m.loGfx.DrawLine(This._oBlackPen, m.x1Scale, m.y0, m.x1Scale, m.y1Scale) m.loGfx.DrawLine(This._oBlackPen, m.x1Scale - m.lnThisScale, m.y0, m.x1Scale - m.lnThisScale, m.y1Scale) Endif Endif Endif m.llDrawBack = Not m.llDrawBack If m.llShowLineZero * Draw the ZERO line If Abs(m.lnValue) < m.lnScale / 100 And m.lnMaxScale > 0 And m.lnMinScale < 0 With _Screen.System.Drawing Local loZeroPen As xfcPen m.loZeroPen = .Pen.New(.Color.FromARGB(This.AxisAlpha, This.ScaleLineZeroColor), 1) If m.ln3D = 0 m.loGfx.DrawLine(m.loZeroPen, m.x1Scale, m.y0, m.x1Scale, m.y1Scale) Else * Following line moved; does not apply to case m.ln3D = 0 m.y1Scale = m.y1Scale + 1 Local laPolygon(4) m.laPolygon(1) = .Point.New(m.x1Scale, m.y0) m.laPolygon(2) = .Point.New(m.x1Scale, m.y1Scale) m.laPolygon(3) = .Point.New(m.x1Scale - m.ln3D, m.y1Scale + m.ln3D) m.laPolygon(4) = .Point.New(m.x1Scale - m.ln3D, m.y0 + m.ln3D) Local loZeroBrush As xfcSolidBrush m.loZeroBrush = .SolidBrush.New(.Color.FromARGB(64, This.ScaleLineZeroColor)) m.loGfx.FillPolygon(m.loZeroBrush, @m.laPolygon) m.loGfx.DrawPolygon(m.loZeroPen, @m.laPolygon) Endif Endwith Endif Endif Endfor Endif Return ENDPROC PROCEDURE _drawshape LPARAMETERS tnX, tnY, tnValue, tcObjType LOCAL x1, y1 IF EMPTY(m.tcObjType) m.tcObjType = "Rect" ENDIF LOCAL luShape, lcType, lnIndex, lnTipPixels m.lnTipPixels = This._TipPixels m.lnIndex = This._ChartIndex * IF This.ChartType = 5 AND NOT EMPTY(This.LineCapsShape) && (VARTYPE(This.LineCapsShape) <> "L") && Line IF NOT EMPTY(This.LineCapsShape) m.luShape = This.LineCapsShape ELSE m.luShape = This.Fields(m.lnIndex).Shape ENDIF m.lcType = VARTYPE(m.luShape) LOCAL loGfx as xfcGraphics m.loGfx = This.oGfx LOCAL loObject as Object DO CASE CASE m.lcType = "N" OR m.lcType = "O" && Graphics path using predefined Shape LOCAL loPath as xfcGraphicsPath LOCAL lnWidth, lnHeight m.lnWidth = 0 m.lnHeight = 0 IF VARTYPE(This._aShapes(m.lnIndex, 1)) = "O" m.loPath = This._aShapes(m.lnIndex, 1) ELSE IF m.lcType = "O" m.loPath = m.luShape.Clone() This._CenterPath(m.loPath, .T., @m.lnWidth, @m.lnHeight) ELSE m.loPath = This._GetShapePath(m.luShape) This._CenterPath(m.loPath, .T., @m.lnWidth, @m.lnHeight) ENDIF ENDIF *!* loRect = loPath.GetBounds() *!* lnWidth = loRect.Width *!* lnHeight = loRect.Height *!* SET STEP ON *!* * Replacement for the GetBounds function *!* #DEFINE EMPTY_FLOAT 0h00000000 *!* #DEFINE EMPTY_LONG 0h00000000 *!* #DEFINE EMPTY_SHORT 0h0000 *!* #DEFINE EMPTY_RECTANGLE EMPTY_LONG+EMPTY_LONG+EMPTY_LONG+EMPTY_LONG *!* #DEFINE EMPTY_RECTANGLEF EMPTY_FLOAT+EMPTY_FLOAT+EMPTY_FLOAT+EMPTY_FLOAT *!* LOCAL lqRect, x, y, w, h *!* lqRect = REPLICATE(CHR(0),16) *!* * lqRect = EMPTY_RECTANGLEF *!* DECLARE Long GdipGetPathWorldBounds IN GDIPLUS.DLL AS ; *!* xfcGdipGetPathWorldBounds2 Long path, String @bounds, Long matrix, Long pen *!* =xfcGdipGetPathWorldBounds2(loPath.Handle, @lqRect, 0, 0) *!* *!* This.SetStatus(xfcGdipGetPathWorldBoundsI(This.Handle, @lcBounds, m.lhMatrix, m.lhPen)) *!* *X = CTOBIN(SUBSTR(lqRect,1,4),"4rs") *!* *Y = CTOBIN(SUBSTR(lqRect,5,4),"4rs") *!* W = CTOBIN(SUBSTR(lqRect,9,4),"4rs") *!* H = CTOBIN(SUBSTR(lqRect,13,4),"4rs") *!* * loRect = _Screen.System.Drawing.RectangleF.New(x,y,w,h) *!* lnWidth = W *!* lnHeight = H LOCAL lnColor IF This.BrushType = 3 && Monochrome m.lnColor = 0 ELSE m.lnColor = This.aColors(m.lnIndex) ENDIF LOCAL loBrush as xfcSolidBrush m.loBrush = _Screen.System.Drawing.SolidBrush.New(_Screen.System.Drawing.Color.FromRGB(m.lnColor)) LOCAL loAdjPath as xfcGraphicsPath LOCAL loMatrix as xfcMatrix m.loAdjPath = m.loPath.Clone() m.loMatrix = _Screen.System.Drawing.Drawing2D.Matrix.New() m.loMatrix.Translate(m.tnX, m.tnY) m.loAdjPath.Transform(m.loMatrix) m.loGfx.FillPath(m.loBrush, m.loAdjPath) m.x1 = m.tnX - (m.lnWidth / 2) m.y1 = m.tnY - (m.lnHeight / 2) m.loObject = m.loPath CASE m.lcType = "C" && Image File LOCAL loBmp as xfcBitmap LOCAL lnWidth, lnHeight IF VARTYPE(This._aShapes(m.lnIndex, 1)) = "O" m.loBmp = This._aShapes(m.lnIndex, 1) m.lnWidth = This._aShapes(m.lnIndex, 2) m.lnHeight = This._aShapes(m.lnIndex, 3) ELSE m.loBmp = _Screen.System.Drawing.Bitmap.FromVarbinary(FILETOSTR(m.luShape)) m.lnWidth = m.loBmp.Width m.lnHeight = m.loBmp.Height ENDIF m.x1 = m.tnX - (m.lnWidth /2) m.y1 = m.tnY - (m.lnHeight /2) m.loGfx.DrawImage(m.loBmp, m.x1, m.y1) m.loObject = m.loBmp OTHERWISE ENDCASE *!* This._UpdateCoordinates(tcObjType, x1, y1, ; *!* MAX(lnTipPixels, m.lnWidth), MAX(lnTipPixels, lnHeight), tnValue) * Fix by Anal Roy Chowdhurry IF NOT (This.LineCaps = .T. AND INLIST(This.ChartType, 5, 18)) This._UpdateCoordinates(m.tcObjType, m.x1, m.y1, ; m.lnWidth, m.lnHeight, m.tnValue) ENDIF * End of Revision new checking This._aShapes(m.lnIndex, 1) = m.loObject This._aShapes(m.lnIndex, 2) = m.lnWidth This._aShapes(m.lnIndex, 3) = m.lnHeight RETURN ENDPROC PROCEDURE _drawshapelegend LPARAMETERS tnX, tnY, tnIndex LOCAL lcExpr, luValue, lnValue m.lcExpr = This.ShapeLegendExpression This.CurrIndex = m.tnIndex m.lnValue = This.CurrValue IF (VARTYPE(m.lcExpr) = "C") AND (NOT EMPTY(m.lcExpr)) *!* Other available properties *!* This.CurrValue *!* This.CurrLegend *!* This.CurrObjType *!* This.CurrRecno *!* This.CurrColumn m.luValue = EVALUATE(m.lcExpr) ELSE IF This._SumRow AND This.ShowPercentages * Show percentages as values DO CASE CASE EMPTY(This.ShapeLegend.Format) AND EMPTY(This.ShapeLegendExpression) This.ShapeLegend._ForceFormat = ; This._GetFieldType(This.SourceAlias, EVALUATE("This.Fields(This.ChartRow).FieldValue"), .T.) + "%" CASE NOT "%" $ This.ShapeLegend.Format This.ShapeLegend._ForceFormat = This.ShapeLegend.Format + "%" ENDCASE m.luValue = ROUND(m.lnValue / This.aCoord(m.tnIndex, 12) * 100, 0) ELSE m.luValue = m.lnValue ENDIF ENDIF This.ShapeLegend._Value = m.luValue * Measure the legend height IF INLIST(This.ChartType, 10, 16) && Stacked area m.tnY = m.tnY - (This.ShapeLegend._Height / 2) && Draw in center ELSE m.tnY = m.tnY - (This.ShapeLegend._Height) && Draw above ENDIF This.ShapeLegend._DrawString(m.tnX, m.tnY) RETURN ENDPROC PROCEDURE _drawsidelegends *!* Property LegendPosition *!* Numeric, *!* Determines the position where the side legend wiil be drawn in the canvas. *1* 0 - No Legend *!* 1 - Vertical Top Left *!* 2 - Vertical Bottom Left *!* 3 - Vertical Top Right *!* 4 - Vertical Bottom Right *!* 5 - Horiz Top Left *!* 6 - Horiz Top Center *!* 7 - Horiz Top Right *!* 8 - Horiz Bottom Left *!* 9 - Horiz Bottom Center *!* 10 - Horiz Bottom Right *!* 11 - Vertical Center Left *!* 12 - Vertical Center Right LOCAL lnPosition, lnOrigAlignment m.lnPosition = This.LegendPosition IF NOT This.ShowSideLegend OR m.lnPosition = 0 RETURN ENDIF * Force left alignment for the side legend - this value will be restored at the end of this method m.lnOrigAlignment = This.SideLegend.Alignment This.SideLegend.Alignment = 0 && Left This._InLegend = .T. LOCAL lnLegendHeight, i, lnExternalMargin, lnCount, lnTopMargin, lnVertHeight LOCAL x1, y1, lnAvailableHeight, lnNeededHeight, lnMargin, lnWidth, lnHeight, llHorizontal m.llHorizontal = INLIST(m.lnPosition, 5, 6, 7, 8, 9, 10) && Horizontal Top or Bottom m.lnLegendHeight = This.SideLegend._Height m.lnExternalMargin = This._LegendExternalMargin m.lnCount = ALEN(This._aSideLegends, 1) m.lnTopMargin = This.MarginTop + This.Margin + This._TitleHeight * Check if we have enough space for legends m.lnAvailableHeight = This.ChartCanvas.Height - m.lnTopMargin - This.Margin m.lnNeededHeight = (m.lnCount * m.lnLegendHeight) + (This.Margin * m.lnCount - 1) IF m.lnNeededHeight > m.lnAvailableHeight * Recalculate the Margin m.lnMargin = (m.lnAvailableHeight - (m.lnCount * m.lnLegendHeight)) / m.lnCount ELSE m.lnMargin = 3 ENDIF STORE m.lnLegendHeight TO m.lnWidth, m.lnHeight m.lnLegendHeight = m.lnLegendHeight + MIN(m.lnMargin, m.lnLegendHeight / 2) m.lnVertHeight = m.lnCount * m.lnLegendHeight DO CASE CASE m.lnPosition = 1 && Vertical Top Left Side m.x1 = This.Margin + This.MarginLeft + m.lnExternalMargin m.y1 = m.lnTopMargin CASE m.lnPosition = 2 && Vertical Bottom Left Side m.x1 = This.Margin + This.MarginLeft + m.lnExternalMargin m.y1 = This.ChartCanvas.Height - This.MarginBottom - This.Margin - m.lnVertHeight CASE m.lnPosition = 11 && Vertical Center Left Side m.x1 = This.Margin + This.MarginLeft + m.lnExternalMargin m.y1 = (This.ChartCanvas.Height - This.MarginBottom - m.lnTopMargin - m.lnVertHeight) / 2 + m.lnTopMargin CASE m.lnPosition = 3 && Vertical Top Right Side (Default) m.x1 = This.ChartCanvas.Width - This._RightOffset + m.lnExternalMargin + This._Axis2ScaleWidth m.y1 = m.lnTopMargin CASE m.lnPosition = 4 && Vertical Bottom Right Side (Default) m.x1 = This.ChartCanvas.Width - This._RightOffset + m.lnExternalMargin + This._Axis2ScaleWidth m.y1 = This.ChartCanvas.Height - This.MarginBottom - This.Margin - m.lnVertHeight CASE m.lnPosition = 12 && Vertical Center Right Side m.x1 = This.ChartCanvas.Width - This._RightOffset + m.lnExternalMargin + This._Axis2ScaleWidth m.y1 = (This.ChartCanvas.Height - This.MarginBottom - m.lnTopMargin - m.lnVertHeight) / 2 + m.lnTopMargin CASE m.llHorizontal && Horizontal Top or Bottom * Calculate the whole legends width in order to obtain the starting point LOCAL lnLength, lnStart m.lnLength = 0 m.lnStart = 0 * Obtain the needed width for the whole horizontal legend FOR m.i = 1 TO m.lnCount This.SideLegend.Caption = This._aSideLegends(m.i, 1) m.lnLength = m.lnLength + m.lnWidth + 10 + This.SideLegend._Width ENDFOR DO CASE CASE INLIST(m.lnPosition, 5, 8) && Left aligned && do nothing CASE INLIST(m.lnPosition, 6, 9) && Center m.lnStart = This._LeftOffset + (This.ChartCanvas.Width - This._LeftOffset - This._RightOffset - m.lnLength) / 2 CASE INLIST(m.lnPosition, 7, 10) && Right m.lnStart = This.ChartCanvas.Width - This._RightOffset - m.lnLength ENDCASE m.x1 = This._LeftOffset + m.lnStart IF INLIST(m.lnPosition, 5, 6, 7) && Horizontal Top m.y1 = m.lnTopMargin + m.lnExternalMargin ELSE && Horizontal Bottom m.y1 = This.ChartCanvas.Height - This._LegendHeight - This.Margin - This.MarginBottom + This._LegendExternalMargin ENDIF OTHERWISE ENDCASE LOCAL lcCaption, lnOrigIndex LOCAL loLinePen as xfcPen * Save the current _CharIndex m.lnOrigIndex = This._ChartIndex FOR m.i = 1 TO m.lnCount IF m.y1 <= 0 EXIT ENDIF This._ChartIndex = m.i m.lcCaption = This._aSideLegends(m.i, 1) IF EMPTY(m.lcCaption) LOOP ENDIF This.SideLegend.Caption = m.lcCaption This.SideLegend._DrawString(m.x1 + m.lnWidth + 3, m.y1) This._UpdateCoordinates("Legend", m.x1, m.y1, m.lnWidth + This.SideLegend._Width + 5, m.lnLegendHeight, m.i, m.lcCaption) DO CASE CASE INLIST(This.ChartType, 5, 18) ; AND This._3D = 0 ; AND This.BrushType = 3 ; && Line, Plain, Monochrome and not This.Multichart m.loLinePen = _Screen.System.Drawing.Pen.New(This._oClrBlack, 3) m.loLinePen.DashStyle = m.i - 1 && _Screen.System.Drawing.Drawing2D.DashStyle.Dash This.oGfx.DrawLine(m.loLinePen, m.x1, m.y1 + m.lnHeight / 2, m.x1 + m.lnWidth, m.y1 + m.lnHeight / 2) CASE (This.ChartType = 4 ; && Point or (INLIST(This.ChartType, 5, 18) and This._3D = 0 and This.LineCaps = .T.)) ; && Plain line and not This.Multichart LOCAL loPath as xfcGraphicsPath m.loPath = This._aShapes(m.i, 1) IF VARTYPE(m.loPath) <> "O" RETURN ENDIF IF INLIST(LOWER(m.loPath.Class), "xfcbitmap", "xfcimage") This.oGfx.DrawImage(m.loPath, m.x1, m.y1, m.lnWidth, m.lnHeight) ELSE This._DrawShape(m.x1 + m.lnWidth / 2, m.y1 + m.lnHeight / 2, 0, "Legend") IF This._aShapes(m.i, 3) > m.lnLegendHeight m.lnLegendHeight = This._aShapes(m.i, 3) + 1 * y1 = y1 + This._aShapes(i,3) + 3 ENDIF ENDIF OTHERWISE This._PrepareBrushes(m.x1, m.y1, m.lnWidth, m.lnHeight, .T., m.i) THIS.oGfx.FillRectangle(This._oMainBrush, m.x1, m.y1, m.lnWidth, m.lnHeight) THIS.oGfx.DrawRectangle(This._oBorderPen, m.x1, m.y1, m.lnWidth, m.lnHeight) ENDCASE IF m.llHorizontal && Horizontal side legends m.x1 = m.x1 + m.lnWidth + 10 + This.SideLegend._Width ELSE m.y1 = m.y1 + m.lnLegendHeight ENDIF ENDFOR * Restore the current _CharIndex This._ChartIndex = m.lnOrigIndex This.SideLegend.Top = m.lnTopMargin This.SideLegend.Left = m.x1 This.SideLegend.Width = This._LegendWidth This.SideLegend.Height = MAX(0, m.y1 - m.lnTopMargin) This._InLegend = .F. * Restore the alignment value to the original This.SideLegend.Alignment = m.lnOrigAlignment RETURN *!* Property LegendPosition *!* Numeric, *!* Determines the position where the side legend wiil be drawn in the canvas. *1* 0 - No Legend *!* 1 - Vertical Top Left *!* 2 - Vertical Bottom Left *!* 3 - Vertical Top Right *!* 4 - Vertical Bottom Right *!* 5 - Horiz Top Left *!* 6 - Horiz Top Center *!* 7 - Horiz Top Right *!* 8 - Horiz Bottom Left *!* 9 - Horiz Bottom Center *!* 10 - Horiz Bottom Right *!* 11 - Vertical Center Left *!* 12 - Vertical Center Right LOCAL lnPosition, lnOrigAlignment m.lnPosition = This.LegendPosition IF NOT This.ShowSideLegend OR m.lnPosition = 0 RETURN ENDIF * Force left alignment for the side legend - this value will be restored at the end of this method m.lnOrigAlignment = This.SideLegend.Alignment This.SideLegend.Alignment = 0 && Left This._InLegend = .T. LOCAL lnLegendHeight, i, lnExternalMargin, lnCount, lnTopMargin, lnVertHeight LOCAL x1, y1, lnAvailableHeight, lnNeededHeight, lnMargin, lnWidth, lnHeight, llHorizontal m.llHorizontal = INLIST(m.lnPosition, 5, 6, 7, 8, 9, 10) && Horizontal Top or Bottom m.lnLegendHeight = This.SideLegend._Height m.lnExternalMargin = This._LegendExternalMargin m.lnCount = ALEN(This._aSideLegends, 1) m.lnTopMargin = This.MarginTop + This.Margin + This._TitleHeight * Check if we have enough space for legends m.lnAvailableHeight = This.ChartCanvas.Height - m.lnTopMargin - This.Margin m.lnNeededHeight = (m.lnCount * m.lnLegendHeight) + (This.Margin * m.lnCount - 1) IF m.lnNeededHeight > m.lnAvailableHeight * Recalculate the Margin m.lnMargin = (m.lnAvailableHeight - (m.lnCount * m.lnLegendHeight)) / m.lnCount ELSE m.lnMargin = 3 ENDIF STORE m.lnLegendHeight TO m.lnWidth, m.lnHeight m.lnLegendHeight = m.lnLegendHeight + MIN(m.lnMargin, m.lnLegendHeight / 2) m.lnVertHeight = m.lnCount * m.lnLegendHeight DO CASE CASE m.lnPosition = 1 && Vertical Top Left Side m.x1 = This.Margin + This.MarginLeft + m.lnExternalMargin m.y1 = m.lnTopMargin CASE m.lnPosition = 2 && Vertical Bottom Left Side m.x1 = This.Margin + This.MarginLeft + m.lnExternalMargin m.y1 = This.ChartCanvas.Height - This.MarginBottom - This.Margin - m.lnVertHeight CASE m.lnPosition = 11 && Vertical Center Left Side m.x1 = This.Margin + This.MarginLeft + m.lnExternalMargin m.y1 = (This.ChartCanvas.Height - This.MarginBottom - m.lnTopMargin - m.lnVertHeight) / 2 + m.lnTopMargin CASE m.lnPosition = 3 && Vertical Top Right Side (Default) m.x1 = This.ChartCanvas.Width - This._RightOffset + m.lnExternalMargin + This._Axis2ScaleWidth m.y1 = m.lnTopMargin CASE m.lnPosition = 4 && Vertical Bottom Right Side (Default) m.x1 = This.ChartCanvas.Width - This._RightOffset + m.lnExternalMargin + This._Axis2ScaleWidth m.y1 = This.ChartCanvas.Height - This.MarginBottom - This.Margin - m.lnVertHeight CASE m.lnPosition = 12 && Vertical Center Right Side m.x1 = This.ChartCanvas.Width - This._RightOffset + m.lnExternalMargin + This._Axis2ScaleWidth m.y1 = (This.ChartCanvas.Height - This.MarginBottom - m.lnTopMargin - m.lnVertHeight) / 2 + m.lnTopMargin CASE m.llHorizontal && Horizontal Top or Bottom * Calculate the whole legends width in order to obtain the starting point LOCAL lnLength, lnStart m.lnLength = 0 m.lnStart = 0 * Obtain the needed width for the whole horizontal legend FOR m.i = 1 TO m.lnCount This.SideLegend.Caption = This._aSideLegends(m.i, 1) m.lnLength = m.lnLength + m.lnWidth + 10 + This.SideLegend._Width ENDFOR DO CASE CASE INLIST(m.lnPosition, 5, 8) && Left aligned && do nothing CASE INLIST(m.lnPosition, 6, 9) && Center m.lnStart = This._LeftOffset + (This.ChartCanvas.Width - This._LeftOffset - This._RightOffset - m.lnLength) / 2 CASE INLIST(m.lnPosition, 7, 10) && Right m.lnStart = This.ChartCanvas.Width - This._RightOffset - m.lnLength ENDCASE m.x1 = This._LeftOffset + m.lnStart IF INLIST(m.lnPosition, 5, 6, 7) && Horizontal Top m.y1 = m.lnTopMargin + m.lnExternalMargin ELSE && Horizontal Bottom m.y1 = This.ChartCanvas.Height - This._LegendHeight - This.Margin - This.MarginBottom + This._LegendExternalMargin ENDIF OTHERWISE ENDCASE LOCAL lcCaption, lnOrigIndex LOCAL loLinePen as xfcPen * Save the current _CharIndex m.lnOrigIndex = This._ChartIndex FOR m.i = 1 TO m.lnCount IF m.y1 <= 0 EXIT ENDIF This._ChartIndex = m.i m.lcCaption = This._aSideLegends(m.i, 1) IF EMPTY(m.lcCaption) LOOP ENDIF This.SideLegend.Caption = m.lcCaption This.SideLegend._DrawString(m.x1 + m.lnWidth + 3, m.y1) This._UpdateCoordinates("Legend", m.x1, m.y1, m.lnWidth + This.SideLegend._Width + 5, m.lnLegendHeight, m.i, m.lcCaption) DO CASE CASE INLIST(This.ChartType, 5, 18) ; AND This._3D = 0 ; AND This.BrushType = 3 ; && Line, Plain, Monochrome and not This.Multichart m.loLinePen = _Screen.System.Drawing.Pen.New(This._oClrBlack, 3) m.loLinePen.DashStyle = m.i - 1 && _Screen.System.Drawing.Drawing2D.DashStyle.Dash This.oGfx.DrawLine(m.loLinePen, m.x1, m.y1 + m.lnHeight / 2, m.x1 + m.lnWidth, m.y1 + m.lnHeight / 2) CASE (This.ChartType = 4 ; && Point or (INLIST(This.ChartType, 5, 18) and This._3D = 0 and This.LineCaps = .T.)) ; && Plain line and not This.Multichart LOCAL loPath as xfcGraphicsPath m.loPath = This._aShapes(m.i, 1) IF VARTYPE(m.loPath) <> "O" RETURN ENDIF IF INLIST(LOWER(m.loPath.Class), "xfcbitmap", "xfcimage") This.oGfx.DrawImage(m.loPath, m.x1, m.y1, m.lnWidth, m.lnHeight) ELSE This._DrawShape(m.x1 + m.lnWidth / 2, m.y1 + m.lnHeight / 2, 0, "Legend") IF This._aShapes(m.i, 3) > m.lnLegendHeight m.lnLegendHeight = This._aShapes(m.i, 3) + 1 * y1 = y1 + This._aShapes(i,3) + 3 ENDIF ENDIF OTHERWISE This._PrepareBrushes(m.x1, m.y1, m.lnWidth, m.lnHeight, .T., m.i) THIS.oGfx.FillRectangle(This._oMainBrush, m.x1, m.y1, m.lnWidth, m.lnHeight) THIS.oGfx.DrawRectangle(This._oBorderPen, m.x1, m.y1, m.lnWidth, m.lnHeight) ENDCASE IF m.llHorizontal && Horizontal side legends m.x1 = m.x1 + m.lnWidth + 10 + This.SideLegend._Width ELSE m.y1 = m.y1 + m.lnLegendHeight ENDIF ENDFOR * Restore the current _CharIndex This._ChartIndex = m.lnOrigIndex This.SideLegend.Top = m.lnTopMargin This.SideLegend.Left = m.x1 This.SideLegend.Width = This._LegendWidth This.SideLegend.Height = MAX(0, m.y1 - m.lnTopMargin) This._InLegend = .F. * Restore the alignment value to the original This.SideLegend.Alignment = m.lnOrigAlignment RETURN ENDPROC PROCEDURE _drawslice LPARAMETERS tnX, tnY, tnWidth, tnHeight, tnStart, tnSweep, tnValue LOCAL llAdjLeft as Boolean, ; llAdjRight as Boolean, h, w IF m.tnWidth <=0 OR m.tnHeight <=0 RETURN ENDIF This._AdjustStartSweep(@m.tnStart, @m.tnSweep, m.tnWidth, m.tnHeight) This._UpdateCoordinates("Pie", m.tnX, m.tnY, m.tnWidth, m.tnHeight, m.tnValue, m.tnStart, m.tnSweep) LOCAL lnXBrush, lnYBrush IF This.PieEnhancedDrawing m.lnXBrush = m.tnX m.lnYBrush = m.tnY ELSE m.lnXBrush = 0 m.lnYBrush = 0 ENDIF This._PrepareBrushes(m.lnXBrush, m.lnYBrush, m.tnWidth, m.tnHeight, .F., RECNO()) LOCAL loPen as xfcPen m.loPen = This._oBorderPen LOCAL loGfx as xfcGraphics m.loGfx = This.oGfx LOCAL loMainBrush as xfcBrush m.loMainBrush = This._oMainBrush LOCAL lo3dBrush as xfcBrush m.lo3dBrush = This._o3DBrush LOCAL lnFinalAngle m.lnFinalAngle = m.tnStart + m.tnSweep IF m.lnFinalAngle > 360 m.lnFinalAngle = m.lnFinalAngle - 360 ENDIF LOCAL ln3D m.ln3D = This._3D WITH _Screen.System.Drawing IF This.PieEnhancedDrawing * Draw the 3D Slice using the GraphicsPath class IF m.ln3D > 0 AND (This.Shadow = .F.) m.x = m.tnX m.y = m.tnY m.w = m.tnWidth m.h = m.tnHeight * Draw the bottom slice m.loGfx.FillPie(m.loMainBrush, m.x, m.y + m.ln3D, m.w, m.h, m.tnStart, m.tnSweep) m.loGfx.DrawPie(m.loPen, m.x, m.y, m.w, m.h, m.tnStart, m.tnSweep) * Get the start point LOCAL loPath as xfcGraphicsPath LOCAL loPoint1 as xfcPoint, loPoint2 as xfcPoint m.loPath = _Screen.System.Drawing.Drawing2D.GraPHICSPATH.New() m.loPath.AddPie(m.x,m.y,m.w,m.h, m.tnStart, 0.0001) m.loPoint1 = m.loPath.GetLastpoint() m.loPath.AddPie(m.x,m.y,m.w,m.h, m.tnStart, m.tnSweep) m.loPoint2 = m.loPath.GetLastpoint() * Draw side Polygon 1 LOCAL laPointsA(4) LOCAL lnCenterX, lnCenterY m.lnCenterX = m.x + (m.w/2) m.lnCenterY = m.y + (m.h/2) m.laPointsA(1) = .Point.New(m.lnCenterX, m.lnCenterY) m.laPointsA(2) = .Point.New(m.lnCenterX, m.lnCenterY + m.ln3D) m.laPointsA(3) = .Point.New(m.loPoint1.x, m.loPoint1.Y + m.ln3D) m.laPointsA(4) = m.loPoint1 * Draw side Polygon 2 LOCAL laPointsB(4) m.laPointsB(1) = m.laPointsA(1) m.laPointsB(2) = m.laPointsA(2) m.laPointsB(3) = .Point.New(m.loPoint2.x, m.loPoint2.Y + m.ln3D) m.laPointsB(4) = m.loPoint2 IF m.tnStart <= 90 OR m.tnStart > 270 m.loGfx.DrawPolygon(m.loPen, @m.laPointsA) m.loGfx.FillPolygon(m.lo3dBrush, @m.laPointsA) ENDIF IF m.lnFinalAngle < 270 AND m.lnFinalAngle > 90 m.loGfx.FillPolygon(m.lo3dBrush, @m.laPointsB) m.loGfx.DrawPolygon(m.loPen, @m.laPointsB) ENDIF * Draw the external 3d Face LOCAL loPath2 as xfcGraphicsPath m.loPath2 = _Screen.System.Drawing.Drawing2D.GraPHICSPATH.New() m.loPath2.FillMode = _Screen.System.Drawing.Drawing2D.FILLMODE.winding m.loPath2.StartFigure() LOCAL lnAdjStart, lnAdjSweep m.lnAdjStart = m.tnStart m.lnAdjSweep = m.tnSweep IF m.tnStart >= 270 AND ; m.tnStart < 360 AND ; BETWEEN(m.lnFinalAngle, 0, 270) m.llAdjRight = .T. * Create a new partial path for the 1st part LOCAL loPath3 as xfcGraphicsPath m.loPath3 = _Screen.System.Drawing.Drawing2D.GraPHICSPATH.New() m.loPath3.StartFigure() m.loPath3.AddArc(m.x,m.y,m.w,m.h, m.tnStart, 360 - m.tnStart) m.loPath3.Reverse() m.loPath3.AddLine(m.loPoint1.x, m.loPoint1.Y, m.loPoint1.x, m.loPoint1.Y + m.ln3D) m.loPath3.AddArc(m.x,m.y + m.ln3D, m.w, m.h, m.tnStart, 360 - m.tnStart) m.loPath3.AddLine(m.tnX + m.tnWidth, m.lnCenterY + m.ln3D, m.tnX + m.tnWidth, m.lnCenterY) m.loGfx.FillPath(m.lo3dBrush, m.loPath3) m.loGfx.DrawPath(m.loPen, m.loPath3) m.loPoint1 = .Point.New(m.tnX + m.tnWidth, m.lnCenterY) m.lnAdjStart = 0 m.lnAdjSweep = m.tnSweep - (360 - m.tnStart) ENDIF IF (m.tnStart < 180 AND m.lnFinalAngle > 180) OR ; (m.tnStart >= 270 AND m.lnFinalAngle > 180 AND m.lnFinalAngle < 270.01) * IF (m.tnStart < 180 AND lnFinalAngle > 180) OR ; (m.tnStart >= 270 AND lnFinalAngle > 180 AND lnFinalAngle < 269.9999) m.llAdjLeft = .T. * Create a new partial path for the 1st part LOCAL loPath4 as xfcGraphicsPath m.loPath4 = _Screen.System.Drawing.Drawing2D.GraphicsPath.New() m.loPath4.StartFigure() IF m.tnStart >= 270 m.lnAdjStart = 0 m.lnAdjSweep = 180 ELSE m.lnAdjStart = m.tnStart m.lnAdjSweep = 180 - m.tnStart ENDIF m.loPath4.AddArc(m.x,m.y,m.w,m.h, m.lnAdjStart, m.lnAdjSweep) m.loPath4.Reverse() m.loPath4.AddLine(m.loPoint1.x, m.loPoint1.Y, m.loPoint1.x, m.loPoint1.Y + m.ln3D) m.loPath4.AddArc(m.x,m.y + m.ln3D, m.w, m.h, m.lnAdjStart, m.lnAdjSweep) m.loPath4.AddLine(m.tnX, m.lnCenterY + m.ln3D, m.tnX, m.lnCenterY) m.loGfx.FillPath(m.lo3DBrush, m.loPath4) m.loGfx.DrawPath(m.loPen, m.loPath4) m.loPoint1 = .Point.New(m.tnX, m.lnCenterY) m.lnAdjStart = 180 m.lnAdjSweep = m.lnFinalAngle - 180 ENDIF m.loPath2.AddArc(m.x,m.y,m.w,m.h, m.lnAdjStart, m.lnAdjSweep) m.loPath2.Reverse() m.loPath2.AddLine(m.loPoint1.x, m.loPoint1.Y, m.loPoint1.x, m.loPoint1.Y + m.ln3D) m.loPath2.AddArc(m.x,m.y + m.ln3D, m.w, m.h, m.lnAdjStart, m.lnAdjSweep) m.loPath2.AddLine(m.loPoint2.x, m.loPoint2.Y + m.ln3D, m.loPoint2.x, m.loPoint2.Y) m.loGfx.FillPath(m.lo3dBrush, m.loPath2) m.loGfx.DrawPath(m.loPen, m.loPath2) IF m.tnStart > 90 AND m.tnStart < 270 m.loGfx.DrawPolygon(m.loPen, @m.laPointsA) m.loGfx.FillPolygon(m.lo3dBrush, @m.laPointsA) ENDIF IF m.lnFinalAngle > 270 OR m.lnFinalAngle <= 90 m.loGfx.FillPolygon(m.lo3dBrush, @m.laPointsB) m.loGfx.DrawPolygon(m.loPen, @m.laPointsB) ENDIF * Draw the top slice m.loGfx.FillPie(m.loMainBrush, m.x, m.y, m.w, m.h, m.tnStart, m.tnSweep) m.loGfx.DrawPie(m.loPen, m.x, m.y, m.w, m.h, m.tnStart, m.tnSweep) ELSE * Draw shadow IF This.Shadow LOCAL loShadowBrush as xfcSolidBrush m.loShadowBrush = .SolidBrush.New(.Color.FromARGB(This.AlphaChannel,128,128,128)) m.loGfx.FillPie(m.loShadowBrush, m.tnX, m.tnY + m.ln3d, m.tnWidth, m.tnHeight, m.tnStart, m.tnSweep) ENDIF * Draw the main slice m.loGfx.FillPie(m.loMainBrush, m.tnX, m.tnY, m.tnWidth, m.tnHeight, m.tnStart, m.tnSweep) m.loGfx.DrawPie(m.loPen, m.tnX, m.tnY, m.tnWidth, m.tnHeight, m.tnStart, m.tnSweep) ENDIF ELSE *** This is the old behavior for Pie slices LOCAL loBmp as xfcBitmap m.loBmp = poTempBmp LOCAL loTempGfx as xfcGraphics m.loTempGfx = .Graphics.FromImage(m.loBmp) m.loTempGfx.Clear(.Color.Transparent) m.loTempGfx.SmoothingMode = .Drawing2D.SmoothingMode.AntiAlias * Draw the 3D Slice using the Hatch Brush IF m.ln3D > 0 LOCAL y1, n m.y1 = m.ln3D * Draw the contour of the 3D Slice m.loTempGfx.FillPie(m.loMainBrush, 0, m.y1, m.tnWidth, m.tnHeight, m.tnStart, m.tnSweep) m.loTempGfx.DrawPie(m.loPen, 0, m.y1, m.tnWidth, m.tnHeight, m.tnStart, m.tnSweep) FOR m.n = 1 TO m.ln3D m.y1 = m.y1 - 1 * Draw the Normal Slice using the Solid Brush m.loTempGfx.FillPie(m.lo3dBrush, 0, m.y1, m.tnWidth, m.tnHeight, m.tnStart, m.tnSweep) && draw the slice IF m.tnStart > 90 m.loTempGfx.DrawArc(m.loPen, 0, m.y1, m.tnWidth, m.tnHeight, m.tnStart, 0.25) ENDIF m.loTempGfx.DrawArc(m.loPen, 0, m.y1, m.tnWidth, m.tnHeight, m.tnStart + m.tnSweep - .25, 0.35) ENDFOR m.loTempGfx.FillPie(m.loMainBrush, 0, m.y1, m.tnWidth, m.tnHeight, m.tnStart, m.tnSweep) && draw the slice * Draw border line from center of pie LOCAL x, y m.x = (m.tnWidth / 2) m.y = (m.tnHeight / 2) + m.y1 IF m.tnStart > 90 m.loTempGfx.DrawLine(m.loPen, m.x, m.Y, m.x, m.Y + m.ln3D) ENDIF m.loTempGfx.DrawPie(m.loPen, 0, m.y1, m.tnWidth, m.tnHeight, m.tnStart, m.tnSweep) m.loTempGfx.FillPie(m.loMainBrush, 0, m.y1, m.tnWidth, m.tnHeight, m.tnStart, m.tnSweep) m.loTempGfx.DrawPie(m.loPen, 0, m.y1, m.tnWidth, m.tnHeight, m.tnStart, m.tnSweep) * Draw the Image m.loBmp.ApplyColorMatrix(poClrMatrix) m.loGfx.DrawImage(m.loBmp, m.tnX, m.tnY) ELSE m.loGfx.FillPie(m.loMainBrush, m.tnX, m.tnY, m.tnWidth, m.tnHeight, m.tnStart, m.tnSweep) m.loGfx.DrawPie(m.loPen, m.tnX, m.tnY, m.tnWidth, m.tnHeight, m.tnStart, m.tnSweep) ENDIF ENDIF ENDWITH RETURN ENDPROC PROCEDURE _drawsliceexternal LPARAMETERS tnX, tnY, tnWidth, tnHeight, tnStart, tnSweep, toPoint1, toPoint2 LOCAL loGfx as xfcGraphics m.loGfx = This.oGfx LOCAL lo3DBrush as xfcSolidBrush m.lo3DBrush = This._o3dBrush LOCAL loPen as xfcPen m.loPen = This._oBorderPen LOCAL ln3D m.ln3D = This._3d * Draw the external 3d Face LOCAL loPath as xfcGraphicsPath m.loPath = _Screen.System.Drawing.Drawing2D.GraphicsPath.New() m.loPath.StartFigure() m.loPath.AddArc(m.tnX, m.tnY, m.tnWidth, m.tnHeight, m.tnStart, m.tnSweep) m.loPath.Reverse() m.loPath.AddLine(m.toPoint1.x, m.toPoint1.Y, m.toPoint1.x, m.toPoint1.Y + m.ln3D) m.loPath.AddArc(m.tnX, m.tnY + m.ln3D, m.tnWidth, m.tnHeight, m.tnStart, m.tnSweep) m.loPath.AddLine(m.toPoint2.X, m.toPoint2.Y + m.ln3D, m.toPoint2.x, m.toPoint2.Y) m.loPath.CloseFigure() m.loGfx.FillPath(m.lo3dBrush, m.loPath) m.loGfx.DrawPath(m.loPen, m.loPath) ENDPROC PROCEDURE _drawstackedareachart * Generates Stacked and Full-Stacked area Charts (ChartTypes and 16) SELECT(This._DataCursor) LOCAL lnMargin, lnWidth, lnHeight, lnValue, lnRecs LOCAL lnBetween, n, i, lnMaxValue, lnPointHeight, ln3D, lnYBase, lnTipPixels, x1, y1 LOCAL lnTipPixels LOCAL llMultiChart m.llMultiChart = .F. m.lnTipPixels = This._TipPixels m.lnMargin = This.Margin m.ln3D = This._3D m.lnRecs = This._nRecords * Calculate the maximum width of the chart m.lnHeight = This.ChartCanvas.Height - This._XAxisHeight - This._TopOffSet - This._3d m.lnWidth = This.ChartCanvas.Width - This._YAxisWidth - This._LeftOffset - m.ln3D - This._RightOffset IF m.lnWidth < 10 OR m.lnHeight < 10 OR This._nRecords < 2 RETURN ENDIF LOCAL loGfx as xfcGraphics m.loGfx = This.oGfx * Get the maximum value of the chart m.lnMaxValue = This._ScaleRange * Get the lower Y point m.lnYBase = This.ChartCanvas.Height - This._xAxisHeight * If MultiChart mode, the chart needs to start half a position further IF m.llMultiChart m.lnBetween = m.lnWidth / (m.lnRecs) ELSE m.lnBetween = m.lnWidth / (m.lnRecs - 1) ENDIF * Prepare array of points * All the main points will be defined here LOCAL laPointsX(lnRecs) LOCAL laPointsY(lnRecs, This.ChartsCount) LOCAL laPointsYAV(lnRecs, This.ChartsCount) LOCAL laPointsI(lnRecs, This.ChartsCount) && Points Index LOCAL lnPrevPoint LOCAL lnTotRow LOCAL laValues(This.ChartsCount) SCAN m.n = RECNO() m.lnPrevPoint = 0 m.x1 = This._YAxisWidth + (m.lnBetween * (m.n - 1)) + IIF(m.llMultiChart, (m.lnBetween / 2), 0) + This._LeftOffset && lnMargin m.laPointsX(m.n) = m.x1 * This._aPoints(n,1) = laPointsX(n) This._aPoints(m.n,1) = m.x1 + m.ln3D m.lnTotRow = 0 * Get the total for the current row FOR m.i = 1 TO This.ChartsCount m.lnValue = This._GetValue(m.i) m.laValues(m.i) = m.lnValue m.lnTotRow = m.lnTotRow + m.lnValue ENDFOR FOR m.i = 1 TO This.ChartsCount m.lnValue = m.laValues(m.i) This._ChartIndex = m.i IF This.ChartType = 16 && Full-stacked Area m.lnPointHeight = m.lnValue / m.lnTotRow * m.lnHeight ELSE m.lnPointHeight = m.lnValue / m.lnMaxValue * m.lnHeight ENDIF m.y1 = m.lnYBase - (m.lnPointHeight + m.lnPrevPoint) m.laPointsY(m.n, m.i) = m.y1 m.laPointsYAV(m.n, m.i) = m.lnYBase - (m.lnPointHeight / 2 + m.lnPrevPoint) m.lnPrevPoint = m.lnPointHeight + m.lnPrevPoint IF m.lnValue = 0 This._UpdateCoordinates("Rect", 0, 0, 0, 0, m.lnValue, m.lnTotRow) ELSE This._UpdateCoordinates("Rect", m.X1 - m.lnTipPixels/2, m.Y1, m.lnTipPixels, m.lnPointHeight, m.lnValue, m.lnTotRow) ENDIF m.laPointsI(m.n,m.i) = This._nIndex ENDFOR ENDSCAN * Draw the vertical line only for the first line This._DrawVerticalLineBack() LOCAL laMainPolygon(lnRecs * 2) LOCAL laLinePolygon(4) LOCAL laSidePolygon(4) LOCAL lnCompl LOCAL loBrush as xfcBrush IF This.BrushType = 1 m.loBrush = "This._o3dbrush" ELSE m.loBrush = "This._oMainBrush" ENDIF WITH _Screen.System.Drawing FOR m.i = 1 TO This.ChartsCount * Fill the main polygon FOR m.n = 1 TO m.lnRecs m.lnCompl = (m.lnRecs * 2) - m.n + 1 m.laMainPolygon(m.n) = .Point.New(m.laPointsX(m.n), m.laPointsY(m.n, m.i)) IF m.i = 1 m.laMainPolygon(m.lnCompl) = .Point.New(m.laPointsX(m.n), m.lnYBase) ELSE m.laMainPolygon(m.lnCompl) = .Point.New(m.laPointsX(m.n), m.laPointsY(m.n, m.i-1)) ENDIF ENDFOR This._PrepareBrushes(0,0,This.ChartCanvas.Width, This.ChartCanvas.Height, .F., m.i) m.loGfx.FillPolygon(This._oMainBrush, @m.laMainPolygon) m.loGfx.DrawPolygon(This._oBorderPen, @m.laMainPolygon) IF m.ln3D > 0 * Draw the 3D line above the main polygon FOR m.n = 1 TO m.lnRecs - 1 m.laLinePolygon(1) = m.laMainPolygon(m.n) m.laLinePolygon(2) = .Point.New(m.laMainPolygon(m.n).X + m.ln3D, m.laMainPolygon(m.n).Y - m.ln3D) m.laLinePolygon(3) = .Point.New(m.laMainPolygon(m.n+1).X + m.ln3D, m.laMainPolygon(m.n+1).Y - m.ln3D) m.laLinePolygon(4) = m.laMainPolygon(m.n+1) This._PrepareBrushes(m.laMainPolygon(m.n).X, m.laMainPolygon(m.n).Y - m.ln3D, ; m.laMainPolygon(m.n+1).X + m.ln3D - m.laMainPolygon(m.n).X, ; MAX(2,ABS(m.laMainPolygon(m.n).Y - m.laMainPolygon(m.n+1).Y)), .F., m.i) m.loGfx.FillPolygon(EVALUATE(m.loBrush), @m.laLinePolygon) m.loGfx.DrawPolygon(This._oBorderPen, @m.laLinePolygon) ENDFOR * Fill the right-most external side of the area * Draw the last 3D polygon, to fill the Area m.laSidePolygon(1) = m.laLinePolygon(3) m.laSidePolygon(2) = m.laLinePolygon(4) m.laSidePolygon(3) = m.laMainPolygon(m.lnRecs + 1) m.laSidePolygon(4) = .Point.New(m.laSidePolygon(3).X + m.ln3D, m.laSidePolygon(3).Y - m.ln3D) This._PrepareBrushes(m.laSidePolygon(2).X, m.laSidePolygon(1).Y, ; m.ln3D, 2, .F., m.i) m.loGfx.FillPolygon(EVALUATE(m.loBrush), @m.laSidePolygon) m.loGfx.DrawPolygon(This._oBorderPen, @m.laSidePolygon) ENDIF ENDFOR * Adjust _aPoints Array to show the information in the correct position FOR m.n = 1 TO m.lnRecs This._aPoints(m.n,1) = This._aPoints(m.n,1) - m.ln3D ENDFOR IF This.ShowValuesOnShapes LOCAL lnIndex FOR m.i = 1 TO This.ChartsCount IF This.Fields(m.i).ShowValuesOnShape *** Draw Legends above the points FOR m.n = 1 TO m.lnRecs m.x1 = m.laPointsX(m.n) m.y1 = m.laPointsYAV(m.n, m.i) m.lnIndex = m.laPointsI(m.n,m.i) This._DrawShapeLegend(m.x1, m.y1, m.lnIndex) ENDFOR ENDIF ENDFOR ENDIF This._DrawXAxisLegend() ENDWITH ENDPROC PROCEDURE _drawtrianglebar LPARAMETERS tnX, tnY, tnWidth, tnHeight, tnValue Local loLeftBrush as Object, ; loRightBrush as Object This._PrepareBrushes(m.tnX, m.tnY, m.tnWidth, m.tnHeight, .F., IIF(This.SingleData, RECNO(),This._ChartIndex)) LOCAL loGfx as xfcGraphics m.loGfx = This.oGfx LOCAL lnAlpha, lnOrigAlpha m.lnOrigAlpha = This.AlphaChannel m.lnAlpha = MIN(255, (This.AlphaChannel * 1.25)) This.AlphaChannel = m.lnAlpha LOCAL loTopBrush as xfcBrush LOCAL loBotBrush as xfcBrush WITH _Screen.System.Drawing LOCAL lnColor, ln3D LOCAL loPen as xfcPen m.lnColor = This.ChangeColor(This._nColor, + 60) m.ln3D = MAX(This._3d, 1) m.loPen = .Pen.New(.Color.FromRGB(m.lnColor)) DO CASE CASE This.BrushType = 1 && SolidColors m.loTopBrush = .SolidBrush.New(.Color.FromARGB(This.AlphaChannel, This.ChangeColor(This._nColor, - 20))) m.loBotBrush = .SolidBrush.New(.Color.FromARGB(This.AlphaChannel, This._nColor)) m.loLeftBrush = .SolidBrush.New(.Color.FromARGB(This.AlphaChannel, This.ChangeColor(This._nColor, - 20))) m.loRightBrush = This._oMainBrush CASE This.BrushType = 2 && Gradient m.loTopBrush = .SolidBrush.New(.Color.FromARGB(This.AlphaChannel, This._nColor)) m.loBotBrush = m.loTopBrush m.loLeftBrush = m.loTopBrush m.loRightBrush = This._oMainBrush OTHERWISE This._PrepareBrushes(m.tnX, m.tnY, m.tnWidth, m.tnHeight, .F., IIF(This.SingleData, RECNO(),This._ChartIndex)) m.loTopBrush = This._oMainBrush m.loBotBrush = m.loTopBrush m.loLeftBrush = m.loTopBrush m.loRightBrush = This._oMainBrush ENDCASE This.AlphaChannel = m.lnOrigAlpha IF This._Orientation = 1 && Vertical LOCAL lnCenterX, x0, x1 m.x0 = m.tnX + m.ln3D / 2 m.x1 = m.x0 + m.tnWidth m.lnCenterX = m.x0 + (m.tnWidth / 2) * Prepare the top triangle LOCAL laTopPoints(3) m.laTopPoints(1) = .Point.New(m.lnCenterX, m.tnY) m.laTopPoints(2) = .Point.New(m.x0, m.tnY - m.ln3D) m.laTopPoints(3) = .Point.New(m.x1, m.tnY - m.ln3D) m.loGfx.DrawPolygon(m.loPen, @m.laTopPoints) m.loGfx.FillPolygon(m.loTopBrush, @m.laTopPoints) * Prepare the bottom triangle LOCAL yBott m.yBott = m.tnY + m.tnHeight LOCAL laBotPoints(3) m.laBotPoints(1) = .Point.New(m.lnCenterX, m.yBott) m.laBotPoints(2) = .Point.New(m.x0, m.yBott - m.ln3D) m.laBotPoints(3) = .Point.New(m.x1, m.yBott - m.ln3D) m.loGfx.DrawPolygon(m.loPen, @m.laBotPoints) m.loGfx.FillPolygon(m.loBotBrush, @m.laBotPoints) * Prepare the LEFT face of the 3d triangle (polygon) LOCAL laLeftPoints(4) m.laLeftPoints(1) = m.laTopPoints(1) m.laLeftPoints(2) = m.laTopPoints(2) m.laLeftPoints(3) = m.laBotPoints(2) m.laLeftPoints(4) = m.laBotPoints(1) m.loGfx.DrawPolygon(m.loPen, @m.laLeftPoints) m.loGfx.FillPolygon(m.loLeftBrush, @m.laLeftPoints) * Prepare the RIGHT face of the 3d triangle (polygon) LOCAL laRightPoints(4) m.laRightPoints(1) = m.laTopPoints(1) m.laRightPoints(2) = m.laTopPoints(3) m.laRightPoints(3) = m.laBotPoints(3) m.laRightPoints(4) = m.laBotPoints(1) m.loGfx.DrawPolygon(m.loPen, @m.laRightPoints) m.loGfx.FillPolygon(m.loRightBrush, @m.laRightPoints) ELSE && Horizontal LOCAL lnCenterY, y0, y1, ln3D m.ln3D = MAX(This._3d, 1) m.x0 = m.tnX m.x1 = m.x0 + m.tnWidth m.lnCenterY = m.tnY + (m.tnHeight / 2) * Prepare the right (top) triangle LOCAL laRightPoints(3) m.laRightPoints(1) = .Point.New(m.X1, m.lnCenterY) m.laRightPoints(2) = .Point.New(m.X1 + m.ln3d, m.tnY) m.laRightPoints(3) = .Point.New(m.X1 + m.ln3d, m.tnY + m.tnHeight) m.loGfx.DrawPolygon(m.loPen, @m.laRightPoints) m.loGfx.FillPolygon(m.loTopBrush, @m.laRightPoints) * Prepare the Left triangle LOCAL laLeftPoints(3) m.laLeftPoints(1) = .Point.New(m.X0, m.lnCenterY) m.laLeftPoints(2) = .Point.New(m.X0 + m.ln3d, m.tnY) m.laLeftPoints(3) = .Point.New(m.X0 + m.ln3d, m.tnY + m.tnHeight) m.loGfx.DrawPolygon(m.loPen, @m.laLeftPoints) m.loGfx.FillPolygon(m.loBotBrush, @m.laLeftPoints) * Prepare the Top face of the 3d triangle (polygon) LOCAL laTopPoints(4) m.laTopPoints(1) = m.laLeftPoints(1) m.laTopPoints(2) = m.laLeftPoints(2) m.laTopPoints(3) = m.laRightPoints(2) m.laTopPoints(4) = m.laRightPoints(1) m.loGfx.DrawPolygon(m.loPen, @m.laTopPoints) m.loGfx.FillPolygon(m.loLeftBrush, @m.laTopPoints) * Prepare the BOTTOM face of the 3d triangle (polygon) LOCAL laBotPoints(4) m.laBotPoints(1) = m.laLeftPoints(1) m.laBotPoints(2) = m.laLeftPoints(3) m.laBotPoints(3) = m.laRightPoints(3) m.laBotPoints(4) = m.laRightPoints(1) m.loGfx.DrawPolygon(m.loPen, @m.laBotPoints) m.loGfx.FillPolygon(m.loRightBrush, @m.laBotPoints) ENDIF * Draw the Values inside the shapes This._DrawLegendinBar(m.X0, m.tnY, m.tnWidth, m.tnHeight, m.tnValue) ENDWITH RETURN ENDPROC PROCEDURE _drawverticallineback IF This._Orientation = 2 RETURN ENDIF LOCAL n, x0, x1, lnLineColor, lnRectColor, lnDashValue LOCAL loBackPen as xfcPen LOCAL loBackBrush as xfcSolidBrush LOCAL llDrawBack, llDrawLines LOCAL ln3D IF This._DeepChart && AND This._GeneralType = "Bar" && Point, Line, 3d Bars or Area m.ln3D = This._3D * This.ChartsCount ELSE m.ln3D = This._3D ENDIF m.llDrawBack = .T. m.llDrawLines = INLIST(This.ScaleBackLinesType, 2, 3) && Vertical, Both WITH _Screen.System.Drawing IF This.BrushType = 3 && Monochrome m.lnRectColor = RGB(255,255,255) && White m.lnLineColor = 0 && Black ELSE m.lnRectColor = This.ScaleBackColor m.lnLineColor = This.ScaleLineColor ENDIF m.loBackBrush = .SolidBrush.New(.Color.FromARGB(This.ScaleBackAlpha, m.lnRectColor)) m.loBackPen = .Pen.New(.Color.FromARGB(This.AxisAlpha, m.lnLineColor),This.ScaleBackLinesWidth - 1) ENDWITH m.lnDashValue = This.ScaleBackLinesDash IF m.lnDashValue > 0 m.loBackPen.DashStyle = m.lnDashValue && _Screen.System.Drawing.Drawing2D.DashStyle.Dash ENDIF LOCAL lnLinesDistance, lnRecs m.lnRecs = This._nRecords IF m.lnRecs > 1 m.lnLinesDistance = This._aPoints(2,1) - This._aPoints(1,1) ELSE m.lnLinesDistance = 0 ENDIF IF m.llDrawBack OR m.llDrawLines FOR m.n = 1 TO m.lnRecs m.x0 = This._aPoints(m.n,1) + IIF(This._GeneralType = "Bar", m.ln3D, 0) IF m.llDrawBack AND (m.n < m.lnRecs) * Draw the rectangle bar on the back IF INLIST(This.ScaleBackBarsType, 2, 3) && Vertical, Both This.oGfx.FillRectangle(m.loBackBrush, m.x0, This._ChartY1, m.lnLinesDistance, This._ChartY0 - This._ChartY1) ENDIF ENDIF IF m.llDrawLines && Vertical, Both * Draw the diagonal line in the X axis IF m.ln3D > 0 This.oGfx.DrawLine(m.loBackPen, m.x0, This._ChartY0, m.x0 - m.ln3D, This._ChartY0 + m.ln3D) ENDIF * Draw the vertical line on the back This.oGfx.DrawLine(m.loBackPen, m.x0, This._ChartY0, m.x0, This._ChartY1) ENDIF m.llDrawBack = NOT m.llDrawBack ENDFOR ENDIF ENDPROC PROCEDURE _drawxaxislegend LPARAMETERS tn3D, tnDistance Local lnAdjust as Number IF EMPTY(This.FieldAxis2) RETURN ENDIF IF VARTYPE(m.tn3D) = "N" m.lnAdjust = m.tn3D ELSE m.lnAdjust = 0 ENDIF * Draw Legends on the X Axis LOCAL loSize as xfcSize LOCAL y0, x0, x1, y1, lcText, lnXPoint, lnXStart m.Y0 = ROUND(This.ChartCanvas.Height - This._XAxisHeight,0) m.y1 = m.y0 + 6 This.AxisLegend2._Setup() m.lnXStart = This._aPoints(1,1) SCAN * Measure the legend width m.lcText = cAxis2 This.AxisLegend2.Caption = m.lcText IF NOT EMPTY(m.tnDistance) m.X0 = m.lnXStart + ((RECNO() - 1) * m.tnDistance) ELSE m.X0 = This._aPoints(RECNO(),1) ENDIF IF VARTYPE(m.X0) <> "N" LOOP ENDIF * Draw the tic mark IF This.ShowAxis2Tics This.oGfx.DrawLine(This._oBlackPen, m.x0 + m.lnAdjust, m.y0, m.x0 + m.lnAdjust, m.y0 + This.TicLength) ENDIF m.x1 = m.X0 + m.lnAdjust This.AxisLegend2._DrawString(m.x1, m.y1) ENDSCAN ENDPROC PROCEDURE _drawyaxis LPARAMETERS tn3D, tnMinLeft, tnYAxisHeight, toBrush, toPen, tnIndex LOCAL ln3d, lnMinLeft, lnYAxisHeight LOCAL loBrush AS xfcBrush, loPen AS xfcPen, loGfx AS xfcGraphics m.loBrush = m.toBrush m.loPen = m.toPen m.loGfx = THIS.oGfx m.lnMinLeft = m.tnMinLeft m.ln3d = m.tn3D m.lnYAxisHeight = m.tnYAxisHeight ************************************************************************************** * DRAWING THE Y Axis LOCAL x0, x1, y0, y1 m.y0 = ROUND(THIS.ChartCanvas.HEIGHT - THIS._XAxisHeight,0) m.y1 = ROUND(THIS._TopOffSet,0) IF m.y0 - m.y1 < m.ln3d RETURN ENDIF IF THIS.ShowAxis = .T. * Draw the main Y Axis caption IF tnIndex = 1 IF EMPTY(THIS.YAxis.CAPTION) This._yAxisWidth = 0 ELSE LOCAL lnYaxisWidth m.lnYaxisWidth = m.y0 - m.y1 IF m.lnYaxisWidth < 5 OR m.lnYAxisHeight < 5 RETURN ENDIF THIS._yAxisWidth = MAX(m.lnMinLeft, THIS.YAxis._Height + 3 + THIS._ScaleW) THIS.YAxis.ROTATION = 270 THIS.YAxis._DrawString(THIS._LeftOffset, m.y1 + m.lnYaxisWidth, m.lnYaxisWidth, m.lnYAxisHeight) ENDIF ENDIF && tnIndex = 1 IF tnIndex = 2 IF EMPTY(THIS.YAxis2.CAPTION) This._yAxisWidth2 = 0 ELSE LOCAL lnYaxisWidth2 m.lnYaxisWidth2 = m.y0 - m.y1 IF m.lnYaxisWidth2 < 5 OR m.lnYAxisHeight < 5 RETURN ENDIF This.YAxis2.Reset() THIS._yAxisWidth2 = THIS.YAxis2._Height && + THIS._ScaleW THIS.YAxis2.ROTATION = 270 * Draw the main Y Axis2 caption LOCAL lcYText2 m.lcYText2 = This.YAxis2.Caption m.lnYaxisHeight = CEILING(This.YAxis2._Height) m.x0 = THIS.ChartCanvas.WIDTH - THIS._RightOffset - m.ln3d - m.lnYaxisHeight + This._ScaleW2 + 6 THIS.YAxis2._DrawString(x0, m.y1 + m.lnYaxisWidth2, m.lnYaxisWidth2, m.lnYAxisHeight) ENDIF ENDIF && tnIndex = 2 LOCAL lnMaxValue m.lnMaxValue = THIS._ScaleRange WITH _SCREEN.SYSTEM.Drawing * Draw the Y Axis IF m.tnIndex = 2 m.x0 = THIS.ChartCanvas.WIDTH - THIS._RightOffset - m.ln3d + 2 - THIS._yAxisWidth2 ELSE m.x0 = THIS._yAxisWidth + THIS._LeftOffset ENDIF m.x1 = m.x0 + m.ln3d + THIS._ScaleW IF m.ln3d = 0 m.loGfx.DrawLine(m.loPen, m.x0 - 1, m.y0, m.x0 - 1, m.y1) ELSE LOCAL laPoints(4) m.laPoints(1) = .POINT.New(m.x0, m.y0) m.laPoints(2) = .POINT.New(m.x0, THIS._TopOffSet + m.ln3d) m.laPoints(3) = .POINT.New(m.x0 + m.ln3d, THIS._TopOffSet) m.laPoints(4) = .POINT.New(m.x0 + m.ln3d, m.y0 - m.ln3d) m.loGfx.FillPolygon(m.loBrush, @m.laPoints) m.loGfx.DrawPolygon(m.loPen, @m.laPoints) LOCAL laPointsB(6) m.laPointsB(1) = .POINT.New(m.x0, m.y0 + 4) m.laPointsB(2) = .POINT.New(m.x0 - 4, m.y0 + 4) m.laPointsB(3) = .POINT.New(m.x0 - 4, THIS._TopOffSet + m.ln3d) m.laPointsB(4) = .POINT.New(m.x0 - 4 + m.ln3d, THIS._TopOffSet) m.laPointsB(5) = .POINT.New(m.x0 + m.ln3d, THIS._TopOffSet) m.laPointsB(6) = .POINT.New(m.x0, THIS._TopOffSet + m.ln3d) m.loGfx.FillPolygon(m.loBrush, @m.laPointsB) m.loGfx.DrawPolygon(m.loPen, @m.laPointsB) ENDIF ENDWITH ENDIF ENDPROC PROCEDURE _drawyaxislegend * Draws the Y axis legends and the chart background horizontal lines and bars LOCAL lnHeight as Number, ; lnXWidth as Number IF EMPTY(This.FieldAxis2) RETURN ENDIF SELECT(This._DataCursor) * Draw Legends on the Y Axis LOCAL x1, y1, lcText m.y1 = This.ChartCanvas.Height - This._XAxisHeight + 6 This.AxisLegend2._Setup() * Save original Alignment settings LOCAL lnOrigAlignment m.lnOrigAlignment = This.AxisLegend2.Alignment * Force Right alignment This.AxisLegend2.Alignment = 1 && Right SCAN * Measure the legend width m.lcText = cAxis2 This.AxisLegend2.Caption = m.lcText m.x1 = This._Yaxiswidth + This._LeftOffset - 6 m.y1 = This._aPoints(RECNO(),2) - This.AxisLegend2._Height / 2 This.AxisLegend2._DrawString(m.x1, m.y1) ENDSCAN * Restore original Alignment settings This.AxisLegend2.Alignment = m.lnOrigAlignment * There's no need to continue drawing scales if the Axis is not present IF NOT This.ShowAxis RETURN ENDIF * Continue drawing the scales and background lines or bars LOCAL ln3D m.ln3D = This._3d LOCAL lnRectColor, lnLineColor IF This.BrushType = 3 && Monochrome m.lnRectColor = RGB(255,255,255) && White m.lnLineColor = 0 && Black ELSE m.lnRectColor = This.ScaleBackColor m.lnLineColor = This.ScaleLineColor ENDIF * A thin black pen to draw the ticks in the Y Axis LOCAL loBlackPen as xfcPen m.loBlackPen = This._oBlackPen LOCAL loBackBrush as xfcSolidBrush LOCAL loBackPen as xfcPen LOCAL loPen as xfcPen LOCAL lnDashValue LOCAL loGfx as xfcGraphics m.loGfx = This.oGfx WITH _Screen.System.Drawing m.loBackBrush = .SolidBrush.New(.Color.FromARGB(This.ScaleBackAlpha, m.lnRectColor)) m.loBackPen = .Pen.New(.Color.FromARGB(This.AxisAlpha, m.lnLineColor),This.ScaleBackLinesWidth - 1) m.lnDashValue = This.ScaleBackLinesDash IF m.lnDashValue > 0 m.loBackPen.DashStyle = m.lnDashValue && _Screen.System.Drawing.Drawing2D.DashStyle.Dash ENDIF LOCAL lnAxisBorderColor m.lnAxisBorderColor = This.ChangeColor(This.AxisColor, -30) LOCAL loAxisBorderColor as xfcColor m.loAxisBorderColor = .Color.FromARGB(This.AxisAlpha, m.lnAxisBorderColor) m.loPen = .Pen.New(m.loAxisBorderColor, 1) ENDWITH m.lnHeight = This.ChartCanvas.Height - This._XAxisHeight - This._TopOffSet - m.ln3D m.lnXWidth = This.ChartCanvas.Width - This._LeftOffset - This._RightOffset - This._yAxisWidth - m.ln3D LOCAL x0, y0, n, y, llDrawBack m.llDrawBack = .T. m.y0 = This.ChartCanvas.Height - This._XAxisHeight m.x0 = This._yAxisWidth + This._LeftOffset LOCAL lnOneScale IF This._nRecords = 1 m.lnOneScale = 0 ELSE m.lnOneScale = This._aPoints(2,2) - This._aPoints(1,2) ENDIF FOR m.n = 1 TO This._nRecords m.x1 = This._yAxisWidth + This._LeftOffset m.y1 = This._aPoints(m.n,2) m.y = ROUND(m.y1,0) * Draw the tic mark IF This.ShowAxis2Tics m.loGfx.DrawLine(m.loBlackPen, m.x0 - 0, m.y, m.x0 - This.TicLength, m.y) ENDIF IF m.n = This._nRecords EXIT ENDIF m.loGfx.DrawLine(m.loPen, m.x0, m.y, m.x0 + m.ln3D, m.y - m.ln3D) * Draw the scale background LOCAL x1Scale, y1Scale m.x1Scale = m.x0 + m.ln3D m.y1Scale = m.y - m.ln3D IF m.llDrawBack IF INLIST(This.ScaleBackBarsType, 1, 3) && Horizontal, Both m.loGfx.FillRectangle(m.loBackBrush, m.x1Scale, m.y1Scale, m.lnxWidth, m.lnOneScale) ENDIF ENDIF IF INLIST(This.ScaleBackLinesType, 1, 3) && Horizontal, Both IF m.n = 1 m.loGfx.DrawLine(m.loBackPen, m.x1Scale, (m.y1Scale), m.x1Scale + m.lnxWidth, (m.y1Scale)) ENDIF m.loGfx.DrawLine(m.loBackPen, m.x1Scale, (m.y1Scale + m.lnOneScale), m.x1Scale + m.lnxWidth, (m.y1Scale + m.lnOneScale)) ENDIF m.llDrawBack = NOT m.llDrawBack ENDFOR RETURN ENDPROC PROCEDURE _getadjustedangle LPARAMETERS tnAngle, tnWidth, tnHeight IF m.tnAngle > 360 m.tnAngle = m.tnAngle - 360 ENDIF IF m.tnAngle < 0 m.tnAngle = m.tnAngle + 360 ENDIF * Fix by Christof Wollenhaupt 2008-10-28 * http://www.codeplex.com/VFPX/WorkItem/View.aspx?WorkItemId=19211 * when the angle is around 270.0000001, this passes the test of BETWEEN(tnAngle,90,270), * but fails on the following TAN() function. m.tnAngle = ROUND(m.tnAngle, 4) LOCAL lnNewAngle DO CASE CASE BETWEEN(m.tnAngle, 90, 270) m.lnNewAngle = RTOD(ATN2(TAN(DTOR(m.tnAngle)) * m.tnHeight, m.tnWidth)) + 180 OTHERWISE m.lnNewAngle = RTOD(ATN2(TAN(DTOR(m.tnAngle)) * m.tnHeight, m.tnWidth)) ENDCASE IF m.lnNewAngle < 0 m.lnNewAngle = m.lnNewAngle + 360 ENDIF IF m.lnNewAngle - m.tnAngle > 170 m.lnNewAngle = m.lnNewAngle - 180 ENDIF RETURN m.lnNewAngle ENDPROC PROCEDURE _getbasiccolor * From LMGRAPH, from Luis Maria Guayan, MVP, Argentina * www.portalfox.com LPARAMETERS tn LOCAL la(28) m.tn = MOD(m.tn-1,28)+1 m.la(1) = RGB(255,0,0) && Rojo m.la(2) = RGB(255,255,0) && Amarillo m.la(3) = RGB(0,0,255) && Azul m.la(4) = RGB(0,128,0) && Verde Oscuro m.la(5) = RGB(255,128,0) && Anaranjado m.la(6) = RGB(255,0,255) && Magenta m.la(7) = RGB(128,0,255) && Violeta m.la(8) = RGB(0,255,255) && Cyan m.la(9) = RGB(128,64,0) && Marrón m.la(10) = RGB(192,192,0) && Amarillo Oscuro m.la(11) = RGB(192,0,0) && Rojo Oscuro m.la(12) = RGB(0,255,0) && Verde m.la(13) = RGB(0,0,128) && Azul Oscuro m.la(14) = RGB(255,192,0) && Anaranjado Claro m.la(15) = RGB(0,192,255) && Azul claro m.la(16) = RGB(128,128,0) && Marrón Claro m.la(17) = RGB(255,192,255) && Magenta Claro m.la(18) = RGB( 64,128,128) && Verde Azulado m.la(19) = RGB(255,0,128) && Fucsia m.la(20) = RGB(255,255,192) && Amarillo Claro m.la(21) = RGB(192,0,255) && Violeta Claro m.la(22) = RGB(192,255,192) && Verde Claro m.la(23) = RGB(128,0,128) && Violeta Oscuro m.la(24) = RGB(192,255,255) && Cyan Claro m.la(25) = RGB(128,128,128) && Gris Oscuro m.la(26) = RGB(255,255,255) && Blanco m.la(27) = RGB(192,192,192) && Gris m.la(28) = RGB(0,0,0) && Negro RETURN m.la(m.tn) ENDPROC PROCEDURE _getcenterpoint LPARAMETERS tnX, tnY, tnWidth, tnHeight * Calculate positions LOCAL lnCenterX, lnCenterY m.lnCenterX = (m.tnWidth / 2) m.lnCenterY = (m.tnHeight / 2) * Create a GraphicsPath object. LOCAL lnAngle, lnDistance, xAdjust, yAdjust m.lnAngle = This.PieGradCenterAngle LOCAL loTempPath as xfcGraphicsPath LOCAL loPoint as xfcPointF LOCAL loRect as xfcRectangle m.loTempPath = _Screen.System.Drawing.Drawing2D.GraphicsPath.New() * Obtaining the needed points m.lnDistance = This.PieGradCenterDistance m.xAdjust = (1 - m.lnDistance) / 2 m.yAdjust = (1 - m.lnDistance) / 2 m.loRect = _Screen.System.Drawing.Rectangle.New(m.tnX + m.xAdjust * m.tnWidth, ; m.tnY + m.yAdjust * m.tnHeight, ; m.lnDistance * m.tnWidth, ; m.lnDistance * m.tnHeight) m.loTempPath.AddArc(m.loRect, m.lnAngle, 0.0001) m.loPoint = m.loTempPath.GetLastPoint() RETURN m.loPoint ENDPROC PROCEDURE _getchartprop Lparameters toPropertiesList, tcProperty, tnType, toSavedProps, lcDescription, tlShowDescriptions Local lcCRLF Local lcName as String, ; lcType as String, ; lcValue as String, ; lxValue m.lcCRLF = Chr(13) Local lbChanged, lcNewType, lcOldType, lnBlue, lnDope, lnGreen, lnPos, lnRed Do Case Case m.tnType = 1 m.lbChanged = .T. Case m.tnType = 2 If "." $ m.tcProperty m.lnPos = Rat (".", m.tcProperty) m.lbChanged = Pemstatus ( Evaluate ("This." + Left(m.tcProperty, m.lnPos - 1)), Substr(m.tcProperty, m.lnPos + 1), 0) Else m.lbChanged = Pemstatus(This, m.tcProperty, 5) And Pemstatus(This, m.tcProperty, 0) * lbChanged = Pemstatus (This, tcProperty, 0) Endif Case m.tnType = 3 m.lcNewType = Vartype(Evaluate("toPropertiesList." + m.tcProperty)) m.lcOldType = Vartype(Evaluate("toSavedProps." + m.tcProperty)) m.lbChanged = (m.lcNewType # m.lcOldType) Or Not ; EVALUATE("toPropertiesList." + m.tcProperty) == Evaluate("toSavedProps." + m.tcProperty) Endcase If Not m.lbChanged Return '' Endif m.lcName = Trim(m.tcProperty) m.lxValue = Evaluate ("toPropertiesList." + m.tcProperty) m.lcType = Vartype (m.lxValue) Do Case Case m.lcType = 'C' m.lxValue = Trim(m.lxValue) Do Case Case Not ['] $ m.lxValue m.lcValue = ['] + m.lxValue + ['] Case Not ["] $ lxValue m.lcValue = ["] + m.lxValue + ["] Otherwise m.lcValue = '[' + m.lxValue + ']' Endcase Case m.lcType = "O" m.lcValue = " " + Chr(38) + Chr(38) + "Custom object - " + m.lxValue.Name Return "* ." + m.lcName + " = " + m.lcValue + m.lcCRLF Case m.lcType = "N" LOCAL lcUpName m.lcUpName = UPPER(m.lcName) m.lnDope = At('***', m.lcDescription) If Inlist(ALLTRIM(Right('.' + m.lcUpName,10)), ; '.FORECOLOR', '.BACKCOLOR') Or ; ('BACKCOLOR2' $ m.lcUpName) OR ; (').COLOR' $ m.lcUpName) OR ; (m.lnDope > 0 And "COLOR" == Upper(Alltrim(Substr(m.lcDescription, m.lnDope + 3)))) m.lnRed = Bitand(m.lxValue, 255) m.lnGreen = Bitrshift(Bitand(m.lxValue, 256 * 255), 8) m.lnBlue = Bitrshift(Bitand(m.lxValue, 256 * 256 * 255), 16) m.lcValue = 'RGB(' + Transform(m.lnRed) + ',' + Transform(m.lnGreen) + ',' + Transform(m.lnBlue) + ')' Else m.lcValue = Transform(m.lxValue) Endif Otherwise m.lcValue = Transform(m.lxValue) Endcase Return Iif (Empty (m.lcDescription) or not m.tlShowDescriptions, '', '* ' + m.lcDescription + m.lcCRLF) + "." + m.lcName + " = " + m.lcValue + m.lcCRLF ENDPROC PROCEDURE _getchartproperties **************************************************************** * Jim Nelson 10/20/2008 * * Returns an object with current settings of all FoxCharts properties Local loProperties Local laProperties(1), laSubProperties(1), lcProperty Local lcProperties, lcName, lcType, loObject, lnI, lnJ, laFieldMembers(1), lcFieldMem, loData Local luPropValue, lcPropType Local loFields as "Collection" m.loProperties = Createobject("Empty") m.lcProperties = "Format, FontName, FontSize, FontBold, FontItalic, FontUnderline, FontCharSet, ForeColor, ForeColorAlpha, BackColor, BackColorAlpha, Alignment, Rotation, RotationCenter" Alines (laSubProperties, m.lcProperties, 5, ',') With This Local laProperties(1), lcProperty Amembers(m.laProperties, This, 3) AddProperty (m.loProperties, "_Descriptions(1)", m.laProperties) Acopy(m.laProperties, m.loProperties._Descriptions) For m.lnI = 1 To Alen (m.laProperties,1) m.lcName = Proper(m.laProperties(m.lnI,1)) m.lcType = Proper(m.laProperties(m.lnI,2)) Do Case Case m.lcType = 'Property' ; && the list of ReadOnly properties And Not Inlist (Upper (m.lcName), "VERSION", "VERSIONA", "CHARTSUM", ; "OBMP", "OGFX", "ACOORD", "ACOLORS", "SINGLEDATA", ; "CURRINDEX", "CURRVALUE", "CURRLEGEND", "CURROBJTYPE", ; "CURRCOLUMN", "CURRRECNO", "LEGEND1", "COLOR1", "FIELDVALUE1", "SHAPE1",; "CHARTTYPE1", "SHOWVALUESONSHAPE1", "FIELDXAXIS", "APALETTECOLORS", "DEBUG") ; and "_" # Left(m.lcName, 1) ; And (Pemstatus(This, m.lcName, 4) Or ; Inlist( Upper(m.lcName), 'BACKCOLOR', 'FORECOLOR', 'MARGIN', 'SHOWTIPS', 'WIDTH', 'HEIGHT')) AddProperty (m.loProperties, m.lcName, Evaluate ("This." + m.lcName)) Case m.lcName = 'Fields' m.loFields = Createobject("Collection") For m.lnJ = 1 To This.Fields.Count m.loData = Createobject("Empty") Amembers(laFieldMembers, This.Fields(m.lnJ)) For Each m.lcFieldMem In m.laFieldMembers m.luPropValue = Evaluate("This.Fields(lnJ)." + m.lcFieldMem) m.lcPropType = VARTYPE(m.luPropValue) IF (m.lcFieldMem = "CHARTTYPE" AND m.lcPropType = "N" AND m.luPropValue = 0) OR ; (m.lcFieldMem = "SHOWVALUESONSHAPE" AND m.lcPropType = "L" AND m.luPropValue = .T.) OR ; (m.lcFieldMem = "SHAPE" AND m.lcPropType = "N" AND m.luPropValue = 0) LOOP ENDIF AddProperty(m.loData, m.lcFieldMem, m.luPropValue) Endfor m.loFields.Add(m.loData) Next m.lnJ AddProperty (m.loProperties, m.lcName, m.loFields) Case m.lcType = 'Object' ; and Inlist (m.lcName, "Title", "Subtitle", "Xaxis", "Axislegend2", "Yaxis", "Shapelegend", "Scalelegend", "Sidelegend", "Yaxis2") * create an object AddProperty (m.loProperties, m.lcName, Createobject("Empty")) m.loObject = Evaluate ("loProperties." + m.lcName) * conditionally add caption If Not Inlist (m.lcName, "Axislegend2", "Shapelegend", "Scalelegend", "Sidelegend") AddProperty (m.loObject, "Caption", Evaluate ("This." + m.lcName + ".Caption")) Endif * and add other properties of that objecgt For Each m.lcProperty In m.laSubProperties AddProperty (m.loObject, m.lcProperty, Evaluate ("This." + m.lcName + "." + m.lcProperty)) Endfor Endcase Endfor Endwith Return m.loProperties ENDPROC PROCEDURE _getchartscript && Returns a complete script to reproduce the current chart in a separate PRG. LOCAL loChart AS FoxCharts OF "FoxCharts.vcx" Local laFields[1], ; lcField as String m.loChart = This LOCAL lcSource, lcCRLF, lcTAB, n, i m.lcCRLF = CHR(13) + CHR(10) m.lcTAB = CHR(9) m.lcSource = m.loChart.SourceAlias SELECT (m.lcSource) * If using Random colors, convert the chart to custom colors, * and set the colors to the same of the current chart IF m.loChart.ColorType = 2 && Random m.loChart.ColorType = 1 && Custom colors IF m.loChart.SingleData SELECT (m.lcSource) SCAN REPLACE (m.lcSource + "." + ALLTRIM(m.loChart.FieldColor)) WITH m.loChart.aColors(RECNO()) ENDSCAN ELSE FOR m.n = 1 TO m.loChart.ChartsCount m.loChart.Fields(m.n).Color = m.loChart.aColors(m.n) ENDFOR ENDIF ENDIF LOCAL lcAlias, lcFldType, lcSQL, lnFields, lcFldName, lcFldType, lnFldInteger, lnFldDecimals m.lcAlias = ALLTRIM(m.lcSource) && "TempCursor" m.lcSQL = "CREATE CURSOR " + m.lcAlias + "( ;" + m.lcCRLF m.lnFields = AFIELDS(laFields, m.lcSource) && Create array. m.lcField = "" FOR m.n = 1 TO m.lnFields m.lcFldName = m.laFields(m.n,1) m.lcFldType = m.laFields(m.n,2) m.lnFldInteger = m.laFields(m.n,3) m.lnFldDecimals = m.laFields(m.n,4) m.lcField = m.lcField + ; m.lcTAB + ; m.lcFldName + " " + m.lcFldType + ; IIF(m.lnFldInteger = 0 or INLIST(m.lcFldType,"I", "L", "D", "T", "M", "W"), " ", " (" + TRANSFORM(m.lnFldInteger) + ; IIF(m.lnFldDecimals = 0, ")", "," + TRANSFORM(m.lnFldDecimals) + ")") ) + ; " NULL , ;" + m.lcCRLF ENDFOR m.lcField = LEFT(m.lcField, LEN(m.lcField) -5 ) m.lcSQL = m.lcSQL + m.lcField + ')' + m.lcCRLF + m.lcCRLF LOCAL lcInserts, lcFields, i, luValue, lcType, lcExpr, lcScript, lcChartScript m.lcInserts = "" SCAN m.lcFields = "" FOR m.i = 1 TO m.lnFields m.luValue = EVALUATE(TRANSFORM(FIELD(m.I))) m.lcType = VARTYPE(m.luValue) DO CASE CASE ISNULL(m.luValue) m.lcExpr = "NULL" CASE m.lcType = "C" m.lcExpr = ["] + ALLTRIM(m.luValue) + ["] CASE m.lcType = "L" m.lcExpr = TRANSFORM(m.luValue) CASE m.lcType = "N" m.lcExpr = TRANSFORM(m.luValue) OTHERWISE ENDCASE m.lcFields = m.lcFields + m.lcExpr + ", " ENDFOR m.lcFields = LEFT(m.lcFields, LEN(m.lcFields) -2) m.lcInserts = m.lcInserts + 'INSERT INTO ' + m.lcAlias + " VALUES (" + m.lcFields + ")" + m.lcCRLF ENDSCAN m.lcScript = m.lcSQL + m.lcInserts LOCAL lcChartScript, lcFormInit, lcFormEnd m.lcChartScript = m.loChart.GetChartProperties(2) && Only non default properties TEXT TO m.lcFormInit NOSHOW SET CLASSLIB TO LOCFILE("FoxCharts.vcx") PUBLIC oForm as Form oForm = CREATEOBJECT("Form") oForm.Newobject("oChart", "FoxCharts", "FoxCharts.vcx") LOCAL loChart as FoxCharts OF "FoxCharts.vcx" m.loChart = oForm.oChart WITH m.loChart ENDTEXT TEXT TO m.lcFormEnd NOSHOW m.loChart.DrawChart() m.loChart.Visible = .T. ENDWITH oForm.Width = m.loChart.Width oForm.Height = m.loChart.Height oForm.Show() ENDTEXT LOCAL lcFullScript m.lcFullScript = m.lcScript + m.lcCRLF + m.lcCRLF + m.lcFormInit + m.lcChartScript + m.lcFormEnd RETURN m.lcFullScript ENDPROC PROCEDURE _getcursorpos LPARAMETERS tnX, tnY * This works better than using MROW() and MCOL() when FoxCharts is not at the active window LOCAL lqPoint AS String DECLARE INTEGER GetCursorPos IN win32api AS FoxCharts_GetCursorPos STRING @lqPoint m.lqPoint = 0h0000000000000000 FoxCharts_GetCursorPos(@m.lqPoint) m.tnx = CTOBIN(SUBSTR(m.lqPoint, 1, 4), "4rs") m.tny = CTOBIN(SUBSTR(m.lqPoint, 5, 4), "4rs") ENDPROC PROCEDURE _getfieldtype LPARAMETERS tcAlias, tcField, tlMask LOCAL gnFieldcount, lnCount, lcCurrField, lnInteger, lnDecimals, lcType LOCAL ARRAY gaMyArray[1] m.gnFieldcount = AFIELDS(gaMyArray, m.tcAlias) && Create array. FOR m.lnCount = 1 TO m.gnFieldcount m.lcCurrField = ALLTRIM(m.gaMyArray(m.lnCount,1)) && Display field names. IF UPPER(m.lcCurrField) = ALLTRIM(UPPER(m.tcField)) m.lnInteger = m.gaMyArray(m.lnCount,3) m.lnDecimals = m.gaMyArray(m.lnCount,4) IF m.tlMask && Return the mask for the format property m.lcType = REPLICATE("9", m.lnInteger) + ; IIF(m.lnDecimals > 0, "." + REPLICATE("9", m.lnDecimals), "") ELSE && Return the field type - eg N(8,2) m.lcType = "N(" + ALLTRIM(STR(m.lnInteger)) + "," + ALLTRIM(STR(m.lnDecimals)) + ")" ENDIF EXIT ENDIF ENDFOR RETURN m.lcType *!* Column number Field info Data type *!* 1 *!* Field name *!* Character *!* *!* 2 *!* Field type: *!* C = Character *!* Y = Currency *!* D = Date *!* T = DateTime *!* B = Double *!* F = Float *!* G = General *!* I = Integer *!* L = Logical *!* M = Memo *!* N = Numeric *!* Q = Varbinary *!* V = Varchar and Varchar (Binary) *!* W = Blob Character *!* *!* 3 *!* Field width *!* Numeric *!* *!* 4 *!* Decimal places *!* Numeric ENDPROC PROCEDURE _getgradientcolor LPARAMETERS tnCount LOCAL lnBasicColor, lnNewColor m.lnBasicColor = This.Fields(1).Color m.tnCount = m.tnCount - 1 IF INLIST(This.ChartType, 5, 6) && Line or Area m.lnNewColor = This.ChangeColor(lnBasicColor, 100 * m.tnCount / This.ChartsCount) ELSE m.lnNewColor = This.ChangeColor(lnBasicColor, 100 * m.tnCount / This._nRecords) ENDIF RETURN m.lnNewColor ENDPROC PROCEDURE _getpalettecolor LPARAMETERS tnPalette, tnIndex LOCAL lnPosition, lnMaxColors m.lnPosition = (m.tnPalette * 8) + m.tnIndex m.lnMaxColors = This._PaletteColors IF m.lnPosition > m.lnMaxColors m.lnPosition = m.lnPosition - m.lnMaxColors ENDIF RETURN This.aPaletteColors(m.lnPosition) ENDPROC PROCEDURE _getrandomcolor RETURN RGB(; INT(RAND() * 255), ; INT(RAND() * 255), ; INT(RAND() * 255)) ENDPROC PROCEDURE _getrelativepositions IF This._InsideForm This._xRelative = This._OBJTOCLIENTex(This, 2) && Left This._yRelative = This._OBJTOCLIENTex(This, 1) && Top ELSE This._xRelative = OBJTOCLIENT(This, 2) && Left This._yRelative = OBJTOCLIENT(This, 1) && Top ENDIF ENDPROC PROCEDURE _getrgb LPARAMETERS tuColor Local lnColor as Number IF VARTYPE(m.tuColor) = "N" RETURN m.tuColor ENDIF IF VARTYPE(m.tuColor) = "C" DO CASE CASE LEFT(m.tuColor,1) = "=" m.lnColor = EVALUATE(SUBSTR(m.tuColor,2)) CASE EMPTY(m.tuColor) m.lnColor = 0 OTHERWISE m.lnColor = EVALUATE("RGB(" + m.tuColor + ")") ENDCASE RETURN m.lnColor ENDIF ENDPROC PROCEDURE _getshapepath LPARAMETERS tnShape WITH _Screen.System.Drawing LOCAL loPath as xfcGraphicsPath m.loPath = _Screen.System.Drawing.Drawing2D.GraphicsPath.New() m.loPath.StartFigure() LOCAL lnShape, lcType m.lcType = VARTYPE(m.tnShape) IF m.lcType = "N" IF m.tnShape = 0 && NO shape selected - go in Automatic mode m.lnShape = This._ChartIndex ELSE m.lnShape = m.tnShape ENDIF ENDIF DO CASE CASE m.lcType = "O" m.loPath = m.tnShape CASE m.lnShape = 1 && Round m.loPath.AddEllipse(0, 0, 6, 6) CASE m.lnShape = 2 && Square m.loPath.AddRectangle(0,0,6,6) CASE m.lnShape = 3 && Triangle LOCAL laPoints(3) m.laPoints(1) = .Point.New(3,0) m.laPoints(2) = .Point.New(0,6) m.laPoints(3) = .Point.New(6,6) m.loPath.AddPolygon(@m.laPoints) CASE m.lnShape = 4 && Cross m.loPath.AddLine(2,0, 4,0) m.loPath.AddLine(4,0, 4,2) m.loPath.AddLine(4,2, 6,2) m.loPath.AddLine(6,2, 6,4) m.loPath.AddLine(6,4, 4,4) m.loPath.AddLine(4,4, 4,6) m.loPath.AddLine(4,6, 2,6) m.loPath.AddLine(2,6, 2,4) m.loPath.AddLine(2,4, 0,4) m.loPath.AddLine(0,4, 0,2) m.loPath.AddLine(0,2, 2,2) m.loPath.AddLine(2,2, 2,0) CASE m.lnShape = 5 && Star LOCAL lnRadius, lnPi, lnRadian72, n m.lnRadius = 6.0 m.lnPi = 3.141592 m.lnRadian72 = (m.lnPi * 4.0 ) / 5.0 LOCAL laPoints(5), n FOR m.n = 1 TO 5 m.laPoints(m.n) = .Point.New(; + m.lnRadius * SIN( m.n * m.lnRadian72 ) + 3, ; - m.lnRadius * COS( m.n * m.lnRadian72 ) + 2) ENDFOR m.loPath.AddPolygon(@m.laPoints) m.loPath.FillMode = _Screen.System.Drawing.Drawing2D.FillMode.Winding CASE m.lnShape = 6 && Cross 2 m.loPath.AddRectangle(0,0,7,7) m.loPath.AddRectangle(1,1,2,2) m.loPath.AddRectangle(4,1,2,2) m.loPath.AddRectangle(1,4,2,2) m.loPath.AddRectangle(4,4,2,2) CASE m.lnShape = 7 && Box m.loPath.FillMode = _Screen.System.Drawing.Drawing2D.FillMode.Alternate m.loPath.AddRectangle(0,0,6,6) m.loPath.AddRectangle(2,2,2,2) CASE m.lnShape = 8 && Button m.loPath.AddEllipse(0, 0, 6, 6) m.loPath.StartFigure() m.loPath.AddEllipse(2,2,2,2) m.loPath.FillMode = _Screen.System.Drawing.Drawing2D.FillMode.Alternate CASE m.lnShape = 9 && Box2 m.loPath.AddLine(9,0,6,5) m.loPath.AddLine(6,5,10,4) m.loPath.AddLine(10,4,2,10) m.loPath.AddLine(2,10,3,5) m.loPath.AddLine(3,5,0,6) m.loPath.AddLine(0,6,6,0) m.loPath.AddLine(6,0,9,0) CASE m.lnShape = 10 && Small Man m.loPath.AddEllipse(3, 0, 3, 3) m.loPath.AddLine(2, 4, 8, 4) m.loPath.AddLine(10, 10, 8, 10) m.loPath.AddLine(7, 6, 7, 10) m.loPath.AddLine(9, 19, 7, 19) m.loPath.AddLine(5, 12, 4, 19) m.loPath.AddLine(2, 19, 3, 10) m.loPath.AddLine(3, 6, 2, 10) m.loPath.AddLine(0, 10, 2, 4) CASE m.lnShape = 55 && Big Man m.loPath.AddEllipse(23, 1, 14, 14) m.loPath.AddLine(18, 16, 42, 16) m.loPath.AddLine(50, 40, 44, 42) m.loPath.AddLine(38, 25, 37, 42) m.loPath.AddLine(45, 75, 37, 75) m.loPath.AddLine(30, 50, 23, 75) m.loPath.AddLine(16, 75, 23, 42) m.loPath.AddLine(22, 25, 16, 42) m.loPath.AddLine(10, 40, 18, 16) CASE m.lnShape = 98 && GDI+X Graphics Path CASE m.lnShape = 99 && Image OTHERWISE * 2013-02-21 CCHALOM * If no valid shape number was sent, then we'll use a basic circle * Like Shape #1 above m.loPath.AddEllipse(0, 0, 6, 6) ENDCASE ENDWITH RETURN m.loPath ENDPROC PROCEDURE _getvalue LPARAMETERS tiIndex, tlAcceptNULL LOCAL luValue, llIsNull m.luValue = EVALUATE((This._DataCursor) + ".nValue" + This._Str(m.tiIndex)) IF ISNULL(m.luValue) AND NOT m.tlAcceptNULL m.luValue = 0 ENDIF RETURN m.luValue ENDPROC PROCEDURE _getylegendsize LPARAMETERS tnAxis tnAxis = EVL(tnAxis, 1) Local lnScaleW, lnScaleH Local lnWidth as Number If This._Orientation = 1 && Vertical If This.ShowScale **************************************************************** * Jim Nelson 10/13/2008 * * Modified to call GetScaleLegend to get representative used to calculate maximum width LOCAL luLegend IF tnAxis = 2 m.luLegend = TRANSFORM(This._MaxScale2) ELSE m.luLegend = This.GetScaleLegend(-1) ENDIF IF VARTYPE(m.luLegend) = "N" This.ScaleLegend._Value = m.luLegend ELSE This.ScaleLegend.Caption = m.luLegend ENDIF m.lnScaleW = This.ScaleLegend._Width + 2 m.lnScaleH = This.ScaleLegend._Height Else m.lnScaleW = 0 m.lnScaleH = 0 Endif ELSE && Horizontal Local lnMaxWidth, lcText Local loFont As xfcFont Local loSize As xfcSize This.AxisLegend2._Setup() m.loFont = This.AxisLegend2._oFont m.lnMaxWidth = 0 Scan * Measure the legend width m.lcText = cAxis2 This.AxisLegend2.Caption = m.lcText m.lnWidth = This.AxisLegend2._Width m.lnMaxWidth = Max(m.lnMaxWidth, m.lnWidth) Endscan m.lnScaleH = This.AxisLegend2._Width m.lnScaleW = m.lnMaxWidth Endif IF tnAxis = 1 This._ScaleH = m.lnScaleH This._ScaleW = m.lnScaleW ELSE && tnAxis = 2 This._ScaleH2 = m.lnScaleH This._ScaleW2 = m.lnScaleW ENDIF Return ENDPROC PROCEDURE _initchart IF TYPE("Thisform.Name") = "C" This._InsideForm = .T. * Add the tooltips object to the form IF NOT PEMSTATUS(Thisform, "FoxChartsToolTip", 5) Thisform.AddObject("FoxChartsToolTip", "Label") ENDIF ELSE This._InsideForm = .F. ENDIF This.BorderWidth = 0 This.BackStyle = 0 && Transparent IF VARTYPE(This._3D) = "L" && Undefined This._Using3D = .F. This._3D = This.Depth ELSE This._Using3D = .T. This.Depth = This._3D ENDIF * Prepare basic color objects This._oClrBlack = _Screen.System.Drawing.Color.FromRGB(0) This._oClrWhite = _Screen.System.Drawing.Color.FromRGB(255,255,255) * A thin black pen to draw the ticks in the Y Axis LOCAL loBlackPen As xfcPen m.loBlackPen = _Screen.System.Drawing.Pen.New(This._oClrBlack, 0) This._oBlackPen = m.loBlackPen * Store the original Mouse Pointer This._OrigMousePointer = This.MousePointer * Initialize the color palettes This._InitPalettes() *!* * GdiPlus API call declarations *!* * to ensure compatibility with all GdiPlusX versions * They are being "Redeclared" here to avoid compiling errors. DECLARE Long GdipSetPathGradientSurroundColorsWithCount IN GDIPLUS.DLL AS xfcGdipSetPathGradientSurroundColorsWithCount Long brush, String @Argb, Long @Count DECLARE Long GdipSetPathGradientCenterPoint IN GDIPLUS.DLL AS xfcGdipSetPathGradientCenterPoint Long brush, String pPoint This.ChartCanvas.ZOrder(0) * Prepare the Fields collection, forcing at least 1 item * for not obliging users to set .ChartsCount in "SingleData" charts IF This.ChartsCount = 0 This._SetFieldsCount(1) ENDIF This._Started = .T. IF _VFP.StartMode = 0 SET ASSERTS ON ENDIF DODEFAULT() ENDPROC PROCEDURE _initpalettes LOCAL lnMaxColors m.lnMaxColors = 184 This._PaletteColors = m.lnMaxColors DIMENSION This.aPaletteColors(m.lnMaxColors) WITH This .aPaletteColors(1) = RGB(151,186,235) && In a fog .aPaletteColors(2) = RGB(239,158,169) .aPaletteColors(3) = RGB(214,164,225) .aPaletteColors(4) = RGB(165,159,230) .aPaletteColors(5) = RGB(242,199,152) .aPaletteColors(6) = RGB(224,218,142) .aPaletteColors(7) = RGB(166,224,144) .aPaletteColors(8) = RGB(147,217,210) .aPaletteColors(9) = RGB(166,141,45) && Apex .aPaletteColors(10) = RGB(102,124,76) .aPaletteColors(11) = RGB(52,133,162) .aPaletteColors(12) = RGB(44,80,166) .aPaletteColors(13) = RGB(72,51,159) .aPaletteColors(14) = RGB(116,68,146) .aPaletteColors(15) = RGB(222,208,153) .aPaletteColors(16) = RGB(187,202,172) .aPaletteColors(17) = RGB(181,88,4) && Aspect .aPaletteColors(18) = RGB(109,24,33) .aPaletteColors(19) = RGB(15,60,88) .aPaletteColors(20) = RGB(51,93,42) .aPaletteColors(21) = RGB(64,47,84) .aPaletteColors(22) = RGB(156,113,52) .aPaletteColors(23) = RGB(248,170,93) .aPaletteColors(24) = RGB(209,84,97) .aPaletteColors(25) = RGB(49,138,210) && Chameleon .aPaletteColors(26) = RGB(203,181,112) .aPaletteColors(27) = RGB(212,120,185) .aPaletteColors(28) = RGB(189,223,120) .aPaletteColors(29) = RGB(109,181,229) .aPaletteColors(30) = RGB(212,196,136) .aPaletteColors(31) = RGB(209,135,189) .aPaletteColors(32) = RGB(172,202,117) .aPaletteColors(33) = RGB(167,60,35) && Civic .aPaletteColors(34) = RGB(148,129,0) .aPaletteColors(35) = RGB(85,126,127) .aPaletteColors(36) = RGB(98,85,76) .aPaletteColors(37) = RGB(87,128,83) .aPaletteColors(38) = RGB(173,105,36) .aPaletteColors(39) = RGB(185,123,108) .aPaletteColors(40) = RGB(255,228,40) .aPaletteColors(41) = RGB(26,111,134) && Concourse .aPaletteColors(42) = RGB(159,18,24) .aPaletteColors(43) = RGB(172,62,11) .aPaletteColors(44) = RGB(33,60,101) .aPaletteColors(45) = RGB(42,44,75) .aPaletteColors(46) = RGB(81,35,45) .aPaletteColors(47) = RGB(92,190,216) .aPaletteColors(48) = RGB(233,101,107) .aPaletteColors(49) = RGB(158,47,13) && Equity / Brick .aPaletteColors(50) = RGB(107,26,18) .aPaletteColors(51) = RGB(112,96,66) .aPaletteColors(52) = RGB(95,60,48) .aPaletteColors(53) = RGB(96,85,85) .aPaletteColors(54) = RGB(89,59,59) .aPaletteColors(55) = RGB(235,114,76) .aPaletteColors(56) = RGB(214,76,61) .aPaletteColors(57) = RGB(7,71,137) && Flow .aPaletteColors(58) = RGB(0,108,156) .aPaletteColors(59) = RGB(5,134,41) .aPaletteColors(60) = RGB(7,132,95) .aPaletteColors(61) = RGB(67,146,43) .aPaletteColors(62) = RGB(125,152,44) .aPaletteColors(63) = RGB(66,156,240) .aPaletteColors(64) = RGB(57,197,255) .aPaletteColors(65) = RGB(76,124,80) && Foundry .aPaletteColors(66) = RGB(86,139,86) .aPaletteColors(67) = RGB(67,140,161) .aPaletteColors(68) = RGB(123,118,94) .aPaletteColors(69) = RGB(150,136,64) .aPaletteColors(70) = RGB(190,61,61) .aPaletteColors(71) = RGB(150,183,154) .aPaletteColors(72) = RGB(182,207,182) .aPaletteColors(73) = RGB(61,115,162) && Median .aPaletteColors(74) = RGB(179,81,27) .aPaletteColors(75) = RGB(109,115,73) .aPaletteColors(76) = RGB(159,118,33) .aPaletteColors(77) = RGB(70,111,102) .aPaletteColors(78) = RGB(108,98,98) .aPaletteColors(79) = RGB(165,193,217) .aPaletteColors(80) = RGB(231,168,130) .aPaletteColors(81) = RGB(81,150,29) && Metro .aPaletteColors(82) = RGB(169,11,81) .aPaletteColors(83) = RGB(181,124,1) .aPaletteColors(84) = RGB(0,108,142) .aPaletteColors(85) = RGB(51,75,146) .aPaletteColors(86) = RGB(14,123,107) .aPaletteColors(87) = RGB(162,222,117) .aPaletteColors(88) = RGB(240,102,155) .aPaletteColors(89) = RGB(224,165,57) && Nature .aPaletteColors(90) = RGB(113,178,30) .aPaletteColors(91) = RGB(207,80,34) .aPaletteColors(92) = RGB(217,184,56) .aPaletteColors(93) = RGB(120,211,64) .aPaletteColors(94) = RGB(160,60,26) .aPaletteColors(95) = RGB(9,141,8) .aPaletteColors(96) = RGB(165,165,0) .aPaletteColors(97) = RGB(49,116,216) && Northern lights .aPaletteColors(98) = RGB(215,59,165) .aPaletteColors(99) = RGB(75,202,249) .aPaletteColors(100) = RGB(205,45,222) .aPaletteColors(101) = RGB(142,184,242) .aPaletteColors(102) = RGB(238,139,207) .aPaletteColors(103) = RGB(147,213,244) .aPaletteColors(104) = RGB(212,115,222) .aPaletteColors(105) = RGB(46,89,140) && Office .aPaletteColors(106) = RGB(138,45,43) .aPaletteColors(107) = RGB(102,130,47) .aPaletteColors(108) = RGB(77,58,101) .aPaletteColors(109) = RGB(38,115,137) .aPaletteColors(110) = RGB(207,89,6) .aPaletteColors(111) = RGB(134,168,208) .aPaletteColors(112) = RGB(215,148,145) .aPaletteColors(113) = RGB(132,138,70) && Opulent .aPaletteColors(114) = RGB(124,56,139) .aPaletteColors(115) = RGB(162,62,20) .aPaletteColors(116) = RGB(194,123,4) .aPaletteColors(117) = RGB(154,44,104) .aPaletteColors(118) = RGB(208,82,3) .aPaletteColors(119) = RGB(206,112,144) .aPaletteColors(120) = RGB(204,159,213) .aPaletteColors(121) = RGB(71,80,115) && Origin .aPaletteColors(122) = RGB(71,113,149) .aPaletteColors(123) = RGB(161,172,41) .aPaletteColors(124) = RGB(228,167,5) .aPaletteColors(125) = RGB(129,77,60) .aPaletteColors(126) = RGB(93,73,67) .aPaletteColors(127) = RGB(154,162,187) .aPaletteColors(128) = RGB(174,195,213) .aPaletteColors(129) = RGB(106,127,83) && Paper .aPaletteColors(130) = RGB(205,109,10) .aPaletteColors(131) = RGB(169,131,15) .aPaletteColors(132) = RGB(153,60,90) .aPaletteColors(133) = RGB(94,64,135) .aPaletteColors(134) = RGB(61,96,140) .aPaletteColors(135) = RGB(189,201,176) .aPaletteColors(136) = RGB(246,190,124) .aPaletteColors(137) = RGB(225,102,82) && Pastel Kit .aPaletteColors(138) = RGB(49,141,206) .aPaletteColors(139) = RGB(239,203,78) .aPaletteColors(140) = RGB(147,219,103) .aPaletteColors(141) = RGB(177,223,252) .aPaletteColors(142) = RGB(244,140,77) .aPaletteColors(143) = RGB(145,111,189) .aPaletteColors(144) = RGB(189,189,189) .aPaletteColors(145) = RGB(34,100,117) && Solstice .aPaletteColors(146) = RGB(195,133,1) .aPaletteColors(147) = RGB(131,25,26) .aPaletteColors(148) = RGB(80,107,28) .aPaletteColors(149) = RGB(97,39,2) .aPaletteColors(150) = RGB(44,58,95) .aPaletteColors(151) = RGB(97,179,199) .aPaletteColors(152) = RGB(255,206,91) .aPaletteColors(153) = RGB(244,213,46) && Technic .aPaletteColors(154) = RGB(68,117,134) .aPaletteColors(155) = RGB(140,118,4) .aPaletteColors(156) = RGB(86,83,110) .aPaletteColors(157) = RGB(68,80,55) .aPaletteColors(158) = RGB(105,96,70) .aPaletteColors(159) = RGB(82,87,94) .aPaletteColors(160) = RGB(152,186,197) .aPaletteColors(161) = RGB(217,98,64) && Terracotta .aPaletteColors(162) = RGB(174,139,76) .aPaletteColors(163) = RGB(212,121,18) .aPaletteColors(164) = RGB(252,193,168) .aPaletteColors(165) = RGB(240,227,176) .aPaletteColors(166) = RGB(247,204,116) .aPaletteColors(167) = RGB(231,146,122) .aPaletteColors(168) = RGB(186,156,101) .aPaletteColors(169) = RGB(126,195,71) && Trees .aPaletteColors(170) = RGB(208,153,62) .aPaletteColors(171) = RGB(230,220,78) .aPaletteColors(172) = RGB(191,238,103) .aPaletteColors(173) = RGB(83,210,136) .aPaletteColors(174) = RGB(184,161,43) .aPaletteColors(175) = RGB(172,69,28) .aPaletteColors(176) = RGB(79,192,63) .aPaletteColors(177) = RGB(255,44,122) .aPaletteColors(178) = RGB(224,0,85) .aPaletteColors(179) = RGB(163,0,57) .aPaletteColors(180) = RGB(102,0,81) .aPaletteColors(181) = RGB(62,0,78) .aPaletteColors(182) = RGB(0,55,139) .aPaletteColors(183) = RGB(0,31,108) .aPaletteColors(184) = RGB(255,105,167) ENDWITH ENDPROC PROCEDURE _newfield LOCAL loData m.loData = CREATEOBJECT("Empty") ADDPROPERTY(m.loData,"ChartType",0) ADDPROPERTY(m.loData,"FieldValue","") ADDPROPERTY(m.loData,"Legend","") ADDPROPERTY(m.loData,"Color",0) ADDPROPERTY(m.loData,"Shape",0) ADDPROPERTY(m.loData,"ShowValuesOnShape",.T.) ADDPROPERTY(m.loData,"AxisIndex",1) RETURN m.loData ENDPROC PROCEDURE _objtoclientex ********************************************************************* * FUNCTION ObjToClientEx ********************************************************************* ** Method: xfcBitmap.ObjToClientEx ** ** This replaces OBJTOCLIENT that has bugs with pageframes and SP2 ** ** History: ** 2007/11/26: CAlloatti/CChalom - Coded Made small adaptation from the original code from Carlos Alloatti in his CTL32SContainer ********************************************************************* LPARAMETERS toControl, tnType && 1 = Top 2 = Left *!* TabOrientation parameters #DEFINE CON_TABOR_TOP 0 #DEFINE CON_TABOR_BOTTOM 1 #DEFINE CON_TABOR_LEFT 2 #DEFINE CON_TABOR_RIGHT 3 LOCAL lnPosition AS INTEGER m.lnPosition = 0 DO CASE CASE m.tnType = 1 && Top DO WHILE NOT UPPER(m.toControl.BASECLASS) == [FORM] IF PEMSTATUS(m.toControl, [Top],5) THEN && Defined Property m.lnPosition = m.lnPosition + m.toControl.TOP ENDIF IF UPPER(m.toControl.BASECLASS) == [PAGE] THEN IF m.toControl.PARENT.TABORIENTATION = CON_TABOR_TOP THEN && Top m.lnPosition = m.lnPosition + ; m.toControl.PARENT.HEIGHT - ; m.toControl.PARENT.PAGEHEIGHT - ; m.toControl.PARENT.BORDERWIDTH * 2 ELSE m.lnPosition = m.lnPosition + 1 ENDIF ENDIF m.toControl = m.toControl.PARENT ENDDO CASE m.tnType = 2 && Left DO WHILE NOT UPPER(m.toControl.BASECLASS) == [FORM] IF PEMSTATUS(m.toControl, [Left], 5) THEN && Defined Property m.lnPosition = m.lnPosition + m.toControl.LEFT ENDIF IF UPPER(m.toControl.BASECLASS) == [PAGE] IF m.toControl.PARENT.TABORIENTATION = CON_TABOR_LEFT THEN && Left m.lnPosition = m.lnPosition + ; m.toControl.PARENT.WIDTH - ; m.toControl.PARENT.PAGEWIDTH - ; m.toControl.PARENT.BORDERWIDTH * 2 ELSE m.lnPosition = m.lnPosition + 1 ENDIF ENDIF m.toControl = m.toControl.PARENT ENDDO ENDCASE RETURN m.lnPosition ENDPROC PROCEDURE _preparebackground WITH _SCREEN.SYSTEM.Drawing IF This.BrushType = 3 && Monochrome This.ChartCanvas.Clear(This._oClrWhite) ELSE LOCAL lcType m.lcType = VARTYPE(This.BackColor2) DO CASE CASE m.lcType <> "N" This.ChartCanvas.Clear(.Color.FromARGB(This.BackColorAlpha, This.BackColor)) CASE m.lcType = "N" AND (This.BackColor = This.BackColor2) This.ChartCanvas.Clear(.Color.FromARGB(This.BackColorAlpha, This.BackColor)) OTHERWISE LOCAL loGradBrush as xfcLinearGradientBrush m.loGradBrush = .Drawing2D.LinearGradientBrush.New(This.ChartCanvas.Rectangle, ; .Color.FromARGB(This.BackColorAlpha, This.BackColor), ; .Color.FromARGB(This.BackColorAlpha, This.BackColor2), ; This.BackGradientMode) This.oGfx.FillRectangle(m.loGradBrush, This.ChartCanvas.Rectangle) ENDCASE ENDIF ENDWITH ENDPROC PROCEDURE _preparebrushes LPARAMETERS tnX, tnY, tnWidth, tnHeight, tlRect, tnCount LOCAL lnShape as Number IF VARTYPE(m.tnCount) = "L" m.tnCount = 1 ENDIF IF PCOUNT() = 0 m.tnX = 0 m.tnY = 0 m.tnWidth = This.ChartCanvas.Width m.tnHeight = This.ChartCanvas.Height ENDIF m.tnWidth = MAX(1,m.tnWidth) m.tnHeight = MAX(1,m.tnHeight) LOCAL lnBrushType, lnMainColor m.lnBrushType = This.BrushType m.lnMainColor = This.aColors(m.tnCount) IF VARTYPE(m.lnMainColor) <> "N" m.lnMainColor = This._GetRandomColor() ENDIF This._nColor = m.lnMainColor WITH _Screen.System.Drawing IF This.BrushType = 3 && Monochrome This._oBorderPen = .Pen.New(This._oClrBlack) ELSE LOCAL lnColor m.lnColor = This.ChangeColor(m.lnMainColor, +30) This._oBorderPen = .Pen.New(.Color.FromRGB(m.lnColor)) * Check if we are drawing on the selected shape IF NOT This._InLegend AND This.ChangeColoronMouse AND ; This._GeneralType <> "Point" LOCAL m.lnShape m.lnShape = This._nMouseOnShape IF m.lnShape > 0 AND This._nMouseOnShape = This._nIndex m.lnMainColor = This.SelectedShapeColor ENDIF ENDIF ENDIF DO CASE CASE m.lnBrushType = 1 && Solid Brush This._oMainBrush = .SolidBrush.New(.COLOR.FromARGB(This.AlphaChannel, m.lnMainColor)) This._o3DBrush = .SolidBrush.New(.Color.FromARGB(This.AlphaChannel, This.ChangeColor(m.lnMainColor, - 20))) CASE m.lnBrushType = 2 && Gradient Path Brush LOCAL loColor1 as xfcColor m.loColor1 = .Color.FromARGB(This.AlphaChannel, This.ChangeColor(m.lnMainColor, - 10)) LOCAL loColor2 as xfcColor m.loColor2 = .COLOR.FromARGB(This.AlphaChannel, This.ChangeColor(m.lnMainColor, This.GradientLevel * 10)) IF This.GradientInvertColors LOCAL loTmpColor as xfcColor m.loTmpColor = m.loColor2 m.loColor2 = m.loColor1 m.loColor1 = m.loTmpColor ENDIF DO CASE CASE This._GeneralType = "Pie" AND NOT m.tlRect && Pie or Donut Chart and still not at legend LOCAL loPath as xfcGraphicsPath m.loPath = .Drawing2D.GraphicsPath.New() m.loPath.AddEllipse(m.tnX, m.tnY, m.tnWidth, m.tnHeight) LOCAL loPathGradBrush as xfcPathGradientBrush m.loPathGradBrush = .Drawing2D.PathGradientBrush.New(m.loPath) m.loPathGradBrush.CenterColor = m.loColor2 IF This.PieGradCenterDistance > 0 LOCAL loCenterPt as xfcPointF m.loCenterPt = This._GetCenterPoint(m.tnX, m.tnY, m.tnWidth, m.tnHeight) * Set the center using direct API call because the original funciorn has bugs * When fixed, the line below should work instead: * m.loPathGradBrush.CenterPoint = m.loCenterPt =xfcGdipSetPathGradientCenterPoint(m.loPathGradBrush.Handle, m.loCenterPt.ToVarBinary()) ENDIF * Not working on version 1.20 official * loPathGradBrush.SurroundColors[1] = loColor1 * loPathGradBrush.SurroundColors = loColor1 * Workaround using direct API call to assign the surround colors LOCAL lqColors m.lqColors = BINTOC(m.loColor1.ARGB,"4rs") =xfcGdipSetPathGradientSurroundColorsWithCount(m.loPathGradBrush.Handle, @m.lqColors, 1) IF This.GradientType = 0 && SigmaBell m.loPathGradBrush.SetSigmaBellShape(This.GradientPosition, 1.0) ELSE && BlendTriangularShape m.loPathGradBrush.SetBlendTriangularShape(This.GradientPosition, 1.0) ENDIF This._oMainBrush = m.loPathGradBrush CASE This._GeneralType = "Bar" OR m.tlRect && Bar Chart m.tnWidth = MAX(1, m.tnWidth) m.tnHeight = MAX(1, m.tnHeight) LOCAL loLinGradBrush as xfcLinearGradientBrush m.loLinGradBrush = .Drawing2D.LinearGradientBrush.New(; .Rectangle.New(m.tnX, m.tnY, m.tnWidth, m.tnHeight), ; m.loColor1, m.loColor2, This.GradientShapeDirection) IF This.GradientType = 0 && SigmaBell m.loLinGradBrush.SetSigmaBellShape(This.GradientPosition, 1) ELSE && BlendTriangularShape m.loLinGradBrush.SetBlendTriangularShape(This.GradientPosition, 1.0) ENDIF This._oMainBrush = m.loLinGradBrush CASE This._GeneralType = "Point" && Line, Point or Area Chart m.loColor2 = .COLOR.FromRGB(This.ChangeColor(m.lnMainColor, This.GradientLevel * 8)) LOCAL loLinGradBrush as xfcLinearGradientBrush m.loLinGradBrush = .Drawing2D.LinearGradientBrush.New(; .Rectangle.New(m.tnX, m.tnY, m.tnWidth, m.tnHeight), ; m.loColor1, m.loColor2, This.GradientShapeDirection) IF This.GradientType = 0 && SigmaBell m.loLinGradBrush.SetSigmaBellShape(This.GradientPosition, 1) ELSE && BlendTriangularShape m.loLinGradBrush.SetBlendTriangularShape(This.GradientPosition, 1.0) ENDIF This._oMainBrush = m.loLinGradBrush ENDCASE This._o3DBrush = .SolidBrush.New(.Color.FromARGB(This.AlphaChannel, This.ChangeColor(m.lnMainColor, - 15))) CASE m.lnBrushType = 3 && Monochrome - HatchBrush LOCAL lnHatchBrushValue IF This.ChartsCount > 1 AND NOT This.SingleData && Pie, Bar or Donut m.lnHatchBrushValue = 4 + m.tnCount * 2 ELSE m.lnHatchBrushValue = m.lnMainColor * 2 ENDIF This._oMainBrush = .Drawing2D.HatchBrush.New( ; m.lnHatchBrushValue, ; && HatchStyle This._oClrBlack, ; && ForeColor This._oClrWhite ) && BackColor This._o3DBrush = .Drawing2D.HatchBrush.New( ; m.lnHatchBrushValue , ; && HatchStyle .COLOR.Gray, ; && ForeColor .COLOR.LightGray ) && BackColor ENDCASE ENDWITH RETURN ENDPROC PROCEDURE _preparecolors SELECT(This._DataCursor) LOCAL lnColorType, n m.lnColorType = This.ColorType IF NOT This.SingleData LOCAL lnColor, lcIndex DIMENSION This.aColors(This.ChartsCount) FOR m.n = 1 TO This.ChartsCount m.lcIndex = This._Str(m.N) DO CASE CASE This.BrushType = 3 && Monochrome m.lnColor = 0 CASE m.lnColorType = 0 && Basic Colors m.lnColor = This._GetBasicColor(m.n) CASE m.lnColorType = 1 && Custom m.lnColor = This.Fields(m.n).Color IF VARTYPE(m.lnColor) <> "N" m.lnColor = This._GetRandomColor() ENDIF * CASE m.lnColorType = 2 AND This._UpdateRandomColors && Random CASE m.lnColorType = 2 AND ; (This._UpdateRandomColors OR VARTYPE(This.aColors(m.n)) = "L") && Random or not initialized m.lnColor = This._GetRandomColor() CASE m.lnColorType = 2 AND NOT This._UpdateRandomColors && Random RETURN && Keep the current color CASE m.lnColorType = 3 && Gradient m.lnColor = This._GetGradientColor(m.n) CASE m.lnColorType >= 4 m.lnColor = This._GetPaletteColor(m.lnColorType - 4, m.n) ENDCASE This.aColors(m.n) = m.lnColor ENDFOR ELSE DIMENSION This.aColors(This._nRecords) SCAN m.n = RECNO() DO CASE CASE This.BrushType = 3 && Monochrome m.lnColor = m.n CASE m.lnColorType = 0 && Basic Colors m.lnColor = This._GetBasicColor(m.n) * CASE m.lnColorType = 2 AND This._UpdateRandomColors && Random CASE m.lnColorType = 2 AND ; (This._UpdateRandomColors OR VARTYPE(This.aColors(m.n)) = "L") && Random or not initialized m.lnColor = This._GetRandomColor() CASE m.lnColorType = 2 AND NOT This._UpdateRandomColors && Random RETURN CASE m.lnColorType = 3 && Gradient m.lnColor = This._GetGradientColor(m.n) CASE m.lnColorType = 1 AND NOT EMPTY(This.FieldColor) && Custom m.lnColor = nColor && Retrieve color from Field CASE m.lnColorType = 1 AND EMPTY(This.FieldColor) && Custom IF This._UpdateRandomColors m.lnColor = This._GetRandomColor() ELSE && no need to update, keep using the same prev color RETURN ENDIF CASE m.lnColorType >= 4 m.lnColor = This._GetPaletteColor(m.lnColorType - 4, m.n) OTHERWISE && Custom color and not Line or Area chart ENDCASE This.aColors(m.n) = m.lnColor ENDSCAN ENDIF This._UpdateRandomColors = .F. ENDPROC PROCEDURE _preparedata LOCAL lcAlias, lcLegend, lcDetach, lcColor, lcSliceHidden, lcNumType, lcCast, lcCursor LOCAL lcAxis2 as String, ; lcValue1 as String, ; loExc as Object IF EMPTY(This._DataCursor) OR NOT USED(This._DataCursor) m.lcCursor = "FCharts_" + SYS(2015) This._DataCursor = m.lcCursor ELSE m.lcCursor = This._DataCursor ENDIF IF This.OldStyleProperties LOCAL luValue, n, lcN FOR m.n = 1 TO This.ChartsCount m.lcN = This._Str(m.n) m.luValue = EVALUATE("This.ChartType" + m.lcN) IF NOT EMPTY(m.luValue) This.Fields(m.n).ChartType = m.luValue ENDIF m.luValue = EVALUATE("This.FieldValue" + m.lcN) IF NOT EMPTY(m.luValue) This.Fields(m.n).FieldValue = m.luValue ENDIF m.luValue = EVALUATE("This.Legend" + m.lcN) IF NOT EMPTY(m.luValue) This.Fields(m.n).Legend = m.luValue ENDIF m.luValue = EVALUATE("This.Color" + m.lcN) IF NOT EMPTY(m.luValue) This.Fields(m.n).Color = m.luValue ENDIF m.luValue = EVALUATE("This.Shape" + m.lcN) IF NOT EMPTY(m.luValue) This.Fields(m.n).Shape = m.luValue ENDIF m.luValue = EVALUATE("This.ShowValuesOnShape" + m.lcN) IF This.Fields(m.n).ShowValuesOnShape <> .F. This.Fields(m.n).ShowValuesOnShape = m.luValue ENDIF IF NOT EMPTY(This.FieldxAxis) This.FieldAxis2 = This.FieldxAxis ENDIF ENDFOR ENDIF WITH This m.lcAlias = .SourceAlias m.lcValue1 = .Fields(1).FieldValue m.lcLegend = IIF(EMPTY(.FieldLegend), "SPACE(0)", .FieldLegend) m.lcDetach = IIF(EMPTY(.FieldDetachSlice), ".F.", .FieldDetachSlice) m.lcColor = IIF(EMPTY(.FieldColor), "EVALUATE('00000000')", .FieldColor) m.lcSliceHidden = IIF(EMPTY(.FieldHideSlice), ".F.", .FieldHideSlice) m.lcAxis2 = IIF(EMPTY(.FieldAxis2), "SPACE(0)", .FieldAxis2) ENDWITH IF EMPTY(m.lcAlias) OR EMPTY(m.lcValue1) OR ("CC" <> (VARTYPE(m.lcAlias) + VARTYPE(m.lcValue1))) ERROR "Must specify properties SourceAlias and FieldValue" RETURN .F. ENDIF LOCAL lcFieldType, lnDecimals m.lcFieldType = This._GetFieldType(m.lcAlias, m.lcValue1) m.lnDecimals = VAL(GETWORDNUM(m.lcFieldType, 2, ",")) This._ValueDecimals = m.lnDecimals IF VARTYPE(EVALUATE(m.lcAlias + "." + m.lcValue1)) == "Y" && Currency This._ValueType = This._GetFieldType(m.lcAlias, m.lcValue1) This._ValueFormat = "Y" m.lcNumType = " AS " + This._ValueType m.lcCast = " CAST(" ELSE This._ValueFormat = "N" m.lcNumType = "" m.lcCast = "" ENDIF LOCAL n, lcN, lcSQL, lcNameZ, lcValueZ, lcField m.lcSQL = "" FOR m.n = 1 TO This.ChartsCount m.lcN = This._Str(m.N) m.lcField = This.Fields(m.n).FieldValue m.lcNameZ = m.lcCast + m.lcField + m.lcNumType + IIF(NOT EMPTY(m.lcCast), ") ", "") m.lcSQL = m.lcSQL + m.lcNameZ + " AS nValue" + m.lcN + ", " * The field property cannot be empty. ASSERT (NOT EMPTY(m.lcField)) MESSAGE "Property: Fields(" + m.lcN + ").FieldValue was NOT assigned" ENDFOR SELECT * FROM (This.SourceAlias) INTO CURSOR FCharts_TempData READWRITE TRY SELECT &lcSQL ; &lcLegend AS cLegend, ; &lcDetach AS lDetach, ; &lcColor AS nColor, ; &lcSliceHidden AS lSliceHidden, ; &lcAxis2 AS cAxis2 ; FROM FCharts_TempData ; INTO CURSOR &lcCursor READWRITE CATCH TO m.loExc LOCAL lcVersion, lcError, lcCRLF, lcLine m.lcCRLF = CHR(13) + CHR(10) m.lcError = "FoxCharts Error in the data source passed" + m.lcCRLF + m.lcCRLF + ; [Message: ] + m.loExc.MESSAGE + m.lcCRLF + ; [Details: ] + m.loExc.DETAILS MESSAGEBOX(m.lcError, 16, "FoxCharts error") SELECT &lcSQL ; &lcLegend AS cLegend, ; &lcDetach AS lDetach, ; &lcColor AS nColor, ; &lcSliceHidden AS lSliceHidden, ; &lcAxis2 AS cAxis2 ; FROM FCharts_TempData ; INTO CURSOR &lcCursor READWRITE ENDTRY This._nRecords = _Tally USE IN FCharts_TempData * Empty cursor stop processing IF This._nRecords = 0 RETURN .F. ENDIF SELECT (m.lcCursor) * Prepare the array of points DIMENSION This._aPoints(This._nRecords, 3) && X, Y, Value * Create a DESCENDING index that can be used in some specific chart types INDEX ON RECNO() TAG Revert DESCENDING SET INDEX TO This._SkipPrepareData = .F. This._nMouseonShape = 0 ENDPROC PROCEDURE _preparelegend * Calculate the height of the X Axis SELECT(This._DataCursor) This.XAxis.Reset() LOCAL lcCaption, lnCurrWidth, lnMaxWidth, lnCurrHeight, lnMaxHeight, lnRotation, lnAxis2Height, lnMaxAxis2Width, lnWidth, lnHeight STORE 0 TO m.lnMaxWidth, m.lnMaxHeight, m.lnAxis2Height SCAN m.lcCaption = ALLTRIM(TRANSFORM(cAxis2)) IF NOT EMPTY(m.lcCaption) This.AxisLegend2.Caption = m.lcCaption m.lnCurrWidth = This.AxisLegend2._Width m.lnMaxWidth = MAX(m.lnMaxWidth, m.lnCurrWidth) m.lnCurrHeight = This.AxisLegend2._Height m.lnMaxHeight = MAX(m.lnMaxHeight, m.lnCurrHeight) ENDIF ENDSCAN m.lnMaxAxis2Width = m.lnMaxWidth m.lnAxis2Height = m.lnMaxHeight IF This._Orientation = 1 && Vertical m.lnRotation = This.AxisLegend2.Rotation IF This.AxisLegend2.Alignment = 1 && Right m.lnRotation = 360 - m.lnRotation ENDIF m.lnHeight = (SIN(DTOR(m.lnRotation)) * m.lnMaxAxis2Width) + This.AxisLegend2._Height m.lnHeight = MAX(m.lnAxis2Height, m.lnHeight) ELSE IF This.ShowScale This.ScaleLegend._Value = This._ScaleRange m.lnWidth = This.ScaleLegend._Width m.lnRotation = This.ScaleLegend.Rotation m.lnHeight = (SIN(DTOR(m.lnRotation)) * m.lnWidth) + This.ScaleLegend._Height m.lnAxis2Height = This.ScaleLegend._Height m.lnHeight = MAX(m.lnAxis2Height, m.lnHeight) ELSE m.lnHeight = 0 ENDIF ENDIF This._XAxisHeight = IIF(EMPTY(This.XAxis.Caption), 0, This.XAxis._Height) + ; m.lnHeight + ; This.Margin + This.MarginBottom + ; IIF(INLIST(This.LegendPosition, 8, 9, 10), This._LegendHeight, 0) + ; && Bottom Side 6 This._LegendPixHeight = m.lnHeight RETURN ENDPROC PROCEDURE _preparelegendinslice LPARAMETERS tnX, tnY, tnWidth, tnHeight, tnStart, tnSweep, tnValue, tnDistance IF EMPTY(m.tnDistance) m.tnDistance = MAX(This.PieLegendDistance, 0.10) ENDIF * Calculate the coordinates to draw the Values inside the shapes This._AdjustStartSweep(@m.tnStart, @m.tnSweep, m.tnWidth, m.tnHeight) * Calculate positions LOCAL lnCenterX, lnCenterY m.lnCenterX = (m.tnWidth / 2) m.lnCenterY = (m.tnHeight / 2) * Create a GraphicsPath object. LOCAL lnAngle, lnDistance, xAdjust, yAdjust m.lnAngle = m.tnStart + (m.tnSweep / 2) m.lnDistance = m.tnDistance && This.PieLegendDistance * lnDistance = IIF(EMPTY(tnDistance), 0.75, tnDistance) LOCAL loTempPath as xfcGraphicsPath LOCAL loPoint as xfcPointF LOCAL loRect as xfcRectangle m.loTempPath = _Screen.System.Drawing.Drawing2D.GraphicsPath.New() * Obtaining the needed points m.xAdjust = (1 - m.lnDistance) / 2 m.yAdjust = (1 - m.lnDistance) / 2 m.loRect = _Screen.System.Drawing.Rectangle.New(m.tnX + m.xAdjust * m.tnWidth, ; m.tnY + m.yAdjust * m.tnHeight, ; m.lnDistance * m.tnWidth, ; m.lnDistance * m.tnHeight) m.loTempPath.AddArc(m.loRect, m.lnAngle, 0.0001) m.loPoint = m.loTempPath.GetLastPoint() * Send back the coordinates m.tnX = m.loPoint.X m.tnY = m.loPoint.Y RETURN ENDPROC PROCEDURE _preparesidelegend *!* Property LegendPosition *!* Numeric, *!* Determines the position where the side legend wiil be drawn in the canvas. *1* 0 - No Legend *!* 1 - Vertical Top Left *!* 2 - Vertical Bottom Left *!* 3 - Vertical Top Right *!* 4 - Vertical Bottom Right *!* 5 - Horiz Top Left *!* 6 - Horiz Top Center *!* 7 - Horiz Top Right *!* 8 - Horiz Bottom Left *!* 9 - Horiz Bottom Center *!* 10 - Horiz Bottom Right *!* 11 - Vertical Center Left LOCAL lnChartsCount m.lnChartsCount = This.ChartsCount IF This.ChartType = 17 && Paired Bars m.lnChartsCount = MIN(2, m.lnChartsCount) ENDIF LOCAL lnScale2W m.lnScale2W = 0 IF This._MaxScale2 > 0 LOCAL lnScale2W, lcCaption IF NOT EMPTY(This.ScaleLegend._ForceFormat) m.lcCaption = This._ScaleLegAxis2ForceFormat ELSE m.lcCaption = TRANSFORM(This._MaxScale2, This.ScaleLegend.Format) ENDIF This.ScaleLegend.Caption = m.lcCaption m.lnScale2W = This.ScaleLegend._Width This._Axis2ScaleWidth = m.lnScale2W ENDIF IF NOT This.ShowSideLegend OR This.LegendPosition = 0 This._LegendWidth = MAX(5, (This.Margin + This.MarginRight)) This._LegendHeight = 0 This._TopOffSet = This.Margin + This.MarginTop + This._TitleHeight This._LeftOffset = This.Margin + This.MarginLeft This._RightOffSet = This.Margin + This.MarginRight + m.lnScale2W * Leaving some extra space for the X Axis legends IF NOT EMPTY(This.FieldAxis2) AND This._AllowAxis * Measure the legend width This.AxisLegend2._Setup() * Last legend GO BOTTOM LOCAL ln3D IF This._DeepChart && Point, Line or Area m.ln3D = This._3D * m.lnChartsCount ELSE m.ln3D = This._3D ENDIF This.AxisLegend2.Caption = cAxis2 && Field text IF m.ln3D < (This.AxisLegend2._Width / 2) This._RightOffSet = This._RightOffSet + (This.AxisLegend2._Width / 2) - m.ln3D ENDIF ENDIF RETURN ENDIF SELECT(This._DataCursor) This.SideLegend.Caption = "12" This.SideLegend.Reset() LOCAL lnCurrWidth, lnMaxWidth, lnCurrHeight, lnMaxHeight, lnLegendHeight, lnLegendPosition, n LOCAL loFont as xfcFont LOCAL loSize as xfcSize m.loFont = This.SideLegend._oFont m.lnMaxWidth = 0 m.lnMaxHeight = 0 m.lnLegendPosition = This.LegendPosition * Measure the maximum legend width IF This.SingleData DIMENSION This._aSideLegends(This._nRecords, 2) SCAN m.n = RECNO() m.lcCaption = TRANSFORM(cLegend) IF This.LegendHideWhenNull IF ISNULL(This._GetValue(This.ChartRow, .T.)) && Accept NULLs m.lcCaption = "" ENDIF ENDIF m.loSize = This.oGfx.MeasureString(m.lcCaption, m.loFont) m.lnCurrWidth = m.loSize.Width m.lnMaxWidth = Max(m.lnMaxWidth, m.lnCurrWidth) m.lnCurrHeight = m.loSize.Height m.lnMaxHeight = Max(m.lnMaxHeight, m.lnCurrHeight) This._aSideLegends(m.n, 1) = m.lcCaption This._aSideLegends(m.n, 2) = m.lnCurrWidth ENDSCAN GO TOP ELSE DIMENSION This._aSideLegends(m.lnChartsCount, 2) FOR m.n = 1 To m.lnChartsCount m.lcCaption = TRANSFORM(This.Fields(m.n).Legend) m.loSize = This.oGfx.MeasureString(m.lcCaption, m.loFont) m.lnCurrWidth = m.loSize.Width m.lnMaxWidth = Max(m.lnMaxWidth, m.lnCurrWidth) m.lnCurrHeight = m.loSize.Height m.lnMaxHeight = Max(m.lnMaxHeight, m.lnCurrHeight) This._aSideLegends(m.n, 1) = m.lcCaption This._aSideLegends(m.n, 2) = m.lnCurrWidth NEXT m.n ENDIF DO CASE CASE INLIST(m.lnLegendPosition, 1, 2, 11) && Left Side This._LegendWidth = m.lnMaxWidth + m.lnMaxHeight + This._LegendExternalMargin * 2 This._LegendHeight = 0 This._LeftOffset = This.Margin + This.MarginLeft + This._LegendWidth This._RightOffSet = This.Margin + This.MarginRight + m.lnScale2W This._TopOffSet = This.Margin + This.MarginTop + This._TitleHeight CASE INLIST(m.lnLegendPosition, 3, 4, 12) && Right Side (Default) This._LegendWidth = m.lnMaxWidth + m.lnMaxHeight + This._LegendExternalMargin This._LegendHeight = 0 This._LeftOffset = This.Margin + This.MarginLeft This._RightOffSet = This.Margin + This.MarginRight + This._LegendWidth + m.lnScale2W This._TopOffSet = This.Margin + This.MarginTop + This._TitleHeight CASE INLIST(m.lnLegendPosition, 5, 6, 7) && Top Side This._LegendWidth = 0 This._LegendHeight = m.lnMaxHeight + (This._LegendExternalMargin * 2) This._LeftOffset = This.Margin + This.MarginLeft This._RightOffSet = This.Margin + This.MarginRight + m.lnScale2W This._TopOffSet = This.Margin + This.MarginTop + This._TitleHeight + This._LegendHeight CASE INLIST(m.lnLegendPosition, 8, 9, 10) && Bottom Side This._LegendWidth = 0 This._LegendHeight = m.lnMaxHeight + (This._LegendExternalMargin * 2) This._LeftOffset = This.Margin + This.MarginLeft This._RightOffSet = This.Margin + This.MarginRight + m.lnScale2W This._TopOffSet = This.Margin + This.MarginTop + This._TitleHeight OTHERWISE ENDCASE ENDPROC PROCEDURE _preparetitle LOCAL lnTitleHeight, lnSubTitleHeight, lnTitleColor STORE 0 TO m.lnTitleHeight, m.lnSubTitleHeight * Check if Title was assigned IF NOT EMPTY(This.Title.Caption) This.Title.Reset() This.Title._DrawString(0, This.Margin + This.MarginTop, This.ChartCanvas.Width, This.ChartCanvas.Height) m.lnTitleHeight = This.Title._height ENDIF * Check if SubTitle was assigned IF NOT EMPTY(This.SubTitle.Caption) This.SubTitle.Reset() This.SubTitle._DrawString(0, This.Margin + This.MarginTop + m.lnTitleHeight, This.ChartCanvas.Width, This.ChartCanvas.Height) m.lnSubTitleHeight = This.SubTitle._Height ENDIF This._TitleHeight = m.lnTitleHeight + m.lnSubTitleHeight RETURN ENDPROC PROCEDURE _preparetooltip IF NOT This.ShowTips OR NOT This._InsideForm RETURN ENDIF LOCAL loTip as Label m.loTip = This.ToolTip * Add the tooltips object to the form IF NOT PEMSTATUS(Thisform, "FoxChartsToolTip", 5) Thisform.AddObject("FoxChartsToolTip", "Label") ENDIF WITH Thisform.FoxChartsToolTip as Label .Alignment = m.loTip.Alignment .Autosize = m.loTip.AutoSize .BackColor = m.loTip.BackColor .BackStyle = m.loTip.BackStyle .BorderStyle = m.loTip.BorderStyle .FontBold = m.loTip.FontBold .FontItalic = m.loTip.FontItalic .FontName = m.loTip.FontName .FontSize = m.loTip.FontSize .FontStrikethru = m.loTip.FontStrikethru .FontUnderline = m.loTip.FontUnderline .ForeColor = m.loTip.ForeColor .WordWrap = m.loTip.WordWrap .ZOrder(0) ENDWITH BINDEVENT(Thisform.FoxChartsToolTip, "MouseMove", This.ToolTip, "MouseMove") ENDPROC PROCEDURE _preparevariables LOCAL lnSumValue as Number, ; loExc as Object *TRY SELECT(This._DataCursor) This._HasNegatives = .F. LOCAL lnValue DO CASE CASE INLIST(This.ChartType, 9, 10, 14) && Stacked Bars or Stacked Area * Get the maximum value of the chart Local i, lnTotal, lnMaxValue, lnMinValue m.lnMaxValue = 0 Scan m.lnTotal = 0 For m.i = 1 To This.ChartsCount m.lnValue = This._GetValue(m.i) IF m.lnValue < 0 This._HasNegatives = .T. ENDIF m.lnTotal = m.lnTotal + m.lnValue Endfor If Recno() = 1 m.lnMinValue = m.lnTotal Else m.lnMinValue = Min(m.lnMinValue, m.lnTotal) Endif m.lnMaxValue = Max(m.lnMaxValue, m.lnTotal) Endscan Case This.SingleData Local lnMaxValue, lcField, lnMinValue m.lcField = (This._DataCursor) + ".nValue" + This._Str(This.ChartRow) Calculate Max (&lcField.) To m.lnMaxValue for not IsNull (&lcField.) Calculate Min (&lcField.) To m.lnMinValue for not IsNull (&lcField.) Calculate Sum (&lcField.) To m.lnSumValue for Nvl(&lcField. , 0) > 0 This.ChartSum = m.lnSumValue CASE This.ChartType = 18 && Double Axis lines *!* 2Axis *!* This.Fields(n).AxisIndex = 2 * Get the maximum value of the chart * Start with the 2nd axis Local lnMaxValue, lnMaxValue1, i, lcField, lnRealChartsCount, lnMinValue, lnMinValue1 m.lnMaxValue = 0 m.lnRealChartsCount = This.ChartsCount LOCAL llHas2Axis && Used to make sure we have data on the 2nd Y axis m.llHas2Axis = .F. FOR m.i = 1 To m.lnRealChartsCount IF This.Fields(m.i).AxisIndex = 1 LOOP ENDIF m.llHas2Axis = .T. m.lcField = (This._DataCursor) + ".nValue" + This._Str(m.i) Calculate Max (&lcField.) To m.lnMaxValue1 for not IsNull (&lcField.) Calculate Min (&lcField.) To m.lnMinValue1 for not IsNull (&lcField.) * CCHALOM 2013-02-21 * Fix in obtaining the Minimum value IF VARTYPE(m.lnMinValue) <> "N" m.lnMinValue = m.lnMinValue1 ENDIF IF m.lnMinValue1 < 0 This._HasNegatives = .T. ENDIF If m.i = 1 m.lnMaxValue = m.lnMaxValue1 m.lnMinValue = m.lnMinValue1 Else m.lnMaxValue = Max(m.lnMaxValue, m.lnMaxValue1) * CCHALOM 2013-02-21 * Fix in obtaining the Minimum value m.lnMinValue = Min(m.lnMinValue, m.lnMinValue1) Endif Endfor IF m.llHas2Axis This._CalculateScale(m.lnMaxValue, m.lnMinValue, 2) This._ScaleLegend2ForceFormat = This.ScaleLegend._ForceFormat * CCHALOM 2013-02-21 * Fix in getting a nice Scale legend format for both axes * New properties inserted: _ScaleLegAxis1ForceFormat , _ScaleLegAxis2ForceFormat This._ScaleLegAxis2ForceFormat = This.ScaleLegend._ForceFormat ENDIF * Do the same for the 1st axis * Get the maximum value of the chart m.lnMaxValue = 0 For m.i = 1 To m.lnRealChartsCount IF This.Fields(m.i).AxisIndex = 2 LOOP ENDIF m.lcField = (This._DataCursor) + ".nValue" + This._Str(m.i) Calculate Max (&lcField.) To m.lnMaxValue1 for not IsNull (&lcField.) Calculate Min (&lcField.) To m.lnMinValue1 for not IsNull (&lcField.) IF m.lnMinValue1 < 0 This._HasNegatives = .T. ENDIF If m.i = 1 m.lnMaxValue = m.lnMaxValue1 m.lnMinValue = m.lnMinValue1 Else m.lnMaxValue = Max(m.lnMaxValue, m.lnMaxValue1) m.lnMinValue = Min(m.lnMinValue, m.lnMinValue1) Endif Endfor OTHERWISE * Get the maximum value of the chart Local lnMaxValue, lnMaxValue1, i, lcField, lnRealChartsCount, lnMinValue, lnMinValue1 m.lnMaxValue = 0 m.lnRealChartsCount = Iif(Inlist(This.ChartType, 1,2,7,12),1,This.ChartsCount) For m.i = 1 To m.lnRealChartsCount m.lcField = (This._DataCursor) + ".nValue" + This._Str(m.i) Calculate Max (&lcField.) To m.lnMaxValue1 for not IsNull (&lcField.) Calculate Min (&lcField.) To m.lnMinValue1 for not IsNull (&lcField.) IF VARTYPE(m.lnMinValue) <> "N" m.lnMinValue = m.lnMinValue1 ENDIF IF m.lnMinValue1 < 0 This._HasNegatives = .T. ENDIF If m.i = 1 m.lnMaxValue = m.lnMaxValue1 m.lnMinValue = m.lnMinValue1 Else m.lnMaxValue = Max(m.lnMaxValue, m.lnMaxValue1) m.lnMinValue = Min(m.lnMinValue, m.lnMinValue1) Endif Endfor Endcase This._CalculateScale(m.lnMaxValue, m.lnMinValue) * CCHALOM 2013-02-21 * Fix in getting a nice Scale legend format for both axes * New properties inserted: _ScaleLegAxis1ForceFormat , _ScaleLegAxis2ForceFormat This._ScaleLegAxis1ForceFormat = This.ScaleLegend._ForceFormat DIMENSION This._aShapes(This.ChartsCount,3) This._aShapes = "" IF NOT This._Using3D This._3D = This.Depth ENDIF ** CATCH TO m.loExc ** SET STEP ON ** ENDTRY ENDPROC PROCEDURE _ps LPARAMETERS tcPrp, toCtrl, tnType LOCAL lcExpr as String DO CASE CASE m.tnType = 1 && GETCOLOR LOCAL luOrig,lnClr,lcRet m.lcExpr = EVAL("toCtrl."+m.tcPrp) IF VARTY(m.lcExpr)="C" IF LEFT(m.lcExpr,1) = "=" m.lcExpr=EVALUATE(STRTR(m.lcExpr,"=","",1,1)) ELSE m.lcExpr = 0 ENDIF ENDIF m.luOrig = EVL(m.lcExpr, 0) m.lnClr = GETCOLOR(m.luOrig) m.lnClr = IIF(m.lnClr=-1,m.luOrig,m.lnClr) m.lcRet = TEXTMERGE( ; "<>,<>,<>") m.toCtrl.WRITEEXPRESSION(m.tcPrp, "") STORE m.lcRet TO ("toCtrl." + m.tcPrp) OTHERWISE ENDCASE ENDPROC PROCEDURE _setfieldscount LPARAMETERS tnCnt LOCAL loData *--MW-->The stock method handled adding fields to the collection but not removing them. IF This.Fields.Count <> m.tnCnt LOCAL lnIncr, lnFieldNo m.lnIncr = m.tnCnt - This.Fields.Count DO WHILE This.Fields.Count <> m.tnCnt IF m.lnIncr > 0 *--Adding fields m.loData = This._NewField() This.Fields.Add(m.loData) ELSE *--Removing fields m.lnFieldNo = This.Fields.Count This.Fields.Remove(m.lnFieldNo) ENDIF ENDDO *--Make sure the ChartsCount matches. This.ChartsCount = m.tnCnt ENDIF ENDPROC PROCEDURE _spellproperty LPARAMETERS tcProperty * Returns upper/lower case name of property LOCAL lcList, lnPos IF EMPTY(This._SpellingList) m.lcList = ".AlphaChannel.Area3dTop.AreaDrawBorders.AxisAlpha.AxisColor.AxisLegend2.Alignment.BackColor.BackColorAlpha.FontBold" m.lcList = m.lcList + ".FontCharSet.FontItalic.FontName.FontSize.FontUnderline.ForeColor.ForeColorAlpha.Format.Rotation.BackColor2.BackGradientMode" m.lcList = m.lcList + ".BarsPerScale.BarsSpaceBetween.BarType.BrushType.ChangeColorOnMouse.ChartRow.ChartsCount.ChartType" m.lcList = m.lcList + ".ColorType.Depth.DonutRatio.FieldAxis2.FieldColor.FieldDetachSlice.FieldHideSlice.FieldLegend.Fields.Color" m.lcList = m.lcList + ".FieldValue.Legend.Shape.Gradientlevel.LegendHideWhenNull.LineCaps.Margin" m.lcList = m.lcList + ".MarginBottom.MarginLeft.MarginRight.MarginTop.MaxValue.MinNumberScaleLegends.MinValue.MultiChart.OldStyleProperties" m.lcList = m.lcList + ".PieCompensateAngles.PieDetachAnimationSteps.PieDetachPixels.PieDetachSliceOnClick.PieEnhancedDrawing.PieShowPercent" m.lcList = m.lcList + ".PointShapeWidth.Scale.ScaleBackAlpha.ScaleBackBarsType.ScaleBackColor.ScaleBackLinesDash.ScaleBackLinesType" m.lcList = m.lcList + ".ScaleBackLinesWidth.ScaleLegend.ScaleLineColor.ScaleLineZeroColor.ScaleStartValue.SelectedShapeColor.Shape1" m.lcList = m.lcList + ".ShapeLegend.ShowAxis.ShowLineZero.ShowScale.ShowSideLegend.ShowTips.ShowValuesOnShapes.ShowValueZero.SideLegend" m.lcList = m.lcList + ".SourceAlias.SubTitle.Title.XAxis.YAxis.YAxis2.Caption" * Add the new Properties since version 1.00RC m.lcList = m.lcList + ".GradientInvertColors.GradientPosition.GradientShapeDirection.GradientType.PieGradCenterAngle" m.lcList = m.lcList + ".PieGradCenterDistance.ScaleDivider.Shadow.ShapeMousePointer.LegendPosition" m.lcList = m.lcList + ".Debug.ScaleAutoFormat.ShowValuesOnShape.ShowValuesOnShapes.BarLegendDirection" m.lcList = m.lcList + ".QualityCompositing.QualitySmoothing.QualityTextRenderingHint.BarLegendType" m.lcList = m.lcList + ".LineCapsShape.PieDetachSliceOnLegendClick.MultiChartMargin.BarLegendDirection" m.lcList = m.lcList + ".PieForceCircle.RotationCenter" m.lcList = m.lcList + ".PieLegendDistance.ShapeLegendExpression.ShowAxis2Tics.TicLength" m.lcList = m.lcList + ".PieDirection.Width.Height.ShowPercentages" This._spellinglist = m.lcList ENDIF m.lnPos = ATCC("." + UPPER(m.tcProperty) + ".", This._spellinglist + ".") IF m.lnPos # 0 RETURN SUBSTR(This._spellingList, m.lnPos + 1, LEN(m.tcProperty)) ELSE RETURN m.tcProperty ENDIF ENDPROC PROCEDURE _str LPARAMETERS tnValue RETURN ALLTRIM(STR(m.tnValue,2,0)) ENDPROC PROCEDURE _updatechartinfo *!* Chart Type Values: *!* 1 - Pie *!* 2 - Doughnut *!* 3 - Full-Stacked Bars *!* 4 - Points *!* 5 - Lines *!* 6 - Area *!* 7 - Simple Bars *!* 8 - Multiple Bars *!* 9 - Stacked Bars *!* 10 - Stacked Area *!* 11 - 3D Bars *!* 12 - Horiz. Simple Bars *!* 13 - Horiz. Multiple Bars *!* 14 - Horiz. Stacked Bars *!* 15 - Horiz. Full-Stacked Bars *!* 16 - Full-Stacked Area *!* 17 - Paired Bars *!* 18 - Double-Axis Lines LOCAL lnChart, llDeep, llAxis, llSingleData, lnOrientation, llFullStacked, ; llAbsoluteScale, llChartsCount, llScalePercent Local lcType as String, ; llStacked as Boolean, ; llUseAxis as Boolean m.lnChart = This.ChartType DO CASE CASE m.lnChart = 1 && Pie m.llDeep = .F. m.llAxis = .F. m.llSingleData = .T. m.lcType = "Pie" m.lnOrientation = 1 && Vertical m.llUseAxis = .F. m.llFullStacked = .T. m.llStacked = .F. m.llAbsoluteScale = .F. m.llScalePercent = .F. CASE m.lnChart = 2 && Doughnut m.llDeep = .F. m.llAxis = .F. m.llSingleData = .T. m.lcType = "Pie" m.lnOrientation = 1 && Vertical m.llUseAxis = .F. m.llFullStacked = .T. m.llStacked = .F. m.llAbsoluteScale = .F. m.llScalePercent = .F. CASE m.lnChart = 4 && Point m.llDeep = .T. m.llAxis = .T. m.llSingleData = .F. m.lcType = "Point" m.lnOrientation = 1 && Vertical m.llUseAxis = .T. m.llFullStacked = .F. m.llStacked = .F. m.llAbsoluteScale = .F. m.llScalePercent = .F. CASE INLIST(m.lnChart, 5, 18) && Line m.llDeep = .T. m.llAxis = .T. m.llSingleData = .F. m.lcType = "Point" m.lnOrientation = 1 && Vertical m.llUseAxis = .T. m.llFullStacked = .F. m.llStacked = .F. m.llAbsoluteScale = .F. m.llScalePercent = .F. CASE m.lnChart = 6 && Area m.llDeep = .T. m.llAxis = .T. m.llSingleData = .F. m.lcType = "Point" m.lnOrientation = 1 && Vertical m.llUseAxis = .T. m.llFullStacked = .F. m.llStacked = .F. m.llAbsoluteScale = .F. m.llScalePercent = .F. CASE m.lnChart = 7 && Simple Bar m.llDeep = .F. m.llAxis = .T. m.llSingleData = .T. m.lcType = "Bar" m.lnOrientation = 1 && Vertical m.llUseAxis = .T. m.llFullStacked = .T. m.llStacked = .F. m.llAbsoluteScale = .F. m.llScalePercent = .F. CASE m.lnChart = 8 && Multiple Bars m.llDeep = .F. m.llAxis = .T. m.llSingleData = .F. m.lcType = "Bar" m.lnOrientation = 1 && Vertical m.llUseAxis = .T. m.llFullStacked = .T. m.llStacked = .F. m.llAbsoluteScale = .F. m.llScalePercent = .F. CASE m.lnChart = 9 && Stacked Bars m.llDeep = .F. m.llAxis = .T. m.llSingleData = .F. m.lcType = "Bar" m.lnOrientation = 1 && Vertical m.llUseAxis = .T. m.llFullStacked = .F. m.llStacked = .T. m.llAbsoluteScale = .F. m.llScalePercent = .F. CASE m.lnChart = 10 && Stacked Area m.llDeep = .F. m.llAxis = .T. m.llSingleData = .F. m.lcType = "Point" m.lnOrientation = 1 && Vertical m.llUseAxis = .T. m.llFullStacked = .T. m.llStacked = .T. m.llAbsoluteScale = .F. m.llScalePercent = .F. CASE m.lnChart = 11 && 3d Bars m.llDeep = .T. m.llAxis = .T. m.llSingleData = .F. m.lcType = "Bar" m.lnOrientation = 1 && Vertical m.llUseAxis = .T. m.llFullStacked = .F. m.llStacked = .F. m.llAbsoluteScale = .F. m.llScalePercent = .F. CASE m.lnChart = 12 && Horizontal Bars m.llDeep = .F. m.llAxis = .T. m.llSingleData = .T. m.lcType = "Bar" m.lnOrientation = 2 && Horizontal m.llUseAxis = .T. m.llFullStacked = .T. m.llStacked = .F. m.llAbsoluteScale = .F. m.llScalePercent = .F. CASE m.lnChart = 13 && Horizontal Multiple Bars m.llDeep = .F. m.llAxis = .T. m.llSingleData = .F. m.lcType = "Bar" m.lnOrientation = 2 && Horizontal m.llUseAxis = .T. m.llFullStacked = .T. m.llStacked = .F. m.llAbsoluteScale = .F. m.llScalePercent = .F. CASE m.lnChart = 14 && Horizontal Stacked Bars m.llDeep = .F. m.llAxis = .T. m.llSingleData = .F. m.lcType = "Bar" m.lnOrientation = 2 && Horizontal m.llUseAxis = .T. m.llFullStacked = .F. m.llStacked = .T. m.llAbsoluteScale = .F. m.llScalePercent = .F. CASE m.lnChart = 3 && Full-Stacked Bars m.llDeep = .F. m.llAxis = .T. m.llSingleData = .F. m.lcType = "Bar" m.lnOrientation = 1 && Vertical m.llUseAxis = .T. m.llFullStacked = .T. m.llStacked = .T. m.llAbsoluteScale = .F. m.llScalePercent = .T. CASE m.lnChart = 15 && Horizontal Full-Stacked Bars m.llDeep = .F. m.llAxis = .T. m.llSingleData = .F. m.lcType = "Bar" m.lnOrientation = 2 && Horizontal m.llUseAxis = .T. m.llFullStacked = .T. m.llStacked = .F. m.llAbsoluteScale = .F. m.llScalePercent = .T. CASE m.lnChart = 16 && Full-Stacked Area m.llDeep = .F. m.llAxis = .T. m.llSingleData = .F. m.lcType = "Point" m.lnOrientation = 1 && Vertical m.llUseAxis = .T. m.llFullStacked = .T. m.llStacked = .T. m.llAbsoluteScale = .F. m.llScalePercent = .T. CASE m.lnChart = 17 && Paired Bars m.llDeep = .F. m.llAxis = .T. m.llSingleData = .F. m.lcType = "Bar" m.lnOrientation = 2 && Horizontal m.llUseAxis = .T. m.llFullStacked = .T. && F m.llStacked = .F. m.llAbsoluteScale = .T. m.llScalePercent = .F. OTHERWISE * ERROR "Chart type " + TRANSFORM(lnChart) + " does not exist" ENDCASE This._DeepChart = m.llDeep This._AllowAxis = m.llAxis This.SingleData = m.llSingleData This._GeneralType = m.lcType This._Orientation = m.lnOrientation This._UseAxis = m.llUseAxis This._SumRow = m.llFullStacked This._STACKED = m.llStacked This._AbsoluteScaleValues = m.llAbsoluteScale This._ScaleInPercent = m.llScalePercent * Clear the chart coodinates IF NOT This._InReport This.aCoord = .F. ENDIF This._nIndex = 0 This.ShapeLegend._ForceFormat = "" ENDPROC PROCEDURE _updatecoordinates LPARAMETERS tcObjType, tnX, tnY, tnWidth, tnHeight, tnValue, tnStart, tnSweep *** SumofTheRow SELECT (This._DataCursor) * During DrawReport(), there's no need to update the coordinates *!* IF This._InReport *!* RETURN *!* ENDIF *!* IF NOT This.ShowTips *!* RETURN *!* ENDIF LOCAL n m.n = This._nIndex + 1 This._nIndex = m.n DIMENSION This.aCoord(m.n,12) This.aCoord(m.n,1) = m.tnX This.aCoord(m.n,2) = m.tnY This.aCoord(m.n,3) = m.tnWidth This.aCoord(m.n,4) = m.tnHeight This.aCoord(m.n,5) = m.tnValue * This.aCoord(n,6) = Legend This.aCoord(m.n,7) = m.tnStart This.aCoord(m.n,8) = m.tnSweep This.aCoord(m.n,9) = This._ChartIndex && ChartRow IF m.tcObjType = "Legend" && on "Legend" mode, tnValue passes the index This.aCoord(m.n,10) = IIF(NOT EMPTY(This._Currentrow), This._CurrentRow, m.tnValue) This.aCoord(m.n,6) = IIF(VARTYPE(m.tnStart) = "C", m.tnStart, "") ELSE This.aCoord(m.n,10) = IIF(NOT EMPTY(This._Currentrow), This._CurrentRow, RECNO()) LOCAL lcLegend IF This.SingleData && Pie, Donut or Single Bar m.lcLegend = cLegend ELSE m.lcLegend = This.Fields(This._ChartIndex).Legend ENDIF This.aCoord(m.n,6) = ALLTRIM(TRANSFORM(m.lcLegend)) ENDIF This.aCoord(m.n,11) = m.tcObjType This.aCoord(m.n,12) = IIF(m.tcObjType = "Rect" and not EMPTY(m.tnStart), m.tnStart, 0) && Sum of the current row ENDPROC PROCEDURE _updatequality LOCAL loCanvas as xfcImgCanvas OF "GdiPlusX.vcx" m.loCanvas = This.ChartCanvas m.loCanvas.SmoothingMode = This.QualitySmoothing m.loCanvas.TextRenderingHint = This.QualityTextRenderingHint m.loCanvas.oGfx.CompositingQuality = This.QualityCompositing ENDPROC PROCEDURE ChartCanvas.activate DODEFAULT() This.Parent._GetRelativePositions() ENDPROC PROCEDURE ChartCanvas.beforedraw This.Parent._BeforeDraw() ENDPROC PROCEDURE ChartCanvas.Click LOCAL lnValue, lcLegend, lcObjType, lnCoordIndex lnCoordIndex = 0 LOCAL lnX, lnY lnX = MCOL(0,3) lnY = MROW(0,3) This.Parent._CheckMousePosition(0, 0, lnX, lnY, @lnValue, @lcLegend, @lnCoordIndex, @lcObjType) This.Parent.CurrValue = lnValue This.Parent.CurrLegend = lcLegend This.Parent.CurrIndex = lnCoordIndex This.Parent.CurrObjType = lcObjType This.Parent.Click() RETURN ENDPROC PROCEDURE ChartCanvas.DblClick LOCAL lnValue, lcLegend, lcObjType, lnCoordIndex, lnX, lnY lnCoordIndex = 0 lnX = MCOL(0,3) lnY = MROW(0,3) **12.4.2013 KP: changed parameters - set tcLegend *!*Lparameters tnButton, tnShift, tnXCoord, tnYCoord, tlnValue, tcLegend, tlnCoordIndex, tlcObjType This.Parent._CheckMousePosition(0, 0, lnX, lnY, @lnValue, '', @lnCoordIndex, @lcObjType) This.Parent.CurrIndex = lnCoordIndex This.Parent.DblClick() RETURN ENDPROC PROCEDURE ChartCanvas.Destroy IF NOT EMPTY(This.Parent._DataCursor) AND USED(This.Parent._DataCursor) USE IN (This.Parent._DataCursor) ENDIF DODEFAULT() ENDPROC PROCEDURE ChartCanvas.Init This.Width = This.Parent.Width This.Height = This.Parent.Height DODEFAULT() ENDPROC PROCEDURE ChartCanvas.MouseLeave LPARAMETERS nButton, nShift, nXCoord, nYCoord Thisform.FoxChartsToolTip.Visible = .F. WITH This.Parent IF .ChangeColoronMouse AND ; (NOT BETWEEN(.Left, nXCoord - .Left, .Width - .Left) AND ; NOT BETWEEN(.Top , nXCoord - .Top , .Height - .Top )) ._nMouseOnShape = 0 ._SkipPrepareData = .T. IF ._Drawing = .F. .DrawChart() ELSE ._Redraw = .T. ENDIF ENDIF ENDWITH ENDPROC PROCEDURE ChartCanvas.MouseMove LPARAMETERS nButton, nShift, nXCoord, nYCoord LOCAL lnValue, lcLegend, lcObjType, lnCoordIndex m.lnCoordIndex = 0 WITH This.Parent ._CheckMousePosition(nButton, nShift, nXCoord, nYCoord, @lnValue, @lcLegend, @lnCoordIndex, @lcObjType) * Update the index property, that will allow all the other "curr"properties to be up to date This.Parent.Currindex = lnCoordIndex * Prepare the ToolTips LOCAL lcType m.lcType = VARTYPE(m.lnValue) + VARTYPE(m.lcLegend) LOCAL loTip as Label m.loTip = Thisform.FoxChartsToolTip IF m.lcType <> "NC" m.loTip.Visible = .F. This.MousePointer = ._OrigMousePointer && = 0 && Default ELSE IF .ShowTips .ShapeToolTip(nButton, nShift, nXCoord, nYCoord, m.lnValue, m.lcLegend, m.lnCoordIndex, m.lcObjType) * Fix by Christof Wollenhaupt * WorkItem #20978 * http://www.codeplex.com/VFPX/WorkItem/View.aspx?WorkItemId=20978 * * IF TYPE("_Screen.ActiveForm") == "O" AND ; (_Screen.ActiveForm = Thisform) AND ; NOT EMPTY(m.loTip.Caption) IF TYPE("_Screen.ActiveForm") == "O" AND ; NOT EMPTY(m.loTip.Caption) LOCAL lnLeft, lnTop, lnWidth, lnHeight, lnX, lnY lnX = m.nXCoord lnY = m.nYCoord m.lnWidth = m.loTip.Width m.lnHeight = m.loTip.Height m.lnLeft = lnX + 1 IF m.lnLeft + m.lnWidth > Thisform.Width m.lnLeft = Thisform.Width - m.lnWidth ENDIF m.lnTop = lnY - m.lnHeight - 1 IF m.lnTop < 0 m.lnTop = 0 ENDIF m.loTip.Left = m.lnLeft m.loTip.Top = m.lnTop IF m.loTip.Visible = .F. m.loTip.Visible = .T. ENDIF ELSE m.loTip.Visible = .F. ENDIF ENDIF ENDIF m.lcObjType = IIF(EMPTY(m.lcObjType),"", m.lcObjType) m.lcLegend = IIF(EMPTY(m.lcLegend),"", m.lcLegend) .MouseMove(nButton, nShift, nXCoord, nYCoord, m.lnValue, m.lcLegend, m.lnCoordIndex, m.lcObjType) ENDWITH RETURN ENDPROC PROCEDURE ChartCanvas.MouseUp LPARAMETERS nButton, nShift, nXCoord, nYCoord LOCAL lnValue, lcLegend, lcObjType, lnCoordIndex lnCoordIndex = 0 This.Parent._CheckMousePosition(nButton, nShift, nXCoord, nYCoord, @lnValue, @lcLegend, @lnCoordIndex, @lcObjType) * Update the index property, that will allow all the other "curr"properties to be up to date This.Parent.Currindex = lnCoordIndex This.Parent.MouseUp(nButton, nShift, nXCoord, nYCoord, lnValue, lcLegend, lnCoordIndex, lcObjType) IF This.Parent._GeneralType = "Pie" IF lcObjType = "Pie" AND This.Parent.PieDetachSliceonClick This.Parent._DetachClickedSlice(lnCoordIndex) ENDIF IF lcObjType = "Legend" AND This.Parent.PieDetachSliceonLegendClick This.Parent._DetachClickedSlice(lnCoordIndex) ENDIF ENDIF RETURN ENDPROC PROCEDURE ScaleLegend._updatemeasures LPARAMETERS tlNumeric IF VARTYPE(This.Parent.oGfx) <> "O" RETURN ENDIF * Measure the Legend height IF VARTYPE(This._oBrush) + VARTYPE(This._oFont) <> "OO" OR (This._initialized = .F.) This._Setup() ENDIF LOCAL lcCaption, lcFormat * _ForceFormat is a forced formatting managed directly from FoxCharts lcFormat = IIF(EMPTY(ALLTRIM(This._ForceFormat)), This.Format, ALLTRIM(This._ForceFormat)) IF tlNumeric lcCaption = ALLTRIM(TRANSFORM(This._Value, lcFormat)) ELSE lcCaption = This.Caption ENDIF LOCAL loSize as xfcSize IF NOT EMPTY(lcCaption) && Modified by Paul Newton 12 Jul 2010 loSize = This.Parent.oGfx.MeasureString(lcCaption, This._oFont) &&, This._oStringFormat) This._Height = loSize.Height This._Width = loSize.Width ELSE This._Height = 0 This._Width = 0 ENDIF This._TransfCaption = lcCaption ENDPROC PROCEDURE ShapeLegend.caption_assign lparameters tcText This.Caption = tcText This._UpdateMeasures() ENDPROC PROCEDURE ShapeLegend._drawstring LPARAMETERS tnX, tnY, tnWidth, tnHeight, tlVertical LOCAL x1, y1, lnAlign, lnMode, xBack, llBar llBar = IIF(This.Parent.Name = "ShapeLegend",.T., .F.) lnMode = 0 && 0 = x,y Coordinates ; 1 = xfcRectangle coordinates lnAlign = This.Alignment * 0 = Left 1 = Right 2 = Center LOCAL loGfx as xfcGraphics loGfx = This.Parent.oGfx WITH _Screen.System.Drawing DO CASE CASE VARTYPE(tnWidth) + VARTYPE(tnHeight) = "NN" lnMode = 1 * Create a STRINGFORMAT object in order to draw the string centered in the image LOCAL loStringFmt as xfcStringFormat LOCAL lnGdipAlign loStringFmt = .StringFormat.New() DO CASE CASE lnAlign = 2 && Center lnGdipAlign = .StringAlignment.Center CASE lnAlign = 1 lnGdipAlign = .StringAlignment.Far OTHERWISE lnGdipAlign = .StringAlignment.Near ENDCASE loStringFmt.Alignment = lnGdipAlign IF tlVertical loStringFmt.FormatFlags = .StringFormatFlags.DirectionVertical loStringFmt.LineAlignment = .StringAlignment.Center ENDIF LOCAL loSize as xfcSize IF tlVertical loSize = .Size.New(This.Parent.Width, This.Parent.Height) ELSE loSize = .Size.New(tnWidth, tnHeight) ENDIF loSize = loGfx.MeasureString(; This._TransfCaption, This._oFont, loSize, loStringFmt) This._Height = CEILING(loSize.Height) This._Width = CEILING(loSize.Width) LOCAL loRect as xfcRectangle loRect = .Rectangle.New(tnX, tnY, tnWidth, This._Height) x1 = tnX y1 = tnY IF tlVertical xBack = tnX + tnWidth / 2 - (This._Width / 2) DO CASE CASE lnAlign = 0 && Left y1 = tnY CASE lnAlign = 1 && Right y1 = tnY + tnHeight - This._Height CASE lnAlign = 2 && Center y1 = tnY + (tnHeight / 2) - (This._Height / 2) ENDCASE ELSE DO CASE CASE lnAlign = 0 && Left xBack = tnX CASE lnAlign = 1 && Right xBack = tnX + tnWidth - This._Width CASE lnAlign = 2 && Center xBack = tnX + (tnWidth - This._Width) / 2 ENDCASE ENDIF CASE lnAlign = 0 && Left STORE tnX TO x1, xBack y1 = tnY CASE lnAlign = 1 && Right x1 = tnX - This._Width xBack = x1 y1 = tnY CASE lnAlign = 2 && Center x1 = tnX - (This._Width / 2) xBack = x1 y1 = tnY ENDCASE LOCAL lnRotation lnRotation = This.Rotation IF lnRotation <> 0 WITH _SCREEN.System.Drawing LOCAL loPointF as xfcPointF LOCAL loMatrix as xfcMatrix loMatrix = .Drawing2D.Matrix.New() IF lnMode = 1 loPointF = .PointF.New(tnX, tnY) && this is the point of rotation ELSE DO CASE CASE lnAlign = 0 && Left loPointF = .PointF.New(x1 + 5, y1 + This._Height / 2) && this is the point of rotation CASE lnAlign = 1 && Right loPointF = .PointF.New(x1 + This._Width - 5, y1 + This._Height / 2) && this is the point of rotation CASE lnAlign = 2 && Center loPointF = .PointF.New(x1 + This._Width / 2, y1 + This._Height / 2) && this is the point of rotation ENDCASE ENDIF loMatrix.RotateAt(lnRotation, loPointF) loGfx.MultiplyTransform(loMatrix) ENDWITH ENDIF lnRotationCenter = This.RotationCenter * Center Rotation IF lnRotationCenter <> 0 WITH _SCREEN.System.Drawing LOCAL loPointFC as xfcPointF LOCAL loMatrixC as xfcMatrix loMatrixC = .Drawing2D.Matrix.New() * loPointFC = .PointF.New(x1 + This._Width / 2, y1 + This._Height / 2) && this is the point of rotation loPointFC = .PointF.New(xBack + This._Width / 2, y1 + This._Height / 2) && this is the point of rotation loMatrixC.RotateAt(lnRotationCenter, loPointFC) loGfx.MultiplyTransform(loMatrixC) ENDWITH ENDIF IF This.BackColorAlpha > 0 * Draw the BackGround Rectangle WITH _Screen.System.Drawing IF lnMode = 0 && default loGfx.FillRectangle( ; .SolidBrush.New(.Color.FromARGB(This.BackColorAlpha, This.BackColor)), ; x1, y1, This._Width, This._Height) ELSE loGfx.FillRectangle( ; .SolidBrush.New(.Color.FromARGB(This.BackColorAlpha, This.BackColor)), ; xBack, y1, This._Width, This._Height) ENDIF ENDWITH ENDIF * Draw the Text IF lnMode = 0 LOCAL loStringFmt as xfcStringFormat LOCAL lnGdipAlign loStringFmt = .StringFormat.New() DO CASE CASE lnAlign = 2 && Center lnGdipAlign = .StringAlignment.Center CASE lnAlign = 1 lnGdipAlign = .StringAlignment.Far OTHERWISE lnGdipAlign = .StringAlignment.Near ENDCASE loStringFmt.Alignment = lnGdipAlign loGfx.DrawString(This._TransfCaption, This._oFont, This._oBrush, ; .Rectangle.New(x1, y1, CEILING(This._Width), This._Height + 2), ; loStringFmt) ELSE IF tlVertical loRect = .Rectangle.New(xBack, y1, This._Width, This._Height) loGfx.DrawString(This._TransfCaption, This._oFont, This._oBrush, loRect, loStringFmt) ELSE loGfx.DrawString(This._TransfCaption, This._oFont, This._oBrush, loRect, loStringFmt) ENDIF ENDIF IF lnRotation <> 0 OR lnRotationCenter <> 0 loGfx.ResetTransform() ENDIF ENDWITH RETURN ENDPROC PROCEDURE ShapeLegend._updatemeasures LPARAMETERS tlNumeric IF VARTYPE(THIS.oGfx)#'O' AND THIS.IsParent THIS.oGfx = THIS.PARENT.oGfx ENDIF IF VARTYPE(THIS.oGfx) <> "O" RETURN ENDIF * Measure the Legend height IF VARTYPE(THIS._oBrush) + VARTYPE(THIS._oFont) <> "OO" OR NOT THIS._initialized THIS._Setup() ENDIF LOCAL lcCaption, lcFormat * _ForceFormat is a forced formatting managed directly from FoxCharts lcFormat = IIF(EMPTY(ALLTRIM(THIS._ForceFormat)), THIS.FORMAT, ALLTRIM(THIS._ForceFormat)) IF tlNumeric IF VARTYPE(THIS._Value) = "C" lcCaption = THIS._Value ELSE IF this.IsParent and EMPTY(lcFormat) lcFormat = "999,999,999,999" + ; IIF(THIS.PARENT._ValueDecimals > 0, ; "." + REPLICATE("9", THIS.PARENT._ValueDecimals), "") ENDIF lcCaption = ALLTRIM(TRANSFORM(THIS._Value, lcFormat)) IF this.IsParent and THIS.PARENT._ValueDecimals>0 lcCaption=RTRIM(RTRIM(lcCaption,'0'),'.') ENDIF ENDIF ELSE lcCaption = STRTRAN(THIS.CAPTION,[CHR(13)+CHR(10)], CHR(13)+CHR(10),-1,-1,1) lcCaption = ALLTRIM(textmerge(lcCaption)) ENDIF LOCAL loSize AS xfcSize loSize = THIS.oGfx.MeasureString(lcCaption, THIS._oFont) &&, This._oStringFormat) THIS._Height = loSize.HEIGHT THIS._Width = CEILING(loSize.WIDTH) THIS._TransfCaption = lcCaption ENDPROC PROCEDURE SideLegend.caption_assign lparameters tcText This.Caption = tcText This._UpdateMeasures() ENDPROC PROCEDURE ToolTip.caption_assign LPARAMETERS tcCaption This.Caption = tcCaption LOCAL llWordWrap llWordWrap = This.WordWrap WITH Thisform.FoxChartsToolTip * .Autosize = This.AutoSize .Alignment = This.Alignment .BackColor = This.BackColor .BackStyle = This.BackStyle .BorderStyle = This.BorderStyle .FontBold = This.FontBold .FontItalic = This.FontItalic .FontName = This.FontName .FontSize = This.FontSize .FontStrikethru = This.FontStrikethru .FontUnderline = This.FontUnderline .ForeColor = This.ForeColor .Zorder(0) IF llWordWrap .WordWrap = .F. .Caption = tcCaption .WordWrap = .T. .Autosize = .T. ELSE .Caption = tcCaption ENDIF ENDWITH ENDPROC PROCEDURE ToolTip.MouseMove LPARAMETERS nButton, nShift, nXCoord, nYCoord This.Parent.ChartCanvas.MouseMove(nButton, nShift, nXCoord, nYCoord) ENDPROC PROCEDURE YAxis._updatemeasures Lparameters tlNumeric If Vartype(This.Parent.oGfx) <> "O" Return Endif * Measure the Legend height If Vartype(This._oBrush) + Vartype(This._oFont) <> "OO" This._Setup() Endif Local lcCaption, lcFormat lcFormat = This._ForceFormat If Empty(lcFormat) lcFormat = This.Format Endif **************************************************************** * Jim Nelson 10/13/2008 * * modified to accept text data even when expecting numeric (specifically for case GetScaleLegend(-1) **** old way *!* If tlNumeric *!* lcCaption = Alltrim(Transform(This._Value, lcFormat)) *!* Else *!* lcCaption = Alltrim(Transform(This.Caption, lcFormat)) *!* * lcCaption = ALLTRIM(TRANSFORM(This.Caption, IIF("%" $ lcFormat, "", lcFormat))) *!* Endif **** new way Do Case Case tlNumeric And "N" = Vartype (This._Value) lcCaption = Alltrim(Transform(This._Value, lcFormat)) Case tlNumeric And "N" # Vartype (This._Value) lcCaption = This._Value Otherwise lcCaption = Alltrim(Transform(This.Caption, lcFormat)) Endcase Local loSize As xfcSize loSize = This.Parent.oGfx.MeasureString(lcCaption, This._oFont) &&, This._oStringFormat) This._Height = loSize.Height This._Width = loSize.Width This._TransfCaption = lcCaption ENDPROC PROCEDURE YAxis2._updatemeasures Lparameters tlNumeric If Vartype(This.Parent.oGfx) <> "O" Return Endif * Measure the Legend height If Vartype(This._oBrush) + Vartype(This._oFont) <> "OO" This._Setup() Endif Local lcCaption, lcFormat lcFormat = This._ForceFormat If Empty(lcFormat) lcFormat = This.Format Endif **************************************************************** * Jim Nelson 10/13/2008 * * modified to accept text data even when expecting numeric (specifically for case GetScaleLegend(-1) **** old way *!* If tlNumeric *!* lcCaption = Alltrim(Transform(This._Value, lcFormat)) *!* Else *!* lcCaption = Alltrim(Transform(This.Caption, lcFormat)) *!* * lcCaption = ALLTRIM(TRANSFORM(This.Caption, IIF("%" $ lcFormat, "", lcFormat))) *!* Endif **** new way Do Case Case tlNumeric And "N" = Vartype (This._Value) lcCaption = Alltrim(Transform(This._Value, lcFormat)) Case tlNumeric And "N" # Vartype (This._Value) lcCaption = This._Value Otherwise lcCaption = Alltrim(Transform(This.Caption, lcFormat)) Endcase Local loSize As xfcSize loSize = This.Parent.oGfx.MeasureString(lcCaption, This._oFont) &&, This._oStringFormat) This._Height = loSize.Height This._Width = loSize.Width This._TransfCaption = lcCaption ENDPROC ENDDEFINE