【パブリッシャー】HTMLとJavaScriptでカスタムレポートを作成してみる

[Sharperlight](https://sharperlight.jp/)**パブリッシャー**で作成される公開クエリは、HTMLやJavaScriptを使用して作成するWEBインターフェースのコンテナとして使用することもできます。その簡単な例をここでは見ていきます。
[Sharperlight](https://sharperlight.jp/)には、jquery、[KendoUI](https://docs.telerik.com/kendo-ui/introduction)、yui、D3、Chart.JsなどのJavaScriptフレームワークが梱包されています。それらを利用してWebインターフェースを作成することができます。
今回は、Chart.Jsを利用して、折れ線グラフを表示してみます。元になるデータもパブリッシャーで公開クエリとして定義します。
## データソースを準備する
**パブリッシャー**を起動して公開クエリを作成します。
グループ名とコードを入力したら、クエリの編集を開始します。
![2022-03-27 Figure 01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/71d8f816-8ead-de0b-c19c-f682f1d49d63.png)
**カスタム定義のデータセット**を使用します。このようなデータセットを準備しましょう。
![2022-03-27 Figure 02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/765d7d1b-6a95-60b0-5d30-7e0eb7368759.png)
```
"日付::Date","金額::Number"
"2022-03-01",1000.00
"2022-03-02",1150.00
"2022-03-03",1050.00
"2022-03-04",1200.00
"2022-03-05",1259.00
"2022-03-06",1268.00
"2022-03-07",1300.00
"2022-03-08",1320.00
"2022-03-09",1340.00
"2022-03-10",1358.00
"2022-03-11",1390.00
"2022-03-12",1400.00
"2022-03-13",800.00
"2022-03-14",1410.00
"2022-03-15",1430.00
"2022-03-16",1459.00
"2022-03-17",1500.00
"2022-03-18",1523.00
"2022-03-19",1523.00
"2022-03-20",1558.00
"2022-03-21",1590.00
"2022-03-22",1600.00
"2022-03-23",1696.00
"2022-03-24",1750.00
"2022-03-25",1754.00
"2022-03-26",1759.00
"2022-03-27",1770.00
"2022-03-28",1800.00
"2022-03-29",1850.00
"2022-03-30",1900.00
"2022-03-31",2000.00

```
**日付**と**金額**フィールドを出力に設定して[OK]ボタンを押し確定します。データセットの準備完了。
![2022-03-27 Figure 03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/4dd42259-6d2a-5165-6de5-48103d253dac.png)
## HTMLとJavaScriptのコードを準備する
このようなコードを準備します。
```
<!DOCTYPE html>
<!-- Ver 01 00 00 -->
<html>
<head>
	<meta charset="utf-8"/>
	<base href="{*Url.Root}">
	<link rel="shortcut icon" type="image/x-ico" href="favicon.ico" />
    <link rel="icon" type="image/x-ico" href="favicon.ico" />
	<title>ChartJS Sample</title>
	
	<link rel="stylesheet" type="text/css" href="{*Url.Root}Resources/Chart.js/Chart.min.css" />
    
	<script type="text/javascript" src="{*Url.Root}Resources/Chart.js/Chart.js"></script>
    <script type="text/javascript" src="{*Url.Root}Resources/Chart.js/Chart.min.js"></script>
    <script type="text/javascript" src="{*Url.Root}Resources/jquery/jquery.min.js"></script>
</head>
<body style="font-family: arial; font-size:13px">
    <div class="chart-container" style="position: relative; height:400px; width:750px">
        <canvas id="myLineChart"></canvas>
    </div>
	
    <script>
        var gDsSomething;       //Data Source
        var gURL_ReadSomething = "{*Row.URLCustomHTMLData.text}";
		
		$(document).ready(function(e) { ChartJS_Sample_Start(e) });
		
        function drawLineChart() {
            // Add a helper to format timestamp data
            Date.prototype.formatMMDDYYYY = function() {
                return (this.getMonth() + 1) +
                "/" +  this.getDate() +
                "/" +  this.getFullYear();
            }

            var jsonData = $.ajax({
                url: gURL_ReadSomething,
                dataType: 'json',
                }).done(
                    function (results) {
                        // Split timestamp and data into separate arrays
                        var labels = [], data=[];
                        results.forEach(function(packet) {
                            labels.push(new Date(packet.Date).toLocaleDateString());
                            data.push(parseFloat(packet.Amount));
                        });

                        // Create the chart.js data structure using 'labels' and 'data'
                        var tempData = {
                            labels : labels,
                            datasets : [
                                {
                                label                 : 'Dataset Sample',    
                                fillColor             : "rgba(151,187,205,0.2)",
                                strokeColor           : "rgba(151,187,205,1)",
                                pointColor            : "rgba(151,187,205,1)",
                                pointStrokeColor      : "#fff",
                                pointHighlightFill    : "#fff",
                                pointHighlightStroke  : "rgba(151,187,205,1)",
                                data                  : data
                                }
                            ]
                        };

                        // Get the context of the canvas element we want to select
                        var ctx = document.getElementById("myLineChart").getContext("2d");

                        // Instantiate a new chart
                        var myLineChart = new Chart(ctx, {
                                                        type: 'line',
                                                        data: tempData,
                                                        options: {
                                                            responsive: true,
                                                            maintainAspectRatio: false,
                                                            scales: {
                                                                xAxes: [{
                                                                    ticks: {
                                                                        autoSkip: false,
                                                                        maxRotation: 45,
                                                                        minRotation: 45
                                                                    }
                                                                }]
                                                            }
                                                        }
                                                    });
                    }
                );
        };

        function ChartJS_Sample_Start(e){
        try { 
            drawLineChart();
        }catch(err){
            alert("Error in ChartJS_Sample_Start(): " + err.message);
        }
        };
	</script>
</body>
</html>
```
ひとつずつみていきます。
**head**の部分です。
スタイツシートとJavaScriptフレームワークの参照構文があります。
その中の```{*Url.Root}```の部分は、実行時に[Sharperlight](https://sharperlight.jp/)のRESTサービスのURLに置き換えられます。
```
<head>
	<meta charset="utf-8"/>
	<base href="{*Url.Root}">
	<link rel="shortcut icon" type="image/x-ico" href="favicon.ico" />
    <link rel="icon" type="image/x-ico" href="favicon.ico" />
	<title>ChartJS Sample</title>
	
	<link rel="stylesheet" type="text/css" href="{*Url.Root}Resources/Chart.js/Chart.min.css" />
    
	<script type="text/javascript" src="{*Url.Root}Resources/Chart.js/Chart.js"></script>
    <script type="text/javascript" src="{*Url.Root}Resources/Chart.js/Chart.min.js"></script>
    <script type="text/javascript" src="{*Url.Root}Resources/jquery/jquery.min.js"></script>
</head>
```
実行時はこんな感じです。
![2022-03-27 Figure 04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/4be06d4c-4900-a1dc-55f6-73151914fe94.png)

次に注目するべきところは、この部分。
```
    <script>
        var gDsSomething;       //Data Source
        var gURL_ReadSomething = "{*Row.URLCustomHTMLData.text}";
		
		$(document).ready(function(e) { ChartJS_Sample_Start(e) });
		
        function drawLineChart() {
            // Add a helper to format timestamp data
            Date.prototype.formatMMDDYYYY = function() {
                return (this.getMonth() + 1) +
                "/" +  this.getDate() +
                "/" +  this.getFullYear();
            }

            var jsonData = $.ajax({
                url: gURL_ReadSomething,
                dataType: 'json',
                }).done(
                    function (results) {
                        // Split timestamp and data into separate arrays
                        var labels = [], data=[];
                        results.forEach(function(packet) {
                            labels.push(new Date(packet.Date).toLocaleDateString());
                            data.push(parseFloat(packet.Amount));
                        });
```
先ずは、この部分```var gURL_ReadSomething = "{*Row.URLCustomHTMLData.text}";```
これは、このHTMLページで使用するデータを取得するためのURLを準備しています。どこから取得するかというと、この記事の上記で定義したデータソース用の公開クエリからです。
![2022-03-27 Figure 05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/3e8d6244-345d-52ee-78be-b5ddb70544f6.png)
そして、この公開クエリをデータソース(JSONを返す)として呼び出すためのURLは、
```
http://{YourSeverName}/mdService1Rest/DataSource/?query=QiitaSample.CustomHTMLData&dfmt=jsonarray&dcat=UseNames
```
であり、本来はこのURLをコード内に直接記述してもいいのだけれど、ここではコントロールタグ```{*Row.URLCustomHTMLData.text}```を使用して、このソースコードのコンテナとなる公開クエリの内部に定義した拡張表現から取得するようにしています。これは後々URLに変更が発生した場合、コードの修正ではなく、公開クエリの内部に定義した拡張表現を変更するだけで変更に対応するためです。このような感じで。
![2022-03-27 Figure 06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/6563e299-7657-6e36-6a74-31bf96ea3581.png)
そのURLはこのajaxコール部分で使用されています。
```
var jsonData = $.ajax({
                url: gURL_ReadSomething,
                dataType: 'json',
```
次に注目すべきところは、どのように取得したデータをChart.JSで使用できる形式に変換しているかという部分です。その箇所がここです。
```
// Split timestamp and data into separate arrays
       var labels = [], data=[];
       results.forEach(function(packet) {
           labels.push(new Date(packet.Date).toLocaleDateString());
           data.push(parseFloat(packet.Amount));
       });
```
ここでは、ラベルとデータの配列をそれぞれ取得したデータセットから作成しています。なぜそうするかはChart.JSの仕様を参照してください。
上記データセットを思い出してください。ここで言うラベルは**日付**、データは**金額**となります。
**labels.push**のところで、**packet.Data**を渡しています。その**Data**の部分、これはデータソース用公開クエリの出力領域に設定した**日付**の**名前**を指し示しています。**data.push**のところも同じく、**Amount**の部分、これはデータソース用公開クエリの出力領域に設定した**金額**の**名前**を指し示しています。
![2022-03-27 Figure 07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/4ba341fe-9845-e17c-a211-e439b8406c1d.png)
このようにして公開クエリで定義されたデータは、JavaScriptコード側で使用できます。
その他のコードは全て、Chart.JSで折れ線グラフを記述するための標準的なコードですので、Chart.JSの仕様を参照してください。
## HTML＋JavaScriptコードの公開クエリへの梱包
上記で記述したコードのコンテナとなる公開クエリを**パブリッシャー**で定義します。
#### コードとグループ
新規作成して、コードとグループ名を記入します。
![2022-03-27 Figure 08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/28183c46-2bb9-844f-5539-1445fb0f2f6b.png)
#### クエリの編集
今回の場合、コンテナ用にクエリを定義する必要はないのですが、**公開クエリにはクエリの定義が必須**という条件があるので、なんでもいいですので簡単なクエリを定義します。しかし、上述したように今回はデータソース用の公開クエリの呼び出しURLを、このクエリ内に拡張表現として定義します。
![2022-03-27 Figure 09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/c6789ff4-e628-929c-3af1-2e7a9430f07a.png)
拡張表現の**名前 %URLCustomHTMLData**に注目、コード内のここで使われているよ。
![2022-03-27 Figure 10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/1ad0a99a-eef2-ba5f-8ed0-296cb962cfb5.png)
これでコンテナ用のクエリの定義はおしまい。
#### コードの梱包と使用
[クエリの公開]ダイアログの[オプション]タブに移動します。そしてこの二つのプロパティを使用します。
![2022-03-27 Figure 11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/b8414ab1-74c8-c93c-436b-534d861b4c40.png)
コードの梱包には、リソースオプションを使用します。[リソース]オプションボタンをクリックすると、専用のダイアログが表示されます。1:[新規]ボタンでアイテムを追加し、2:ファイルオプションを選びます。あとは3:ファイル参照ボタンで記述したHTMLコードファイルを指定します。最後に、4:リソースコードをコピーし、[閉じる]ボタンで終了します。
![2022-03-27 Figure 12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/dd942e81-3430-c347-5353-d525d46a51ec.png)
次に[カスタムHTML]オプションの[編集]ボタンをクリックします。カスタムHTMLテキストエディタが表示されるので、クリップボードに保存してあるリソースコードを貼り付けます。
![2022-03-27 Figure 13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/9adcbf99-8354-9c6e-604f-b986c6a8878e.png)
[OK]を押して完了です。公開クエリを保存して、さあ動作確認してみましょう。
## 動作確認
[Sharperlight](https://sharperlight.jp/)サービスを起動して、このURLをブラウザのアドレスバーに貼り付けるだけ。:grin:
**http://{YourServerName}/mdService1Rest/Report/?query=QiitaSample.CustomHTML**
このような折れ線グラフが表示されます。
![2022-03-27 Figure 14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/b719ead3-636b-e40e-36a5-a7a4fb62ee01.png)
:postbox:[Sharperlight](https://sharperlight.jp/)