Newer
Older
2024-C1232021_kanata / ikiikiMAP.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>いきいきMAP</title>
    
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css"/>
    
    <style>
        /* Base Styles & Layout */
        html, body {
            height: 100%;
            margin: 0;
            padding: 0;
            font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; /* Modern font */
            color: #333;
            background-color: #f4f7f6; /* Light background for the whole page */
        }
 
        #container {
            display: flex;
            height: 100vh;
            width: 100vw;
            overflow: hidden; /* Prevent overall scrollbars */
        }
 
        /* Sidebar Styles */
        #sidebar {
            width: 320px; /* Fixed width for better control */
            flex-shrink: 0; /* Prevent shrinking below fixed width */
            background-color: #ffffff;
            padding: 25px; /* More generous padding */
            overflow-y: auto;
            border-right: 1px solid #e0e0e0; /* Softer border */
            box-shadow: 3px 0 10px rgba(0, 0, 0, 0.08); /* More subtle shadow */
            z-index: 1000;
            transition: width 0.3s ease-in-out; /* Smooth resizing */
            display: flex;
            flex-direction: column;
        }

        #sidebar h2 {
            margin-top: 0;
            margin-bottom: 25px;
            color: #2e7d32; /* Deeper green */
            font-size: 1.8em; /* Larger, more prominent heading */
            border-bottom: 2px solid #a5d6a7; /* Underline for emphasis */
            padding-bottom: 10px;
            text-align: center;
        }
 
        #comments-list {
            flex-grow: 1; /* Allow list to take available space */
            margin-top: 15px;
            padding-right: 5px; /* Space for scrollbar */
        }
 
        /* Map Styles */
        #map {
            flex-grow: 1; /* Map takes remaining space */
            height: 100vh;
            z-index: 0;
            background-color: #e0e0e0; /* Default map background */
        }
 
        /* History Entry Styles */
        .history-entry {
            background-color: #f8fcf9; /* Very light green background */
            border: 1px solid #e8f5e9; /* Light green border */
            border-radius: 8px; /* Rounded corners */
            padding: 15px;
            margin-bottom: 15px; /* Spacing between entries */
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05); /* Soft shadow */
            transition: all 0.2s ease-in-out;
            position: relative; /* For button positioning */
        }

        .history-entry:hover {
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); /* Enhanced shadow on hover */
            transform: translateY(-2px); /* Slight lift on hover */
        }
        
        .history-entry p {
            margin: 5px 0;
            font-size: 0.95em;
        }

        .history-entry p strong {
            color: #388e3c; /* Darker green for labels */
        }
 
        /* Editable Comment Text */
        .comment-text[contenteditable="true"] {
            border: 1px solid #c8e6c9; /* Light green border */
            border-radius: 5px;
            padding: 8px; /* More padding */
            background-color: #ffffff; /* White background for editable area */
            display: block; /* Take full width */
            width: calc(100% - 16px); /* Adjust for padding */
            box-sizing: border-box;
            font-size: 0.9em;
            line-height: 1.5;
            min-height: 60px; /* Minimum height for comments */
            overflow: auto; /* Enable scroll if content overflows */
            word-wrap: break-word; /* Ensure long words break */
        }
        .comment-text[contenteditable="true"]:focus {
            outline: 2px solid #4CAF50; /* Brighter outline on focus */
            border-color: #4CAF50;
        }

        /* Delete Button in History Entry */
        .history-entry button {
            background-color: #f44336; /* Red for delete */
            color: white;
            border: none;
            padding: 8px 12px;
            border-radius: 5px;
            cursor: pointer;
            font-size: 0.85em;
            position: absolute; /* Position at top right */
            top: 10px;
            right: 10px;
            transition: background-color 0.2s ease;
            opacity: 0; /* Hidden by default */
            visibility: hidden;
        }

        .history-entry:hover button {
            opacity: 1; /* Visible on hover */
            visibility: visible;
        }
 
        .history-entry button:hover {
            background-color: #d32f2f; /* Darker red on hover */
        }

        /* Leaflet Popup Overrides */
        .leaflet-popup-content-wrapper {
            background: #ffffff;
            border-radius: 12px; /* Smoother rounded corners */
            box-shadow: 0 5px 20px rgba(0, 0, 0, 0.15); /* More pronounced shadow */
            padding: 0; /* Remove default padding */
        }
        
        .leaflet-popup-content {
            margin: 15px 20px 15px 20px; /* Adjust padding inside content */
            width: 320px !important; /* Slightly adjusted for better fit */
            max-width: none !important;
            font-size: 0.95rem;
            color: #444;
        }

        .leaflet-popup-content p {
            margin-top: 0;
            margin-bottom: 10px;
        }
        .leaflet-popup-content p:last-child {
            margin-bottom: 0;
        }
 
        .leaflet-popup-content textarea,
        .comment-input { /* Assuming comment-input is also used elsewhere for consistency */
            width: calc(100% - 12px); /* Adjust for padding within text area */
            height: 90px; /* Slightly less height */
            font-size: 0.9rem;
            padding: 6px;
            box-sizing: border-box;
            border-radius: 6px; /* Slightly more rounded */
            border: 1px solid #bdbdbd; /* Softer border */
            resize: vertical;
            transition: border-color 0.2s ease;
        }
        .leaflet-popup-content textarea:focus,
        .comment-input:focus {
            border-color: #4CAF50; /* Green highlight on focus */
            outline: none;
        }
 
        .leaflet-popup-content button {
            margin-top: 15px; /* More space above button */
            width: 100%;
            padding: 12px; /* Larger click area */
            font-size: 1.05rem; /* Slightly larger text */
            background-color: #4CAF50; /* Vibrant green */
            color: white;
            border: none;
            cursor: pointer;
            border-radius: 6px; /* Slightly more rounded */
            transition: background-color 0.2s ease, transform 0.1s ease;
        }
 
        .leaflet-popup-content button:hover {
            background-color: #45a049; /* Darker green on hover */
            transform: translateY(-1px); /* Slight lift effect */
        }

        .leaflet-popup-tip {
            background: #ffffff; /* Match popup background */
            box-shadow: 0 3px 14px rgba(0,0,0,0.15); /* Match popup shadow */
        }
    </style>
