Archive for October, 2008

Campaign Member Summary using Google Charts

I was inspired by Sam Arjmandi’s post about embedding Google Charts into VisualForce pages.  I have a use case that requires a little different approach.  I needed to get a quick view of the Campaign Member Statuses for a Campaign.  I went ahead and started with Sam’s example and tweaked it for my purpose.  Here’s the result!

It’s an embedded VisualForce component in the Results section of my Campaign page.  It shows a quick count for each Member Status that is being used.  To get it going in your org, here’s what you need.

VisualForce Page

It’s a simple page containing 1 DIV so that I can set the background color to match that of a Page Layout.  Other than that it’s just an image returned from Google Charts.  There is a lot of flexibility with Google Charts.  Therefore, I made it so most of the URL can be tweaked in VisualForce. Only the data values and its labels come from the controller.  This is nice because you can edit VF in a production org, but you can’t edit Apex. This will let you change things like width, height, chart colors, chart type, etc.

<apex:page standardController="Campaign" extensions="VFController_CampaignMemberStatusChart">
        #DIV_Container{padding: 0; margin: 0; background-color: #F3F3EC;}
    <div id="DIV_Container">
        <!-- See for more info on customizing the chart -->
        <apex:image url=",s,F3F3EC&chco=CC9933{!chartData}"></apex:image>

Apex Controller
The controller is an extension of the Campaign standard controller. This is so the VisualForce page becomes an option to include on a Campaign Page Layout. The method that does all the work is getChartData. It gets the available Campaign Member Statuses and then queries the Campaign Member object for that Campaign and adds a data/label value for each one. It then returns a query string that you include into the Image src on the Visual Force page.

I am bad at Test classes, but there is 1 in there that passes and should be good enough. This functionality is pretty harmless.

public class VFController_CampaignMemberStatusChart {

	private final Campaign camp;

