投稿日:2021年6月1日

LチカとはLEDをチカチカさせることです。
俗に、ラズパイ(Raspberry Pi) にLEDを装着しチカチカと発光させることを言います。
 

以前購入しようと思いましたが、その前にJavaScriptとブラウザを使って作ったことがありました。
ラズパイを期待した人、申し訳ございませんm(_ _)m
Qiitaの記事はこちら 
 


▲今回、Reactで作ったものです。
 

▼全体のソースコードです。

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Lチカ React</title>
    <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
</head>

<body style="margin:0; padding:0;">
    <div id="root"></div>
    <script type="text/babel">

        class CircleObj extends React.Component {
            constructor(props) {
                super(props);
                // ▼ このstateの設定でも動く。。。
                let count = setInterval(() => {
                    this.setState((state) => ({
                    }));
                }, 1000);
            }

            windowWidth = window.innerWidth; //ウィンドウの横の表示領域
            windowHeight = window.innerHeight; //ウィンドウの横の表示領域
            maxObjSize = this.windowWidth / 10; //オブジェクト最大サイズ 横の個数は10に固定

            verticalQuantity = Math.floor(this.windowHeight / this.maxObjSize); //縦の個数
            objQuantity = 10 * this.verticalQuantity; //ウィンドウ内のオブジェクトの総数

            bgStyle = { //背景のスタイル
                backgroundColor: "#000",
                width: this.windowWidth + "px",
                height: this.windowHeight + "px",
                overflow: "hidden",
                display: "flex",
                flexWrap: "wrap",
                alignContent: "space-between"
            }

            // ▼関数
            zeroPad(zeroNum) { // ゼロパディング
                var zeroNum = ('00' + zeroNum).slice(-2);
                return zeroNum;
            }

            getRanNum(max, min) { // ランダムな数値を取得
                var randomNum = Math.floor(Math.random() * (max - min + 1) + min);
                return randomNum;
            }

            getRandomColor(rgbColor) { // ランダムなカラー値を取得
                let colorArray = []; // RGB3色分の処理
                for (let j = 0; j < 3; j++) {
                    colorArray.push(this.zeroPad(this.getRanNum(255, 0).toString(16).toUpperCase()));
                }
                for (let i = 0; i < this.objQuantity; i++) { // オブジェクトの個数分の処理
                    rgbColor = '#' + colorArray[0] + colorArray[1] + colorArray[2];
                }
                return rgbColor;
            }

            // ▼可変しないスタイル
            objStyle = { //カラーとサイズ以外の円のスタイル
                borderRadius: "50%",
                filter: "blur(5px)",
                transition: ".5s",
            }

            render() {
                // ここにstateを配置すると全て同じ色になってしまう
                return (
                    <div style={this.bgStyle}>
                        {(() => { // JSX内の繰り返しのための即時関数
                            const objs = []; // 配列を準備
                            for (let i = 0; i < this.objQuantity; i++) {
                                let objSize = this.getRanNum(this.maxObjSize, 2); //最大サイズ〜2pxの間でランダムな大きさを設定
                                let objColorStyle = { // オブジェクト分、異なる色、大きさにしたいのでここに配置
                                    backgroundColor: this.getRandomColor(), //ランダムな色
                                    width: objSize + "px",
                                    height: objSize + "px",
                                    margin: (this.maxObjSize - objSize) / 2 + 'px' //マージン、最大サイズ-オブジェサイズ/2で算出
                                }
                                objs.push(<div key={i} style={Object.assign({}, this.objStyle, objColorStyle)}></div>); //配列に追加
                            }
                            return objs;
                        })()}
                    </div >);
            }
        }
        ReactDOM.render(<CircleObj />, document.getElementById('root'));
    </script>
</body>

</html>

 

ではブロックごとに説明していきましょう。