</head>
<body>
    <div id="container">
        <div id="sidebar">
            <h2>いきいきMAP 活動履歴</h2>
            <div id="comments-list"></div>
        </div>
        <div id="map"></div>
    </div>
    
    <script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>
    
    <script>
        // 地図の初期化
        const map = L.map('map').setView([38.9122, 139.8360], 13);
 
        // 国土地理院の地図タイルレイヤーを追加
        L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png', {
            attribution: '<a href="https://maps.gsi.go.jp/development/ichiran.html">国土地理院</a>',
            maxZoom: 18,
            minZoom: 5
        }).addTo(map);
 
        window.addEventListener('load', () => {
            loadSavedComments();
            setTimeout(() => {
                map.invalidateSize(); // マップのリサイズを強制
            }, 100); // 遅延で確実に実行
        });
 
        // ページ読み込み時に保存されたコメントを表示
        window.addEventListener('load', loadSavedComments);
 
        // マーカーを管理する配列
        let markers = [];
 
        // 地図をクリックしてマーカーと情報ウィンドウを追加
        map.on('click', (e) => {
            const { lat, lng } = e.latlng;
            addMarker(lat, lng);
        });
 
        // マーカーとコメント入力ウィンドウを追加
        function addMarker(lat, lng) {
            const marker = L.marker([lat, lng]).addTo(map);
            const popupContent = `
                <div class="info-window">
                    <p>活動日記を入力してください:</p>
                    <textarea id="comment" rows="3" style="width:100%;"></textarea>
                    <button onclick="saveComment('${lat}', '${lng}')">保存</button>
                </div>
            `;
            marker.bindPopup(popupContent).openPopup();
        }
 
        // コメントを保存し、右側の履歴に追加
        function saveComment(lat, lng) {
            const comment = document.getElementById("comment").value;
            const timestamp = new Date().toLocaleString();
 
            if (!comment.trim()) {
                alert("コメントを入力してください。");
                return;
            }
 
            const entry = { lat, lng, comment, timestamp };
            addCommentToHistory(entry); // 履歴に表示
            saveToLocalStorage(entry);  // ローカルストレージに保存
            const marker = L.marker([lat, lng]).addTo(map); // マーカーを追加
            markers.push(marker); // マーカーを配列に保存
            marker.bindPopup(`
                <div class="info-window">
                    <p><strong>日時:</strong> ${timestamp}</p>
                    <p><strong>コメント:</strong> ${comment}</p>
                </div>
            `);
        }
 
        // ローカルストレージにコメントを保存
        function saveToLocalStorage(entry) {
            let comments = JSON.parse(localStorage.getItem('comments')) || [];
            comments.push(entry);
            localStorage.setItem('comments', JSON.stringify(comments));
        }
 
        // 保存されたコメントをロードして表示
        function loadSavedComments() {
            const comments = JSON.parse(localStorage.getItem('comments')) || [];
            comments.forEach((entry, index) => {
                addCommentToHistory(entry, index);
                const marker = L.marker([entry.lat, entry.lng]).addTo(map);
                markers[index] = marker; // マーカーを管理
                marker.bindPopup(`
                    <div class="info-window">
                        <p><strong>日時:</strong> ${entry.timestamp}</p>
                        <p><strong>コメント:</strong> ${entry.comment}</p>
                    </div>
                `);
            });
        }
 
        // 履歴にコメントを追加(削除・編集ボタン付き)
        function addCommentToHistory({ lat, lng, comment, timestamp }, index) {
            const commentEntry = `
                <div class="history-entry" data-index="${index}">
                    <p><strong>日時:</strong> ${timestamp}</p>
                    <p><strong>場所:</strong> 緯度 ${lat}, 経度 ${lng}</p>
                    <p><strong>活動日記:</strong> 
                        <span class="comment-text" contenteditable="true" onblur="updateComment(${index}, this)">
                            ${comment}
                        </span>
                    </p>
                    <button onclick="deleteComment(${index})">削除</button>
                </div>
            `;
            document.getElementById("comments-list").innerHTML += commentEntry;
        }
 
        // コメントを削除(対応するマーカーも削除)
        function deleteComment(index) {
            let comments = JSON.parse(localStorage.getItem('comments')) || [];
            
            // ローカルストレージのデータを削除
            comments.splice(index, 1); // 指定されたコメントを削除
            localStorage.setItem('comments', JSON.stringify(comments)); // 更新されたコメントリストを保存
 
            // 対応するマーカーを削除
            if (markers[index]) {
                map.removeLayer(markers[index]); // 地図から削除
            }
 
            // マーカー配列を更新
            markers.splice(index, 1); // 配列から削除
 
            // コメント履歴をリロード
            reloadComments();
        }
 
        // コメントを直接編集し保存する(直接編集時に保存)
        function updateComment(index, element) {
            let comments = JSON.parse(localStorage.getItem('comments')) || [];
            const newComment = element.textContent.trim(); // 編集後の内容を取得(空白を除去)
 
            if (!newComment) {
                alert("コメントは空白にできません。元の内容に戻します。");
                element.textContent = comments[index].comment; // 元のコメントに戻す
                return;
            }
 
            // コメントを更新して保存
            comments[index].comment = newComment;
            localStorage.setItem('comments', JSON.stringify(comments)); // ローカルストレージを更新
            reloadComments(); // コメント履歴をリロード
        }
 
        // コメント履歴をリロード
        function reloadComments() {
            document.getElementById("comments-list").innerHTML = ""; // 履歴をクリア
            markers.forEach(marker => map.removeLayer(marker)); // 地図上の全マーカーを削除
            markers = []; // マーカー配列をリセット
            loadSavedComments(); // 保存されたコメントを再ロード
        }
    </script>
</body>
</html>