JavaScript Remoting を使用したグラフデータの更新
1<apex:page controller="PieChartRemoteController">
2 <script>
3 function retrieveChartData(callback) {
4 var year = document.getElementById('theYear').value;
5 Visualforce.remoting.Manager.invokeAction(
6 '{!$RemoteAction.PieChartRemoteController.getRemotePieData}',
7 year,
8 function(result, event) {
9 if(event.status && result && (result.constructor === Array)) {
10 callback(result);
11 RemotingPieChart.show();
12 }
13 else if (event.type === 'exception') {
14 document.getElementById("remoteResponseErrors").innerHTML = event.message +
15 '<br/>' + event.where;
16 }
17 else {
18 document.getElementById("remoteResponseErrors").innerHTML = event.message;
19 }
20 },
21 { escape: true }
22 );
23 }
24 function refreshRemoteChart() {
25 var statusElement = document.getElementById('statusDisplay');
26 statusElement.innerHTML = "loading...";
27 retrieveChartData(function(statusElement){
28 return function(data){
29 RemotingPieChart.reload(data);
30 statusElement.innerHTML = '';
31 };
32 }(statusElement)
33 );
34 }
35 </script>
36
37 <apex:pageBlock title="Charts">
38
39 <apex:pageBlockSection title="Visualforce Charting + JavaScript Remoting">
40
41 <apex:chart height="350" width="450" data="retrieveChartData"
42 name="RemotingPieChart" hidden="true">
43 <apex:pieSeries dataField="data" labelField="name"/>
44 <apex:legend position="right"/>
45 </apex:chart>
46
47 <div>
48 <select id="theYear" onChange="refreshRemoteChart();">
49 <option value="2013">2013</option>
50 <option value="2012">2012</option>
51 <option value="2011">2011</option>
52 <option value="2010">2010</option>
53 </select>
54 <span id="statusDisplay"></span>
55 <span id="remoteResponseErrors"></span>
56 </div>
57
58 </apex:pageBlockSection>
59
60 </apex:pageBlock>
61</apex:page>このマークアップでは、グラフの data 属性を JavaScript 関数 retrieveChartData の名前に設定することで、グラフコンポーネントをデータソースに添付します。データはこの関数から返されます。関数の名前は文字列として指定します。
静的 HTML <select> メニューには、グラフで使用可能な年が表示されます。メニューは、どの種類のフォーム要素とも関連付けられておらず、値がコントローラに直接返送されることはありません。代わりに、<select> メニューの onChange 属性が、メニューが変更されたときには常に JavaScript 関数 refreshRemoteChart() をコールします。さらに 2 つの静的 HTML 要素として、ID を持つ <span> タグが 2 つあります。<span> タグは、ページ読み込み時は空で、JavaScript 経由で更新されると必要に応じて状況とエラーメッセージを表示します。
- グラフコンポーネントの data 属性は、最初の JavaScript 関数の名前である「retrieveChartData」に設定されます。これにより、グラフコンポーネントに、その JavaScript 関数を使用してデータを読み込むように指示します。グラフコンポーネントは、グラフが最初に作成されてデータが初期読み込みされるときに retrieveChartData() を 1 回だけ直接呼び出します。
- 再読み込みは、2 つ目の JavaScript 関数 refreshRemoteChart() がコールされると行われます。これが、theYear メニューからの 2 つ目のリンクです。年メニューが変更されると、refreshRemoteChart() が呼び出され、そこから retrieveChartData() 関数が再呼び出しされて新しいデータのセットが読み込まれます。
- refreshRemoteChart() が retrieveChartData() を呼び出すと、コールバックとして匿名関数が提供され、この匿名関数が @RemoteAction コールで返された結果を処理します。このコールバックが、RemotingPieChart.reload(data) をコールしてグラフを更新します。グラフ自体は name 属性を設定して指定した RemotingPieChart であり、reload() は、作成された Visualforce グラフで使用可能な JavaScript 関数で、新しいデータを受け入れてグラフを再描画します。
この図は、ページのさまざまなコンポーネント間のリンクを示しています。
グラフの初期読み込みシーケンスは単純です。RemotePieChart という <apex:chart> が retrieveChartData() をコールして初期データを取得し、retrieveChartData() はデータを取得すると RemotePieChart.show() をコールします。こうしてグラフが表示されます。
更新はもっと複雑です。新しい年が theYear メニューから選択されると、メニューの onChange イベントが起動され、refreshRemoteChart() 関数をコールします。次に refreshRemoteChart() が retrieveChartData() 関数をコールし、@RemoteAction が新しいデータを返すと、retrieveChartData() が (refreshRemoteChart() で提供されるコールバック経由で) RemotePieChart.reload() をコールします。こうしてグラフが更新されます。
その他に、いくつか注意点があります。
- <apex:chart> は hidden="true" 属性を使用して、表示するデータが揃う前にグラフが表示されないようにします。グラフデータが読み込まれたら、retrieveChartData() 関数が RemotingPieChart.show() をコールしてグラフを表示します。これと RemotingPieChart.reload() によって、<apex:actionSupport> を使用して表示する場合よりもはるかに滑らかなグラフアニメーションを表示できます。
- refreshRemoteData() 関数は、retrieveChartData() をコールしてデータの更新を試みる前に、statusElement HTML <span> を「loading… (読み込み中)」メッセージに設定し、データが返されてグラフが更新されたら、匿名コールバック関数が空の文字列に設定してメッセージを非表示にします。基本的に同じ効果を得るために <apex:actionStatus> を使用する場合よりも作業が若干多くなります。同じ手法を使用して「busy (処理中)」アニメーションやグラフィックを簡単に表示できます。
PieChartRemoteController
1public class PieChartRemoteController {
2
3 // The year to be charted
4 public String chartYear {
5 get {
6 if (chartYear == Null) chartYear = '2013';
7 return chartYear;
8 }
9 set;
10 }
11
12 // Years available to be charted, for <apex:selectList>
13 public static List<SelectOption> getChartYearOptions() {
14 List<SelectOption> years = new List<SelectOption>();
15 years.add(new SelectOption('2013','2013'));
16 years.add(new SelectOption('2012','2012'));
17 years.add(new SelectOption('2011','2011'));
18 years.add(new SelectOption('2010','2010'));
19 return years;
20 }
21
22 public List<PieWedgeData> getPieData() {
23 // Visualforce expressions can't pass parameters, so get from property
24 return PieChartRemoteController.generatePieData(this.chartYear);
25 }
26
27 @RemoteAction
28 public static List<PieWedgeData> getRemotePieData(String year) {
29 // Remoting calls can send parameters with the call
30 return PieChartRemoteController.generatePieData(year);
31 }
32
33 // Private data "generator"
34 private static List<PieWedgeData> generatePieData(String year) {
35 List<PieWedgeData> data = new List<PieWedgeData>();
36 if(year.equals('2013')) {
37 // These numbers are absolute quantities, not percentages
38 // The chart component will calculate the percentages
39 data.add(new PieWedgeData('Jan', 30));
40 data.add(new PieWedgeData('Feb', 15));
41 data.add(new PieWedgeData('Mar', 10));
42 data.add(new PieWedgeData('Apr', 20));
43 data.add(new PieWedgeData('May', 20));
44 data.add(new PieWedgeData('Jun', 5));
45 }
46 else {
47 data.add(new PieWedgeData('Jan', 20));
48 data.add(new PieWedgeData('Feb', 35));
49 data.add(new PieWedgeData('Mar', 30));
50 data.add(new PieWedgeData('Apr', 40));
51 data.add(new PieWedgeData('May', 5));
52 data.add(new PieWedgeData('Jun', 10));
53 }
54 return data;
55 }
56
57 // Wrapper class
58 public class PieWedgeData {
59
60 public String name { get; set; }
61 public Integer data { get; set; }
62
63 public PieWedgeData(String name, Integer data) {
64 this.name = name;
65 this.data = data;
66 }
67 }
68}- Visualforce 式 {!pieData} を使用してインスタンスメソッド getPieData() をコールする
- @RemoteAction 静的メソッド getRemotePieData() を JavaScript メソッドからコールして JavaScript Remoting を使用する