This project is read-only.

Charts Enhancement

Topics: Enhancement Request
Aug 12, 2008 at 8:46 AM
Edited Aug 12, 2008 at 9:44 AM

Hi Cesar,
Thanks to your answer. I'm pressed of time now.
Hope we'll continue discussion. Now I want to show you simple code for MouseUp .
Just put following code to your ChartCanvas.MouseUp

LPARAMETERS

nButton, nShift, nXCoord, nYCoord
WITH this.
parent
IF INLIST
(this.parent
.ChartType, 7, 8, 9, 10, 12, 13)
FOR lnLine=1 TO ALEN
(.laCoord,1)
IF BETWEEN
(nXCoord,.laCoord(lnLine,1),.laCoord(lnLine,1)+.laCoord(lnLine,3)) AND ;
BETWEEN
(nYCoord,.laCoord(lnLine,2),.laCoord(lnLine,2)+.laCoord(lnLine,4))
MESSAGEBOX(.laCoord(lnLine,5)) && I use balloon here. It works according Mouse nXCoord, nYCoord

 

RETURN
ENDIF
NEXT
ENDIF
ENDWITH

Next code to modify Foxcharts.DrawbarChart
 

CASE This

.ChartType = 7 && Simple Bar
LOCAL lnZeroY
lnZeroY =
This._TitleHeight + ln3D + (This._MaxScale / lnMaxValue * lnHeight)
lnBarCount=0
SCAN
lnValue = ChartCursor.nValue1
lnBarHeight = lnValue / lnMaxValue * lnHeight
x1 = lnLeftMargin + ((lnBarWidth + lnBetween) * (
RECNO() - 1))
IF lnValue < 0
y1 = lnZeroY
ELSE
y1 = This._TitleHeight + ln3D + lnHeight - lnBarHeight - (This._ScaleAdjust / lnMaxValue * lnHeight)
ENDIF 

 

 

lnBarCount=lnBarCount+1
IF TYPE('THIS.laCoord')='U'
this.AddProperty ('laCoord(1)',0)
endif
DIMENSION THIS
.laCoord (lnBarCount,5)
THIS.laCoord (lnBarCount,1)=X1
THIS.laCoord (lnBarCount,2)=y1
THIS.laCoord (lnBarCount,3)=lnBarWidth
THIS.laCoord (lnBarCount,4)=lnBarHeight
TEXT TO this.laCoord (lnBarCount,5)
<<
ALLTRIM(CLegend)>>
<<lnValue>>
ENDTEXT 

 

This

.DrawBar(x1, y1, lnBarWidth, lnBarHeight, lnValue)
ENDSCAN

 

Aug 12, 2008 at 9:53 AM
Edited Aug 12, 2008 at 10:03 AM
Cesar, next for pie I use this code (not yet implemented in your program)

TEXT TO THIS.laCoord (lnline,1)
<<X1+lnWidth/2>>,<<Y1+lnHeight/2>>,<<lnAngle1>>,<<lnAngle2>>,<<lnWidth>>,<<lnHeight>>
ENDTEXT

* For message in balloon to show
TEXT TO THIS

 

.laCoord (lnline,2)
<<
THIS.laColumnHeaders(1)>>
<<totext(Value1)>>
<<Value1/lnDelta*100>>%

 

ENDTEXT

* For title in Balloon
TEXT TO THIS

 

.laCoord (lnline,3)
<<lnline>>. <<
THIS.laNames(lnline)>>

 

 

ENDTEXT

And Mouseup consist next code

 

IF THIS

.ChartType=5 && Pie in my program
LOCAL la1(1), ln1
lc=''
ln1=0

 

 

FOR lnLine=1 TO ALEN(THIS.laCoord,1)  

 

 

 

=ALINE(la1,THIS.laCoord(lnLine,1),',')
lnX0=
VAL(la1(1,1))
lnY0=
VAL(la1(1,2))

lnX=nXCoord

- lnX0

 

lnY=nYCoord

-lnY0

 

lnRad =

SQRT(lnX*lnX + lnY*lnY)

 

 

lnWidth =

VAL(la1(1,5))/2
lnHeight=
VAL(la1(1,6))/2

 

 

IF ABS(lnX)>lnWidth OR ABS(lnY)>lnHeight OR lnRad>MAX(lnWidth,lnHeight)

 

LOOP

ENDIF

 

lnX = lnX/lnRad
lnY = lnY/lnRad
lnAngle1=
ICASE(lnX>=0 AND lnY>=0,RTOD(ACOS(lnX)), ;
lnX>0 AND lnY<0,360-
RTOD(ACOS(lnX)), lnX<0 AND lnY<0,RTOD(ACOS(-lnX))+180, .T.,RTOD(ACOS(lnX)))

lnAngle1=lnAngle1-270

 

IF lnAngle1<0
lnAngle1=lnAngle1+360
ENDIF
la1(3)=EVALUATE(la1(3))
la1(4)=
EVALUATE(la1(4))
IF BETWEEN(lnAngle1,la1(3),la1(4))

ln1=lnLine

EXIT

 

ENDIF

NEXT

TEXT TO

lc addi

 

----- <<ln1>> -----<<la1(5)>>,<<la1(6)>>

<<lnangle1>>

 

endt

 

 

IF

ln1>0
DO CASE

 

CASE

nButton=1

 

=balloon(

THISFORM,THIS.laCoord(ln1,2),THIS.laCoord(ln1,3),5,5)

 

 

 

OTHERWISE

 

GO

ln1

 

 

REPLACE Detach WITH NOT Detach

 

 

 

THIS.Redraw()
ENDCASE

 

RETURN

EXIT

ENDIF
ENDIF

