JavaScriptで入力残り文字数をプログレスバーに表示する

(1/1)
Bluesky投稿用プログラムのフロントエンドで使うことを目的に、JavaScript だけでテキストボックスに入力できる残り文字数をリアルタイムにプログレスバーに表示するプログラムを作ってみた。

目次

サンプル・プログラムの実行例

JavaScriptでテキスト入力中に残り文字数をプログレスバーに表示する

サンプル・プログラムのダウンロード

圧縮ファイルの内容
textProgressBar.htmlサンプル・プログラム本体
textProgressBar.html 更新履歴
バージョン 更新日 内容
1.0.0 2024/12/01 初版

解説:初期値

pasteImage.html

  25: // 初期値(START) ==========================================================
  26: const TITLE = 'クリップボードにある画像を取得'// プログラム・タイトル
  27: const REFERENCE = 'https://www.pahoo.org/e-soul/webtech/js01/js01-17-01.shtm';
  28: const WIDTH  = 600;                             // 横幅(ピクセル)
  29: const MAX_IMAGES = 4;                           // 最大画像数
  30: // imgのリスト;MAX_IMAGESの数だけ用意すること
  31: const IMAGE_LIST = ['image1', 'image2', 'image3', 'image4'];
  32: 
  33: document.addEventListener('DOMContentLoaded', () => {
  34:     //タイトル等を表示する.
  35:     document.title = TITLE;
  36:     document.getElementById('title').innerHTML = TITLE + '&nbsp;<span style="font-size:small;">' + getLastModified() + '版</span>';
  37:     document.getElementById('reference').innerHTML =`
  38: ※参考サイト&nbsp;<a href="${REFERENCE}">${REFERENCE}</a>
  39: `;
  40: 
  41:     //スタイルシートをセットする.
  42:     document.getElementById('help').style.width  = WIDTH + 'px';
  43:     document.getElementById('help1').innerHTML = `画像は ${MAX_IMAGES}個までペーストできます.`;
  44:     let width = Math.floor(WIDTH / MAX_IMAGES);
  45:     IMAGE_LIST.forEach((value, index) => {
  46:         document.getElementById(value).style.width  = width + 'px';
  47:         document.getElementById(value).style.height  = 'auto';
  48:     });
  49: });
  50: // 初期値(END) ==========================================================

各種初期値は変更可能である。id属性を変更した場合は、HTML本文のid属性もあわせて変更すること。
Bluesky では、2024年(令和6年)12月時点の1メッセージあたり最大文字数は300文字(英数字も日本語も1文字とカウントする)であり、これを定数 MAX_LENGTH にあらかじめ代入した。また、メッセージ中のURLは1つにつき23文字とカウントされるため、これも URL_LENGTH に代入した。

解説:指定コンテナにプログレスバーの原型を追加する

textProgressBar.html

  74: /**
  75:  * 指定コンテナにプログレスバーの原型を追加する
  76:  * @param   Object containar コンテナ
  77:  * @return  なし
  78: */
  79: function addProgressBar(containar) {
  80:     containar.innerHTML = `
  81: <span id="${CHARCOUNTER}"></span>
  82: <svg id="${PROGRESS}" viewBox="0 0 36 36">
  83: <path
  84:     d = "M18 2a16 16 0 1 1 0 32 16 16 0 0 1 0-32"
  85:     fill = "none"
  86:     stroke = "lightsteelblue"
  87:     stroke-width = "4.0"
  88: />
  89: <path
  90:     id = "${PROGRESSBAR}"
  91:     d = "M18 2a16 16 0 1 1 0 32 16 16 0 0 1 0-32"
  92:     fill = "none"
  93:     stroke = "royalblue"
  94:     stroke-width = "4.0"
  95:     stroke-dasharray ="100, 100"
  96: />
  97: </svg>
  98: `;
  99:     document.getElementById(PROGRESS).style.width  = '24px';
 100:     document.getElementById(PROGRESS).style.height  = '24px';
 101:     document.getElementById(PROGRESS).style.marginRight  = '5px';
 102: }

ドーナツ型をしたプログレスバーは SVG図形として用意した。これは <svg id="${PROGRESS} にあらかじめ用意する。かなり大きいものなので、関数松部でスタイルシートを設定し、直径24ピクセルのドーナツ型に縮小した。