class CircleObj extends React.Component {
 constructor(props) {
    super(props);
    // ▼ このstateの設定でも動く。。。
    let count = setInterval(() => {
      this.setState((state) => ({
      }));
    }, 1000);
  }

▲今回はclassコンポーネントで書きました。
stateの設定はこれだけでsetIntervalも動きます。
不思議ですね。。。
 

windowWidth = window.innerWidth; //ウィンドウの横の表示領域
windowHeight = window.innerHeight; //ウィンドウの横の表示領域
maxObjSize = this.windowWidth / 10; //オブジェクト最大サイズ 横の個数は10に固定

verticalQuantity = Math.floor(this.windowHeight / this.maxObjSize); //縦の個数
objQuantity = 10 * this.verticalQuantity; //ウィンドウ内のオブジェクトの総数

bgStyle = { //背景のスタイル
  backgroundColor: "#000",
  width: this.windowWidth + "px",
  height: this.windowHeight + "px",
  overflow: "hidden",
  display: "flex",
  flexWrap: "wrap",
  alignContent: "space-beetween"
}

▲変数の設定。
コメントの表記通りです。
bgStyleはLチカオブジェクトのラッパー(背景)のスタイルです。
 

zeroPad(zeroNum) { // ゼロパディング
 let zeroNum = ('00' + zeroNum).slice(-2);
 return zeroNum;
}

getRanNum(max, min) { // ランダムな数値を取得
 let randomNum = Math.floor(Math.random() * (max - min + 1) + min);
 return randomNum;
}

getRandomColor(rgbColor) { // ランダムなカラー値を取得
 let colorArray = []; // RGB3色分の処理
 for (let j = 0; j < 3; j++) {
  colorArray.push(this.zeroPad(this.getRanNum(255, 0).toString(16).toUpperCase()));
 }
 for (let i = 0; i < this.objQuantity; i++) { // オブジェクトの個数分の処理
  rgbColor = '#' + colorArray[0] + colorArray[1] + colorArray[2];
 }
 return rgbColor;
}

▲関数。
getRandomColor関数内の1つ目のfor文は、R、G、Bの各色を配列に格納しているので3回の繰り返し。
また、2つ目のfor文はLチカオブジェの総数(objQuantity)分RGBを付与する処理をしています。
 

objStyle = { //カラー以外の円のスタイル
 borderRadius: "50%",
 filter: "blur(5px)",
 transition: ".5s",
}

▲可変しないスタイルです。
カラー値とサイズは変動するので別途用意します。
 

render() {
// ここにstateを配置すると全て同じ色になってしまう
 return (
    <div style={this.bgStyle}>
      {(() => { // JSX内の繰り返しのための即時関数
        const objs = []; // 配列を準備
       for (let i = 0; i < this.objQuantity; i++) {
          let objSize = this.getRanNum(this.maxObjSize, 2); //最大サイズ〜2pxの間でランダムな大きさを設定
          let objColorStyle = { // オブジェクト分、異なる色、大きさにしたいのでここに配置
            backgroundColor: this.getRandomColor(), //ランダムな色
            width: objSize + "px",
            height: objSize + "px",
            margin: (this.maxObjSize - objSize) / 2 + 'px' //マージン、最大サイズ-オブジェサイズ/2で算出
         }
          objs.push(<div key={i} style={Object.assign({}, this.objStyle, objColorStyle)}></div>); //配列に追加
        } 
      return objs;
      })()}
    </div >);
  }
}
ReactDOM.render(<CircleObj />, document.getElementById('root'));

▲最後にJSXです。
変数objSizeは、ランダム値を取得する関数getRanNum()を使い、最大値maxObjSize(ウィンドウサイズ/10)、最小値2pxで設定しています。
スタイルを格納するオブジェクトobjColorStylebackgroundColorは、関数this.getRandomColor()で乱数を取得し、widthheightは先ほどの変数objSizeから取得しています。
ここで大切なのがmarginです。
marginを設定しないと、▼このようにオブジェクトの大きさの変化で位置が動いてしまいます。

 

style={Object.assign({}, this.objStyle, objColorStyle)}

▲スタイルを2つ適用するのにObject.assign()関数を使いました。
重複するオブジェクトは上書きされるので注意が必要です。
最後にReactDOM.render()に渡しDOMに出力します。
 

まとめ

Reactについて何となく分かってきたような気がしますが、まだまだ勉強不足です。
カラー値やサイズといった可変の値だけDOMが書き換わるようにしたつもりですが、検証ツールで確認したところ他のスタイルも同じ値で再度レンダリングしているように見えます。
▼YouTubeにアップしてみました。

 

さらに勉強したいと思います。
 

最後まで読んでくださりありがとうございました。
 

関連サイト

 

Pocket