If you need I can modify your code later.

 

Aug 28, 2008 at 3:18 AM
Hi Yudin,

GREAT JOB !
I've already implemented this in a very similar way, and your code has brought some other cool ideas.
For the BarCharts, the most recommended is to create a new procedure, like "UpdateCoords", called from the method "DrawBar" - This way, all kinds of Bar charts will be available at one time.

What baloontip class are you using ? The CTL32 from Carlos ?

Regards

Cesar
Aug 28, 2008 at 5:24 AM
Edited Aug 28, 2008 at 5:44 AM
Hi again Yudin,

I could not resist, and started implementing the tooltips and the Click event (this, just for a simple test)..

Please download again the newest version, again from here: http://www.codeplex.com/VFPX/Release/ProjectReleases.aspx?ReleaseId=15318

Get this file: FoxCharts 0.54 BETA WITH TOOLTIPS

See that in the sample form "ChartsSample_New.scx" I added a checkbox in the "Legends" PageFrame, in order to allow or disallow the tooltips in any of the BarCharts available.

Obviously, I added the property "ShowTips" to the FoxCharts class, as well as "_aCoord", the array that stored the coordinates, exactly the way you planned.

A new method was created, "UpdateCoordinates", that is called from "DrawBar", that is the method that effectively draws each of the bars.
Some code also at the "MouseMove" event from the "ChartCanvas".

When you find some time, please have a look at it, and tell me if you like it.

For the lines / points and Area, I'm thinking of using the same principle from the bars, but this time allowing a small square region around each point.

For the Pie Chart, I totally agree with you, the best solution will be to use the angles to know if in which slice we are.


Can you go ahead with the Pie slice detecting stuff ?

At this moment, I just added a simple and default Textbox class, that you can even setup in design mode, changing colors, fonts, etc...


Further, I hope to create 2 new Methods: "ChartShapeMouseMove" and "ChartShapeMouseClick", reciving the following parameters: tnValue, tcLegend, tnChartIndex, tnChartPosition.

Regards

Cesar
Aug 29, 2008 at 10:16 AM
Edited Aug 29, 2008 at 11:29 AM

Here's my

code for pie and Doughnut

 

 

*---------------------------------

* FoxCharts.ChartCanvas.MouseUp

*---------------------------------

LPARAMETERS

nButton, nShift, nXCoord, nYCoord

 

 

WITH This

.Parent

 

IF

 

NOT .ShowTips

 

RETURN

ENDIF

IF

 

._GeneralType = "Bar"

 

 

 

LOCAL lnLine, lnValue, lcLegend

 

 

 

FOR lnLine=1 TO ALEN(._aCoord,1)

 

 

 

IF BETWEEN(nXCoord,._aCoord(lnLine,1), ._aCoord(lnLine,1) + ._aCoord(lnLine,3)) AND ;

 

 

 

BETWEEN(nYCoord,._aCoord(lnLine,2), ._aCoord(lnLine,2) + ._aCoord(lnLine,4))

 

 

lnValue = ._aCoord(lnLine, 5)

lcLegend = ._aCoord(lnLine, 6)

.ToolTip.

 

Left = nXCoord

 

.ToolTip.

 

Top = nYCoord - .ToolTip.Height

 

 

 

lcText = CHR(13) + CHR(13) + "Value : " + ALLTRIM(TRANSFORM(lnValue, This.Parent.ShapeLegend.Format)) + ;

 

 

 

IIF(EMPTY(lcLegend),"", CHR(13) + "Legend : " + lcLegend)

 

 

 

MESSAGEBOX("You clicked in the slice:" + lcText, 64, "Clicked on Shape")

 

 

 

 

RETURN

 

ELSE

 

 

.ToolTip.Visible = .F.

 

 

 

ENDIF

 

NEXT

ENDIF

IF INLIST

 

(.ChartType,1,2) && Pie, Doughnut

 

 

 

LOCAL la1(1)

 

lc=''

ln1=0

 

 

FOR lnLine=1 TO ALEN(._aCoord,1)

 

=

 

ALINE(la1,._aCoord(lnLine,1),',')

 

lnX0=

 

VAL(la1(1,1))

 

lnY0=

 

VAL(la1(1,2))

 

lnX=nXCoord - lnX0

lnY=nYCoord -lnY0

lnRad =

 

SQRT(lnX*lnX + lnY*lnY)

 

lnWidth =

 

VAL(la1(1,5))/2

 

lnHeight=

 

VAL(la1(1,6))/2

 

 

IF ABS

(lnX)>lnWidth OR ABS(lnY)>lnHeight OR lnRad>MAX(lnWidth,lnHeight)

 

 

LOOP

ENDIF

 

lnX = lnX*lnHeight/lnWidth

 

lnRad =

 

SQRT(lnX*lnX+lnY*lnY)

 

lnX = lnX/lnRad

lnY = lnY/lnRad

lnAngle1=

 

ICASE(lnX>=0 AND lnY>=0,RTOD(ACOS(lnX)), ;

 

lnX>0 AND lnY<0,360-

 

RTOD(ACOS(lnX)), ;

 

lnX<0 AND lnY<0,

 

RTOD(ACOS(-lnX))+180, .T.,RTOD(ACOS(lnX)))

 

lnAngle1=lnAngle1-270

 

 

IF lnAngle1<0

 

lnAngle1=lnAngle1+360

 

 

ENDIF

 

 

 

la1(3)=EVALUATE(la1(3))

 

la1(4)=

 

EVALUATE(la1(4))

 

 

 

IF BETWEEN(lnAngle1,la1(3),la1(4))

 

ln1=lnLine

 

 

EXIT

 

ENDIF

