【Handsontable】セル内にプログレスバー(Progress)の表示

# はじめに
IE 11 のサポート終了が2022年6月15日と決まりました。Delphi 5で作成されたWebアプリケーションがあり、Active Xのグリッドを使用しています。Microsoft EdgeのIEモードで動作するとはいえ、IE対応は流石にやめたいです。

WebアプリケーションをASP.NETで作り替えようとしているのですが、Active Xのグリッドにはパーセント表示の際に進捗バーが表示されています。
移植する上で、Handsontableでプログレスバー(Progress)の表示に挑戦してみました。

# 環境
HandsontableはMITライセンス版のバージョン 6.2.2を使用しています。

# Handsontableフォーラムのサンプル
Handsontableフォーラムの質問者の回答に答える形で、JsFiddleにサンプルが作成されています。

https://forum.handsontable.com/t/progress-bar-custom-cell-formatting/1425

http://jsfiddle.net/gaq4y6w4/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/ff35baeb-c7bd-f598-2470-2caaa79d7c1a.png)

```css
.process {
  height: 5px;
  widths: 10px;
  border-radius: 2px;
  margin-top: 10px;
  background: green;
}
```

```javascript
function myRenderer(instance, td, row, col, prop, value, cellProperties) {
    Handsontable.renderers.TextRenderer.apply(this, arguments);
    td.innerHTML = '';
    var div = document.createElement('DIV');
    div.className = 'process';
    div.style.width = value + 'px';
    td.appendChild(div);
  }
```

# Boostrap 4によるプログレスバー
Handsontableフォーラムのサンプルにより作り方が分かりました。ただ、数値の同時表示も実現したいのです。
そこでネットでプログレスバーで検索すると、Boostrapを使用したサンプルが見つかったので採用してみました。
バーの表示をストライプとかにすれば、よりオシャレになりそうです。

* [Bootstrap4でプログレスバー（Progress）の作り方](https://medium-company.com/bootstrap-progress/)
* [Bootstrap 4入門 > プログレス - とほほのBootstrap 4入門](https://www.tohoho-web.com/bootstrap/progress.html)

<p class="codepen" data-height="300" data-default-tab="result" data-slug-hash="oNWrGwM" data-user="yaju-the-encoder" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/yaju-the-encoder/pen/oNWrGwM">
  Handsontable  ProgressBar</a> by やじゅ (<a href="https://codepen.io/yaju-the-encoder">@yaju-the-encoder</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

CSS部分は、Boostrap 4側に定義されています。

```javascript
function progressRenderer(instance, td, row, col, prop, value, cellProperties) {
  Handsontable.renderers.TextRenderer.apply(this, arguments);
  if (value === null) value = 0;

  let str = '<div class="progress">';
  str = str + '<div class="progress-bar bg-danger" role="progressbar" aria-valuenow="{0}" ';
  str = str + 'aria-valuemin="0" aria-valuemax="100" style="width: {0}%;">{0}%</div>';
  str = str + '</div>';
  str = str.replace(/\{0\}/g, value);
  td.innerHTML = str;
}
```


# オリジナルのプログレスバー
Boostrap 4によるプログレスバーは悪くないのですが、数値の表示が進捗の位置に左右されるので数値が小さいと数字が見切れてしまうのです。そうするとセルの幅を広げる必要が出てきてしまいます。

ActiveX版のグリッドのパーセント表示の際に進捗バーの見た目とBoostrap 4によるプログレスバーの見た目を活かしてみました。
プログレスバーはグラデーションしています。グラデーションには下記ツールを使用しました。

https://cssgradient.io/

<p class="codepen" data-height="300" data-default-tab="result" data-slug-hash="RwVzZwV" data-user="yaju-the-encoder" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/yaju-the-encoder/pen/RwVzZwV">
  Handsontable  ProgressBar</a> by やじゅ (<a href="https://codepen.io/yaju-the-encoder">@yaju-the-encoder</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

```css
.progressBox {
  position: relative;
  width: 100%;
  height: 80%;
  font-size: 0.75rem;
  border: solid 1px silver;
  background-color: #e9ecef;
  border-radius: 0.25rem;
}

.progressBar {
  position: absolute;
  display: inline-block;
  top: 0px;
  left: 0px;
  height: 100%;
  background: rgb(255,0,0);
  background: linear-gradient(90deg, rgba(255,0,0,1) 0%, rgba(255,80,80,1) 30%, rgba(255,200,200,1) 100%);
}

.progressLabel {
  position: absolute;
  color: black;
  top: -1px;
}
```

```javascript
function progressRenderer(instance, td, row, col, prop, value, cellProperties) {
  Handsontable.renderers.TextRenderer.apply(this, arguments);
  if (value === null) value = 0;

  let left = instance.getColWidth(col) / 22 * 10 - 5;
  let str = '<div class="progressBox">';
  str = str + '<div class="progressBar" style="width:{0}%"></div>'
  str = str + '<span class="progressLabel" style="left:' + (left - String(value).length * 3) + 'px;">{0}%</span></div>'
  str = str.replace(/\{0\}/g, value);
  td.innerHTML = str;
}
```

セル幅によって数値表示の中央位置を調整していますが、ズレている場合はleftの値を調整してみてください。

# 最後に
Handsontableのレンダラーを使いこなせれば何でも表示できてしまいますね。
Boostrapは、文字の大きさやボーターの角丸や背景色などのデザインを見習うところはあるので参考にしています。