Oracle JETやその他のチャート描画ライブラリの組み込み作業で表示したチャートと、同じチャートを表示してみます。
直接amChartsで描画
amChartsのGetting startedを参照して、作業を進めます。
ページ・プロパティのJavaScriptのファイルURLに以下を記述します。
https://cdn.amcharts.com/lib/5/index.js
https://cdn.amcharts.com/lib/5/xy.js
https://cdn.amcharts.com/lib/5/themes/Animated.js
チャートに描画するデータを保持するページ・アイテムとしてP1_VALUEを作成します。タイプは非表示です。
ページ・アイテムP1_VALUEに計算を作成し、ページの描画前にデータを設定します。計算のタイプとしてSQL問合せ(単一の値を返す)を選択し、SQL問合せに以下を記述します。
select
json_arrayagg(
json_object(
'ename' value ename,
'sal' value sal
)
order by empno asc )
from emp where deptno = 10
チャートを描画するJavaScriptのコードを、ページ・プロパティのページ・ロード時に実行に記述します。
amChartsのDemosに含まれるClustered Bar Chartのコードを簡素にしています。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
am5.ready(function() { | |
// Create root element | |
// https://www.amcharts.com/docs/v5/getting-started/#Root_element | |
var root = am5.Root.new("myChart"); | |
// Set themes | |
// https://www.amcharts.com/docs/v5/concepts/themes/ | |
root.setThemes([ | |
am5themes_Animated.new(root) | |
]); | |
// Create chart | |
// https://www.amcharts.com/docs/v5/charts/xy-chart/ | |
var chart = root.container.children.push(am5xy.XYChart.new(root, { | |
panX: false, | |
panY: false, | |
wheelX: "panX", | |
wheelY: "zoomX", | |
paddingLeft:0, | |
layout: root.verticalLayout | |
})); | |
// Data | |
const value = apex.item("P1_VALUE").getValue(); | |
var data = JSON.parse(value); | |
// Create axes | |
// https://www.amcharts.com/docs/v5/charts/xy-chart/axes/ | |
var yAxis = chart.yAxes.push(am5xy.CategoryAxis.new(root, { | |
categoryField: "ename", | |
renderer: am5xy.AxisRendererY.new(root, { | |
inversed: true, | |
cellStartLocation: 0.1, | |
cellEndLocation: 0.9, | |
minorGridEnabled: true | |
}) | |
})); | |
yAxis.data.setAll(data); | |
var xAxis = chart.xAxes.push(am5xy.ValueAxis.new(root, { | |
renderer: am5xy.AxisRendererX.new(root, { | |
strokeOpacity: 0.1, | |
minGridDistance: 50 | |
}), | |
min: 0 | |
})); | |
// Add series | |
// https://www.amcharts.com/docs/v5/charts/xy-chart/series/ | |
var series = chart.series.push(am5xy.ColumnSeries.new(root, { | |
xAxis: xAxis, | |
yAxis: yAxis, | |
valueXField: "sal", | |
categoryYField: "ename", | |
sequencedInterpolation: true, | |
fill: am5.color('#309fdb') | |
})); | |
series.columns.template.setAll({ | |
height: am5.p50, | |
strokeOpacity: 0, | |
}); | |
series.data.setAll(data); | |
series.appear(); | |
// Make stuff animate on load | |
// https://www.amcharts.com/docs/v5/concepts/animations/ | |
chart.appear(1000, 100); | |
}); // end am5.ready() |
以上で実装は完了です。ページを実行すると以下のように表示されます。
テンプレート・コンポーネントの作成
amChartsのバー・チャートを描画するテンプレート・コンポーネントについて、設定内容を説明します。
テンプレート・コンポーネントの名前はamCharts Bar Chartとしました。テンプレートの部分には以下を記述しています。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="#CSS_CLASSES#"> | |
<a-amcharts-bar-chart id="#APEX$DOM_ID#" categoryY="#CATEGORY_Y#" valueX="#VALUE_X#" value="#VALUE#" color="#COLOR#" width="#WIDTH#" height="#HEIGHT#"></a-amcharts-bar-chart> | |
</div> |
カスタム属性としてCSS Classes、Category Y, Value X, Value、Color、Width、Heightを作成しています。Category YはY軸となる(Valueに含まれる)属性で、今回の実装ではenameを指定します。Value XはX軸となる値の属性で、今回の実装ではsalです。Valueのタイプはセッション・ステート値、Colorはカラー、WidthとHeightは両方とも整数です。
ディレクトリをjs、ファイル名をscript.jsとして、カスタム要素a-amcharts-bar-chartの実装を記述します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function (debug) { | |
"use strict"; | |
class amChartsBarChart extends HTMLElement { | |
chart; | |
chartId; | |
constructor() { | |
super(); | |
this.chartId = new Date().getTime(); | |
debug.info("%s, constructor", this.chartId); | |
} | |
connectedCallback() { | |
debug.info("%s, %s, connectedCallback, %s", this.chartId, new Date().getTime(), this.isConnected); | |
if (this.isConnected) { | |
/* prepare div for chart region */ | |
var chart; | |
const categoryY = this.getAttribute("categoryY"); | |
const valueX = this.getAttribute("valueX"); | |
const value = this.getAttribute("value"); | |
const color = this.getAttribute("color"); | |
const div = document.createElement("div"); | |
const width = this.getAttribute("width"); | |
if ( width ) { | |
div.classList.add(`w${width}`); | |
}; | |
const height = this.getAttribute("height"); | |
if ( height ) { | |
div.classList.add(`h${height}`); | |
}; | |
this.appendChild(div); | |
/* draw chart with amCharts */ | |
am5.ready(function() { | |
var root = am5.Root.new(div); | |
// Set themes | |
root.setThemes([ | |
am5themes_Animated.new(root) | |
]); | |
// Create chart | |
chart = root.container.children.push(am5xy.XYChart.new(root, { | |
panX: false, | |
panY: false, | |
wheelX: "panX", | |
wheelY: "zoomX", | |
paddingLeft:0, | |
layout: root.verticalLayout | |
})); | |
// Data | |
var data = JSON.parse(value); | |
debug.info(data); | |
// Create axes | |
var yAxis = chart.yAxes.push(am5xy.CategoryAxis.new(root, { | |
categoryField: categoryY, | |
renderer: am5xy.AxisRendererY.new(root, { | |
inversed: true, | |
cellStartLocation: 0.1, | |
cellEndLocation: 0.9, | |
minorGridEnabled: true | |
}) | |
})); | |
yAxis.data.setAll(data); | |
var xAxis = chart.xAxes.push(am5xy.ValueAxis.new(root, { | |
renderer: am5xy.AxisRendererX.new(root, { | |
strokeOpacity: 0.1, | |
minGridDistance: 50 | |
}), | |
min: 0 | |
})); | |
// Add series | |
const seriesConfig = { | |
xAxis: xAxis, | |
yAxis: yAxis, | |
valueXField: valueX, | |
categoryYField: categoryY, | |
sequencedInterpolation: true | |
}; | |
if ( color ) { | |
seriesConfig.fill = am5.color(color); | |
}; | |
var series = chart.series.push(am5xy.ColumnSeries.new(root, seriesConfig)); | |
series.columns.template.setAll({ | |
height: am5.p50, | |
strokeOpacity: 0, | |
}); | |
series.data.setAll(data); | |
series.appear(); | |
// Make stuff animate on load | |
chart.appear(1000, 100); | |
}); // end am5.ready() | |
this.chart = chart; | |
} | |
} | |
disconnectedCallback() { | |
debug.info("%s, %s, disconnectedCallback", this.chartId, new Date().getTime()); | |
if (this.firstChild) { | |
this.removeChild(this.firstChild); | |
} | |
} | |
} | |
document.addEventListener('DOMContentLoaded', () => { | |
if ( window.customElements.get("a-amcharts-bar-chart") === undefined ) { | |
debug.info("define custom element"); | |
window.customElements.define("a-amcharts-bar-chart", amChartsBarChart); | |
}; | |
}); | |
})(apex.debug); |
https://cdn.amcharts.com/lib/5/index.js
https://cdn.amcharts.com/lib/5/xy.js
https://cdn.amcharts.com/lib/5/themes/Animated.js
#PLUGIN_FILES#js/script#MIN#.js
以上でテンプレート・コンポーネントは完成です。
リージョンにamChartsのテンプレート・コンポーネントを実装します。
ページ・アイテムP2_VALUEは、最初に作成したP1_VALUEと同じ設定で作成します。
識別の名前をamCharts、タイプをamCharts Bar Chartとします。
リージョンの属性を開き、Category Yとしてename、Value Xとしてsal、ValueとしてP2_VALUE、Colorとして#309fdbを設定します。Heightは400とします。
以上で実装は完了です。ページを実行すると以下のように表示されます。
対話モード・レポートへの組み込み
対話モード・レポートのソースのSQL問合せとして以下を記述します。
select
dname,
json_arrayagg(
json_object(
'ename' value ename,
'sal' value sal
)
order by empno asc ) value,
'' chart
from emp_dept_v group by dname
対話モード・レポートの列CHARTを選択し、識別のタイプをamCharts Bar Chartに変更します。
設定のCategory Yにename、Value Xにsal、ValueにVALUE、Colorに#309fdbを設定します。Widthは400、Heightに200を設定します。