NEXT

IF

 

ln1>0

 

 

GO VAL

(la1(7)) IN (.SourceAlias)

 

 

REPLACE

Detach WITH NOT detach IN (.SourceAlias)

 

.DrawChart()

 

 

ENDIF

 

ENDIF

ENDWITH

 

*********************

 

*---------------------------------

* FoxCharts.ChartCanvas.MouseMove

*---------------------------------

LPARAMETERS

nButton, nShift, nXCoord, nYCoord

 

 

WITH This

.Parent

 

IF

 

NOT .ShowTips

 

RETURN

ENDIF

 

nXCoord=nXCoord-.

left

 

 

nYCoord=nYCoord-.

top

 

IF

 

._GeneralType = "Bar"

 

 

 

LOCAL lnLine, lnValue, lcLegend

 

 

 

FOR lnLine=1 TO ALEN(._aCoord,1)

 

 

 

IF BETWEEN(nXCoord,._aCoord(lnLine,1), ._aCoord(lnLine,1) + ._aCoord(lnLine,3)) AND ;

 

 

 

BETWEEN(nYCoord,._aCoord(lnLine,2), ._aCoord(lnLine,2) + ._aCoord(lnLine,4))

 

 

lnValue = ._aCoord(lnLine, 5)

lcLegend = ._aCoord(lnLine, 6)

.ToolTip.

 

Left = nXCoord

 

.ToolTip.

 

Top = nYCoord - .ToolTip.Height - 2

 

.ToolTip.

 

Caption = " " + ;

 

 

 

ALLTRIM(TRANSFORM(lnValue, This.Parent.ShapeLegend.Format)) + " " + ;

 

 

 

IIF(EMPTY(lcLegend),"", CHR(13) + " " + lcLegend + " ")

 

.ToolTip.

 

Visible = .T.

 

 

 

 

RETURN

 

ELSE

 

 

.ToolTip.Visible = .F.

 

 

 

ENDIF

 

NEXT

ENDIF

IF INLIST

 

(.ChartType,1,2) && Pie, Doughnut

 

 

 

LOCAL la1(1)

 

lc=''

ln1=0

 

 

FOR lnLine=1 TO ALEN(._aCoord,1)

 

 

*****

 

=ALINE(la1,._aCoord(lnLine,1),',')

 

lnX0=

 

VAL(la1(1,1))

 

lnY0=

 

VAL(la1(1,2))

 

lnX=nXCoord - lnX0

lnY=nYCoord -lnY0

lnRad =

 

SQRT(lnX*lnX + lnY*lnY)

 

lnWidth =

 

VAL(la1(1,5))/2

 

lnHeight=

 

VAL(la1(1,6))/2

 

 

IF ABS

(lnX)>lnWidth OR ABS(lnY)>lnHeight OR lnRad>MAX(lnWidth,lnHeight)

 

 

LOOP

ENDIF

 

lnX = lnX*lnHeight/lnWidth

 

lnRad =

 

SQRT(lnX*lnX+lnY*lnY)

 

lnX = lnX/lnRad

lnY = lnY/lnRad

lnAngle1=

 

ICASE(lnX>=0 AND lnY>=0,RTOD(ACOS(lnX)), ;

 

lnX>0 AND lnY<0,360-

 

RTOD(ACOS(lnX)), ;

 

lnX<0 AND lnY<0,

 

RTOD(ACOS(-lnX))+180, .T.,RTOD(ACOS(lnX)))

 

lnAngle1=lnAngle1-270

 

 

IF lnAngle1<0

 

lnAngle1=lnAngle1+360

 

 

ENDIF

 

 

 

la1(3)=EVALUATE(la1(3))

 

la1(4)=

 

EVALUATE(la1(4))

 

 

 

IF BETWEEN(lnAngle1,la1(3),la1(4))

 

ln1=lnLine

 

 

EXIT

 

ENDIF

NEXT

IF

 

ln1>0

 

.ToolTip.

 

Left = nXCoord

 

.ToolTip.

 

Top = nYCoord - .ToolTip.Height - 2

 

.ToolTip.

 

Caption = ._aCoord(ln1,2)+' : '+ALLTRIM(STR(nXCoord))+' - '+ALLTRIM(STR(nYCoord)) ;

 

+'('+._aCoord(ln1,1)+') lnAngle1='+

 

ALLTRIM(STR(lnAngle1))

 

.ToolTip.

 

Visible = .T.

 

 

 

ENDIF

 

ENDIF

ENDWITH

 

 

*---------------------------------

* FoxCharts.DrawPieChart

*---------------------------------

LOCAL

lnDetachPixels, lnStart, lnSweep, lnAngle, ln3D, lnValue

 

 

LOCAL

lnWidth, lnHeight, lnX, lnY, lnTotal, lnMaxWidth, lnMaxHeight

 

 

PRIVATE

lnDelta

 

lnDetachPixels =

 

This.PieDetachPixels

 

lnMaxWidth =

 

THIS.WIDTH - (lnDetachPixels * 2) - This.Margin - This._LegendWidth

 

lnMaxHeight =

 

THIS.HEIGHT - This.Margin - This._3D - This._TitleHeight - (lnDetachPixels * 2)

 

lnWidth =

 

MIN(lnMaxWidth, lnMaxHeight)

 

lnHeight = lnWidth

 

* Adjust the maximum width in order to ensure that the chart will retain

LOCAL

lnFactor

 

lnFactor = 0.80

 

IF

lnMaxWidth <= lnWidth / lnFactor

 

lnWidth = lnMaxWidth

 

ELSE

 

lnWidth = lnWidth / lnFactor

 

 

ENDIF

 

IF This

.PieCompensateAngles

 

