作成したアプリケーションは以下のように動作します。
データはJETの記事で作成している表EBAJ_DEMO_HOUSE_PRICEを流用します。
このアプリケーションもホーム・ページにすべてを実装しています。
以下よりアプリケーションの作成手順を紹介します。
アプリケーション作成ウィザードを起動し、空のアプリケーションを作成します。名前はClassic Report Heat Mapとします。
アプリケーションが作成されます。
ページ・デザイナでホーム・ページを開き、クラシック・レポートのリージョンを作成します。
識別の名前はHeat Map、タイプはクラシック・レポートです。ソースのタイプにSQL問合せを返すファンクション本体を選択し、SQL問合せを戻すPL/SQLファンクション本体として、以下を記述します。
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
declare | |
l_periods apex_t_varchar2; | |
l_idx integer; | |
l_pivod_columns varchar2(32767); | |
l_sql clob; | |
e_too_many_pivod_columns exception; | |
begin | |
/* 列名の設定 */ | |
apex_session_state.set_value('P1_COL01', 'Region'); | |
l_idx := 1; /* P1_COL01はRegionなので、年月の列はP1_COL02から始まる。 */ | |
for p in ( | |
select period from ebaj_demo_house_price | |
group by period order by to_date(period, 'MonthYYYY', 'NLS_DATE_LANGUAGE=English') asc | |
) | |
loop | |
l_idx := l_idx + 1; | |
/* l_idxが20を超えると例外を上げる - Region列があるので年月列は19が上限 */ | |
if l_idx > 20 then | |
raise e_too_many_pivod_columns; | |
end if; | |
apex_session_state.set_value('P1_COL' || to_char(l_idx, 'FM00'), p.period ); | |
end loop; | |
/* ピボット列の取り出し */ | |
select listagg(chr(39) || prd || chr(39) || ' as ' || prd,',') | |
within group (order by to_date(prd, 'MonthYYYY', 'NLS_DATE_LANGUAGE=English') asc) | |
into l_pivod_columns | |
from ( | |
select distinct period prd from ebaj_demo_house_price | |
); | |
/* Pivotを使ったSELECT文を返す */ | |
l_sql := 'select * from (select region, period, price from ebaj_demo_house_price) '; | |
l_sql := l_sql || 'pivot ( sum(price) for period in (' || l_pivod_columns || '))'; | |
return l_sql; | |
end; |
このファンクションは以下のSELECT文を返します。PIVOT列は列PERIODの値から決まるため、動的にSQLを作成しています。また、列名は開発時では不明なため、汎用列名の使用をオンにしています。汎用列数に20を指定しているため、Region列を除いた19列がピボット列の上限になります。
select
*
from
(
select
region,
period,
price
from
ebaj_demo_house_price
) pivot (
sum(price) for period in (
'January2013' as January2013, 'February2013' as February2013,
'March2013' as March2013, 'April2013' as April2013,
'May2013' as May2013, 'June2013' as June2013,
'July2013' as July2013, 'August2013' as August2013,
'September2013' as September2013,
'October2013' as October2013, 'November2013' as November2013,
'December2013' as December2013, 'January2014' as January2014,
'February2014' as February2014, 'March2014' as March2014,
'April2014' as April2014, 'May2014' as May2014
)
)
不要な修飾を無くすために、外観のテンプレートにBlack with Attributes (No Grid)を選択しています。また、JavaScriptとCSSの中でレポート・リージョンを指定するために、静的IDとしてHEATMAPを設定します。
汎用列の列名を保持するページ・アイテムを作成します。汎用列は20個あるため、ページ・アイテムとしてP1_COL01からP1_COL20の20個のページ・アイテムを作成します。タイプは非表示です。
クラシック・レポートのソースであるPL/SQLファンクション内で、これらのページ・アイテムに列名を設定しています。
汎用列のヘッダーにページ・アイテムに設定した値が反映されるように、それぞれの列のヘッダーに置換文字列&P1_COL01.(列名に合わせて&P1_COL01.から&P1_COL20.まで)を設定します。
ページを実行して、これまでの作業を確認します。
表EBAJ_DEMO_HOUSE_PRICEの内容がピボットされてレポートに表示されていることが確認できます。
列COL01はリージョンを表示しているため除外し、列COL02からCOL20までの列の書式のHTML式に以下を記述します。
<div class="ht-cell">
<div class="ht-text">
#COL02#
</div>
</div>
また、これらの列でソートすることは無いので、ソートのソート可能はオフにします。HTML式に含まれる置換文字列#COL02#は、列名に合わせて変更します。
今回のソート可能のように、複数のアイテムのプロパティを同じ値にする場合、対象をすべて選択した上で値を変更すると設定漏れを防げます。
ページ・プロパティのCSSのインラインに以下を記述します。年月の列名を縦方向に印字する、数値のセルを正方形にする、数値の色を白にしてセルの中央に配置するようにしています。それ以外に、CSS変数の値を変更し、セルのパディングを除いています。
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
/* | |
* make cell square-shape. | |
*/ | |
.ht-cell { | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
width: 60px; | |
height: 60px; | |
} | |
/* | |
* text inside the cell | |
*/ | |
.ht-text { | |
color: white; | |
} | |
/* | |
* remove padding from td (cell) except row headers | |
*/ | |
#HEATMAP td:not([headers="REGION"]) { | |
--ut-report-cell-padding-x: 0rem; | |
--ut-report-cell-padding-y: 0rem; | |
} | |
/* | |
* 年月を縦書きにする。 | |
*/ | |
#HEATMAP th:not([id="REGION"]) { | |
writing-mode: vertical-lr; | |
transform: rotate(180deg); | |
} |
これまでの変更で、レポートは以下のように表示されます。
クラシック・レポートに動的アクションを作成します。タイミングのイベントはリフレッシュ後です。
TRUEアクションとしてJavaScriptコードの実行を選択し、設定のコードに以下を記述します。JETの実装と同じ色味になるように、色付けのクラスとしてOracle JETで定義されているクラスを設定しています。
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
const report = document.getElementById("HEATMAP"); | |
const cells = report.querySelectorAll('.ht-cell'); | |
cells.forEach( (cell) => { | |
let data = Number(cell.textContent); | |
let color; | |
if (data < -1.25) { | |
color = 'oj-bg-success-30'; | |
} | |
// -1% > data >= -1.25% | |
else if (data < -1) { | |
color = 'oj-bg-brand-30'; | |
} | |
// -0.75% > data >= -1% | |
else if (data < -0.75) { | |
color = 'oj-bg-warning-30'; | |
} | |
// -0.5% > data >= -0.75% | |
else if (data < -0.5) { | |
color = 'oj-bg-warning-20'; | |
} | |
// -0.25% > data >= -0.5% | |
else if (data < -0.25) { | |
color = 'oj-bg-warning-10'; | |
} | |
// data > 2.25% | |
else if (data > 2.25) { | |
color = 'oj-bg-neutral-200'; | |
} | |
// 2% < data <= 2.25% | |
else if (data > 2) { | |
color = 'oj-bg-neutral-170'; | |
} | |
// 1.75% < data <= 2% | |
else if (data > 1.75) { | |
color = 'oj-bg-success-20'; | |
} | |
// 1.5% < data <= 1.75% | |
else if (data > 1.5) { | |
color = 'oj-bg-brand-20'; | |
} | |
// 1.25% < data <= 1.5% | |
else if (data > 1.25) { | |
color = 'oj-bg-info-30'; | |
} | |
// 1% < data <= 1.25% | |
else if (data > 1) { | |
color = 'oj-bg-info-20'; | |
} | |
// 0.75% < data <= 1% | |
else if (data > 0.75) { | |
color = 'oj-bg-info-10'; | |
} | |
// 0.5% < data <= 0.75% | |
else if (data > 0.5) { | |
color = 'oj-bg-neutral-20'; | |
} | |
// 0.25% < data <= 0.5% | |
else if (data > 0.25) { | |
color = 'oj-bg-neutral-10'; | |
} | |
// between -0.25 and 0.25 | |
else { | |
color = 'oj-bg-neutral-0'; | |
}; | |
cell.classList.add(color); | |
}); |
#JET_CSS_DIRECTORY#redwood/oj-redwood-notag-min.css
ページ・ロード時にリフレッシュ後のイベントが発生するようにします。
クラシック・レポートの属性を開き、パフォーマンスの遅延ロードをオンにします。遅延ロードをオンにすると、ページ・ロードとレポート表示が非同期で実行されるようになり、レポート表示が完了した時点でリフレッシュ後イベントが発生します。
クラシック・レポートの属性に含まれる外観のテンプレート・オプションを開き、Alternating RowsおよびRow Highlightingの双方をDisableにします。
以上でアプリケーションは完成です。
今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/classic-report-heat-map.zip
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完