- Gráficas de barra sin complicaciones
- Traducción: http://comunidadvfp.blogspot.com/2006/08/graficas-de-barra-sin-complicaciones.html
- Original: http://weblogs.foxite.com/vfpimaging/2006/03/21/bar-graphics-without-complications/
y
- Gráficas de tarta con código VFP puro
- Traducción: http://comunidadvfp.blogspot.com/2006/08/graficas-de-tarta-con-codigo-vfp-puro.html
- Original: http://weblogs.foxite.com/vfpimaging/2006/03/24/pie-graphics-with-pure-vfp-code/
El objetivo de este artículo es tener otra opción (siempre VFP nos da esta posibilidad) de generar gráficas con solo el uso del objeto Shape, sin depender del uso de ninguna otra herramienta de terceras partes.
La idea
Con el uso del objeto Shape es fácil crear barras rectangulares configurando las propiedades Width (ancho) y Height (alto) con las dimensiones correspondientes, según la cantidad de barras del gráfico y el valor a graficar. El tema aquí es como graficar las distintas porciones de una torta (sección circular) o las secciones de un anillo con este objeto.A partir de Visual FoxPro 9.0, disponemos de la nueva propiedad PolyPoints en el objeto Shape (también en el objeto Line), que nos permiten graficar formas poligonales (ver el artículo Dibujando polígonos con VFP 9.0). Con esta técnica, graficaremos cada porción como un polígono con sus respectivas dimensiones, e iremos añadiendo las restantes porciones hasta completar la gráfica como se observa en las figuras siguientes.

Nota: Las opciones del tipo de gráfica torta, anillo y cono, solo se podrá ejecutar en la versión 9.0 de Visual FoxPro, por el uso de la propiedad PolyPoints de los objetos Shapes.
La clase
Como mencioné al principio de estas líneas, mi objetivo es generar gráficas con código VFP puro, para ello he creado una clase a partir de un objeto Container, al que se irán agregando en tiempo de ejecución los objetos Shape para formar la gráfica y también se agregaran las correspondientes leyendas. Su uso es muy fácil, y solo de deben configurar 5 propiedades y ejecutar el método GenerarGrafica() como se expone en las siguientes líneas de código:
WITH THISFORM.lmGraph .TipoGrafica = 1 && Anillo .TipoLeyenda = 3 && Rótulos .TipoColor = 0 && Aleatorios .TituloGrafica = "Consumos por mes" .Alias = "MiTabla" .GenerarGrafica() ENDWITHLas propiedades de la clase y sus valores son los siguientes:
- TipoGrafica: 0=Torta, 1=Anillo, 2=Barras verticales, 3=Barras horizontales, 4=Conos verticales, y 5=Conos horizontales
- TipoLeyenda: 0=Sin leyendas, 1=Valores, 2=Porcentajes, 3=Rótulos, 4=Rótulos y valores, y 5=Porcentajes y rótulos
- TipoColor: 0=Aleatorios y 1=Colores básicos (28 colores definidos)
- TituloGrafica: Cadena con el título superior de la gráfica
- Alias: Alias de la tabla o cursor que contiene los rótulos y valores a graficar
- 1° Campo: Este campo contiene los valores y debe ser Numérico.
- 2° Campo: Este campo contiene los rótulos y puede ser de tipo Caracter, Date, DateTime o Numérico.
Los ejemplos
Ejecutando el formulario de ejemplo con la clase incluida, podemos lograr gráficas simples y agradables como lo muestran las figuras siguientes:Gráfica de torta, con leyenda de porcentajes y rótulos, y colores aleatorios

Gráfica de anillo, con leyenda de rótulos y valores, y colores básicos

Gráfica de barras verticales, con leyenda de rótulos, y colores aleatorios

Gráfica de barras horizontales, sin leyenda, y colores básicos

Gráfica de conos verticales, con leyenda de porcentajes, y colores aleatorios

Gráfica de conos verticales, con leyenda de valores, y colores aleatorios

