Basic example of Google Charts with DataFlex WebApp
By Mike Peat
Below we will create a DataFlex wrapper component for the Google Charts component.
A wrapper consists of multiple parts working together, so that you can use the control directly from your DataFlex web application. The first two elements are the client-side JavaScript part (actually a JavaScript pseudo-class) and the server-side DataFlex class, which together make up the new component.
The JavaScript part
Create a new folder GoogleCharts in your AppHtml folder and put the following in the file Charts.js
(AppHTML\GoogleCharts\Charts.js):
if (!myCharts) { // Configure namespace if not already defined
var myCharts = {};
}
myCharts.chart = function chart(sName, oParent) {
// Forward send constructor
myCharts.chart.base.constructor.call(this, sName, oParent);
// Load the Visualization API and the corechart package.
google.charts.load('current', {'packages':['corechart']});
// Properties:
this.prop(df.tString, "psTitle", "");
this.prop(df.tInt, "piChartHeight", 0);
this.prop(df.tInt, "piChartWidth", 0);
this.prop(df.tString, "psChartType", "");
// Private:
this._eWrap = null;
this._eCols = [];
this._eData = [];
// Configure super classes
this._sControlClass = "chart";
};
df.defineClass("myCharts.chart", "df.WebBaseControl", {
openHtml : function(aHtml) {
// Forward send
myCharts.chart.base.openHtml.call(this, aHtml);
aHtml.push('<div class="chart-wrp">');
aHtml.push(' <div id="', this.psHtmlId, 'chartDiv"', ' style="height: 100%;"></div>');
aHtml.push('</div>');
},
afterRender : function() {
this._eControl = df.dom.query(this._eElem, "div.chart-wrp > div");
this._eWrap = df.dom.query(this._eElem, "div.chart-wrp");
// Forward send
myCharts.chart.base.afterRender.call(this);
},
initalize : function() {
this._eCols = [];
this._eData = [];
},
addColumn : function(sName, iType) {
var i = this._eCols.length;
this._eCols[i] = [iType, sName];
},
addData : function(sName, nValue) {
var i = this._eData.length;
this._eData[i] = [sName, Number(nValue)]
},
drawChart : function() {
myCharts.obj = this;
// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(this.chartDef);
},
chartDef : function() {
var data = new google.visualization.DataTable();
var options, chart, obj = myCharts.obj;
for (var i = 0; i < obj._eCols.length; i++) {
data.addColumn(obj._eCols[i][0], obj._eCols[i][1]);
}
data.addRows(obj._eData);
options = {
title : obj.psTitle,
width : obj.piChartWidth,
height : obj.piChartHeight
};
switch (obj.psChartType) {
case "PieChart":
chart = new google.visualization.PieChart(obj._eControl);
break;
case "BarChart":
chart = new google.visualization.BarChart(obj._eControl);
break;
case "AreaChart":
chart = new google.visualization.AreaChart(obj._eControl);
break;
default:
chart = new google.visualization.PieChart(obj._eControl);
}
chart.draw(data, options);
}
});
The DataFlex counterpart class
Create a new file called cWebChart.pkg in the AppSrc folder and copy the following in there.
DataFlex class (AppSrc\cWebChart.pkg):
Use cWebBaseControl.pkg
Use cJsonObject.pkg // Just to get the types
Define C_chartTypePie for "PieChart"
Define C_chartTypeBar for "BarChart"
Define C_chartTypeArea for "AreaChart"
// etc...
Class cWebChart is a cWebBaseControl
Procedure Construct_Object
Forward Send Construct_Object
{ WebProperty=Client }
Property String psTitle
{ WebProperty=Client }
Property Integer piChartHeight
{ WebProperty=Client }
Property Integer piChartWidth
{ WebProperty=Client }
Property String psChartType
Set psJSClass to "myCharts.chart"
End_Procedure
Procedure Initalize
Send ClientAction "initalize"
End_Procedure
Procedure AddColumn String sName Integer iType
String[] asParams
String sType
Case Begin
Case (iType = jsonTypeString)
Move "string" to sType
Case Break
Case (iType = jsonTypeInteger)
Move "number" to sType
Case Break
Case (iType = jsonTypeInteger)
Move "number" to sType
Case Break
Case (iType = jsonTypeDouble)
Move "number" to sType
Case Break
Case (iType = jsonTypeBoolean)
Move "boolean" to sType
Case Break
Case Else
Move "string" to sType
Case End
Move sName to asParams[0]
Move sType to asParams[1]
Send ClientAction "addColumn" asParams
End_Procedure
Procedure AddData String sName Number nValue
String[] asParams
Move sName to asParams[0]
Move nValue to asParams[1]
Send ClientAction "addData" asParams
End_Procedure
Procedure DrawChart
Send ClientAction "drawChart"
End_Procedure
End_Class
An example web object
Now that we have our component, we need to deploy it, so here is a sample view using it:
Use cWebView.pkg
Use cWebPanel.pkg
Use cWebForm.pkg
Use cWebButton.pkg
Use cWebChart.pkg
Use cWebRadio.pkg
Object oChart is a cWebView
Set piWidth to 700
Set psCaption to "Chart"
Delegate Set phoDefaultView to Self
Object oWebMainPanel is a cWebPanel
Set piColumnCount to 12
Object oPie is a cWebRadio
Set piColumnSpan to 3
Set psCaption to "Pie Chart"
Set psRadioValue to C_chartTypePie
End_Object
Object oBar is a cWebRadio
Set piColumnSpan to 3
Set piColumnIndex to 3
Set psCaption to "Bar Chart"
Set psRadioValue to C_chartTypeBar
End_Object
Object oArea is a cWebRadio
Set piColumnSpan to 3
Set piColumnIndex to 6
Set psCaption to "Area Chart"
Set psRadioValue to C_chartTypeArea
End_Object
Object oDrawChart is a cWebButton
Set piColumnSpan to 2
Set psCaption to "Show Chart"
Procedure OnClick
String sType
Send Initalize of oChart
WebGet psValue of oPie to sType
WebSet psTitle of oChart to "How Much Pizza I Ate Last Night"
WebSet piChartHeight of oChart to 500
WebSet piChartWidth of oChart to 600
WebSet psChartType of oChart to sType
Send AddColumn of oChart "Topping" jsonTypeString
Send AddColumn of oChart "Slices" jsonTypeInteger
Send AddData of oChart "Mushrooms" 6
Send AddData of oChart "Onions" 3
Send AddData of oChart "Olives" 2
Send AddData of oChart "Frogs Legs" 1
Send AddData of oChart "Pepperoni" 4
Send AddData of oChart "Anchovies" 5
Send DrawChart of oChart
End_Procedure
End_Object
Object oChart is a cWebChart
End_Object
End_Object
End_Object
Add new control to your app
In order to be able to use that new control, you have to add it to the index.html file like so:
...
<!-- DataFlex Custom Controls (do not remove this line, used for automatic insertion) -->
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script src="GoogleCharts/Charts.js"></script>
<!-- Initialization of the WebApp -->
...
Screenshots and example workspace
You can download a completely functional DataFlex 19.1 Workspace down here, unzip, register in DataFlex 19.1, let the Studio create the javascript engine folders and run:
File:GoogleChartsDemo-20200326.zip
Addendum...
Never one to leave well enough alone, I have been playing further...
In the JavaScript, I extended the "switch" statement in the chartDef function as follows:
switch (obj.psChartType) {
case "PieChart":
chart = new google.visualization.PieChart(obj._eControl);
break;
case "BarChart":
chart = new google.visualization.BarChart(obj._eControl);
break;
case "AreaChart":
chart = new google.visualization.AreaChart(obj._eControl);
break;
case "ColChart":
chart = new google.visualization.ColumnChart(obj._eControl);
break;
case "LineChart":
chart = new google.visualization.LineChart(obj._eControl);
break;
case "ScatterChart":
chart = new google.visualization.ScatterChart(obj._eControl);
break;
default:
chart = new google.visualization.PieChart(obj._eControl);
}
In order to include more chart types.
In the DataFlex class, all that changed was the definition of some new constants:
Define C_chartTypePie for "PieChart" Define C_chartTypeBar for "BarChart" Define C_chartTypeArea for "AreaChart" Define C_chartTypeScat for "ScatterChart" Define C_chartTypeLine for "LineChart" Define C_chartTypeCol for "ColChart" // etc...
Then in the sample view (Chart.wo), I got rid of the button and just had the radio controls themselves set things off:
Use cWebView.pkg
Use cWebPanel.pkg
Use cWebForm.pkg
Use cWebButton.pkg
Use cWebChart.pkg
Use cWebRadio.pkg
Object oChart is a cWebView
Set piWidth to 1000
Set psCaption to "Chart"
Delegate Set phoDefaultView to Self
Object oWebMainPanel is a cWebPanel
Set piColumnCount to 12
Object oPie is a cWebRadio
Set piColumnSpan to 2
Set psCaption to "Pie Chart"
Set psRadioValue to C_chartTypePie
Set pbServerOnChange to True
Procedure OnChange
Send DrawChart
End_Procedure
Procedure OnLoad
Send DrawChart
End_Procedure
End_Object
Object oBar is a cWebRadio
Set piColumnSpan to 2
Set piColumnIndex to 2
Set psCaption to "Bar Chart"
Set psRadioValue to C_chartTypeBar
End_Object
Object oArea is a cWebRadio
Set piColumnSpan to 2
Set piColumnIndex to 4
Set psCaption to "Area Chart"
Set psRadioValue to C_chartTypeArea
End_Object
Object oColumn is a cWebRadio
Set piColumnSpan to 2
Set piColumnIndex to 6
Set psCaption to "Column Chart"
Set psRadioValue to C_chartTypeCol
End_Object
Object oLine is a cWebRadio
Set piColumnSpan to 2
Set piColumnIndex to 8
Set psCaption to "Line Chart"
Set psRadioValue to C_chartTypeLine
End_Object
Object oScatter is a cWebRadio
Set piColumnSpan to 2
Set piColumnIndex to 10
Set psCaption to "Scatter Chart"
Set psRadioValue to C_chartTypeScat
End_Object
Procedure DrawChart
String sType
Send Initalize of oChart
WebGet psValue of oPie to sType
WebSet psTitle of oChart to "How Much Pizza I Ate Last Night"
WebSet piChartHeight of oChart to 500
WebSet piChartWidth of oChart to 600
WebSet psChartType of oChart to sType
Send AddColumn of oChart "Topping" jsonTypeString
Send AddColumn of oChart "Slices" jsonTypeInteger
Send AddData of oChart "Mushrooms" 6
Send AddData of oChart "Onions" 3
Send AddData of oChart "Olives" 2
Send AddData of oChart "Frogs Legs" 1
Send AddData of oChart "Pepperoni" 4
Send AddData of oChart "Anchovies" 5
Send DrawChart of oChart
End_Procedure
Object oChart is a cWebChart
End_Object
End_Object
End_Object
Note that we only really have to add stuff to one of the radio (OK, cWebRadio!) objects, because they all operate as a set, so oBar, oArea and friends are just vanilla radio objects, while oPie has the added Set pbServerOnChange, OnChange procedure and OnLoad procedure and is the one the DrawChart procedure WebGets the psValue of to know what kind of chart to produce.
Now the Pie Chart will be displayed when the view loads, while the various other chart types will be shown as the user clicks on the appropriate radio buttons.