Handsontableでセルのマージみたいなものを実現する

Handsontableでセルのマージみたいなものを実現する
                 
最終更新日から90日以上経過しています。

以前、Handsontableで添付ファイルを表示するカスタマイズを行いましたが、それに引き続きのカスタマイズです。

元々Handsontableを使用していた案件で「セルをマージして表示したい」という要望が出てきたので調べてみたのですが、どうやらライブラリ側でセルのマージ機能は提供されているようで。ただし、この提供されているセルのマージ機能が思っていたものと違うものでした。

そこで、提供されているセルのマージ機能ではなく、独自のカスタマイズで実装してみた、という形です。

結論としては、タイトルの通り、セルのマージ”みたい”な表示をする事で実現しました。

前述のライブラリ側で提供されているマージ機能について調べてみると、やっぱり「思ったものと違うよ」という意見もあるようで。代替案の一つとしてシェアします。

Handsontableの概要

Handsontableはブラウザ(=JavaScript)側でExcelのようにデータをグリッドに表示できるライブラリです。

公式ドキュメントがとっても見やすいので、詳しい機能などは公式を参照のこと。APIが非常に豊富なのでドキュメントのボリュームも凄いです。さくっとどんな事ができるのか確認したい場合はQiitaに良記事があったので、そちらも参考になるかもしれません。

(このページをご覧になっているという事は、この説明も要らないかもしれないですね。)

やりたいこと

例えば、以下はWikipediaから拝借した日本の市の面積トップ10の表ですが、9位、10位に注目。岩手県が続いている。

引用:Wikipedia

このように複数行続けて同じ値がある時は、以下のようにセルをマージして表示したい。

準備

環境

Handsontableを使用する為、下記のhtmlとJavaScriptを用意しました。

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/handsontable/dist/handsontable.full.min.css" />
    </head>
    <body>
        <div id="container"></div>
        <script src="https://cdn.jsdelivr.net/npm/handsontable/dist/handsontable.full.min.js"></script>        
        <script src="../javascript/handsontable.js"></script>
    </body>
</html>

handsontable.js

(function() {
    var data = [
        { prefecture: '岐阜県', city: "高山市", area: 2177.6, },
        { prefecture: '静岡県', city: "浜松市", area: 1558.1, },
        { prefecture: '栃木県', city: "日光市", area: 1449.8, },
        { prefecture: '北海道', city: "北見市", area: 1427.4, },
        { prefecture: '静岡県', city: "静岡市", area: 1411.9, },
        { prefecture: '北海道', city: "釧路市", area: 1362.9, },
        { prefecture: '山形県', city: "鶴岡市", area: 1311.5, },
        { prefecture: '岩手県', city: "宮古市", area: 1259.2, },
        { prefecture: '岩手県', city: "一関市", area: 1256.4, },
        { prefecture: '広島県', city: "庄原市", area: 1246.5, },
    ]

    const grid = document.getElementById("container");
    const hot = new Handsontable(grid, {
        data: data,
        rowHeaders: true,
        colHeaders: true,
        columns: [
            { data: "prefecture", type: 'text'},
            { data: "city", type: 'text'},
            { data: "area", type: 'text'},
        ],
        columnSorting: true
    });
})();

 

とりあえず参照元のランキングが表示された

こんな感じで表示される。ほぼほぼExcel。

これをカスタマイズしていきます。

カスタマイズ内容

独自レンダラを実装

Handsontableはセルの描画処理に手を加える事ができる

これはセルのオプションにrendererを追加する事で実現するが、詳しい説明はドキュメント参照のこと。

実際に手を加えた内容としては、columnsで各列を定義している部分を、

columns: [
    { data: "prefecture", type: 'text'},
    { data: "city", type: 'text'},
    { data: "area", type: 'text'},
],

 

こんな感じに変更。

セル描画時にmy.rendererというレンダラを実行する。

columns: [
    { data: "prefecture", type: 'text', renderer: 'my.renderer'},
    { data: "city", type: 'text'},
    { data: "area", type: 'text'},
],

 

ではmy.rendererはなにをやってるの、というとこんな感じ。

// register custom renderer
Handsontable.renderers.registerRenderer('my.renderer', function(instance, td, row, col, prop, value, cellProperties) {
    const top = instance.getDataAtCell(row-1, 0);
    const current = instance.getDataAtCell(row, 0);
    const bottom = instance.getDataAtCell(row+1, 0);
    if (top === current) {
        td.style.color = "white";
        td.style.borderTopStyle = "hidden";
    }
    if (bottom === current) {
        td.style.borderBottomStyle = "hidden";
    }
    td.innerText = (value === null ? "" : value);
    return td;
});

 

レンダラの内容をざっくり解説

1行ずつ描画されていく時に、キーの値(今回は県名)を

  • 上の行の値と比較し、同じ値の場合、文字色を白、セルの上枠を非表示とする。
  • 同様に下の値と比較し、同じ値の場合、セルの下枠を非表示とする。

するとこんな感じになります

めでたくマージっぽく表示されました。

ソートするとどうなる?

Excelでは、セルをマージするとソートができません。

今回の実装ではソートできます。

マージっぽい表示もソート後の値に応じて処理されます。

おわりに

欲を言えばマージした後、値を中央に持ってきたかったが、それは無理そう。

JavaScript(TypeScript)カテゴリの最新記事