解説:文字数カウンタとプログレスバーを更新する

textProgressBar.html

 104: /**
 105:  * 文字数カウンタとプログレスバーを更新する
 106:  * @param   なし
 107:  * @return  なし
 108: */
 109: function updateCounter() {
 110:     const textarea      = document.getElementById(TEXTAREA);
 111:     const charCount     = document.getElementById(CHARCOUNTER);
 112:     const progressBar   = document.getElementById('progressBar');
 113:     const urlRegex = /https?:\/\/[^\s]+/g;  // URLパターン
 114:     const text = textarea.value;
 115:     let textLength = text.length;
 116:     
 117:     // URLを23文字としてカウント
 118:     const urls = text.match(urlRegex);
 119:     if (urls) {
 120:         const actualUrlLength = urls.join('').length;
 121:         textLength = textLength - actualUrlLength + (urls.length * URL_LENGTH);
 122:     }
 123: 
 124:     // 残り文字数とプログレスバーを更新する
 125:     const remainingChars = MAX_LENGTH - textLength;
 126:     charCount.textContent = remainingChars;
 127: 
 128:     const percentage = Math.max((remainingChars / MAX_LENGTH* 100, 0);
 129:     progressBar.setAttribute('stroke-dasharray', `${percentage}, 100`);
 130: 
 131:     // 制限文字数を下回ったら red
 132:     if (remainingChars < 0) {
 133:         progressBar.setAttribute('stroke', 'red');
 134:         charCount.style.color = 'red';
 135:     // 残り20文字未満なら orange
 136:     } else if (remainingChars < 20) {
 137:         progressBar.setAttribute('stroke', 'orange');
 138:         charCount.style.color = 'orange';
 139:     // それ以外は royablue
 140:     } else {
 141:         progressBar.setAttribute('stroke', 'royalblue');
 142:         charCount.style.color = 'royalblue';
 143:     }
 144: }

テキストボックスに inputイベントが発生したら動かす関数として updateCounter を定義する。

まず、テキスト中にあるURLを正規表現でキャッチアップし、冒頭で定義した URL_LENGTH としてカウントする。
残り文字数を remainingChars に代入したら、カウンタの値を更新する。
残り文字数の全体に対する割合(パーセント)を計算したら、これをプログレスバーの属性 stroke-dasharray に代入する。stroke-dasharray は、SVG図形に適用する属性で、ダッシュ(線の部分)とギャップ(空白の部分)の長さを、カンマやスペースで区切った数値リストとして指定する。ここでは、残り文字数の割合がダッシュで、全体は空白の扱いになる。
さらに、制限文字数を下回ったり、残り20文字未満になったらカウンタやプログレスバーの色を変更するようにした。

解説:HTML本文

textProgressBar.html

 150: <body>
 151: <h2 id="title" name="title"></h2>
 152: テキストボックス<br>
 153: <textarea id="msg" name="msg"></textarea>
 154: <div id="counter" name="counter"></div>
 155: 
 156: 
 157: <!-- 使い方 -->
 158: <div id="help" name="help" style="border-style:solid; border-width:1px; margin:20px 0px 0px 0px; padding:5px; font-size:small; overflow-wrap:break-word; word-break:break-all;">
 159: 
 160: <h3>使い方</h3>
 161: <ol>
 162: <li>テキストボックスに文字を入力してください.</li>
 163: <li>入力文字数に応じ,右下のプログレスバーが変化します.</li>
 164: </ol>
 165: <div id="reference" name="reference"></div>
 166: 
 167: <script>
 168: // プログレスバー更新イベント登録
 169: document.getElementById(TEXTAREA).addEventListener('input', updateCounter);
 170: </script>
 171: 
 172: </body>

HTML本文はご覧の通りである。
入力テキストボックス <textarea> とカウンタやプログレスバーを配置するコンテナ <div id="counter"> を静的に配置している。これらはJavaScriptで動的に生成しても構わない。

最後に、先ほど定義したユーザー関数 updateCounter を、テキストボックスの inputイベントとして追加登録する。オブジェクトがないと登録できないので、この位置にスクリプトを書いている。

参考サイト

(この項おわり)
header