jQuery DataTablesのスクロールバーをリッチにする

# はじめに

jsfiddleに動作するデモを設置したのでこちらをご覧下さい。横スクロールするテーブルのスクロールバーがリッチになっていますよね。

https://jsfiddle.net/tkosuga/dkzr3h1v/3/

現状ではCSSだけでスクロールバーのカスタマイズが出来ないためHTMLの構造から組み替えて対応する必要があります。そのためのプラグインが多数公開されています。

標準のスクロールバーがサイトのデザインに合わないと気になったのでカスタマイズする事にしたのですが、これが思いのほか大変で、近しい投稿がStackoverflowなど色々な所で相談されているのが散見されましたが最後まで完結したものが無かったのでQiitaにメモがてら残します。

# 利用するライブラリの説明
## DataTables

DataTablesはHTMLのtableをソートしたりカスタマイズするのに一番使われているプラグインだと思います。

https://www.datatables.net/

テーブルに導入するにはDataTable()を呼び出すだけです。

```js
$(document).ready(function(){
 $('#myTable').DataTable();
});
```

## mCustomScrollbar

scrollbarのカスタマイズにはmCustomScrollbarを使う事にしました。

pluginの説明
http://manos.malihu.gr/jquery-custom-content-scroller/

githubプロジェクト
https://github.com/malihu/malihu-custom-scrollbar-plugin

このプラグインの使い方は簡単で対象に対してmCustomScrollbar()を呼び出すだけです。

```js
$(window).load(function(){
 $(".content").mCustomScrollbar();
});
```

## FixedColumnsプラグイン

DataTablesで先頭カラムを固定するにはFixedColumnsプラグインを使います。

https://datatables.net/extensions/fixedcolumns/

先頭カラムを固定する簡単なサンプルコード。

```js
var table = $('#table').DataTable(options);
new $.fn.dataTable.FixedColumns(table);
```

先頭の2カラムを固定にするにはleftColumnsを2にします。

```js
var table = $('#table').DataTable(options);
new $.fn.dataTable.FixedColumns(table, {
  leftColumns: 2
});
```

横長のテーブルで先頭カラムを固定するとスクロールバーが表示されます。

# DataTablesでmCustomScrollbarを動かす

さあ、ここからが本題です。DataTablesで作った横スクロールできるテーブルのスクロールバーをリッチにしましょう。

まずHTMLのテーブルを準備します。

```html
<div id="parentId">
<table id="tableId" class="table">
  <thead>
    <tr>
      <th>xxx1</th>
      <th>...</th>
      <th>xxx9</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>xxx1</td>
      <td>...</td>
      <td>xxx9</td>
    </tr>
  </tbody>
</table> 
</div>
```

次にDataTableの初期化します。この時にsScrollXとsScrollXInnerを100%に指定します。FixedColumnsを呼び出した後にスクロールバーをリッチにするchangeRichScrollbarを呼び出します。

```js
$(function() {
  var tableParentSelector = "#parentId";
  var tableSelector = "#tableId";
  var table = $(tableSelector).DataTable({
    sScrollX: "100%",
    sScrollXInner: "100%",
  });
  new $.fn.dataTable.FixedColumns(table);
  changeRichScrollbar(tableParentSelector, tableSelector);
});
```

changeRichScrollbarではまずテーブルのヘッダ部分で余分な部分が下にはみ出さないためにtableSelector > thead > tr > th の高さを0にします。

FixedColumnsを呼び出すと元テーブルと別に固定カラムとスクロールに対応したブロックが作られます。

このスクロールするブロックのclassにdataTables_scrollBodyが指定されていますので、これに対しmCustomScrollbarを初期化します。

callbacks#whileScrollingはbodyをスクロールした際にテーブルのヘッダーも合わせてスクロールするための処理です。dataTables_scrollHeadの左位置とdataTables_scrollBodyの左位置を揃えています。

```js
function changeRichScrollbar(parentSelector, tableSelector) {
  
  $(tableSelector + ' thead tr th').each(function(index, v) {
    var style = $(v).attr('style');
    $(v).css({
      cssText: style + "; height: 0 !important; padding-top: 0 !important; padding-bottom: 0 !important;"
    });
  });

  $(parentSelector + ' .dataTables_scrollBody').mCustomScrollbar({
    axis: "x",
    scrollInertia: 0,
    theme: "inset-2-dark",
    callbacks: {
      whileScrolling: function() {
        $(parentSelector + " .dataTables_scrollHead").scrollLeft(this.mcs.left * -1);
      },
    },
  });
  $(parentSelector + ' .dataTables_scrollBody').css("border-bottom", "none");
}

```

最終的に動作するものはこちらからご確認下さい。

https://jsfiddle.net/tkosuga/dkzr3h1v/3/

# ページを切り替えたりソートするとテーブルが崩れる問題への対処

ページ切り替えやソートなどテーブルの再構築が行われると表示が崩れてしまいました。

これに対処するにはテーブル再構築のタイミングに合わせてmCustomScrollbarの削除と生成を行います。

fnDrawCallbackはテーブル描画後に呼ばれるコールバックハンドラーです。ここで削除してから再初期化を行うと崩れなくなります。

```js
    fixedColumns: {
      leftColumns: 1,
    },
    fnDrawCallback: function(oSettings) {
      $(tableParentSelector + ' .dataTables_scrollBody').mCustomScrollbar('destroy');
      changeRichScrollbar(tableParentSelector, tableSelector);
    },
```

# リファレンス

- https://jquery.com/
- https://datatables.net/
- https://datatables.net/extensions/fixedcolumns/
- https://github.com/malihu/malihu-custom-scrollbar-plugin

# さいごに

質問などあればコメントにお願いします。直接メッセージをしたい方は[Twitter](https://twitter.com/tkosuga)宛にお願いします。