lnWidth = lnMaxWidth

 

ENDIF

 

 

* Calculate the chart basic positions

lnX = lnDetachPixels +

This.Margin + ((lnMaxWidth - lnWidth) / 2)

 

lnY =

 

This.Margin + This._TitleHeight + ((lnMaxHeight - lnHeight) / 2) + lnDetachPixels

 

ln3D =

 

This._3D

 

 

LOCAL

lcField

 

lcField = "ChartCursor.nValue" +

 

This._Str(This.ChartRow)

 

 

CALCULATE SUM

(NVL(&lcField. ,0)) TO lnTotal

 

 

* Prepare the Gdi+ objects

WITH _Screen

.System.Drawing

 

 

 

This._oTempBmp = .Bitmap.New(lnWidth + ln3d + 2, lnHeight + ln3d + 2)

 

 

 

This._oClrMatrix = .Imaging.ColorMatrix.New()

 

 

 

This._oClrMatrix.Matrix33 = This.AlphaChannel / 255

 

 

ENDWITH

LOCAL

laLegends(This._nRecords + 1, 3)

 

 

LOCAL

lnRec, llHidden, llDrawLegend

 

llDrawLegend =

 

This.ShowValuesonShapes

 

lnRec = 1

 

* Draw the pie

lnDelta = 0

SCAN

 

lnDelta=lnDelta+NVL(nValue1,0)

 

 

ENDSCAN

lcTextMerge =

SET("Textmerge")

 

 

SET TEXTMERGE ON

* Draw the RIGHT side of the pie

lnStart = 270

lnRecs=

RECCOUNT()

 

lnline=0

 

SCAN FOR

lnStart < 450

 

x1 = lnX

y1 = lnY

 

* Calculate Start point and Sweep

 

lnValue = This._GetValue(This.ChartRow)

 

 

 

IF lnValue = 0

 

 

 

LOOP

 

ENDIF

 

lnline=lnline+1

DIMENSION THIS

._aCoord (lnLine,2)

 

 

lnSweep = lnValue / lnTotal * 360

llHidden = ChartCursor.lSliceHidden

 

 

 

IF ChartCursor.lDetach = .T.

 

 

lnTempStart = lnStart

lnTempSweep = lnSweep

 

 

This.AdjustStartSweep(@lnTempStart, @lnTempSweep, lnWidth, lnHeight)

 

lnDetachAngle = 360 - (lnTempStart + (lnTempSweep / 2))

x1 = lnX + (

 

COS(DTOR(lnDetachAngle)) * lnDetachPixels)

 

y1 = lnY - (

 

SIN(DTOR(lnDetachAngle)) * lnDetachPixels)

 

 

 

ELSE

 

 

 

x1 = lnX

 

y1 = lnY

 

 

ENDIF

 

 

IF

 

NOT llHidden

 

 

 

IF This.ChartType = 1 && Pie

 

 

 

This.DrawSlice(x1, y1, lnWidth, lnHeight, lnStart, lnSweep)

 

 

 

ELSE && 2 - Doughnut

 

 

 

This.DrawDonutSlice(x1, y1, lnWidth, lnHeight, lnStart, lnSweep)

 

 

 

ENDIF

 

 

 

lnAngle1=lnStart-270

 

lnAngle1=

 

IIF(lnAngle1>=0,lnAngle1,360+lnAngle1)

 

lnAngle2=lnStart-270+lnSweep

lnAngle2=

 

IIF(lnAngle2>=0,lnAngle2,360+lnAngle2)

 

lnAngle2=

 

IIF(lnAngle2>=lnAngle1,lnAngle2,360+lnAngle2)

 

 

 

TEXT TO THIS._aCoord (lnline,1)

 

<<X1+lnWidth/2>>,<<Y1+lnHeight/2>>,<<lnAngle1>>,<<lnAngle2>>,<<lnWidth>>,<<lnHeight>>,<<

 

RECNO()>>

 

 

 

ENDTEXT

 

 

lnPercent=

ROUND(lnValue/lnDelta*100,0)

 

 

 

TEXT TO THIS._aCoord (lnline,2)

 

<<lnValue>> (<<lnPercent>>%)

<<

 

ALLTRIM(CLegend)>>

 

 

 

ENDTEXT

 

IF

 

llDrawLegend

 

 

 

