javascript

文字列をシャッフルして表示させる方法【JavaScript】

仕事で数字をシャッフルする仕組みが必要になったので、簡単に実装してみました。

jQueryはあまり使いたくなかったので生のJavaScriptです。

既存のライブラリとしては、Chaffle.jsなどが便利だと思います。

完成したもの

/* usage
 * shuffleNumber(対象の要素, シャッフルの間隔, 1文字が変わる回数, 結果);
 */
var element = document.getElementById('target');
shuffleNumber(element, 100, 10, 256);

/******************************************************************/

function shuffleNumber(element, speed = 50, time = 500, after = 256) {
  // 対象の桁数を取得
  const numLength = element.textContent.length;
  // 結果後の文字
  const afterStr = after.toString(10);
  // 結果後の桁数
  const resultLength = afterStr.length;
  // 結果の文字列
  let result = '';

  function shuffle(remain) {
    // Promiseを返す
    return new Promise(resolve => {
      let count = 0;
      // speedの周期でシャッフル
      const si = setInterval(function() {
        // ランダムな文字列を生成
        let shuffleStr = '';
        for (let i = 0; i < numLength - remain; i++) {
          shuffleStr += Math.floor(Math.random() * 9);
        }
        // timeに達するまで繰り返す
        if(count < time) {
          // テキストを書き換え
          element.textContent = result + shuffleStr;
          count++;
        } else {
          if (remain == resultLength - 1) {
            // 結果の該当する桁を代入
            result += afterStr.slice(remain, remain + 1);
            element.textContent = result;
          } else {
            result += afterStr.slice(remain, remain + 1);
            element.textContent = result + shuffleStr;
          }
          // Intervalを解除
          clearInterval(si);
          // resolveを返す
          resolve();
        }
      }, speed);
    })
  }

  // async/awaitで処理を待ってループ
  async function start() {
    for (var i = 0; i < resultLength; i++) {
      const res = await shuffle(i);
    }
  }

  // 実行
  start();
}

shuffleNumber(対象の要素, シャッフルの間隔, 1文字が変わる回数);で使用することができます。

非同期処理をループ内で使いたかったので、async/awaitを利用し実装しました。

今回は必要なかったので数字のみでしたが、英語などの文字列をシャッフルしたいときは文字コードの範囲を指定してそこでランダムに取ってくるといいと思います。

 

*追記

文字列も扱う必要があったため、文字列もシャッフル可能にしました。

全体的に使いやすくなっていると思います。

/*******************************************************************************************
 * Usage
 * shuffleStr(対象要素, 結果文字列, 文字が変わる周期(ms), 1文字あたり変更する回数);
 * speed, timeは省略可能
 * async/await用にresolveを返します
 * getRandomStr内のRangeで好きに文字列を設定できます(unicode)
 *******************************************************************************************/

export default function shuffleStr(element, afterStr, speed = 40, time = 1) {
  return new Promise(resolve => {
    const resultLength = afterStr.length;
    let result = '';

    function shuffle(remain) {
      return new Promise(resolve => {
        let count = 0;
        const si = setInterval(function() {
          let shuffleStr = '';
          shuffleStr += getRandomStr();
          if(count < time) {
            element.textContent = result + shuffleStr;
            count++;
          } else {
            result += afterStr.slice(remain, remain + 1);
            element.textContent = result;
            clearInterval(si);
            resolve();
          }
        }, speed);
      })
    }

    function Range(first, last) {
      var first = first.charCodeAt(0);
      var last = last.charCodeAt(0);
      var result = new Array();
      for(var i = first; i <= last; i++) {
        result.push(String.fromCodePoint(i));
      }
      return result;
    }

    function getRandomStr() {
      const str = Range('0', 'z');
      return str[Math.round(Math.random() * str.length)];
    }

    async function start() {
      for (var i = 0; i < resultLength; i++) {
        const res = await shuffle(i);
      }
      return resolve();
    }

    start();
  });
}

第二引数にシャッフル後の文字列を入れることで任意の文字列をシャッフルしながら生成できます。

Promiseを返しているため、複数の要素を連続してシャッフルといったことが可能です。

Reactで使用しているためexportしています。