page.tsx (3584B)
1 "use client"; 2 import { useState } from "react"; 3 import { 4 APIProvider, 5 Map, 6 Marker, 7 MapEvent, // MapEvent型をインポートに追加 (もしあれば) 8 } from "@vis.gl/react-google-maps"; 9 import styles from "./page.module.css"; 10 11 // 座標の型を定義 12 type Coords = { 13 lat: number; 14 lng: number; 15 } | null; 16 17 export default function Home() { 18 const [currentPosition, setCurrentPosition] = useState<Coords>(null); 19 const [copied, setCopied] = useState(false); 20 21 // MapコンポーネントのonClickイベントハンドラ 22 const handleMapClick = (e: any) => { 23 // イベントオブジェクトから緯度経度情報が取得できることを確認 24 console.log(e.type); 25 if (e.type == "click") { 26 const coords: any = e.detail.latLng; 27 setCurrentPosition(coords); 28 setCopied(false); // 新しい座標が選ばれたらコピー状態をリセット 29 console.log( 30 `新しい座標: Lat ${coords.lat.toFixed(6)}, Lng ${coords.lng.toFixed(6)}`, 31 ); 32 } else { 33 setCurrentPosition(null); 34 setCopied(false); 35 } 36 }; 37 const handleCopy = async () => { 38 if (!currentPosition) return; 39 40 const lat = currentPosition.lat.toFixed(6); 41 const lng = currentPosition.lng.toFixed(6); 42 const textToCopy = `lat: ${lat}, lng: ${lng}`; 43 44 try { 45 await navigator.clipboard.writeText(textToCopy); 46 setCopied(true); 47 setTimeout(() => setCopied(false), 2000); // 2秒後にメッセージを非表示 48 } catch (err) { 49 console.error("Failed to copy text: ", err); 50 // エラー処理(例:alert('コピーに失敗しました')) 51 setCurrentPosition(null); 52 } 53 }; 54 55 const defaultCenter = { lat: 35.486404, lng: 133.06863 }; 56 57 return ( 58 <div> 59 <main> 60 <div className={styles.mapContainer}> 61 <APIProvider 62 apiKey={process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY || ""} 63 > 64 <Map 65 style={{ width: "100%", height: "85vh" }} 66 defaultCenter={defaultCenter} 67 defaultZoom={17} 68 gestureHandling={"greedy"} 69 disableDefaultUI={false} 70 mapId={process.env.NEXT_PUBLIC_MAP_ID || ""} 71 // useMapEventsの代わりにMapコンポーネントに直接onClickを渡す 72 onClick={handleMapClick} 73 > 74 {/* マーカーを直接描画する */} 75 {currentPosition && <Marker position={currentPosition} />} 76 </Map> 77 </APIProvider> 78 </div> 79 </main> 80 <footer className={styles.footer}> 81 <div className={styles.coordinateDisplay}> 82 {currentPosition ? ( 83 <div> 84 <p> 85 **タップした座標:** <br /> 86 lat: {currentPosition.lat.toFixed(6)}, lng:{" "} 87 {currentPosition.lng.toFixed(6)} 88 </p> 89 <button 90 onClick={handleCopy} 91 style={{ 92 marginLeft: "10px", 93 padding: "5px 10px", 94 backgroundColor: copied ? "#4CAF50" : "#007BFF", 95 color: "white", 96 border: "none", 97 borderRadius: "5px", 98 cursor: "pointer", 99 }} 100 > 101 {copied ? "コピーしました!" : "座標をコピー"} 102 </button> 103 </div> 104 ) : ( 105 <p>地図上の任意の場所をタップしてください。</p> 106 )} 107 </div> 108 </footer> 109 </div> 110 ); 111 }