This._PrepareLegendinSlice(@X1, @Y1, lnWidth, 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

 

 

 

LOOP

 

ENDIF

 

 

lnSweep = lnValue / lnTotal * 360

 

lnline=lnline+1

 

DIMENSION THIS

._aCoord (lnLine,2)

 

lnStart = lnStart - lnSweep

llHidden = ChartCursor.lSliceHidden

 

 

IF ChartCursor.lDetach = .T.

 

lnTempStart = lnStart

lnTempSweep = lnSweep

 

 

This.AdjustStartSweep(@lnTempStart, @lnTempSweep, lnWidth, lnHeight)

 

lnDetachAngle = 360 - (lnTempStart + (lnTempSweep / 2))

x1 = lnX + (

 

COS(DTOR(lnDetachAngle)) * lnDetachPixels)

 

y1 = lnY - (

 

SIN(DTOR(lnDetachAngle)) * lnDetachPixels)

 

 

 

ENDIF

 

 

IF

 

NOT llHidden

 

 

 

IF This.ChartType = 1 && Pie

 

 

 

This.DrawSlice(x1, y1, lnWidth, lnHeight, lnStart, lnSweep)

 

 

 

ELSE && 2 - Doughnut

 

 

 

This.DrawDonutSlice(x1, y1, lnWidth, lnHeight, lnStart, lnSweep)

 

 

 

ENDIF

 

 

 

lnAngle1=lnStart-270

 

lnAngle1=

 

IIF(lnAngle1>=0,lnAngle1,360+lnAngle1)

 

lnAngle2=lnStart-270+lnSweep

lnAngle2=

 

IIF(lnAngle2>=0,lnAngle2,360+lnAngle2)

 

lnAngle2=

 

IIF(lnAngle2>=lnAngle1,lnAngle2,360+lnAngle2)

 

 

 

TEXT TO THIS._aCoord (lnline,1)

 

<<X1+lnWidth/2>>,<<Y1+lnHeight/2>>,<<lnAngle1>>,<<lnAngle2>>,<<lnWidth>>,<<lnHeight>>,<<

 

RECNO()>>

 

 

 

ENDTEXT

 

 

lnPercent=

ROUND(lnValue/lnDelta*100,0)

 

 

 

TEXT TO THIS._aCoord (lnline,2)

 

<<lnValue>> (<<lnPercent>>%)

<<

 

ALLTRIM(CLegend)>>

 

 

 

ENDTEXT

 

IF

 

llDrawLegend

 

 

 

This._PrepareLegendinSlice(@X1, @Y1, lnWidth, lnHeight, lnStart, lnSweep, lnValue)

 

laLegends(lnRec,1) = x1

laLegends(lnRec,2) = y1

laLegends(lnRec,3) = lnValue

lnRec = lnRec + 1

 

 

ENDIF

 

ENDIF

SKIP

 

-1

 

 

ENDDO

 

* Draw the legends at the end of the process in order to avoid

* a slice hiding a legend

IF

llDrawLegend
This.ShapeLegend.Alignment = 2 && Force Center

 

FOR n = 1 TO lnRec - 2

 

x1 = laLegends(n,1)

 

 

IF VARTYPE(x1) <> "N"

 

 

 

EXIT

 

ENDIF

 

 

y1 = laLegends(n,2)

 

 

This.ShapeLegend._Value = laLegends(n,3) + This.ScaleStartValue
* Draw the Text

 

This.ShapeLegend._DrawString(x1, y1)
ENDFOR

 

ENDIF

IF

lcTextMerge='OFF'  

 

SET TEXTMERGE &lcTextMerge
ENDIF

Aug 29, 2008 at 1:57 PM
Hi Yudin,

Thanks a lot for you super valuable contribution !
I hope to put this to work this weekend and then we could even pass FoxCharts to "Release Candidate" status.

Best Regards

Cesar
Sep 1, 2008 at 7:17 AM
Hi Yudin,

Thanks again!
Your code was really very inspiring :-)

I've kept all the same codes in the "DrawPie", and passed all the calculations to "MouseMove".
Please download it again...

http://www.codeplex.com/VFPX/Release/ProjectReleases.aspx?ReleaseId=15318

The mouse detection is now REALLY very accurate, even for Doughnuts !
Tomorrow I'll finish coding the "MouseUp" codes to allow detaching slice dynamically, as you suggested and showed.

I'm really feeling that we are almost there !
Maybe in the next week we'll have FoxCharts published as "Release Candidate" !!!

Cheers

Cesar
Sep 1, 2008 at 8:13 AM
Hi, Cesar!
Something"s wrong with my code as for detaching. See field "Detach" or "lDetach".
Sure not problem for you.
Next,  please, change

 

"FOR lnLine=1 TO ALEN(._aCoord,1)"

in ChartCanvas.MouseMove and MouseUp for "bars"
to
"FOR lnLine=ALEN(._aCoord,1) TO 1 STEP -1"

This is important for detecting multiple rows. You'll see.
Thanks, I'm happy to contact you.
Regards
Yudin

 

Sep 1, 2008 at 11:15 AM
Hi Yudin,

Thanks, I've already noticed the important difference, specially for BarCharts.
If you run the "MultiChart"sample, selecting Lines chart, set 3d to 0, and you'll see how cool the points detection has become.

Thanks again !

Cesar
Sep 1, 2008 at 12:32 PM
Hi Cesar!
Really, it's cool!
And what do you think of detecting legend row (while MouseMove)?
It seems to be easy  making the same effect as for existing.detection.
I like your yellow label. It works fast. Good idea for MouseMove. And looks like balloon.
Maybe you can add something like that to imitate FontUnderline for legend to show
what row (or value) is detected.

Thanks.
Sep 3, 2008 at 6:44 AM
Hi Yudin,

Now we already have also the SLices detaching when users click on the slices, with a slight animation.
Can you test this and tell e what you think ?

Please download the latest version from here - at least 0.64:
http://www.codeplex.com/VFPX/Release/ProjectReleases.aspx?ReleaseId=15318

Hope you like it !
Sep 4, 2008 at 2:35 AM
Hi,
I have downloaded and have a look at sample exe. May I know is it only Pie chart support slice animation? I didn't see any animation for other chart type.

Thank you
Sep 4, 2008 at 6:39 AM
Hi Chan,

>>May I know is it only Pie chart support slice animation?

Yes, for the moment, only Pie and Doughnut charts accept animation.

For the future, I'm thinking of redrawing the current shape in a different color, maybe brighter, or just draw the borders in a different color.
The version that I uploaded yesterday had some bugs, I've just uploaded a brand new containing some fixes that have been reported.

Pls get the version 0.65 (or newer) from here:
http://www.codeplex.com/VFPX/Release/ProjectReleases.aspx?ReleaseId=15318

Thanks !
Sep 4, 2008 at 7:17 AM
Hi, Cesar!
Great! I really like it!
Sep 4, 2008 at 9:32 AM

Hi, Cesar! Here's my

