はじめに
皆さんはドリトライという漫画をご存知でしょうか。
週刊少年ジャンプで連載されていたボクシング漫画です。
全19話と短命に終わった本作ですが、登場人物の一人である虹村凶作という人物がコラ画像に使われている点で一部で有名な漫画です。
あまりにも特徴的だったので、「福笑いしたら面白そう」という動機で作りました。
試作段階なので雑な部分はありますが、以下は今回作る正統後継者福笑いです。
好き放題して遊びます。
react-moveableとは
要素に拡大縮小、回転などの動きを実装できるライブラリです。
今回のリポジトリ
ディレクトリ構成及び使用する画像です。
環境構築
viteで環境構築します。この辺あたりが参考になると思います。
react-moveableをインストールします。
npm install react-moveable
実装
App.tsx
import React, { useState } from 'react';
import './App.css';
import NijimuraHana from './component/nijimuraHana.tsx';
import NijimuraKuchi from './component/nijimuraKuchi.tsx';
import NijimuraHidarime from './component/nijiruraHidarime.tsx';
import NijimuraMigime from './component/nijimuraMigime.tsx';
import NijimuraHidariMayu from './component/nijimuraHidariMayu.tsx';
import NijimuraMigiMayu from './component/nijimuraMigiMayu.tsx';
import NijimuraHidariShiwa from './component/nijimuraHidariShiwa.tsx';
import NijimuraMigiShiwa from './component/nijimuraMigiShiwa.tsx';
import NijimuraMiken from './component/nijimuraMiken.tsx';
const App = () => {
// useState()で画像のパスを保持
const [profileImage, setProfileImage] = useState('seitoukoukeisya.png');
const onFileInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (!e.target.files) return;
// React.ChangeEvent<HTMLInputElement>よりファイルを取得
const fileObject = e.target.files[0];
// オブジェクトURLを生成し、useState()を更新
setProfileImage(window.URL.createObjectURL(fileObject));
};
return (
<React.Fragment>
<input type="file" accept="image/*" onChange={onFileInputChange} />
<div style={{backgroundImage: `url('${profileImage}')`, backgroundRepeat: "no-repeat"}}>
<NijimuraHana/>
<NijimuraKuchi/>
<NijimuraHidarime/>
<NijimuraMigime/>
<NijimuraHidariMayu/>
<NijimuraMigiMayu/>
<NijimuraHidariShiwa/>
<NijimuraMigiShiwa/>
<NijimuraMiken/>
</div>
</React.Fragment>
);
};
export default App;
背景画像のアップロードとそれぞれのパーツを配置しています。
backgroundImage
でdiv
内の背景画像を指定しています。
各コンポーネント
import React, { useState, useEffect } from 'react';
import Moveable from 'react-moveable';
import nijimuraMigime from '/nijimuramigime.png';
const NijimuraMigime = () => {
const [target, setTarget] = useState(null);
useEffect(() => {
setTarget(document.querySelector('.migime'));
}, []);
return (
<>
<div className={'moveable migime'}><img src={nijimuraMigime}/></div>
<Moveable
target={target}
draggable={true}
scalable={true}
rotatable={true}
origin={false}
throttleScale={0}
keepRatio={true}
onDrag={e => {
e.target.style.transform = e.transform;
}}
onScale={e => {
e.target.style.transform = e.transform;
}}
onRotate={e => {
e.target.style.transform = e.transform;
}}
/>
</>
);
};
export default NijimuraMigime
moveable migime
内の要素が操作可能になります。この中にnijimuraMigime
から取得した画像が含まれています。
Moveable
コンポーネントではuseState
で指定したtarget
を対象にしています。このMoveable
コンポーネント内の
draggable={true}
scalable={true}
rotatable={true}
は指定された要素をドラッグ可能、サイズ変更可能、回転可能にします。
onDrag
, onScale
, onRotate
はそれぞれ、要素がドラッグ、サイズ変更、回転されたときの処理を定義します。
これを顔のパーツごとにコンポーネントを作成していきます。
App.css
!important
をつけることで、要素のカスタマイズができるようになります。
.moveable {
width: 50px!important;
height: 100px!important;
margin: 0 0 0 auto;
}
.moveable-control {
width: 10px!important;
height: 10px!important;
margin-top: -10px!important;
margin-left: -10px!important;
}
.moveable-line {
position: absolute!important;
width: 1px!important;
height: 1px!important;
background: #000!important;
transform-origin: 0px 0.5px!important;
}
.moveable
は高さ長さを指定することで要素の判定を変更できます。
moveable-control
は拡大、縮小、回転の際の頂点を示します。
moveable-line
は頂点のつなぎ目になります。
他にもいろいろいじれる点があります。詳しくは以下の公式ドキュメントをご覧ください。
まとめ
かなり短くなりましたがこれで完成です。
やはり正統後継者の顔はインパクトあって、動かしているだけでも結構楽しいです。
とはいえ試作段階なので、完成したものを画像に起こすといった機能も追加して公開してみたいなと思います。