作成日:2023-09-20
画像をフルスクリーンで表示させるライブラリを探して見たが、良いと思える物が無かったので最終的にモーダルウィンドウを使用し自作した。
このブログで使用しているが、Reactで画像をただ単に大きく見せ、ズームできる。それだけの機能が欲しかったのですが、ライブラリを探してみると、なかなか良いものが無かった。そのな時react-map-interactionというライブラリを発見した。
これです。ただズームが出来ればいいんです。
しかし、このライブラリは領域に画像を表示させ、ズームインができるだけのライブラリであり、モーダルウィンドウではない。
その辺を解決するため今回使用したものは
モーダルウィンドウは全画面に表示させたいが、問題が発生する。
react-map-interactionを使い画面いっぱい、いっぱい表示させたいのだが、親のタグに影響されて位置がずれたり、うまくフルスクリーンになってくれない。
通常のJS DOM操作なら一番大元の親のid element探して、そこにくっつければいいのだが、React jsxでは無理そう。
探しているうちにRreact Portalを知る。
React Portalはその大元の親を指定して、そこにjsxでレンダリングさせる物であり、の使い道としては、トースト通知、モーダルウィンドウがあるようだ。
react-map-interactionはどんな感じで使うのか確認するため、とりあえずこのモジュールを公式ページを参照し、使用してみる。
react-map-interactionをインストールする。
npm install --save react-map-interaction
使い方は公式のBasicを参考にこんな感じでとりあえず表示させてみた。
コード量も少なく、簡単に使えてしまう。
import logo from './logo.svg';
import './App.css';
import { MapInteractionCSS } from 'react-map-interaction';
function App() {
return (
<div className="App">
<div style={{backgroundColor:"gray"}}>
<MapInteractionCSS>
<img src="logo192.png" />
</MapInteractionCSS>
</div>
</div>
);
}
export default App;
React Portalは参照先のelementを指定して、jsxのレンダリングをするものなので、今回新しく、htmlでelementを作成した。
<!--
追加要素
モーダルウィンドウの親のelement「modal-root」を作成します。
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="modal-root"></div>
<div id="root"></div>
</body>
</html>
モーダルウィンドウのを作るために、次にReactDOM.createPortalを使います。
import logo from './logo.svg';
import ReactDOM from 'react-dom';//<--追加
import './App.css';
import { MapInteractionCSS } from 'react-map-interaction';
function App() {
//先ほどのReactDom.createPortalを使い、引数に、id="modal-root"を指定。
const ModalDemo =(()=>{
return ReactDOM.createPortal(
<div className="App">
<div style={{backgroundColor:"gray"}}>
<MapInteractionCSS>
<img src="logo192.png" />
</MapInteractionCSS>
</div>
</div>,document.getElementById('modal-root'));
})
return (
<div className="App" style={{height:"120vh"}}>
<ModalDemo/>
</div>
);
}
export default App;
cssのスタイリングをして、モーダルウィンドウのトグルボタンを作成しました。
import ReactDOM from 'react-dom';
import './App.css';
import { MapInteractionCSS } from 'react-map-interaction';
import { useState } from 'react';
function App() {
const [ShowModal , setShowModal] = useState(false)
//displayとpositionのこの指定が重要。
const ModalBox ={
display:"flex",position:"fixed",
top:"0",left:"0",width:"100vw",height:"100vh", padding:0, zIndex:20, backgroundColor:"gray"
}
const InnerBox = {
transform:"translate(50%, 50%)",
width:"50%",height:"50%",
position:'absolute', backgroundColor:"#ddd"
}
const ToggleModal = (()=>{
setShowModal(!ShowModal)
})
const ModalDemo =(()=>{
return ReactDOM.createPortal(
<div style={ModalBox}>
<div style={InnerBox}>
<MapInteractionCSS>
<img src="logo192.png" />
</MapInteractionCSS>
</div>
</div>,document.getElementById('modal-root'));
})
return (
<div className="App">
<button onClick={ToggleModal}>モーダルウィンドウボタン</button>
{ShowModal && <ModalDemo/>}
</div>
);
}
export default App;
モーダルウィンドウ全画面が出来ましたが、モーダルウィンドウが全面にくるため、このモーダルウィンドウを消す方法がありません。
消すためには、「ShowModal」をfalseにする必要があります。
外枠の背景をクリックすると消えるようにします。と言ってもonClickを追加するだけでいいのですが、
//onCLick=onClick={ToggleModal}
return ReactDOM.createPortal(
<div style={ModalBox} onClick={ToggleModal}>
<div style={InnerBox}>
<MapInteractionCSS>
<img src="logo192.png" />
</MapInteractionCSS>
</div>
</div>,document.getElementById('modal-root'));
これでいいと思ったが、中の画像をクリックしてしまうと「ToggleModal」のイベントが実行されてしまう!!
stopPropagationの出番です。
中の白色枠にクリックイベントを追加し、クリックした場合、その後親に渡るクリックイベントを無効にします。
return ReactDOM.createPortal(
<div style={ModalBox} onClick={ToggleModal}>
<div style={InnerBox} onClick={((e)=>e.stopPropagation())}>
<MapInteractionCSS>
<img src="logo192.png" />
</MapInteractionCSS>
</div>
</div>,document.getElementById('modal-root'));
これで完成です。
import ReactDOM from 'react-dom';
import './App.css';
import { MapInteractionCSS } from 'react-map-interaction';
import { useState } from 'react';
function App() {
const [ShowModal , setShowModal] = useState(false)
const ModalBox ={
display:"flex",position:"fixed",
top:"0",left:"0",width:"100vw",height:"100vh", padding:0, zIndex:20, backgroundColor:"gray"
}
const InnerBox = {
transform:"translate(50%, 50%)",
width:"50%",height:"50%",
position:'absolute', backgroundColor:"#ddd"
}
const ToggleModal = (()=>{
setShowModal(!ShowModal)
})
const ModalDemo =(()=>{
return ReactDOM.createPortal(
<div style={ModalBox} onClick={ToggleModal}>
<div style={InnerBox} onClick={((e)=>e.stopPropagation())}>
<MapInteractionCSS>
<img src="logo192.png" />
</MapInteractionCSS>
</div>
</div>,document.getElementById('modal-root'));
})
return (
<div className="App">
<button onClick={ToggleModal}>モーダルウィンドウボタン</button>
{ShowModal && <ModalDemo/>}
</div>
);
}
export default App;
モーダルウィンドウを作るためにライブラリを探したが、自分の求めているものが無く、仕方なく自作したが、こんなに簡単にできるのであれば、初めから自作にすれば良かった。
今回覚えた物が以下3つ今後も汎用性あり。十分便利な機能だった。
質問や、間違いがありましたら、お気軽にどうぞ
※お名前とコメントの内容を入力してください。
※全てこのブログ上に公表されます。
※許可なく管理者によって修正・削除する場合がございます。 詳しくはプライバシーポリシーを参照ください