LoginSignup
4
0

More than 3 years have passed since last update.

【React】ホットラインマイアミっぽい文字を表示できるコンポーネントを開発してみた

Last updated at Posted at 2019-08-02

最近Gatsby製のブログを作ったので、そこで使うためにReactのコンポーネントを開発しました!
↓こんな感じの文字が出せます。
react-hlm.gif
リポジトリ : https://github.com/Y0KUDA/react-hlm
デモページ : https://y0kuda.github.io/react-hlm/index.html
NPM : https://www.npmjs.com/package/react-hlm

名前の由来はタイトルの通り、Hotline Miamiです。
marqueeと合わせて使いたくなる90年代っぽい感じにできたと思います。

使い方

npmで公開しているのでnpmyarnreact-hlmをインストールすれば使えます。
こんな感じのコードで簡単にバナーを出せます。

<HLM.Banner text="sample"/>

詳しくはリポジトリを参照してください。

技術的な話

立体に表示する方法

エレメントの高さを0にすることで、同じ場所に複数のテキストを表示することができます。
少しずつずらして表示することで3Dっぽく表示してます。

{Array.from(Array(layers).keys()).map(layer=>{
  return  <div  key={layer+"_key"} 
                style={Object.assign({top:`calc(${vecY*layer*distance}px - ${elementHeight}px )`,
                                      left:vecX*layer*distance,
                                      position:"relative",
                                      height:"0", // 高さが0
                                      color:acid(time*colorSpeed+layer*0.1),
                                      zIndex:layer},style)}>
            {text}
          </div>
})}

正しい領域を設定する方法

立体表示をするためにエレメントの高さを0にしてしまっているので、そのままだと領域がおかしくなってしまいます。
今回は同じテキストのエレメントを非表示で作成し、その領域内にずらして入れ込むことで領域を設定しています。
まず、以下のコードで何も表示しない領域を作成します。

<div style={{visibility:"hidden"}} ref={ref}> // visibility:"hidden" にすると表示されない。
                                              // ref={ref} とすると、refからエレメントを参照できる。
{text}
</div>

すると、こんな感じの領域が発生します。
box-shift.png
次に、以下のコードでエレメントの高さを取得します。

    useEffect(() => {
      setElementHeight(ref.current.offsetHeight); // refからエレメントの高さを取得し、設定。
      window.addEventListener('resize', ()=>setElementHeight(ref.current.offsetHeight)); // ウインドウがリサイズされたときに高さが更新されるようにイベントを設定。
      const id = setInterval(() => {
        updateTime(t => t + 50);
      }, 50);
      return () => {
        clearInterval(id);
      };
    },[]);

最後に、取得した高さ分を差し引いて表示するようにします。

{Array.from(Array(layers).keys()).map(layer=>{
  return  <div  key={layer+"_key"} 
                style={Object.assign({top:`calc(${vecY*layer*distance}px - ${elementHeight}px )`, // - ${elementHeight}px で必要な高さを差し引く。
                                      left:vecX*layer*distance,
                                      position:"relative",
                                      height:"0",
                                      color:acid(time*colorSpeed+layer*0.1),
                                      zIndex:layer},style)}>
            {text}
          </div>
})}

いい感じに収まりました。
box.png

最後に

ブログやってるので見てくれると嬉しいです!
まだ中身があまりないですが・・・
https://unearned-in.com/

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0