code for Legend. Just to show the way to do it.
I'm sure you'll do it much better.
And it works only for Bar chart now.

 

1. I added

to form.init

 

this

.AddObject('_LegendShape','Shape')
this._LegendShape.BackStyle=0

 

2.

*---------------------------------

* FoxCharts._CheckMousePosition

* only top part of text

*---------------------------------

LPARAMETERS

nButton, nShift, nXCoord, nYCoord, lnValue, lcLegend, lnCoordIndex

 

* Passed by reference: lnValue, lcLegend

WITH This

IF

NOT .ShowTips OR VARTYPE(._aCoord(1,1)) <> "N"

 

 

This.MouseMove(nButton, nShift, nXCoord, nYCoord)

 

 

RETURN

 

ENDIF

LOCAL

n, lnValue, lcLegend, lnStart, lnSweep, lnCoordIndex

 

 

LOCAL lnLeft, lnTop

 

lnLeft = .

Left

 

 

lnTop = .Top

 

THISFORM

._LegendShape.visible=.f.

 

FOR

lnLine=1 TO IIF(TYPE('this._alegendcoord')='C',ALEN(this._alegendcoord,1),0)

 

IF ALINES

(la,this._alegendcoord(lnLine),',')<4

 

LOOP

endif

IF

nXCoord>=VAL(la(1)) AND BETWEEN(nYCoord-this.top,VAL(la(2)),VAL(la(4)))

 

WITH THISFORM

._LegendShape

 

.

Left=this.left+VAL(la(1))-1

 

.

Width=VAL(la(3))-VAL(la(1))+2

 

.

Top=this.top+VAL(la(2))-1

 

.

Height=VAL(la(4))-VAL(la(2))+2

 

.

visible=.T.

 

ENDWITH

ENDIF

NEXT

DO CASE

 

CASE

._GeneralType = "Bar" OR ._GeneralType = "Point"

 

 

FOR n = ALEN(._aCoord,1) TO 1 STEP -1 && Reverse in order to catch the first drawin

 

 

IF BETWEEN(nXCoord - lnLeft,;

 

._aCoord(n,1), ;

._aCoord(n,1) + ._aCoord(n,3)) ;

AND ;

 

BETWEEN(nYCoord - lnTop, ;

 

._aCoord(n,2) , ;

._aCoord(n,2) + ._aCoord(n,4))

lnValue = ._aCoord(n, 5)

lcLegend = ._aCoord(n, 6)

lnCoordIndex = n

try

IF ALINES

(la,this._alegendcoord(n),',')>3

 

WITH THISFORM

._LegendShape

 

.

Left=this.left+VAL(la(1))-1

 

.

Width=VAL(la(3))-VAL(la(1))+2

 

.

Top=this.top+VAL(la(2))-1

 

.

Height=VAL(la(4))-VAL(la(2))+2

 

.

visible=.T.

 

ENDWITH

ENDIF

CATCH

endtry

RETURN

ELSE

ENDIF

NEXT

3.

*---------------------------------

* FoxCharts.DrawLegends

* only bottom part

*---------------------------------

*** Draw Legends on the right side

 

x1 = This.Width - This._LegendWidth + 15

 

y1 =

This._TitleHeight

 

ln=0

 

SCAN

 

ln=ln+1

DIMENSION this

._alegendcoord (ln)

 

TEXT TO this

._alegendcoord (ln)

 

<<x1>>,<<y1>>,<<x1+lnWidth>>,<<y1+lnHeight>>,<<ln>>

ENDTEXT

This

.PrepareBrushes(X1, Y1, lnWidth, lnHeight, .T.)

 

 

THIS.oGfx.FillRectangle(This._oMainBrush, x1, y1, lnWidth, lnHeight)

 

 

THIS.oGfx.DrawRectangle(This._oBorderPen, x1, y1, lnWidth, lnHeight)

 

 

This.SideLegend.Caption = ChartCursor.cLegend

 

 

This.SideLegend._DrawString(x1 + lnWidth + lnMargin, y1 + 3)

 

y1 = y1 + lnLegendHeight +

MIN(lnMargin, lnLegendHeight / 2)

 

 

ENDSCAN

 

GO TOP

ENDCASE

ENDWITH

Sep 4, 2008 at 1:22 PM
P.S. I added
_alegendcoord(1) to Foxcharts' properties.

So, moving through legenda or Bar you can see that shape appears on legenda's color square.
Sep 8, 2008 at 8:21 AM
Edited Sep 8, 2008 at 10:41 AM

Hi Cesar!

Now you

make your charts look like alive being. Congratulations!
I propose
to make ._Coord array more flexible. Say, you can use first column for object type,
second for coordinates in text format with delimiters,and third for message. And you can continue this list.
Then you can add detecting such objects like legenda,title, subtitle and so on. And you'll do it with  ease.
Wanna
edit Title, subtitle or legend - please, right click. Cool ?!
And maybe YAxis, Chart properties and so
on.
And as for me 
your charts are the best in the world right now.
Sure you've got it! Now, my folk in Russian speaking Foxclub estimate your job as perfect.

 

 

 

Sep 8, 2008 at 12:59 PM
Edited Sep 8, 2008 at 1:07 PM
Hi Yudin,

>>>make your charts look like alive being

Heheh, did you see the colors changing on "MouseMove"
I've created the events: "ShapeMouseEnter", "ShapeMouseLeave".
Still have to apply many tweaks on this, in order to allow users to have full control over many events on the charts.
I want to add:
- TitleMouseEnter, TitleMouseLeave, TitleMouseMove, TitleClick, etc...
- LegendMouseEnter...
- YAxisMouseEnter
- XAxisMouseEnter
... etc etc...


