Apex S-Control Source

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>