El formulario del ejemplo tiene una casilla de verificación (DEMO) que marcada, generará aleatoria y automáticamente cada 2 segundos, las distintas combinaciones posibles para cada una de las propiedades de la clase.
El código
El siguiente es el código del formulario de ejemplo y la clase para generar las gráficas:
PUBLIC goForm
goForm = CREATEOBJECT("frmEjemplo")
goForm.SHOW
RETURN
*--
*-- Definición del formulario de ejemplo
*--
DEFINE CLASS frmejemplo AS FORM
HEIGHT = 431
WIDTH = 496
SHOWWINDOW = 2
AUTOCENTER = .T.
CAPTION = "Gráficas con VFP9"
ICON = (HOME(4) + "icons\office\graph11.ico")
NAME = "frmEjemplo"
ADD OBJECT tmr AS TIMER WITH ;
ENABLED = .F., INTERVAL = 2000, NAME = "tmr"
ADD OBJECT opgColores AS OPTIONGROUP WITH ;
BUTTONCOUNT = 2, ANCHOR = 6, VALUE = 1, ;
HEIGHT = 48, LEFT = 344, TOP = 280, WIDTH = 136, ;
TABINDEX = 4, NAME = "opgColores", ;
Option1.BACKSTYLE = 0, Option1.CAPTION = "Colores aleatorios", ;
Option1.VALUE = 1, Option1.HEIGHT = 17, Option1.LEFT = 8, Option1.TOP = 8, ;
Option1.WIDTH = 120, Option1.AUTOSIZE = .T., Option1.NAME = "Option1", ;
Option2.BACKSTYLE = 0, Option2.CAPTION = "Colores básicos", ;
Option2.VALUE = 0, Option2.HEIGHT = 17, Option2.LEFT = 8, Option2.TOP = 24, ;
Option2.WIDTH = 109, Option2.AUTOSIZE = .T., Option2.NAME = "Option2"
ADD OBJECT cmdGenerar AS COMMANDBUTTON WITH ;
TOP = 392, LEFT = 376, HEIGHT = 32, WIDTH = 104, ;
ANCHOR = 6, WORDWRAP = .T., CAPTION = "Generar gráfica", ;
TABINDEX = 9, NAME = "cmdGenerar"
ADD OBJECT opgGraficas AS OPTIONGROUP WITH ;
BUTTONCOUNT = 6, ANCHOR = 6, VALUE = 1, ;
HEIGHT = 112, LEFT = 16, TOP = 280, WIDTH = 144, ;
TABINDEX = 2, NAME = "opgGraficas", ;
Option1.BACKSTYLE = 0, Option1.CAPTION = "Torta", ;
Option1.VALUE = 1, Option1.HEIGHT = 17, Option1.LEFT = 8, Option1.TOP = 8, ;
Option1.WIDTH = 46, Option1.AUTOSIZE = .T., Option1.NAME = "Option1", ;
Option2.BACKSTYLE = 0, Option2.CAPTION = "Anillo", ;
Option2.VALUE = 0, Option2.HEIGHT = 17, Option2.LEFT = 8, Option2.TOP = 24, ;
Option2.WIDTH = 48, Option2.AUTOSIZE = .T., Option2.NAME = "Option2", ;
Option3.BACKSTYLE = 0, Option3.CAPTION = "Barras verticales", ;
Option3.HEIGHT = 17, Option3.LEFT = 8, Option3.TOP = 40, Option3.WIDTH = 110, ;
Option3.AUTOSIZE = .T., Option3.NAME = "Option3", ;
Option4.BACKSTYLE = 0, Option4.CAPTION = "Barras horizontales", ;
Option4.HEIGHT = 17, Option4.LEFT = 8, Option4.TOP = 56, Option4.WIDTH = 125, ;
Option4.AUTOSIZE = .T., Option4.NAME = "Option4", ;
Option5.BACKSTYLE = 0, Option5.CAPTION = "Conos verticales", ;
Option5.HEIGHT = 17, Option5.LEFT = 8, Option5.TOP = 72, Option5.WIDTH = 110, ;
Option5.AUTOSIZE = .T., Option5.NAME = "Option5", ;
Option6.BACKSTYLE = 0, Option6.CAPTION = "Conos horizontales", ;
Option6.HEIGHT = 17, Option6.LEFT = 8, Option6.TOP = 88, Option6.WIDTH = 125, ;
Option6.AUTOSIZE = .T., Option6.NAME = "Option6"
ADD OBJECT opgLeyendas AS OPTIONGROUP WITH ;
BUTTONCOUNT = 6, ANCHOR = 6, VALUE = 6, ;
HEIGHT = 112, LEFT = 176, TOP = 280, WIDTH = 152, ;
TABINDEX = 3, NAME = "opgLeyendas", ;
Option1.BACKSTYLE = 0, Option1.CAPTION = "Sin leyendas", ;
Option1.HEIGHT = 17, Option1.LEFT = 8, Option1.TOP = 8, Option1.WIDTH = 89, ;
Option1.AUTOSIZE = .T., Option1.NAME = "Option1", ;
Option2.BACKSTYLE = 0, Option2.CAPTION = "Valores", ;
Option2.HEIGHT = 17, Option2.LEFT = 8, Option2.TOP = 24, Option2.WIDTH = 60, ;
Option2.AUTOSIZE = .T., Option2.NAME = "Option2", ;
Option3.BACKSTYLE = 0, Option3.CAPTION = "Porcentajes", ;
Option3.HEIGHT = 17, Option3.LEFT = 8, Option3.TOP = 40, Option3.WIDTH = 84, ;
Option3.AUTOSIZE = .T., Option3.NAME = "Option3", ;
Option4.BACKSTYLE = 0, Option4.CAPTION = "Rótulos", ;
Option4.HEIGHT = 17, Option4.LEFT = 8, Option4.TOP = 56, Option4.WIDTH = 61, ;
Option4.AUTOSIZE = .T., Option4.NAME = "Option4", ;
Option5.BACKSTYLE = 0, Option5.CAPTION = "Rótulos y valores", ;
Option5.VALUE = 0, Option5.HEIGHT = 17, Option5.LEFT = 8, Option5.TOP = 72, ;
Option5.WIDTH = 112, Option5.AUTOSIZE = .T., Option5.NAME = "Option5", ;
Option6.BACKSTYLE = 0, Option6.CAPTION = "Porcentajes y rótulos", ;
Option6.VALUE = 1, Option6.HEIGHT = 17, Option6.LEFT = 8, Option6.TOP = 88, ;
Option6.WIDTH = 133, Option6.AUTOSIZE = .T., Option6.NAME = "Option6"
ADD OBJECT lmGraph AS lmgraph WITH ;
ANCHOR = 15, TOP = 8, LEFT = 8, WIDTH = 480, HEIGHT = 264, ;
TABINDEX = 1, NAME = "lmGraph", lbl.NAME = "lbl"
ADD OBJECT chk AS CHECKBOX WITH ;
TOP = 404, LEFT = 304, HEIGHT = 17, WIDTH = 53, ANCHOR = 6, ;
WORDWRAP = .T., AUTOSIZE = .T., ALIGNMENT = 0, BACKSTYLE = 0, ;
CAPTION = "DEMO", VALUE = .F., TABINDEX = 8, NAME = "chk"
ADD OBJECT opgDatos AS OPTIONGROUP WITH ;
BUTTONCOUNT = 2, ANCHOR = 6, VALUE = 1, HEIGHT = 48, ;
LEFT = 344, TOP = 336, WIDTH = 136, TABINDEX = 5, NAME = "opgDatos", ;
Option1.BACKSTYLE = 0, Option1.CAPTION = "Ejemplo semanal", ;
Option1.VALUE = 1, Option1.HEIGHT = 17, Option1.LEFT = 8, Option1.TOP = 8, ;
Option1.WIDTH = 116, Option1.AUTOSIZE = .T., Option1.NAME = "Option1", ;
Option2.BACKSTYLE = 0, Option2.CAPTION = "Ejemplo anual", ;
Option2.VALUE = 0, Option2.HEIGHT = 17, Option2.LEFT = 8, Option2.TOP = 24, ;
Option2.WIDTH = 98, Option2.AUTOSIZE = .T., Option2.NAME = "Option2"
ADD OBJECT lblTitulo AS LABEL WITH ;
AUTOSIZE = .T., ANCHOR = 6, BACKSTYLE = 0, CAPTION = "Título", ;
HEIGHT = 17, LEFT = 16, TOP = 404, WIDTH = 32, TABINDEX = 6, NAME = "lblTitulo"
ADD OBJECT txtTitulo AS TEXTBOX WITH ;
ANCHOR = 6, VALUE = "TOTAL DE VENTAS", HEIGHT = 23, LEFT = 56, ;
TABINDEX = 7, TOP = 400, WIDTH = 232, NAME = "txtTitulo"
PROCEDURE GenerarCursor
LPARAMETERS tnDatos
CREATE CURSOR MiCursor (Valor N(10,2), Rotulo C(20))
IF tnDatos = 1
INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Lunes")
INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Martes")
INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Miércoles")
INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Jueves")
INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Viernes")
INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Sábado")
INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Domingo")
ELSE
INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Enero")
INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Febrero")
INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Marzo")
INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Abril")
INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Mayo")
INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Junio")
INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Julio")
INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Agosto")
INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Setiembre")
INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Octubre")
INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Noviembre")
INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Diciembre")
ENDIF
ENDPROC
PROCEDURE tmr.TIMER
THISFORM.opgGraficas.VALUE = CEILING(RAND()*6)
THISFORM.opgLeyendas.VALUE = CEILING(RAND()*6)
THISFORM.opgColores.VALUE = CEILING(RAND()*2)
THISFORM.opgDatos.VALUE = CEILING(RAND()*2)
THISFORM.txtTitulo.VALUE = IIF(THISFORM.opgDatos.VALUE = 1, ;
"Total de ventas por día", "Total de ventas por mes")
THISFORM.cmdGenerar.CLICK
ENDPROC
PROCEDURE cmdGenerar.CLICK
WITH THISFORM.lmGraph
.TipoGrafica = THISFORM.opgGraficas.VALUE - 1
.TipoLeyenda = THISFORM.opgLeyendas.VALUE - 1
.TipoColor = THISFORM.opgColores.VALUE - 1
.ALIAS = "MiCursor"
.TituloGrafica = ALLTRIM(THISFORM.txtTitulo.VALUE)
THISFORM.GenerarCursor(THISFORM.opgDatos.VALUE)
.GenerarGrafica()
ENDWITH
ENDPROC
PROCEDURE chk.VALID
IF THIS.VALUE
THISFORM.tmr.TIMER
ENDIF
THISFORM.SETALL("Enabled", NOT THIS.VALUE, "CommandButton")
THISFORM.SETALL("Enabled", NOT THIS.VALUE, "OptionGroup")
THISFORM.SETALL("Enabled", NOT THIS.VALUE, "TextBox")
THISFORM.tmr.ENABLED = THIS.VALUE
ENDPROC
ENDDEFINE
*--
*-- Definición de la clase lmGraph
*--
DEFINE CLASS lmgraph AS CONTAINER
WIDTH = 200
HEIGHT = 100
SPECIALEFFECT = 1
BACKCOLOR = RGB(255,255,255)
ALIAS = ""
TipoLeyenda = 5
TipoColor = 0
TipoGrafica = 0
TituloGrafica = "Título"
NAME = "lmgraph"
ADD OBJECT lbl AS LABEL WITH ;
AUTOSIZE = .T., FONTBOLD = .T., BACKSTYLE = 0, ;
CAPTION = "lmGraph v.1.0", HEIGHT = 17, LEFT = 8, ;
TOP = 8, VISIBLE = .F., WIDTH = 79, NAME = "lbl"
*-- Genera la Gráfica
PROCEDURE GenerarGrafica
LOCAL lcCampoRotulo, lcCampo, lnSaltoH, lnSaltoV, lnReg, ;
lnTotal, lnCantReg, lnMaximo, lnMaxWidth, lcRotulo, lnValor, lnPorc, ;
lcObjPor, lcObjShp, lcObjLey, lnDim, lnHasta, ;
lnI, lnJ, lnAng, lnCos, lnSen, lcObj1, lcObj2
*--
*-- Limpio los objetos del gráfico
*--
THIS.LimpiarGrafica()
*---
*--- Verifico la versión de VFP y tipo de gráfica
*---
IF VERSION(5) < 900 AND INLIST(THIS.TipoGrafica, 0, 1, 4, 5)
MESSAGEBOX("El tipo de gráfica seleccionada no esta disponible para" + ;
CHR(13) + VERSION(), 48, "lmGraph")
RETURN
ENDIF
*--
*-- Tabla de datos
*--
IF EMPTY(THIS.ALIAS)
MESSAGEBOX("No especificó la propiedad Alias.", 48, "lmGraph")
RETURN
ENDIF
IF NOT USED(THIS.ALIAS)
MESSAGEBOX("La tabla " + PROPER(THIS.ALIAS) + ;
" no está en uso.", 48, "lmGraph")
RETURN
ENDIF
IF AFIELDS(la,THIS.ALIAS) < 2
MESSAGEBOX("La tabla " + PROPER(THIS.ALIAS) + ;
" tiene menos de dos campos.", 48, "lmGraph")
RETURN
ENDIF
IF NOT INLIST(la(1,2), "N", "I")
MESSAGEBOX("El segundo campo de la tabla " + PROPER(THIS.ALIAS) + ;
" no es numérico.", 48, "lmGraph")
RETURN
ENDIF
SELECT (THIS.ALIAS)
lcCampoValor = la(1,1)
lcCampoRotulo = la(2,1)
CALCULATE COUNT() TO lnCantReg
IF lnCantReg = 0
MESSAGEBOX("La tabla " + PROPER(THIS.ALIAS) + ;
" no contiene datos.", 48, "lmGraph")
RETURN
ENDIF
CALCULATE SUM(EVALUATE(lcCampoValor)) TO lnTotal
CALCULATE MAX(EVALUATE(lcCampoValor)) TO lnMaximo
*--
*-- Variables y área del gráfico
*--
#DEFINE AnguloPrimerSector 270
#DEFINE AngulosParaGraficar 360
lnAnguloSector = AnguloPrimerSector
lnLeft = 10
lnTop = IIF(EMPTY(THIS.TituloGrafica),10,30)
lnWidth = THIS.WIDTH - lnLeft * 2
lnHeight = THIS.HEIGHT - lnTop - lnLeft
lnSaltoH = FLOOR(lnHeight / lnCantReg)
*--
*-- Titulo del gráfico
*--
IF NOT EMPTY(THIS.TituloGrafica) && Con título
THIS.ADDOBJECT("lblTitulo","Label")
WITH THIS.lblTitulo
.BACKSTYLE = 0
.ALIGNMENT = 2
.FONTSIZE = 12
.FONTBOLD = .T.
.CAPTION = THIS.TituloGrafica
.TOP = 5
.LEFT = lnLeft
.WIDTH = lnWidth
.HEIGHT = 30
ENDWITH
ENDIF
*--
*-- Armo leyenda y tomo el ancho
*--
IF THIS.TipoLeyenda # 0 && Con leyenda
lnMaxWidth = 0
lnReg = 1
SCAN ALL
lcRotulo = ALLTRIM(TRANSFORM(EVALUATE(lcCampoRotulo)))
lnValor = EVALUATE(lcCampoValor)
lnPorc = lnValor / lnTotal * 100
lcObjLey = "oLey" + TRANSFORM(lnReg)
THIS.ADDOBJECT(lcObjLey,"Label")
WITH THIS.&lcObjLey
.TOP = lnSaltoH * lnReg - lnSaltoH + lnTop
DO CASE
CASE THIS.TipoLeyenda = 1
.CAPTION = TRANSFORM(lnValor)
CASE THIS.TipoLeyenda = 2
.CAPTION = TRANSFORM(ROUND(lnPorc,2)) + "%"
CASE THIS.TipoLeyenda = 3
.CAPTION = lcRotulo
CASE THIS.TipoLeyenda = 4
.CAPTION = lcRotulo + " - " + TRANSFORM(lnValor)
OTHERWISE
.CAPTION = TRANSFORM(ROUND(lnPorc,2)) + "% - " + lcRotulo
ENDCASE
.FONTSIZE = 8
.BACKSTYLE = 0
.LEFT = lnWidth + 100
.AUTOSIZE = .T.
.VISIBLE = .T.
lnMaxWidth = MAX(lnMaxWidth,.WIDTH)
ENDWITH
lnReg = lnReg + 1
ENDSCAN
lnLeftLeyenda = MAX(lnWidth * .60, lnWidth - lnMaxWidth - 40)
ENDIF
*--
*-- Armo el resto del gráfico
*--
lnReg = 1
SCAN ALL
lnValor = EVALUATE(lcCampoValor)
lnPorc = lnValor / lnTotal * 100
*--
*-- Armo cada porcion
*--
lcObjPor = "oPor" + TRANSFORM(lnReg)
THIS.ADDOBJECT(lcObjPor,"Shape")
WITH THIS.&lcObjPor
DO CASE
CASE THIS.TipoGrafica = 0 OR THIS.TipoGrafica = 1 && Torta/Anillo
IF THIS.TipoLeyenda = 0 && Sin leyenda
STORE MIN(lnWidth ,lnHeight) TO .WIDTH, .HEIGHT
.TOP = FLOOR((lnHeight - .HEIGHT) / 2 + lnTop)
.LEFT = FLOOR((lnWidth - .WIDTH) / 2 + lnLeft)
ELSE
STORE MIN(lnLeftLeyenda, lnHeight) TO .WIDTH, .HEIGHT
.TOP = FLOOR((lnHeight - .HEIGHT) / 2 + lnTop)
.LEFT = FLOOR((lnLeftLeyenda - .WIDTH) / 2 + lnLeft)
ENDIF
.POLYPOINTS = "This.aPoly"
lnDim = AngulosParaGraficar * lnPorc / 100
lnHasta = CEILING(lnDim) + 1
.ADDPROPERTY("aPoly[" + TRANSFORM(lnHasta) + ",2]")
STORE 50 TO .aPoly[1,1], .aPoly[1,2]
FOR lnI = 2 TO lnHasta
lnAng = (360 / AngulosParaGraficar) * (lnI - 2)
lnCos = COS(DTOR(lnAng + lnAnguloSector))
lnSen = SIN(DTOR(lnAng + lnAnguloSector))
.aPoly(lnI,1) = 50 * lnCos + 50
.aPoly(lnI,2) = 50 * lnSen + 50
ENDFOR
lnAnguloSector = lnAnguloSector + lnDim * 360 / AngulosParaGraficar
CASE THIS.TipoGrafica = 2 OR THIS.TipoGrafica = 4 && Barras/Conos Verticales
IF THIS.TipoLeyenda = 0 && Sin leyenda
lnSaltoV = FLOOR(lnWidth / lnCantReg)
ELSE
lnSaltoV = FLOOR(lnLeftLeyenda / lnCantReg)
ENDIF
.WIDTH = lnSaltoV + 1
.LEFT = lnSaltoV * lnReg - lnSaltoV + lnLeft
.HEIGHT = lnValor / lnMaximo * lnHeight
.TOP = lnHeight - .HEIGHT + lnTop
IF THIS.TipoGrafica = 4 && Conos
.POLYPOINTS = "This.aPoly"
.ADDPROPERTY("aPoly[" + TRANSFORM(4) + ",2]")
STORE 0 TO .aPoly[1,1], .aPoly[2,2], .aPoly[3,2]
STORE 100 TO .aPoly[1,2], .aPoly[4,1], .aPoly[4,2]
.aPoly[2,1] = 30
.aPoly[3,1] = 70
ENDIF
CASE THIS.TipoGrafica = 3 OR THIS.TipoGrafica = 5 && Barras/Conos Horizontales
IF THIS.TipoLeyenda = 0 && Sin leyenda
.WIDTH = lnValor / lnMaximo * lnWidth
ELSE
.WIDTH = lnValor / lnMaximo * lnLeftLeyenda
ENDIF
.LEFT = lnLeft
.HEIGHT = lnSaltoH + 1
.TOP = lnSaltoH * lnReg - lnSaltoH + lnTop
IF THIS.TipoGrafica = 5 && Conos
.POLYPOINTS = "This.aPoly"
.ADDPROPERTY("aPoly[" + TRANSFORM(4) + ",2]")
STORE 0 TO .aPoly[1,1], .aPoly[2,1], .aPoly[2,2]
STORE 100 TO .aPoly[1,2], .aPoly[3,1], .aPoly[4,1]
.aPoly[3,2] = 25
.aPoly[4,2] = 75
ENDIF
OTHERWISE
MESSAGEBOX("Tipo de gráfica no definida.", 48, "lmGraph")
RETURN
ENDCASE
*--
*-- Color de la porción
*--
IF THIS.TipoColor = 0
.BACKCOLOR = FLOOR(RAND() * 16777216) && Aleatorio
ELSE
.BACKCOLOR = THIS.ColoresBasicos(lnReg)
ENDIF
ENDWITH
*--
*-- Armo leyendas
*--
IF THIS.TipoLeyenda # 0 && Con leyenda
lcObjShp = "oShp" + TRANSFORM(lnReg)
THIS.ADDOBJECT(lcObjShp,"Shape")
WITH THIS.&lcObjShp
.HEIGHT = 12
.WIDTH = 12
.BACKCOLOR = EVALUATE("THIS.oPor" + TRANSFORM(lnReg) + ".BACKCOLOR")
.TOP = lnSaltoH * lnReg - lnSaltoH + lnTop
.LEFT = lnLeftLeyenda + lnLeft + 10
ENDWITH
lcObjLey = "oLey" + TRANSFORM(lnReg)
WITH THIS.&lcObjLey
.LEFT = lnLeftLeyenda + lnLeft + 30
ENDWITH
ENDIF
lnReg = lnReg + 1
ENDSCAN
*--
*-- Anillo
*--
IF THIS.TipoGrafica = 1 && Anillo
THIS.ADDOBJECT("oShpMed","Shape")
WITH THIS.oShpMed
IF THIS.TipoLeyenda = 0 && Sin leyenda
STORE MIN(lnWidth ,lnHeight) * .45 TO .WIDTH, .HEIGHT
.TOP = FLOOR((lnHeight - .HEIGHT) / 2 + lnTop)
.LEFT = FLOOR((lnWidth - .WIDTH) / 2 + lnLeft)
ELSE
STORE MIN(lnLeftLeyenda, lnHeight) * .45 TO .WIDTH, .HEIGHT
.TOP = FLOOR((lnHeight - .HEIGHT) / 2 + lnTop)
.LEFT = FLOOR((lnLeftLeyenda - .WIDTH) / 2 + lnLeft)
ENDIF
.BACKCOLOR = THIS.BACKCOLOR
.CURVATURE = 99
ENDWITH
ENDIF
*--
*-- Uno porciones en Torta/Anillo
*--
IF THIS.TipoGrafica = 0 OR THIS.TipoGrafica = 1 && Torta/Anillo
FOR lnI = 1 TO lnCantReg - 1
lcObj1 = "This.oPor" + TRANSFORM(lnI)
lcObj2 = "This.oPor" + TRANSFORM(lnI+1)
lnJ = ALEN(&lcObj1..aPoly,1)
&lcObj1..aPoly(lnJ,1) = &lcObj2..aPoly(2,1)
&lcObj1..aPoly(lnJ,2) = &lcObj2..aPoly(2,2)
ENDFOR
lcObj1 = "This.oPor" + TRANSFORM(1)
lnJ = ALEN(&lcObj2..aPoly,1)
&lcObj2..aPoly(lnJ,1) = &lcObj1..aPoly(2,1)
&lcObj2..aPoly(lnJ,2) = &lcObj1..aPoly(2,2)
ENDIF
*--
*-- Hago visible los objetos creados
*--
THIS.SETALL("Visible",.T., "Shape")
THIS.SETALL("Visible",.T., "Label")
ENDPROC
PROCEDURE ColoresBasicos
LPARAMETERS tn
LOCAL la(28)
tn = MOD(tn-1,28)+1
la(1) = RGB(255,0,0) && Rojo
la(2) = RGB(255,255, 0) && Amarillo
la(3) = RGB(0,0,255) && Azul
la(4) = RGB(0,128,0) && Verde Oscuro
la(5) = RGB(255,128,0) && Anaranjado
la(6) = RGB(128,64,0) && Marrón
la(7) = RGB(255,0,255) && Magenta
la(8) = RGB(128,0,255) && Violeta
la(9) = RGB(0,255,255) && Cyan
la(10) = RGB(192,192,0) && Amarillo Oscuro
la(11) = RGB(192,0,0) && Rojo Oscuro
la(12) = RGB(0,255,0) && Verde
la(13) = RGB(0,0,128) && Azul Oscuro
la(14) = RGB(255,192,0) && Anaranjado Claro
la(15) = RGB(0,192,255) && Azul claro
la(16) = RGB(128,128,0) && Marrón Claro
la(17) = RGB(255,192,255) && Magenta Claro
la(18) = RGB( 64,128,128) && Verde Azulado
la(19) = RGB(255,0,128) && Fucsia
la(20) = RGB(255,255,192) && Amarillo Claro
la(21) = RGB(192,0,255) && Violeta Claro
la(22) = RGB(192,255,192) && Verde Claro
la(23) = RGB(128,0,128) && Violeta Oscuro
la(24) = RGB(192,255,255) && Cyan Claro
la(25) = RGB(128,128,128) && Gris Oscuro
la(26) = RGB(255,255,255) && Blanco
la(27) = RGB(192,192,192) && Gris
la(28) = RGB(0,0,0) && Negro
RETURN la(tn)
ENDPROC
PROCEDURE LimpiarGrafica
LOCAL lnI
FOR lnI = THIS.CONTROLCOUNT TO 1 STEP -1
THIS.REMOVEOBJECT(THIS.CONTROLS(lnI).NAME)
ENDFOR
ENDPROC
PROCEDURE INIT
SET TALK OFF
RAND(-1)
ENDPROC
ENDDEFINE
La descarga
Pueden descargar el proyecto con el formulario de ejemplo y la clase lmGraph desde el enlace siguiente:
El final
Con la clase presentada en este artículo, ustedes podrán generar gráficas simples y muy fáciles de incorporar en formularios de VFP. Si necesitan gráficas mas avanzadas utilizando solo Visual FoxPro, los invito a que lean el excelente artículo de Cesar Ch. publicado en la revista UTMag y se sorprenderán de todo lo que se puede realizar con GDI+
- Gráficos en torta avanzados con GDI+
- http://www.utmag.com/wconnect/wc.dll?9,7,10,Spanish,2094
Los comentarios
Cualquier comentario que quieran realizar sobre este artículo y esta clase, será bienvenido. Solo envien sus comentario haciendo clic en el botón "Enviar comentario" al final de este artículo.
Hasta la próxima.
Luis María Guayán
¿Cómo se podría guardar, por programación, una imagen (bmp, gif, jpg) del gráfico generado?
ResponderBorrarEstimado, ¿encontraste como copiar a una imagen el gráfico generado?
BorrarLo quiero quiero llevar a mi reporte vfp.
Gracias
Lo puedes hacer con la clase GDIPlusX de Cesar Ch.
ResponderBorrarhttp://vfpx.codeplex.com/wikipage?title=GDIPlusX&ProjectName=vfpx
En tu formulario con la clase lmGraph, en el método Click de un botón Imprimir por ej:
Do System.App
local loBmp as xfcBitmap
With _Screen.System.Drawing
loBmp = .Bitmap.FromScreen(Thisform.lmGraph1) && parametro objecto lmGraph
*-- Para guardar como imagen
*loBmp.Save("c:\lmGraph.Png", .Imaging.ImageFormat.Png)
*-- Para imprimir
loBmp.ToPrinter()
EndWith
Buen día muy buen ayuda gracias
ResponderBorrarComo podría imprimir la gráfica que se genera en la clase?
En la respuesta de arriba está la solución:
ResponderBorrarLo puedes hacer con la clase GDIPlusX de Cesar Ch.
http://vfpx.codeplex.com/wikipage?title=GDIPlusX&ProjectName=vfpx
En tu formulario con la clase lmGraph, en el método Click de un botón Imprimir por ej:
Do System.App
local loBmp as xfcBitmap
With _Screen.System.Drawing
loBmp = .Bitmap.FromScreen(Thisform.lmGraph1) && parametro objecto lmGraph
*-- Para guardar como imagen
*loBmp.Save("c:\lmGraph.Png", .Imaging.ImageFormat.Png)
*-- Para imprimir
loBmp.ToPrinter()
EndWith
¿Como lo hago con la versión 6.0 ?
BorrarGracias.
Buenas tardes. como podríamos en vista previa
ResponderBorrarUna vez guardado como imagen, puedes poner en un reporte un objeto picture y referenciar el archivo generado.
Borrar