Visualforce Charting. salesforce Visualforce Developer Guide
Oglas
Oglas
CHAPTER 15 Visualforce Charting
Visualforce charting is a collection of components that provide a simple and intuitive way to create charts in your Visualforce pages and custom components.
What is Visualforce Charting?
Visualforce charting gives you an easy way to create customized business charts, based on data sets you create directly from SOQL queries, or by building the data set in your own Apex code. By combining and configuring individual data series, you can compose charts that display your data in ways meaningful to your organization.
Visualforce charts are rendered client-side using JavaScript. This allows charts to be animated and visually exciting, and chart data can load and reload asynchronously, which can make the page feel more responsive.
Why Would You Use Visualforce Charting?
Use Visualforce charting when the standard Salesforce charts and dashboards are insufficient, or when you wish to compose custom pages that combine charts and data tables in ways that are more useful to your organization.
Alternatives to Visualforce Charting
Salesforce provides a number of dashboards and reports, which support a variety of business charts. These charts can be simpler to create and customize because they do not require programming in Visualforce or Apex. See Dashboards Help You Visualize Complex
Information for more details about built-in charting and reporting.
Visualforce charting is designed to be flexible, but also easy to use. It offers variations on bar, line, area, and pie charts commonly used in business graphics, as well as radar, gauge, and scatter charts for more specialized charting. If you need different chart types, or want to add advanced user or page interactions, you might want to investigate using a JavaScript charting library instead. This is more work, but allows greater customization. For example, see
Integrating Visualforce and Google Charts
on page 131.
Using JavaScript in Visualforce
Pages on page 299 provides more information about how to use JavaScript libraries with Visualforce.
Visualforce Charting Limitations and Considerations
This section lists considerations and known limitations for Visualforce Charting.
•
Visualforce charts only render in browsers which support scalable vector graphics (SVG). For more information, see WC3 SVG Working
Group .
•
Visualforce charting uses JavaScript to draw the charts. Visualforce charts won’t display in pages rendered as PDFs.
•
Email clients do not usually support JavaScript execution in messages. Don’t use Visualforce charting in email messages or email templates.
213
Visualforce Charting How Visualforce Charting Works
•
Visualforce charting sends errors and messages to the JavaScript console. Keep a JavaScript debugging tool, such as Firebug, active during development.
•
Dynamic (Apex-generated) charting components are not supported at this time.
How Visualforce Charting Works
A Visualforce chart is defined using a series of charting components, which are then linked to a data source to be graphed on the chart.
Create a chart with Visualforce by doing the following:
1. Write an Apex method that queries for, calculates, and wraps your chart data to send to the browser.
2. Define your chart using the Visualforce charting components.
When the page containing the chart loads, the chart data is bound to a chart component, and the JavaScript that draws the chart is generated. When the JavaScript executes, the chart is drawn in the browser.
A Simple Charting Example
A Visualforce chart requires that you create a chart container component, which encloses at least one data series component. You can optionally add additional series components, chart axes, as well as labeling components such as a legend, chart labels, and tooltips for data points.
Here is a simple pie chart and the markup that creates it:
<apex:page controller= "PieChartController" title= "Pie Chart" >
<apex:chart height= "350" width= "450" data= "{!pieData}" >
<apex:pieSeries dataField= "data" labelField= "name" />
<apex:legend position= "right" />
</apex:chart >
</apex:page >
The
<apex:chart >
component defines the chart container, and binds the component to the data source, the getPieData() controller method. The
<apex:pieSeries >
describes the label and data fields to access in the returned data, to label and size each data point.
Here’s the associated controller: public class PieChartController { public List<PieWedgeData> getPieData() {
214
Visualforce Charting Providing Chart Data
List<PieWedgeData> data = new List<PieWedgeData>(); data.add( new PieWedgeData( 'Jan' , 30)); data.add( new PieWedgeData( 'Feb' , 15)); data.add( new PieWedgeData( 'Mar' , 10)); data.add( new PieWedgeData( 'Apr' , 20)); data.add( new PieWedgeData( 'May' , 20)); data.add( new PieWedgeData( 'Jun' , 5)); return data;
}
// Wrapper class public class PieWedgeData { public String name { get; set; } public Integer data { get; set; } public PieWedgeData( String name, Integer data) { this .name = name; this .data = data;
}
}
}
This controller is deliberately simple; you normally issue one or more SOQL queries to collect your data.
These are the important points illustrated by the example:
•
The getPieData()
method returns a List of simple objects, an inner class PieWedgeData used as a wrapper. Each element in the list is used to create a data point.
•
The PieWedgeData class is just a set of properties, and is essentially used as a name
=
value
store.
•
The chart series component
<apex:pieSeries >
defines which properties from the PieWedgeData class to use to determine each point in the series. In this simple example there’s no mystery, but in charts with multiple series and axes this convention allows the efficient return of the entire data set in one List object.
Providing Chart Data
A Visualforce chart binds to the source of its data through the data attribute on the
<apex:chart >
component.
Data can be provided several different ways:
•
As an expression that represents a controller method reference
•
As a string representing a JavaScript function
•
As a string representing a JavaScript array
SEE ALSO:
Providing Chart Data via a Controller Method
Providing Chart Data Using a JavaScript Function
Providing Chart Data via a JavaScript Array
215
Visualforce Charting Providing Chart Data
Providing Chart Data via a Controller Method
The most straightforward way to provide data to a chart is using a Visualforce expression that references a controller method. Simply reference the controller in the
<apex:chart > data
attribute.
Charting Example on page 214, sObjects, or
AggregateResult
objects. The method is evaluated server-side, and the results serialized to JSON. On the client, these results are used directly by
<apex:chart >
, with no further opportunity for processing.
To illustrate this technique with sObjects, here is a simple controller that returns a list of Opportunities, and a bar chart for their amounts: public class OppsController {
// Get a set of Opportunities public ApexPages.StandardSetController setCon { get { if (setCon == null ) {
} set; setCon = new ApexPages.StandardSetController(Database.getQueryLocator(
[SELECT name, type, amount, closedate FROM Opportunity])); setCon.setPageSize(5);
} return setCon;
} public List<Opportunity> getOpportunities() { return (List<Opportunity>) setCon.getRecords();
}
}
<apex:page controller= "OppsController" >
<apex:chart data= "{!Opportunities}" width= "600" height= "400" >
<apex:axis type= "Category" position= "left" fields= "Name" title= "Opportunities" />
<apex:axis type= "Numeric" position= "bottom" fields= "Amount" title= "Amount" />
<apex:barSeries orientation= "horizontal" axis= "bottom" xField= "Name" yField= "Amount" />
</apex:chart >
<apex:dataTable value= "{!Opportunities}" var= "opp" >
<apex:column headerValue= "Opportunity" value= "{!opp.name}" />
<apex:column headerValue= "Amount" value= "{!opp.amount}" />
</apex:dataTable >
</apex:page >
216
Visualforce Charting Providing Chart Data
There are two important things to notice about this example:
•
The Visualforce chart components access the data attributes from a List of Opportunity sObjects the same way as from the simple
Data object used in A Simple Charting Example on page 214.
•
The object field names used as data attributes are case-sensitive in JavaScript while field names in Apex and Visualforce are case-insensitive. Be careful to use the precise field name in the fields
, xField
, and yField
attributes of axes and data series components, or your chart will silently fail.
SEE ALSO:
Refreshing Chart Data Using <apex:actionSupport>
Providing Chart Data Using a JavaScript Function
To access data using JavaScript remoting, or an external (non-Salesforce) data source, provide the
<apex:chart >
component with the name of a JavaScript function that provides the data. That JavaScript function must be defined in or linked from your Visualforce page.
This function has the opportunity to manipulate the results before passing it to
<apex:chart >
, or to perform other user interface or page updates.
The JavaScript function must take a callback function as a parameter, and invoke the callback with the function's data result object. The simplest working JavaScript function looks like this:
<apex:page >
<script > function getRemoteData(callback) {
PieChartController.getRemotePieData(function(result, event) { if(event.status && result && result.constructor === Array) { callback(result);
}
});
}
</script >
<apex:chart data= "getRemoteData" ...> </apex:chart >
</apex:page >
217
Visualforce Charting Providing Chart Data
To support this chart, add the following controller method to the
PieChartController
class defined in A Simple Charting Example
on page 214:
@RemoteAction public static List<PieWedgeData> getRemotePieData() {
List<PieWedgeData> data = new List<PieWedgeData>(); data.add( new PieWedgeData( 'Jan' , 30)); data.add( new PieWedgeData( 'Feb' , 15)); data.add( new PieWedgeData( 'Mar' , 10)); data.add( new PieWedgeData( 'Apr' , 20)); data.add( new PieWedgeData( 'May' , 20)); data.add( new PieWedgeData( 'Jun' , 5)); return data;
}
SEE ALSO:
JavaScript Remoting for Apex Controllers
Refreshing Chart Data Using JavaScript Remoting
Providing Chart Data via a JavaScript Array
You can use Visualforce charting with non-Salesforce data sources by building a JavaScript array, in your own JavaScript code in your page, and providing the name of that array to
<apex:chart >
.
The following trivial code illustrates this technique:
<apex:page >
<script >
// Build the chart data array in JavaScript var dataArray = new Array(); dataArray.push({ 'data1' :33, 'data2' :66, 'data3' :80, 'name' : 'Jan' }); dataArray.push({ 'data1' :33, 'data2' :66, 'data3' :80, 'name' : 'Feb' });
// ...
</script >
<apex:chart data= "dataArray" ...> </apex:chart >
</apex:page >
When using this technique, if your data is coming from a non-Salesforce source, you might not need any server-side Apex code at all.
SEE ALSO:
Chart Data Format
Data provided to a Visualforce chart must meet some specific requirements. Every element in the data collection must contain all fields referenced in the
<apex:chart >
component hierarchy that is bound to that data source. If all fields aren’t provided, a client-side
JavaScript error is thrown, which you can view in a JavaScript console such as Firebug.
Chart data provided by an Apex method should be a List of uniform objects. These objects can be simple wrappers, sObjects, or
AggregateResult
objects. Data fields can be made accessible as public member variables or properties.
218
Visualforce Charting Building a Complex Chart with Visualforce Charting
Chart data provided by JavaScript methods should be a JavaScript array of arrays. Each inner array represents a record or data point. Data fields are made accessible as name: value pairs. See
Providing Chart Data via a JavaScript Array
on page 218 for an example.
SEE ALSO:
Providing Chart Data via a JavaScript Array
Building a Complex Chart with Visualforce Charting
Use Visualforce charting to assemble a variety of chart components into a complex chart that represents multiple sets of related data.
The end result can be quite sophisticated and attention getting.
The Chart Controller
It includes more data, and methods that can be called by
remote JavaScript invocation :
public class ChartController {
// Return a list of data points for a chart public List<Data> getData() { return ChartController.getChartData();
}
// Make the chart data available via JavaScript remoting
@RemoteAction public static List<Data> getRemoteData() { return ChartController.getChartData();
}
// The actual chart data; needs to be static to be
// called by a @RemoteAction method public static List<Data> getChartData() {
List<Data> data = new List<Data>(); data.add( new Data( 'Jan' , 30, 90, 55)); data.add( new Data( 'Feb' , 44, 15, 65)); data.add( new Data( 'Mar' , 25, 32, 75)); data.add( new Data( 'Apr' , 74, 28, 85)); data.add( new Data( 'May' , 65, 51, 95)); data.add( new Data( 'Jun' , 33, 45, 99)); data.add( new Data( 'Jul' , 92, 82, 30)); data.add( new Data( 'Aug' , 87, 73, 45)); data.add( new Data( 'Sep' , 34, 65, 55)); data.add( new Data( 'Oct' , 78, 66, 56)); data.add( new Data( 'Nov' , 80, 67, 53)); data.add( new Data( 'Dec' , 17, 70, 70)); return data;
}
// Wrapper class public class Data { public String name { get; set; } public Integer data1 { get; set; }
219
Visualforce Charting Building a Complex Chart with Visualforce Charting public Integer data2 { get; set; } public Integer data3 { get; set; } public Data( String name, Integer data1, Integer data2, Integer data3) { this .name = name; this .data1 = data1; this .data2 = data2; this .data3 = data3;
}
}
}
Note:
The
@RemoteAction
method isn’t used in the chart examples in this topic, but it illustrates how you can re-use your data generation method for both server-side and JavaScript remoting methods.
Creating a Simple Line Chart
Here is a simple line chart that graphs one of the three data series in the data set, “Opportunities Closed-Won,” over a calendar year:
<apex:page controller= "ChartController" >
<apex:chart height= "400" width= "700" data= "{!data}" >
<apex:axis type= "Numeric" position= "left" fields= "data1" title= "Opportunities Closed" grid= "true" />
<apex:axis type= "Category" position= "bottom" fields= "name" title= "Month of the Year" >
</apex:axis >
<apex:lineSeries axis= "left" fill= "true" xField= "name" yField= "data1" markerType= "cross" markerSize= "4" markerFill= "#FF0000" />
</apex:chart >
</apex:page >
Things to note about this example:
•
Line and bar charts require you to define the X and Y axes for the chart.
•
The vertical axis is defined on the left side of the chart, and measures the dollar amount of the Opportunities closed in that month.
•
The horizontal axis is defined on the bottom of the chart, and represents the months of the calendar year.
•
The actual line chart, the
<apex:lineSeries >
component, is bound to a specific axis.
220
Visualforce Charting Building a Complex Chart with Visualforce Charting
•
There are a number of marker attributes that you can use to differentiate each line in the chart.
Adding a Second Data Series
Adding a second data series with the same unit of measure is simple. Here, the “Opportunities Closed-Lost” data set is added as a second line series:
<apex:page controller= "ChartController" >
<apex:chart height= "400" width= "700" data= "{!data}" >
<apex:axis type= "Numeric" position= "left" fields= "data1,data2" title= "Opportunities Closed" grid= "true" />
<apex:axis type= "Category" position= "bottom" fields= "name" title= "Month of the Year" >
</apex:axis >
<apex:lineSeries axis= "left" fill= "true" xField= "name" yField= "data1" markerType= "cross" markerSize= "4" markerFill= "#FF0000" />
<apex:lineSeries axis= "left" xField= "name" yField= "data2" markerType= "circle" markerSize= "4" markerFill= "#8E35EF" />
</apex:chart >
</apex:page >
The important thing to note is how both data1
and data2
fields are bound to the vertical
<apex:axis >
by the fields attribute of that component. This allows the charting engine to determine appropriate scale and tick marks for the axis.
Adding a Bar Chart Series with a Second Axis
To add another data series, but charted against a different set of units, you need to add a second vertical axis. The following example shows a data series, “Revenue by Month,” added as a bar chart:
221
Visualforce Charting Building a Complex Chart with Visualforce Charting
<apex:page controller= "ChartController" >
<apex:chart height= "400" width= "700" data= "{!data}" >
<apex:axis type= "Numeric" position= "left" fields= "data1,data2" title= "Opportunities Closed" grid= "true" />
<apex:axis type= "Numeric" position= "right" fields= "data3" title= "Revenue (millions)" />
<apex:axis type= "Category" position= "bottom" fields= "name" title= "Month of the Year" />
<apex:lineSeries axis= "left" fill= "true" xField= "name" yField= "data1" markerType= "cross" markerSize= "4" markerFill= "#FF0000" />
<apex:lineSeries axis= "left" xField= "name" yField= "data2" markerType= "circle" markerSize= "4" markerFill= "#8E35EF" />
<apex:barSeries orientation= "vertical" axis= "right" xField= "name" yField= "data3" />
</apex:chart >
</apex:page >
Notice the following:
•
To add a data series with a new unit of measure, you need to add a second vertical axis on the right side of the chart.
•
You can have up to four different axes, one for each edge of the chart.
•
The bar chart is set to a vertical orientation and bound to the right axis. Bind a horizontal bar chart to the top or bottom axis.
Adding a Legend, Labels, and Chart Tips
You can improve the comprehensibility of the chart by adding a chart legend, series labels, and by making sure that chart labels are readable:
222
Visualforce Charting Building a Complex Chart with Visualforce Charting
<apex:page controller= "ChartController" >
<apex:chart height= "400" width= "700" data= "{!data}" >
<apex:legend position= "right" />
<apex:axis type= "Numeric" position= "left" fields= "data1" title= "Opportunities Closed" grid= "true" />
<apex:axis type= "Numeric" position= "right" fields= "data3" title= "Revenue (millions)" />
<apex:axis type= "Category" position= "bottom" fields= "name" title= "Month of the Year" >
<apex:chartLabel rotate= "315" />
</apex:axis >
<apex:barSeries title= "Monthly Sales" orientation= "vertical" axis= "right" xField= "name" yField= "data3" >
<apex:chartTips height= "20" width= "120" />
</apex:barSeries >
<apex:lineSeries title= "Closed-Won" axis= "left" xField= "name" yField= "data1" fill= "true" markerType= "cross" markerSize= "4" markerFill= "#FF0000" />
<apex:lineSeries title= "Closed-Lost" axis= "left" xField= "name" yField= "data2" markerType= "circle" markerSize= "4" markerFill= "#8E35EF" />
</apex:chart >
</apex:page >
Note the following about the additions:
•
, the bar chart was in the foreground. In this example, the bar chart has been placed in the background because the
<apex:barSeries > component is before the two
<apex:lineSeries >
components.
•
The
<apex:legend >
component can be in any of four positions: left, right, top, or bottom. The legend is placed within the boundary of the chart; in this example the legend has compressed the horizontal width of the chart itself.
•
Add legend titles using the data series component title
attribute.
•
To rotate the labels for the bottom chart axis, the
<apex:chartLabel >
component is enclosed in the
<apex:axis > component it affects.
223
Visualforce Charting Updating Charts with Refreshed Data
•
The
<apex:chartTips >
component enables rollover tool tips that provide additional information about each data point in the series that encloses it.
SEE ALSO:
How Visualforce Charting Works
Updating Charts with Refreshed Data
Redraw a chart with new or updated data by using the
<apex:actionSupport >
component, or by using JavaScript remoting and your own JavaScript code.
<apex:actionSupport >
allows you to update the chart using only Visualforce. JavaScript remoting requires you to write some
JavaScript code, but provides more flexibility and smoother transitions.
IN THIS SECTION:
Refreshing Chart Data Using <apex:actionSupport>
Update a Visualforce chart in response to a user’s actions by adding the
<apex:actionSupport >
component to Visualforce user interface elements that affect the chart’s data.
Refreshing Chart Data Using JavaScript Remoting
Update a Visualforce chart periodically, or in response to a user’s actions, using custom JavaScript. JavaScript code can respond to complex user activity or timer events, and use JavaScript remoting to retrieve new chart data whenever required.
Refreshing Chart Data Using
<apex:actionSupport >
Update a Visualforce chart in response to a user’s actions by adding the
<apex:actionSupport >
component to Visualforce user interface elements that affect the chart’s data.
The following markup displays a pie chart that can be updated by choosing a new year from a menu next to the chart:
<apex:page controller= "PieChartRemoteController" >
<apex:pageBlock title= "Charts" >
<apex:pageBlockSection title= "Standard Visualforce Charting" >
<apex:outputPanel id= "theChart" >
<apex:chart height= "350" width= "450" data= "{!pieData}" >
<apex:pieSeries dataField= "data" labelField= "name" />
<apex:legend position= "right" />
</apex:chart >
</apex:outputPanel >
<apex:form >
<apex:selectList value= "{!chartYear}" size= "1" >
<apex:selectOptions value= "{!chartYearOptions}" />
<apex:actionSupport event= "onchange" reRender= "theChart" status= "actionStatusDisplay" />
</apex:selectList >
<apex:actionStatus id= "actionStatusDisplay" startText= "loading..." stopText= "" />
</apex:form >
224
Visualforce Charting Refreshing Chart Data Using <apex:actionSupport>
</apex:pageBlockSection >
</apex:pageBlock >
</apex:page >
This markup attaches a chart component to its data source by setting the chart’s data
attribute to the Visualforce expression
{!pieData}
. The expression calls the getPieData()
controller method, which returns the data. The chart is wrapped in an
<apex:outputPanel >
with an id
attribute of theChart
.
An
<apex:form >
component is used to submit a new year back to the page’s controller when the chart needs to be updated. The
<apex:selectList >
tag displays the years available to chart, and a child
<apex:actionSupport >
tag submits the form whenever the menu changes. The id
of the chart’s
<apex:outputPanel >
, theChart
, is used in the
<apex:actionSupport > reRender
attribute to limit updating to the chart, instead of reloading the whole page. Finally, an
<apex:actionStatus >
component provides a status message while the chart is refreshing. It’s easy to replace the minimal text message with an animated graphic or text effect.
PieChartRemoteController
The controller for this page is an expansion of the pie chart controller used in
on page 214.
public class PieChartRemoteController {
// The year to be charted public String chartYear { get {
} set; if (chartYear == Null) chartYear = '2013' ; return chartYear;
}
// Years available to be charted, for <apex:selectList> public static List<SelectOption> getChartYearOptions() {
List<SelectOption> years = new List<SelectOption>(); years.add( new SelectOption( '2013' , '2013' )); years.add( new SelectOption( '2012' , '2012' )); years.add( new SelectOption( '2011' , '2011' )); years.add( new SelectOption( '2010' , '2010' )); return years;
} public List<PieWedgeData> getPieData() {
// Visualforce expressions can't pass parameters, so get from property return PieChartRemoteController.generatePieData( this .chartYear);
}
@RemoteAction public static List<PieWedgeData> getRemotePieData( String year) {
// Remoting calls can send parameters with the call return PieChartRemoteController.generatePieData(year);
}
// Private data "generator"
225
Visualforce Charting Refreshing Chart Data Using JavaScript Remoting private static List<PieWedgeData> generatePieData( String year) {
List<PieWedgeData> data = new List<PieWedgeData>(); if (year.equals( '2013' )) {
// These numbers are absolute quantities, not percentages
// The chart component will calculate the percentages data.add( new PieWedgeData( 'Jan' , 30)); data.add( new PieWedgeData( 'Feb' , 15)); data.add( new PieWedgeData( 'Mar' , 10)); data.add( new PieWedgeData( 'Apr' , 20)); data.add( new PieWedgeData( 'May' , 20)); data.add( new PieWedgeData( 'Jun' , 5));
} else { data.add( new PieWedgeData( 'Jan' , 20)); data.add( new PieWedgeData( 'Feb' , 35)); data.add( new PieWedgeData( 'Mar' , 30)); data.add( new PieWedgeData( 'Apr' , 40)); data.add( new PieWedgeData( 'May' , 5)); data.add( new PieWedgeData( 'Jun' , 10));
} return data;
}
// Wrapper class public class PieWedgeData { public String name { get; set; } public Integer data { get; set; } public PieWedgeData( String name, Integer data) { this .name = name; this .data = data;
}
}
}
This controller supports providing data to a Visualforce chart two different ways:
•
Using a Visualforce expression,
{!pieData}
, which calls the instance method getPieData()
.
•
Using JavaScript remoting, by calling the
@RemoteAction
static method getRemotePieData()
from a JavaScript method.
SEE ALSO:
Refreshing Chart Data Using JavaScript Remoting
Providing Chart Data via a Controller Method
Refreshing Chart Data Using JavaScript Remoting
Update a Visualforce chart periodically, or in response to a user’s actions, using custom JavaScript. JavaScript code can respond to complex user activity or timer events, and use JavaScript remoting to retrieve new chart data whenever required.
226
Visualforce Charting Refreshing Chart Data Using JavaScript Remoting
The following markup displays a pie chart that can be updated by choosing a new year from a menu next to the chart:
<apex:page controller= "PieChartRemoteController" >
<script > function retrieveChartData(callback) { var year = document.getElementById( 'theYear' ).value;
Visualforce.remoting.Manager.invokeAction(
'{!$RemoteAction.PieChartRemoteController.getRemotePieData}' , year, function(result, event) { if(event.status && result && (result.constructor === Array)) { callback(result);
RemotingPieChart.show();
} else if (event.type === 'exception' ) { document.getElementById( "remoteResponseErrors" ).innerHTML = event.message
+
'<br/>' + event.where;
} else { document.getElementById( "remoteResponseErrors" ).innerHTML = event.message;
}
},
{ escape: true }
);
} function refreshRemoteChart() { var statusElement = document.getElementById( 'statusDisplay' ); statusElement.innerHTML = "loading..." ; retrieveChartData(function(statusElement){ return function(data){
RemotingPieChart.reload(data);
);
}
</script > statusElement.innerHTML = '' ;
};
}(statusElement)
<apex:pageBlock title= "Charts" >
<apex:pageBlockSection title= "Visualforce Charting + JavaScript Remoting" >
<apex:chart height= "350" width= "450" data= "retrieveChartData" name= "RemotingPieChart" hidden= "true" >
<apex:pieSeries dataField= "data" labelField= "name" />
<apex:legend position= "right" />
</apex:chart >
<div >
<select id= "theYear" onChange= "refreshRemoteChart();" >
<option value= "2013" >2013 </option >
<option value= "2012" >2012 </option >
<option value= "2011" >2011 </option >
227
Visualforce Charting Refreshing Chart Data Using JavaScript Remoting
<option value= "2010" >2010 </option >
</select >
<span id= "statusDisplay" > </span >
<span id= "remoteResponseErrors" > </span >
</div >
</apex:pageBlockSection >
</apex:pageBlock >
</apex:page >
This markup attaches a chart component to its data source by setting the chart’s data
attribute to the name of a JavaScript function, retrieveChartData
, which returns the data. The name of the function is provided as a string.
A static HTML
<select >
menu displays the years available to chart. The menu is not associated with a form element of any kind, and its value is never submitted directly back to the controller. Instead, the
<select >
menu’s onChange
attribute calls a JavaScript function, refreshRemoteChart()
, whenever the menu changes. There are two additional static HTML elements: two
<span > tags with IDs. The
<span >
tags are empty when the page loads, and are updated via JavaScript to display status and error messages when necessary.
The two JavaScript functions that precede the Visualforce markup are the glue between the Visualforce chart and the
@RemoteAction controller method that provides the data. There are three links between the functions and the chart component:
1. The chart component’s data
attribute is set to “retrieveChartData”, the name of the first JavaScript function. This tells the chart component to use the JavaScript function to load its data. The chart component invokes retrieveChartData()
directly
only once, when the chart is first created and the data is initially loaded.
2. Reloading happens when the second JavaScript function, refreshRemoteChart()
, is called. This is the second link, from the theYear
menu. When the year menu changes, refreshRemoteChart()
is invoked, and it re-invokes the retrieveChartData()
function to load a new set of data.
3. When refreshRemoteChart()
invokes retrieveChartData()
, it provides an anonymous function as a callback, which handles the result of the
@RemoteAction
call when it returns. This callback updates the chart by calling
RemotingPieChart.reload(data)
. The chart itself is
RemotingPieChart
, named by setting the name
attribute, and reload()
is a JavaScript function available on Visualforce charts once created, which accepts new data and then redraws the chart.
This diagram illustrates these links between the different components of the page:
228
Visualforce Charting Refreshing Chart Data Using JavaScript Remoting
The sequence for the initial loading of the chart is simple: the
<apex:chart >
named
RemotePieChart
calls retrieveChartData()
to get its initial data, and retrieveChartData()
calls
RemotePieChart.show()
when it has the data. And, the chart appears.
Updates are more complicated. When a new year is chosen from the theYear
menu, the menu’s onChange
event fires, which calls the refreshRemoteChart()
function. refreshRemoteChart()
in turn calls the retrieveChartData()
function, and when the
@RemoteAction
returns new data, retrieveChartData()
(via the callback provided by refreshRemoteChart()
) calls
RemotePieChart.reload()
. And, the chart updates.
Here are a couple of other items to note:
•
The
<apex:chart >
uses the hidden= "true"
attribute to prevent the chart from displaying before there’s data to display.
The retrieveChartData()
function calls
RemotingPieChart.show()
to display the chart once the chart data is loaded. This and
RemotingPieChart.reload()
provide for much smoother chart animations than can be achieved using
<apex:actionSupport >
.
•
The refreshRemoteData()
function sets the statusElement
HTML
<span >
to a “loading…” message before it attempts to update the data by calling retrieveChartData()
, and then the anonymous callback function sets it to an empty string to hide the message once the data is returned and the chart updated. It’s a bit more work than using
<apex:actionStatus >
, for basically the same effect. You can easily show a “busy” animation or graphic using the same technique.
PieChartRemoteController
The controller for this page is an expansion of the pie chart controller used in
on page 214.
public class PieChartRemoteController {
// The year to be charted public String chartYear { get {
229
Visualforce Charting Refreshing Chart Data Using JavaScript Remoting
} set; if (chartYear == Null) chartYear = '2013' ; return chartYear;
}
// Years available to be charted, for <apex:selectList> public static List<SelectOption> getChartYearOptions() {
List<SelectOption> years = new List<SelectOption>(); years.add( new SelectOption( '2013' , '2013' )); years.add( new SelectOption( '2012' , '2012' )); years.add( new SelectOption( '2011' , '2011' )); years.add( new SelectOption( '2010' , '2010' )); return years;
} public List<PieWedgeData> getPieData() {
// Visualforce expressions can't pass parameters, so get from property return PieChartRemoteController.generatePieData( this .chartYear);
}
@RemoteAction public static List<PieWedgeData> getRemotePieData( String year) {
// Remoting calls can send parameters with the call return PieChartRemoteController.generatePieData(year);
}
// Private data "generator" private static List<PieWedgeData> generatePieData( String year) {
List<PieWedgeData> data = new List<PieWedgeData>(); if (year.equals( '2013' )) {
// These numbers are absolute quantities, not percentages
// The chart component will calculate the percentages data.add( new PieWedgeData( 'Jan' , 30)); data.add( new PieWedgeData( 'Feb' , 15)); data.add( new PieWedgeData( 'Mar' , 10)); data.add( new PieWedgeData( 'Apr' , 20)); data.add( new PieWedgeData( 'May' , 20)); data.add( new PieWedgeData( 'Jun' , 5));
} else { data.add( new PieWedgeData( 'Jan' , 20)); data.add( new PieWedgeData( 'Feb' , 35)); data.add( new PieWedgeData( 'Mar' , 30)); data.add( new PieWedgeData( 'Apr' , 40)); data.add( new PieWedgeData( 'May' , 5)); data.add( new PieWedgeData( 'Jun' , 10));
} return data;
}
// Wrapper class public class PieWedgeData {
230
Visualforce Charting Controlling the Appearance of Charts public String name { get; set; } public Integer data { get; set; } public PieWedgeData( String name, Integer data) { this .name = name; this .data = data;
}
}
}
This controller supports providing data to a Visualforce chart two different ways:
•
Using a Visualforce expression,
{!pieData}
, which calls the instance method getPieData()
.
•
Using JavaScript remoting, by calling the
@RemoteAction
static method getRemotePieData()
from a JavaScript method.
SEE ALSO:
Refreshing Chart Data Using <apex:actionSupport>
Providing Chart Data Using a JavaScript Function
JavaScript Remoting for Apex Controllers
Controlling the Appearance of Charts
Visualforce charts are highly customizable. You can combine various types of data series, control the colors of most elements in a chart, and control the look of markers, lines, and so on.
You can customize the following:
•
Line and fill colors for data series elements.
•
Opacity of fill colors and lines.
•
Marker shape and color for data points.
•
Line width for connecting lines.
•
Highlighting for data elements.
•
Tick and grid line styles for axes.
•
Legends, labels, and “tool tip”-style rollover annotations.
require combinations of attributes and components, and are explained more completely in this document.
Chart Colors
By default, chart colors match those of the built-in reporting and analytics charts so that you can create visually-consistent dashboards.
If you want to create your own color scheme you can customize the colors of most chart elements.
To provide a set of color definitions to draw data series elements (bars, pie wedges, and so on), use the colorSet
attribute. Set
<apex:chart colorSet= "..." >
to specify the colors to be used for every data series in a chart. Set colorSet
on a data series component to specify colors for that series only.
A colorSet
is a string that is a comma-delimited list of HTML-style hexadecimal color definitions. For example, colorSet= "#0A224E,#BF381A,#A0D8F1,#E9AF32,#E07628"
. Colors are used in sequence. When the end of the list is reached, the sequence starts over at the beginning.
231
Visualforce Charting
Here’s a pie chart that uses a custom color scheme for the pie wedge colors:
Chart Layout and Annotation
<apex:pageBlockSection title= "Simple colorSet Demo" >
<apex:chart data= "{!pieData}" height= "300" width= "400" background= "#F5F5F5" >
<apex:legend position= "left" />
<apex:pieSeries labelField= "name" dataField= "data1" colorSet= "#37241E,#94B3C8,#4D4E24,#BD8025,#816A4A,#F0E68C" />
</apex:chart >
</apex:pageBlockSection >
Use the background
attribute to set a background color for the entire chart.
You can use a colorSet
with all data series components except
<apex:radarSeries >
. Additional colorSet
details and further options for configuring colors of other chart elements are described for specific data series components.
Chart Layout and Annotation
To make your chart more understandable, add a legend, meaningful axes ranges and labels, and tips or labels on data elements.
By default all charts have a legend. To suppress the default legend, set
<apex:chart legend= "false" >
. To control the placement of the legend and the spacing of legend entries, add an
<apex:legend >
component to the chart. Place the legend on any of the four edges of a chart using the position
attribute. Use the font
attribute to control the text style used in the legend.
The font
attribute is a string specifying a CSS-style shorthand font property . For example,
<apex:legend position= "left"
font="bold 24px Helvetica"/>
.
Appropriate axis scaling and labeling can mean the difference between a chart that is illegible or misleading and one that is clear and persuasive. By default, an
<apex:axis type= "Numeric" >
component sets the scale automatically based on the data fields set in the fields
attribute. Automatic scaling ensures that all data fits on the chart but the chart might not begin or end with meaningful numbers. Use the minimum
and maximum
attributes to override the automatic scaling. To set the interval for tick marks, use the steps
attribute. This attribute is an integer that specifies the number of steps between the two ends of the axis. Use the dashSize
, grid
, and gridFill
attributes to add lines or shading to the chart to make it easier to compare measurements to the scale.
You can apply chart labels to axes and data series. When
<apex:chartLabel >
is a child of
<apex:axis >
, the labels are drawn on the outside of the axis. When
<apex:chartLabel >
is a child of a data series component, the labels are drawn on or near the data elements on the chart. Use the field
attribute to set the text for the label. Use the display
attribute to set where the label is drawn. Use the orientation
and rotate
attributes to adjust the text of the label so that it fits on the chart.
Note:
The orientation
attribute has no effect when a
<apex:chartLabel >
component is used with a
<apex:pieSeries >
component.
This sample chart uses many of these components and attributes to create a meaningful visual design:
232
Visualforce Charting Bar Charts
<apex:chart data= "{!data}" height= "400" width= "500" >
<apex:legend position= "left" font= "bold 14px Helvetica" />
<apex:axis type= "Numeric" position= "left" title= "Closed Won" grid= "true" fields= "data1,data2,data3" minimum= "0" maximum= "225" steps= "8" dashSize= "2" >
<apex:chartLabel />
</apex:axis >
<apex:axis type= "Category" position= "bottom" fields= "name" title= "2012" >
<apex:chartLabel rotate= "315" />
</apex:axis >
<apex:barSeries orientation= "vertical" axis= "left" xField= "name" yField= "data1,data2,data3" stacked= "true" />
</apex:chart >
Bar Charts
Bar charts are one of several linear data series charts available in Visualforce. Linear series charts are charts plotted against a standard rectangular grid.
Each data element in a linear series is described by an
X,Y
coordinate. The data series defines how to draw the coordinate on the grid.
The
<apex:barSeries >
charts draw bars stretching between an origin axis and the
X,Y
coordinates. The orientation attribute determines whether the origin axis is the left axis (Y) or the bottom axis (X). Set
<apex:barSeries orientation= "horizontal" >
for bars that originate on the left side of the chart, and
<apex:barSeries orientation= "vertical" >
for a column chart with bars that rise from the bottom of the chart.
To plot multiple data points for each bar interval, group or stack the bars within a single
<apex:barSeries >
tag. Multiple
<apex:barSeries >
tags in a single chart draw on top of each other, obscuring all but the last data series. To create a vertical column chart, add all fields to be grouped or stacked to the yField
attribute:
<apex:barSeries orientation= "vertical" axis= "left" xField= "name"
yField="data1,data2,data3"/>
By default, data fields in an
<apex:barSeries >
are grouped on a chart. To stack them on top of each other, set stacked= "true"
.
233
Visualforce Charting Bar Charts
Use the gutter
attribute to adjust spacing between grouped bars. Use the groupGutter
attribute to adjust spacing between groups. Use the xPadding
and yPadding
attributes to adjust the spacing between the chart axes and the bars themselves.
By default, legend titles for stacked or grouped bar charts use the names of fields in the yField
attribute. In the previous example, the default titles are “data1”, “data2”, and “data3”. To give the legend more meaningful titles, use the title
attribute of the
<apex:barSeries >
component. Use commas to separate items. For example, title= "MacDonald,Promas,Worle"
:
<apex:chart data= "{!data}" height= "400" width= "500" >
<apex:legend position= "left" />
<apex:axis type= "Numeric" position= "left" title= "Closed Won" grid= "true" fields= "data1,data2,data3" dashSize= "2" >
<apex:chartLabel/ >
</apex:axis >
<apex:axis type= "Category" position= "bottom" fields= "name" title= "Stacked Bars" >
<apex:chartLabel rotate= "315" />
</apex:axis >
<apex:barSeries orientation= "vertical" axis= "left" stacked= "true"
234
Visualforce Charting Other Linear Series Charts xField= "name" yField= "data1,data2,data3" title= "MacDonald,Promas,Worle" />
</apex:chart >
SEE ALSO:
Other Linear Series Charts
Other linear data series charts include
<apex:areaSeries >
,
<apex:lineSeries >
, and
<apex:scatterSeries >
.
You can combine linear data series charts on the same graph, but to create meaningful charts, keep the following in mind:
•
Data series charts draw on top of each other in the order you define them in Visualforce markup.
•
Define
<apex:barSeries >
charts first because they usually need to be in the background because they can’t be transparent.
The
<apex:areaSeries >
components are similar to stacked bar charts, except that the chart is drawn as shaded areas defined by a line connecting the points of the series instead of as individual bars. To combine
<apex:areaSeries >
with other data series, use the opacity
attribute to make the area chart partially transparent. The opacity
attribute is a floating point number between
0.0 and 1.0, with 0.0 being fully transparent and 1.0 being fully opaque. Here’s an area series combined with a bar series:
<apex:chart height= "400" width= "700" animate= "true" data= "{!data}" >
<apex:legend position= "left" />
<apex:axis type= "Numeric" position= "left" title= "Closed Won" grid= "true" fields= "data1,data2,data3" >
<apex:chartLabel />
</apex:axis >
<apex:axis type= "Numeric" position= "right" fields= "data1" title= "Closed Lost" />
<apex:axis type= "Category" position= "bottom" fields= "name" title= "Month of the Year" >
<apex:chartLabel rotate= "315" />
</apex:axis >
<apex:areaSeries axis= "left" tips= "true" opacity= "0.4" xField= "name" yField= "data1,data2,data3" />
235
Visualforce Charting Other Linear Series Charts
<apex:barSeries orientation= "vertical" axis= "right" xField= "name" yField= "data1" >
<apex:chartLabel display= "insideEnd" field= "data1" color= "#333" />
</apex:barSeries >
</apex:chart >
By default, legend titles for area charts use the names of fields in the yField
attribute. In the previous example, the default titles are
“data1”, “data2”, and “data3”. To give the legend more meaningful titles, use the title
attribute of the
<apex:areaSeries > component. Use commas to separate items. For example, title= "MacDonald,Promas,Worle"
:
<apex:chart height= "400" width= "700" animate= "true" data= "{!data}" >
<apex:legend position= "left" />
<apex:axis type= "Numeric" position= "left" fields= "data1,data2,data3" title= "Closed Won" grid= "true" >
<apex:chartLabel />
</apex:axis >
<apex:axis type= "Category" position= "bottom" fields= "name" title= "2011" >
<apex:chartLabel rotate= "315" />
</apex:axis >
<apex:areaSeries axis= "left" xField= "name" tips= "true" yField= "data1,data2,data3" title= "MacDonald,Picard,Worlex" />
</apex:chart >
Like
<apex:areaSeries >
charts,
<apex:lineSeries >
charts use lines to connect a series of points. You can fill the area under the line. Unlike
<apex:areaSeries >
charts,
<apex:lineSeries > charts don’t stack. When
<apex:lineSeries > charts aren’t filled, you might choose to put several series in the same chart. Line series can display markers for the data points and you can define the color and size of both the markers and the connecting lines. Here’s a chart that combines three line series, one of which is filled:
236
Visualforce Charting Pie Charts
<apex:chart height= "400" width= "700" animate= "true" legend= "true" data= "{!data}" >
<apex:legend position= "left" />
<apex:axis type= "Numeric" position= "left" title= "Volatility" grid= "true" fields= "data1,data2,data3" >
<apex:chartLabel />
</apex:axis >
<apex:axis type= "Category" position= "bottom" title= "Month" grid= "true" fields= "name" >
<apex:chartLabel />
</apex:axis >
<apex:lineSeries axis= "left" xField= "name" yField= "data1" strokeColor= "#0000FF" strokeWidth= "4" />
<apex:lineSeries axis= "left" fill= "true" xField= "name" yField= "data2" markerType= "cross" markerSize= "4" markerFill= "#FF0000" />
<apex:lineSeries axis= "left" xField= "name" yField= "data3" markerType= "circle" markerSize= "4" markerFill= "#8E35EF" >
<apex:chartTips height= "20" width= "120" />
</apex:lineSeries >
</apex:chart >
Note: An
<apex:lineSeries >
component might not fill as expected if a Numeric axis doesn’t increase in order as it moves up and to the right. The solution is to set the axis to type= "Category"
and sort the values manually before passing the data to the chart.
The
<apex:scatterSeries >
charts are like
<apex:lineSeries >
charts without the connecting lines. By varying the marker size, type, and color, it’s easy to plot many scatter series on the same chart.
SEE ALSO:
Pie Charts
The most common customizations to
<apex:pieSeries >
charts is to colors and labels. Use the colorSet
attribute and the
<apex:chartLabel >
component that were demonstrated in previous examples.
237
Visualforce Charting Gauge Charts
To create a ring chart instead of a pie chart, set the donut
attribute. The donut
attribute is an integer between 0 and 100 and represents the percentage of the radius of the hole. Here’s a simple ring chart:
<apex:chart data= "{!pieData}" height= "400" width= "500" background= "#F5F5F5" >
<apex:legend position= "left" />
<apex:pieSeries labelField= "name" dataField= "data1" donut= "50" >
<apex:chartLabel display= "middle" orientation= "vertical" font= "bold 18px Helvetica" />
</apex:pieSeries >
</apex:chart >
SEE ALSO:
Gauge Charts
Gauge charts show a single measurement against a defined axis or scale. Although it charts a single number, you can vary the axis and chart colors to communicate what that number means.
Use the minimum
and maximum
attributes of the
<apex:axis >
tag to define the range of values. Use the colorSet
attribute of the
<apex:gaugeSeries >
tag to indicate whether the current value is good or bad. Here’s a chart that indicates the metric is well within an acceptable range:
238
Visualforce Charting Radar Charts
<apex:chart height= "250" width= "450" animate= "true" data= "{!data}" >
<apex:axis type= "Gauge" position= "gauge" title= "Transaction Load" minimum= "0" maximum= "100" steps= "10" />
<apex:gaugeSeries dataField= "data1" donut= "50" colorSet= "#78c953,#ddd" />
</apex:chart >
Note: Gauge charts don’t support legends or labels.
SEE ALSO:
Radar Charts
Radar charts are like line charts but they use a circular axis instead of a linear grid.
Use the markerType
, markerSize
, and markerFill
attributes to set the style, size, and color of the markers. Use the strokeColor
and strokeWidth
attributes to set the color and thickness of the connecting lines. Optionally, set fill=true to fill the area enclosed by the series, and use opacity
to make it transparent so that other series remain visible. The opacity attribute is a floating point number between 0.0 and 1.0, with 0.0 being fully transparent and 1.0 being fully opaque.
Here’s an example of a radar chart, and the markup that creates it:
239
Visualforce Charting
<apex:chart height= "530" width= "700" legend= "true" data= "{!data}" >
<apex:legend position= "left" />
<apex:axis type= "Radial" position= "radial" >
<apex:chartLabel />
</apex:axis >
<apex:radarSeries xField= "name" yField= "data1" tips= "true" opacity= "0.4" />
<apex:radarSeries xField= "name" yField= "data2" tips= "true" opacity= "0.4" />
<apex:radarSeries xField= "name" yField= "data3" tips= "true" markerType= "cross" strokeWidth= "2" strokeColor= "#f33" opacity= "0.4" />
</apex:chart >
SEE ALSO:
240
Radar Charts
Prenesi
Oglas