	public VFController_CampaignMemberStatusChart(ApexPages.StandardController stdController) { = (Campaign)stdController.getRecord();
	public String getChartData() {
		// The list of chart items	
		List<ChartDataItem> items = new List<ChartDataItem>();
		// List of valid Campaign Member Statuses for the Campaign
		List<CampaignMemberStatus> list_cms = [select Id, Label from CampaignMemberStatus where CampaignId =];
		// Loop through each Campaign Member Status, get a count of Campaign Members and add it to the items list 
		for (CampaignMemberStatus cms:list_cms) {
			integer Count = [select count() from CampaignMember where CampaignId = AND Status = :cms.Label];
			if (Count > 0) {
				items.add(new ChartDataItem(cms.Label, Count.format()));
		// Initialize Strings
		String chd = ''; // Data
		String chl = ''; // Labels
		for(ChartDataItem citem : items) {
			chd += citem.ItemValue + ',';
			chl += citem.Label + ' (' + citem.ItemValue + ')|';
		//remove the last comma or pipe
		if (items.size() > 0) {
			chd = chd.substring(0, chd.length() -1);
			chl = chl.substring(0, chl.length() -1);
		// We are only returning the values and labels. The rest of the URL string is in the VF page
		String result = '&chd=t:' + chd + '&chl=' + chl; // &chl returns with labels pointing to pie pieces
		//String result = '&chd=t:' + chd + '&chdl=' + chl; // &chdl returns with labels in a legend
		return result;

	// Class holding each chart data item
	public class ChartDataItem {
		public String ItemValue {get; set;}
		public String Label {get; set;}
		public ChartDataItem(String Label, String Value)
			this.Label = Label;
			this.ItemValue = Value;
	static testMethod void testVFController_Sidebar_Summary() {
		// Create Campaign
        Campaign c = new Campaign();
        c.Name = 'Test Campaign';
        insert c;
        // Create Lead
        Lead l = new Lead();
        l.LastName = 'Last Name';
        l.Company = 'Company';
        insert l;
        // Create Campaign Member
        CampaignMember cms = new CampaignMember();
        cms.CampaignId =;
        cms.LeadId =;
        insert cms;
		ApexPages.StandardController sc = new ApexPages.StandardController(c);
		VFController_CampaignMemberStatusChart controller = new VFController_CampaignMemberStatusChart(sc);
		String s1 = controller.getChartData();


Page Layout
When you add it to the Page Layout, make the height of the component the same as the height you specified in the VF page’s image src for Google Charts. In this example, it’s 125. Doing this will ensure the background colors match your Page Layout.

Comments (7) comments feed

ActevaRSVP Review

The demandblog has been posting some AppExchange application reviews recently.  They did a good one for ActevaRSVP, who has a pretty impressive product.  See their review at

Note: ActevaRSVP is a current advertiser on this blog.

Comments off comments feed

Arrowpointe @ Dreamforce 2008

Dreamforce 2008Dreamforce is just around the corner.  If you are already registered, be sure to visit the Attendee Portal to create a calendar of the sessions to attend.  Also, if you are so inclined, it’s a great opportunity to get certified.  Salesforce is offering a voucher for a free certification exam sitting ($200 value). Go here for more information.

One session you won’t want to miss is the one I am speaking at!

Enhancing Your Force Platform Apps with Google Geo & Maps APIs
You’ve seen basic Google Maps mashups, but did you know there are new API capabilities that support Flash-based maps, Google Earth, geo-coding, and other advanced visualizations? Join experts from the Google Geo API team as they show you how to implement new types of geo-enabled Force Platform apps.

Wednesday, November 5
11:30 a.m. – 12:30 p.m.

Presented By
Ron Hess,
Billy Rutledge, Google Inc.
Ossama Alami, Google Inc.
Scott Hemmeter, Arrowpointe Corp.

It is on the Tour De Force track.  In that session, I will be making an exciting announcement. If you are familiar with Arrowpointe Maps, you can probably guess what that announcement will be.

Arrowpointe does not have a booth this year, but I will all around the convention, primarily attending the developer track sessions.  If you would like to try and meet up, contact me.  If we don’t have each other’s contact information, please submit your’s here.

Comments (1) comments feed

Arrowpointe Maps 1.2.1

Version 1.2.1 of Arrowpointe Maps was just released. You can read about all the improvements on the Change History page.

The changes most applicable to end users are:

  • Search Nearby now includes the ability to start from an arbitrary address.  The Other Tools section of the front page now has a “Search Nearby” link.  This link will let you search for a Lead, Account or Contact or you can manually enter an address.  When in the midst of a Search Nearby process, clicking the Start Over button will also bring you to this page.
  • You can now assign specific icons/colors to your Data Sets.  Edit your Data Set and select a Data Set Image.  You can see the image used for each Data Set by viewing your list of Data Sets in the Admin Area of the application.
  • The Company/Account Name is automatically included for Lead/Contact Search Nearby searches.
  • The first 3 fields configured for a Data Set will now appear in the table of results.  All configured fields still appear in the map marker bubble on the map.
  • Search Nearby queries now allow you to use decimal amounts for a range (e.g. 0.25 miles)
  • Number fields on Map Pages now accept decimal amounts.
  • You can now see a list of the records that failed to map.  On a result set, you currently see something like “29 of 30 records successfully mapped”.  If there is an errored record, a link that says “Show Unmappable Records” will appear and you can click it to see a list of the records that did not map properly.
  • The Color Markers By parameter now saves with each Map Report run and will be automatically set for users when that report is mapped the next time.
  • The Language and Unit of Measure (miles vs. kilometers) on the Routing screen are now saved as a user preference.
  • The last Data Set, Range and Unit of Measure (miles vs. kilometers) used in a Search Nearby query are now saved as a user preference.
  • Improved performance on the initial load of the Routing screen.  This improvement also fixes the issue with IE6 and its sporadic inability to load routed records.

NOTE: This upgrade was automatically completed for all users.  It does not require any changes to the AppExchange installation.

About Arrowpointe Maps

Arrowpointe Maps is an on-demand mapping platform that facilitates a conversation between & MapQuest allowing for easy deployment of mapping capabilities in your organization and providing end-users a simple means for mapping their data. Arrowpointe Maps is configurable and can be tailored to your organization, so that your users can work with their information in a meaningful way.

The official location for information on Arrowpointe Maps is its product page at There, you will find answers to the most frequently asked questions, screencasts and links to its AppExchange page.

Comments (1) comments feed

“Salesforce User Community 3.0” on Facebook

A new Facebook Group popped up recently called “Salesforce User Community 3.0“.  The group moderator, Pete Fife, asked me to communicate the following note to my readers:

Do you wonder if listens to their customers and what they want from the user community? Take it from me, they do even if it takes a little squeaking to get their ear. Join me, Pete Fife, to discuss taking the community beyond disucssion boards and into the new world of social commuinty. I started the customer salesforce user groups back in 2003 and although we have come a long way since then, there is a long way to go to really enable us customers to define our own vision of the Community. Take advantage of the chance to bring our collective wishes for the user community to the ears of They are our captive audience and ready to listen.

Join the Facebook group Salesforce User Community 3.0 to stay up to date and find out when and were we’ll meet at Dreamforce.

FB group link:

Please join the group if you wish to participate in the community.

Comments (1) comments feed