Yellowfinのコードモードを使って、重ね合わせた複数のレポートをボタンで表示切替できるようにする

Yellowfinには **コードモード** という機能があり、JavaScriptやCSSを独自に記述することで、Yellowfin単体では困難なUIを実現できます。

今回やることはタイトルそのままです。
コードモードを使って下のイメージのような動作を実現します。

![1_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116818/f1b7ad68-6148-264a-7321-19a579e2a86c.png)


# コードモードを有効にする

コードモードを使用するには、システム設定とロール権限が有効になっている必要があります。
YellowfinのWiki（オンラインマニュアル）の記述に従って、コードモードを有効にしてください。

https://wiki.yellowfin.co.jp/pages/viewpage.action?pageId=3801108

# ダッシュボードにオブジェクトを配置する

### レポートの配置

ダッシュボードにレポートを配置していきます。
このとき、レポートの名前を半角英数記号のみに変更します。そうしないとJavaScriptから操作することができないからです。
![1_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116818/a8fa2377-31a9-c406-f991-4278d97a4587.png)

レポート配置の操作を繰り返していくのですが、サイズと位置を同じ値にして重ね合わせます。
また、背景色は白にして、重なった背後にあるレポートが透けて見えないようにします。
![1_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116818/ecef423a-45f2-5076-4fd0-84530f302760.png)

今回の例では4つのレポートを重ねました。レポート名は **report_1** から **report_4** まで連番で振っています。report_1が最前面に、report_4が再背面になるよう配置しました。

### ボタンと線の配置

次にボタンを配置します。レポート同様、名前は半角英数記号のみにします。
![1_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116818/d2f713d2-ce36-5d21-48bd-9ed275cbc1dd.png)

そしてボタンのサイズと位置やテキスト、境界線のスタイルなどを調整します。
![1_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116818/6f66cd1f-270d-0714-95ac-33cd40f1a10c.png)

同じようにして、ボタンの下に線を配置します。
最終的には下のイメージのように、**button_1**から**button_4**と**line_1**から**line_4**が並んでいる状態にします。
![1_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116818/328ce623-6c43-d213-85bf-a18bc6d9c0c9.png)

# コードモードにJavaScriptを記述する

画面をコードモードに切り替えて、JavaScriptを記述します。
![1_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116818/e78a3fca-2090-aa9e-4a68-35565f1ceb6b.png)

以下が実際に動作するサンプルコードです。

```javascript
// ここに変数を宣言したり、コードを記述します

/**
 * キャンバスとそのすべての子要素をページにレンダリングしたりアタッチするときに呼び出されます。
 */
this.onRender = function () {
    // 初期値
    let button1 = this.apis.canvas.select('button_1');
    let button2 = this.apis.canvas.select('button_2');
    let button3 = this.apis.canvas.select('button_3');
    let button4 = this.apis.canvas.select('button_4');
    let report1 = this.apis.canvas.select('report_1');
    let report2 = this.apis.canvas.select('report_2');
    let report3 = this.apis.canvas.select('report_3');
    let report4 = this.apis.canvas.select('report_4');
    let line1 = this.apis.canvas.select('line_1');
    let line2 = this.apis.canvas.select('line_2');
    let line3 = this.apis.canvas.select('line_3');
    let line4 = this.apis.canvas.select('line_4');
    report1.style.display = "";
    report2.style.display = "none";
    report3.style.display = "none";
    report4.style.display = "none";
    line1.style.display = "";
    line2.style.display = "none";
    line3.style.display = "none";
    line4.style.display = "none";

    // レポート切り替えのボタンをクリックしたときの動作 
    button1.addEventListener('click', () => {
        report1.style.display = "";
        report1.style = "z-index:0";
        report1.left = 0;
        report1.top = 100;
        report1.width = 1000;
        report1.height = 550;
        report2.style.display = "none";
        report3.style.display = "none";
        report4.style.display = "none";
        line1.style.display = "";
        line2.style.display = "none";
        line3.style.display = "none";
        line4.style.display = "none";
    });

    button2.addEventListener('click', () => {
        report1.style.display = "none";
        report2.style.display = "";
        report2.style = "z-index:0";
        report2.left = 0;
        report2.top = 100;
        report2.width = 1000;
        report2.height = 550;
        report3.style.display = "none";
        report4.style.display = "none";
        line1.style.display = "none";
        line2.style.display = "";
        line3.style.display = "none";
        line4.style.display = "none";
    });

    button3.addEventListener('click', () => {
        report1.style.display = "none";
        report2.style.display = "none";
        report3.style.display = "";
        report3.style = "z-index:0";
        report3.left = 0;
        report3.top = 100;
        report3.width = 1000;
        report3.height = 550;
        report4.style.display = "none";
        line1.style.display = "none";
        line2.style.display = "none";
        line3.style.display = "";
        line4.style.display = "none";
    });

    button4.addEventListener('click', () => {
        report1.style.display = "none";
        report2.style.display = "none";
        report3.style.display = "none";
        report4.style.display = "";
        report4.style = "z-index:0";
        report4.left = 0;
        report4.top = 100;
        report4.width = 1000;
        report4.height = 550;
        line1.style.display = "none";
        line2.style.display = "none";
        line3.style.display = "none";
        line4.style.display = "";
    });
};

/**
 * キャンバスとそのすべての子要素がページから削除されるときに呼び出されます。
 */
this.onRemove = function () {
    // ここにコードを記述します。これは、イベントリスナーを削除するのに理想的な場所です
};
```

やっていることは非常に単純で、button_1〜4のどれかをクリックしたときに、対応するline_1〜4とreport_1〜4の表示を切り替えています。もう少しスマートな書き方がありそうですが、ひとまず動かすのが目的なのでご容赦ください。

ボタンクリック時に、レポートの**z-index**（表示順。0は最前面）, **left**（x位置）, **top**（y位置）, **width**（幅）, **height**（高さ）の値を更新しています。わざわざこんなことをしている理由は、こうしておかないとフィルターと連動させた場合にうまく表示できなかったからです。今回の例のようにフィルターを使用していない場合であれば、これらの値更新は行わなくても問題ありません。

あとは保存さえすれば、ボタンでレポート表示切替できるダッシュボードが完成です。
限られたスペースを有効に使用できて、自由度の高いダッシュボードを作ることができますね！