
This is the source for the main S-Control described in the article, it contains the controlling logic and none of the user interface. Copy this code into a new S-Control.
<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- use new ajax -->
<script src="/soap/ajax/8.0/connection.js"></script>
<!-- and snippet holds the src for FlexAJAX bridge, could be included here also -->
{!INCLUDE($SControl.FlexAjaxBridge)}
<script language="javascript">
var debug = true;
var $alert = function(s) { if (debug) alert(s); }
var flexApp = null;
var selectedItem = null;
var sfDataList = null;
</script>
<!-- JS Controler code for loading initial dataset and responding events that come via the FABridge -->
<script language="javascript">
// setup the PIE
// the query must contain all the fields we push into the pie or labels
var query = "Select ID, Name, StageName, Type, Amount,CloseDate from Opportunity where AccountId = '{!Account.Id}' order by stagename";
var chartTitle = 'Opportunities at {!Account.Name}';
function groupBy(r) { return r.StageName; } // given a record, return the value from the group by field.
// this function is called from the flash movie for each dataitem
// we construct the pie label from bits of the dataitem (di)
function pieSetLabel(di, field, index, percentValue) {
return di.StageName + '\n$' + di.Amount.toString().replace(/\.0/,"");
//return di.Name + '\n$' + di.Amount.toLocaleString();
}
// some exploding pie effects
function explodePieOnClick( event) {
var hit = event.hitData().item();
selectedItem = hit; // save in a global
var data = flexApp.chart().dataProvider(); // pull out the data array
var explodeData = [];
for (var i = 0; i < data.length(); i++ ) { // match on Name
if ( groupBy(data.getItemAt(i) ) == groupBy(hit) ) { explodeData[i] = 0.15; }
}
flexApp.chart_series().setPerWedgeExplodeRadius( explodeData );
//debug('clicked this ' + hit.Name +'(' + hit.Amount+')');
// drill down chart... with related data?
pushColumnChart(selectedItem);
}
// end PIE helpers
// mx:ColumnChart helpers
function pushColumnChart( data ) { // called when a pie wedge is selected
/* set these here: categoryField , xField, yField
* rather than in the flex xml
<mx:ColumnChart id="ColumnChart"
<mx:horizontalAxis>
<mx:CategoryAxis categoryField="Name"/>
<mx:series>
<mx:ColumnSeries xField="Name" yField="Amount
*/
var cc = flexApp.ColumnChart();
cc.horizontalAxis().setCategoryField('Name');
with ( cc.series()[0] ) { setXField('Name'); setYField('Amount'); }
// construct a data provider using all rows of data that have matching stagename
var columnDataProvider =[];
for (var i = 0; i < sfDataList.length; i++) {
if ( groupBy( sfDataList[i] ) == groupBy(data) ) { // is a match
columnDataProvider.push( { Name:sfDataList[i].Name, Amount:sfDataList[i].Amount ,Id:sfDataList[i].Id} );
}
}
cc.setDataProvider( columnDataProvider );
cc.validateNow();
}
function jumpColumnChartClick( event ) {
var hit = event.hitData().item();
// alert('you clicked ' + hit.Name);
window.parent.location.href = "/"+hit.Id;
}
/************* some utility functions */
function windowLocationGoto(url) {
$alert('goto where');
window.location.href = url;
}
function debug(s){try {
document.getElementById('dbg').innerHTML += s +'<br>';
} catch(e){}
}
/*************
* main()
***************/
function sfdcQueryCallback(queryResult) {
flexApp.panel().setTitle( chartTitle ); // set a property across the bridge
flexApp.chart_series().setField('Amount'); // this field must be set, used to proportion pie
// setDataProvider walks our list of sobjects constructing dataitems
sfDataList = queryResult.getArray('records');
debug('sfdcQueryCallback, found ' + sfDataList.length +' records');
// group this list by one of the paramaters, StageName in this case
// then the column chart can hold the drill down of the grouped data point
if ( sfDataList.length < 1) { alert('no data found '); return }
var stages = [];
stages[0] = { StageName: sfDataList[0].StageName, Amount:sfDataList[0].Amount}; // push first entry
for ( var i = 1; i < sfDataList.length; i++ ) {
// if this stage is != previous stage, push a fresh row
if ( groupBy( stages[stages.length-1] ) != groupBy( sfDataList[i] ) ) {
stages.push( {StageName:sfDataList[i].StageName, Amount:sfDataList[i].Amount-0} );
} else { // add ammount from matching stage to current row
stages[stages.length-1].Amount = (stages[stages.length-1].Amount-0) + (sfDataList[i].Amount-0);
}
}
debug(' found stages '+stages.length);
// now stages array has grouped the opps by stagename with amounts totaled
var oppsByStage = [];
for ( var i = 0; i < stages.length; i++ ) {
oppsByStage.push( {StageName:stages[i].StageName,Amount:stages[i].Amount} );
debug(oppsByStage[oppsByStage.length-1].StageName + ' ' +oppsByStage[oppsByStage.length-1].Amount);
}
flexApp.chart().setDataProvider(oppsByStage); // pass data array to the chart, it will draw
// register for click callback by adding an event listener on a pie item
// ask for the itemClick event to get the data we need
flexApp.chart().addEventListener('itemClick', explodePieOnClick);
// respond to clicks on the column chart also
flexApp.ColumnChart().addEventListener('itemClick', jumpColumnChartClick);
}
function sfdcOnLoad() {
flexApp = FABridge.flash.root(); // set a global for the bridge
sforce.connection.query(query,sfdcQueryCallback); // launch a query to load the initial chart data
}
</script>
</head>
<body scroll="no" onload="FABridge.addInitializationCallback('flash',sfdcOnLoad);">
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" id="PieChartExample" width="100%" height="100%"
codebase="https://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
<param name="movie" value="{!Scontrol.JavaArchive}" />
<param name="quality" value="high" /><param name="play" value="true" />
<param name="bgcolor" value="#f3f3ec" /><param name="allowScriptAccess" value="always" />
<embed src="{!Scontrol.JavaArchive}" play="true" bgcolor="#f3f3ec" width="100%" height="250" name="PieChartExample" align="middle"
loop="false" allowScriptAccess="always" type="application/x-shockwave-flash" pluginspage="http://www.adobe.com/go/getflashplayer"></embed>
</object>
<div id="dbg" style="display:none;">debug</div>
</body>
</html>