>>>Now, my folk in Russian speaking Foxclub estimate your job as perfect.

I'm sure we're getting really close for the release of version 1.0
Perfect ?
Come on ! There will always be lots of things to add...

And in this last month your suggestions, fixes and codes represented a VERY IMPORTANT help. You not only asked for features, but also provided ways showing how we could do it.

THANKS VERY MUCH !


PS: I still did not put the "Legends" stuff you've sent me in the prev. message to work...

Hope to do it ASAP


Regards

Cesar
Sep 8, 2008 at 3:24 PM

Hi Cesar!

Look at

spnChartsRow in Pf.P1

 

1. You can lift

label and locate Combobox at it's place. (And I removed container)
Let it be cmbChartsRow.

 

In Form

.Init at the bottom:
FOR lnLine = 1 TO Thisform.Foxcharts1.ChartsCount
this.Pf.P1.CmbChartRow.AddItem(ALLTRIM(STR(lnLine))+'. '+EVALUATE("This.Foxcharts1.Legend" + ALLTRIM(STR(lnLine))))
NEXT
this
.Pf.P1.CmbChartRow.ListIndex=1

 

2. spnChartsRow.

InteractiveChange:

 

this

.Value=ICASE(this.Value<0,This.FoxCharts1.ChartCount, ;
this.Value>Thisform.FoxCharts1.ChartsCount,1,.t.,this.Value)
this.Parent.cmbChartRow.ListIndex=this.value
Thisform
.FoxCharts1.ChartRow = This.Value
Thisform
.FoxCharts1.DrawChart()

 

3. cmbChartsRow.

InteractiveChange:

 

this

.Parent.spnChartsRow.Value=this.ListIndex
this
.Parent.spnChartsRow.InteractiveChange

 

So,

user can see ChartRow name (legend) and select what he need directly.

 

Sep 9, 2008 at 8:25 AM

Hi, Cesar!

Some information is large for this topic, some off.
Let's contact through email
as well.
I'm ready send you may email, but the way
to protect it from SPAM.
Say, I can mount it in my next code or maybe you know another better way.

 

As for

colors changing on "MouseMove". Good idea, but it works slowly.
And I don't think you can
make it work faster.
But good
for Mouse Click (or Right Click).
Surely, you are
in condition to declare release of version 1.0 right now.
Why not? And it's
up to you to continue with 1.1, ... later.
As you said "There will always be lots of things to add".

 

Regards

Alex Yudin

Sep 9, 2008 at 1:50 PM
Edited Sep 9, 2008 at 1:56 PM
Hi Yudin,

>>Some information is large for this topic some off
>>Let's contact through email as well.
>>I'm ready send you may email, but the way to protect it from SPAM.

I've already sent you a private message vis CODEPLEX. If you pay attention, there you'll find my email. Feel free to contact me directly. I have a specific email for Codeplex subjecs as well: vfpimaging AT hotmail DOT com

>>As for colors changing on "MouseMove". Good idea, but it works slowly.
>>And I don't think you can make it work faster.

For Bar charts it is working fast. The big problem is at Pie and Doughnut charts, that are really slower to draw... But I'm sure I can make it at least 50% faster, because there are other techniques for drawing, and we could even cache some parts of the charts in order to avoid completely redrawing in some situations. For the case of a solid color background, this could be really easy. >>But good for Mouse Click (or Right Click).
What do you think would be the best way to handle "MouseMove"

1 - One option is to keep using just "MouseMove" event, and pass to it an array or collection containing some info about the current position or ;

2 - Create separate events for each of the Objects in the chart, eg: "LegendMouseEnter", "TitleMouseLeave" or;

3 - Adapt the current "Labels" that are responsible for the legends, and use their own events. >>Surely, you are in condition to declare release of version right now.


GREAT ! At this moment, I just want to finish this "MouseMove" stuff, and fix some few remaining bugs.
 
Regards

Cesar
Oct 3, 2008 at 1:54 PM
Hi, Cesar!
I tried your new version with GDIPlusX 1.20. I use system.prg (not System.app).
I've got "Unhandled structured exception" at Foxchart1._beforedraw.
Say me if I make something wrong, please.

Regards

Alex
Oct 4, 2008 at 3:25 AM
Hi Yudin !
It's been a long time !

Thanks for testing the new version.
In fact, this new version requires that you use the most recent GdiPlusX version to work.

Please, make sure that FoxCharts is using the correct version.
Maybe you have in your path another version of System.App or System.Prg.
You may try the following:

in your command window:

_Screen.System = NULL
DO ?

Then select the file "System.app" that comes with the latest FoxCharts version (at least version 0.77)
And try running the sample again.


I followed some people's suggestions, and implemented a very basic error trapping system as well.
When an error occurs, an "Exception" is generated.

Click on suspend, and open the DEBUG window
There, expand the "LoException" object in the treeview where the variables are.
So you'll be able to see more details about the bug.

I added also a new method, "_CheckParams", that verifies the main parameters values passed, and if there's something wrong fires an "ASSERT"


Please test it again, and tell me how it goes !

regards

Cesar
Oct 6, 2008 at 10:24 AM
Hi, Cesar!
I've got latest GdiPlusX. With System.app no problem. With System.prg failed.
No other path, just your zip unpacked to folder.
Instead of "DO LOCFILE("System.app")" stands DO LOCFILE("System.prg").

In earlier versions it works.

Cesar, now Legend is in right top corner (if shown) and chart are left side.
If legend is wide and takes only 2-3 rows, I would like to put it at the same side or top center,
but chart below it to take all canvas width. Can you give us Property to control legend location?

As for DadosX, can you put them two floors way? I mean like next

01 Legend    03 Legend
     02 Legend      04 Legend

Regarts
Alex Yudin, Ukraine
Oct 8, 2008 at 1:29 AM
Hi Yudin,

I really didn't understand the issue with System.app and system.prg. Can you describe it better ?

About legends: Yes, I plan to do it, but after the release of version 1.0.
Right now I need your help to fix all the remaining bugs :-D

In a previous message in this thread you mentioned to control mouse behavior on mouse move. Unfortunately, I could not make your sample work. Can you test the latest release to see if that was what you were looking for ?

Thanks in advance for your support !
Regards

Cesar
Oct 8, 2008 at 8:40 AM
Hi, Cesar!
I've just uinpacked your 0.81 version and the error disappeared.
I even deleted system.app to be sure. No error. At all.

Well, as for behavior on mouse move. It's not exactly what I mean.
Now, I think it would be better to leave it untill you finish testing.
There are a lot of small "how to improve". But time is time.

- "Right now I need your help to fix all the remaining bugs "
OK, I'll try

Regards
Alex
Oct 8, 2008 at 11:00 AM
Cesar, Put all zeros to your Chart1 field. And try.

You can say it's not really valid data. But it can be.

Oct 9, 2008 at 12:19 PM

Hi, Cesar.

In FoxCharts._CheckMousePosition you can prevent possible error for zero slice of Pie.
Not
all ._aCoord values are defined (equal .F.).

 

[code]

* Now we need to find the shape
FOR n = 1 TO ALEN(._aCoord,1)
lnStart =
EVL(._aCoord(n,7),0) && 1
lnSweep = EVL(._aCoord(n,8),0) && 2
IF BETWEEN(lnAngle, lnStart, lnStart + lnSweep) OR ;
BETWEEN(lnAngle + 360, lnStart, lnStart + lnSweep)
lnFoundShape = n
EXIT
ENDIF
ENDFOR
[/code]

 

Oct 10, 2008 at 12:26 PM
Hi, Cesar!

1. Can you add property for animation on/off? For some pie charts it works slow.
2. In _legend._update to delete right zeros after decimal point
 you can add next string before "loSize = This.Parent.oGfx.MeasureString(lcCaption, This._oFont) &&, This._oStringFormat)"

lcCaption =

RTRIM(RTRIM(lcCaption,'0'),'.')

Regards
Alex

 

Oct 10, 2008 at 2:04 PM
Cesar, can you look my next code?
1. Foxcharts1.ShapeMouseEnter

LPARAMETERS

nButton, nShift, nXCoord, nYCoord, tnValue, tcLegend, tnCoordIndex
local lnChart,lcLegend, lnLine
lnChart=
this._aCoord(tnCoordIndex,9)
lcLegend=
this._aCoord(tnCoordIndex,6)
FOR lnLine=1 TO ALEN(this._aCoord,1)
IF this._aCoord(lnLine,11)='Legend' AND this._aCoord(lnLine,6)=lcLegend
    
IF TYPE('THISFORM.Rect1')='U'
        
THISFORM.AddObject('Rect1','Shape')
        
THISFORM.rect1.backstyle=0
    ENDIF

 

    THISFORM

.Rect1.Left=this._aCoord(lnLine,1)-1
    THISFORM.Rect1.width=this._aCoord(lnLine,3)+2
    THISFORM.Rect1.Top=this._aCoord(lnLine,2)+this.top-1
    THISFORM.Rect1.height=this._aCoord(lnLine,4)
    THISFORM.Rect1.visible=.t.
    retu
ENDIF
NEXT

2. Foxcharts1.ShapeMouseEnter

 

LPARAMETERS

nButton, nShift, nXCoord, nYCoord, tnValue, tcLegend, tnCoordIndex
THISFORM.Rect1.visible=.f.

It seems to me as usefull.
Regards

 

Oct 10, 2008 at 3:08 PM
Hi yudin,

Thanks again fo all your inputs.
For the next messages, please create a new topic...
CodePlex is super sloooow, when dealing with such a long thread.

1 - In FoxCharts._CheckMousePosition you can prevent possible error for zero slice of Pie.
Not
all ._aCoord values are defined (equal .F.).


Did you face any errors in this situation ?
I though they would not happen, because _CheckMousePosition 1st checks for the _GeneralType property, and these are only checked when dealing with the "Pie" type


2 - Can you add property for animation on/off? For some pie charts it works slow.

Sure ! It's already there !
See the property "ChangeColorOnMouse" that accepts logical values

In the sample, in the style tab, on the right, see the CheckBox "Change color on mouse over"



3 - In _legend._update to delete right zeros after decimal point
 you can add next string before "loSize = This.Parent.oGfx.MeasureString(lcCaption, This._oFont) &&, This._oStringFormat)"

lcCaption =

RTRIM(RTRIM(lcCaption,'0'),'.')


Thanks ! I'll check this



4 - About adding a shape in the legends.
That's super cool !
Can you download my latest version and try your code again and see if my last modifications will break your sample ?
I added some code showing how to click over the legands, identifying each of them.
I'd like to have your opinion on this as well.

THANKS VERY MUCH !!!

Oct 13, 2008 at 5:04 AM
Hi Yudin,

Thanks very much for your last sample.
SUPER COOOOOOOL !

I've implemented it as a sample. I'm still not sure if it should be added to the main class as a feature, let's wait for some testers and see what should be done.
Please download the latest version - at least 0.92, and run "ChartsSample_Mouse.scx"

Your code is there!

The main class needed some few tweaks in order to return the correct coordinates, and right now seems to be working fine with it.

THANKS VERY MUCH !

Please let me know if you have any other ideas regarding this.

Regards

Cesar