|
68 | 68 | floatingTooltip.style.display = 'none' |
69 | 69 | } |
70 | 70 |
|
| 71 | + // Tile layer styles |
| 72 | + var tileStyles = { |
| 73 | + osm: { |
| 74 | + url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', |
| 75 | + attribution: '© OpenStreetMap contributors', |
| 76 | + label: 'Street' |
| 77 | + }, |
| 78 | + satellite: { |
| 79 | + url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', |
| 80 | + attribution: '© Esri', |
| 81 | + label: 'Satellite' |
| 82 | + }, |
| 83 | + terrain: { |
| 84 | + url: 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', |
| 85 | + attribution: '© OpenTopoMap', |
| 86 | + label: 'Terrain' |
| 87 | + } |
| 88 | + } |
| 89 | + |
| 90 | + // Get saved style from localStorage, or use default from mapData |
| 91 | + var STORAGE_KEY = 'chattomap-style' |
| 92 | + var savedStyle = null |
| 93 | + try { |
| 94 | + savedStyle = localStorage.getItem(STORAGE_KEY) |
| 95 | + } catch (e) { |
| 96 | + // localStorage not available |
| 97 | + } |
| 98 | + var currentStyle = savedStyle && tileStyles[savedStyle] ? savedStyle : (mapData.defaultStyle || 'osm') |
| 99 | + |
71 | 100 | // Initialize map |
72 | 101 | var map = L.map('map').setView([mapData.center.lat, mapData.center.lng], mapData.zoom) |
73 | 102 |
|
74 | | - L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { |
75 | | - attribution: '© OpenStreetMap contributors' |
| 103 | + var currentTileLayer = L.tileLayer(tileStyles[currentStyle].url, { |
| 104 | + attribution: tileStyles[currentStyle].attribution |
76 | 105 | }).addTo(map) |
77 | 106 |
|
| 107 | + // Style toggle control |
| 108 | + function setMapStyle(style) { |
| 109 | + if (!tileStyles[style] || style === currentStyle) return |
| 110 | + map.removeLayer(currentTileLayer) |
| 111 | + currentTileLayer = L.tileLayer(tileStyles[style].url, { |
| 112 | + attribution: tileStyles[style].attribution |
| 113 | + }).addTo(map) |
| 114 | + currentStyle = style |
| 115 | + try { |
| 116 | + localStorage.setItem(STORAGE_KEY, style) |
| 117 | + } catch (e) { |
| 118 | + // localStorage not available |
| 119 | + } |
| 120 | + updateStyleButtons() |
| 121 | + } |
| 122 | + |
| 123 | + function updateStyleButtons() { |
| 124 | + var buttons = document.querySelectorAll('.style-btn') |
| 125 | + buttons.forEach(function (btn) { |
| 126 | + var style = btn.getAttribute('data-style') |
| 127 | + btn.classList.toggle('active', style === currentStyle) |
| 128 | + }) |
| 129 | + } |
| 130 | + |
| 131 | + // Create style toggle control |
| 132 | + var styleControl = document.getElementById('styleControl') |
| 133 | + if (styleControl) { |
| 134 | + var styleHtml = Object.keys(tileStyles) |
| 135 | + .map(function (style) { |
| 136 | + var isActive = style === currentStyle ? ' active' : '' |
| 137 | + return ( |
| 138 | + '<button class="style-btn' + |
| 139 | + isActive + |
| 140 | + '" data-style="' + |
| 141 | + style + |
| 142 | + '">' + |
| 143 | + tileStyles[style].label + |
| 144 | + '</button>' |
| 145 | + ) |
| 146 | + }) |
| 147 | + .join('') |
| 148 | + styleControl.innerHTML = styleHtml |
| 149 | + styleControl.addEventListener('click', function (e) { |
| 150 | + var btn = e.target.closest('.style-btn') |
| 151 | + if (btn) { |
| 152 | + setMapStyle(btn.getAttribute('data-style')) |
| 153 | + } |
| 154 | + }) |
| 155 | + } |
| 156 | + |
78 | 157 | var markersLayer = mapData.clusterMarkers |
79 | 158 | ? L.markerClusterGroup({ |
80 | 159 | maxClusterRadius: 50, |
|
83 | 162 | }) |
84 | 163 | : L.layerGroup() |
85 | 164 |
|
86 | | - // Add markers |
87 | | - mapData.points.forEach(function (p) { |
| 165 | + // Add markers (only for geocoded activities) |
| 166 | + var geocodedPoints = mapData.activities.filter(function (p) { |
| 167 | + return p.lat !== null && p.lng !== null |
| 168 | + }) |
| 169 | + |
| 170 | + geocodedPoints.forEach(function (p) { |
88 | 171 | var messagesEncoded = encodeURIComponent(JSON.stringify(p.messages)).replace(/'/g, '%27') |
89 | 172 | var senderDisplay = formatSenders(p.messages) |
90 | 173 | var mentionCount = p.messages.length |
|
190 | 273 |
|
191 | 274 | // Render info box |
192 | 275 | document.getElementById('infoTitle').textContent = mapData.title |
193 | | - document.getElementById('infoCount').textContent = mapData.points.length |
| 276 | + document.getElementById('infoCount').textContent = mapData.activities.length |
| 277 | + document.getElementById('infoWithLocations').textContent = '(' + geocodedPoints.length + ' with locations)' |
194 | 278 |
|
195 | 279 | // Render legend |
196 | 280 | var legendHtml = Object.entries(mapData.senderColors) |
|
214 | 298 | document.getElementById('legend').innerHTML = legendHtml |
215 | 299 |
|
216 | 300 | // Activity list |
217 | | - var activities = mapData.points.map(function (p) { |
| 301 | + var activities = mapData.activities.map(function (p) { |
218 | 302 | return { |
219 | 303 | id: p.activityId, |
220 | 304 | activity: p.activity, |
| 305 | + category: p.category, |
221 | 306 | sender: p.sender.split(' ')[0], |
222 | 307 | location: p.location, |
223 | 308 | date: p.date, |
|
238 | 323 | '&query_place_id=' + |
239 | 324 | a.placeId |
240 | 325 | : null |
241 | | - var thumb = a.imagePath |
242 | | - ? '<img src="' + a.imagePath + '" class="activity-thumb" alt="" />' |
243 | | - : '<div class="activity-thumb-placeholder"></div>' |
| 326 | + var mentionCount = a.messages.length |
| 327 | + var badge = mentionCount > 1 ? '<span class="mention-badge">' + mentionCount + '</span>' : '' |
| 328 | + |
| 329 | + var thumbContent |
| 330 | + if (mapData.hasImages && a.imagePath) { |
| 331 | + thumbContent = '<img src="' + a.imagePath + '" class="activity-thumb" alt="" />' |
| 332 | + } else { |
| 333 | + var icon = mapData.categoryIcons[a.category] || mapData.categoryIcons.other |
| 334 | + var color = mapData.categoryColors[a.category] || mapData.categoryColors.other |
| 335 | + thumbContent = |
| 336 | + '<div class="activity-thumb-placeholder" style="background-color:' + |
| 337 | + color + |
| 338 | + ';">' + |
| 339 | + icon + |
| 340 | + '</div>' |
| 341 | + } |
| 342 | + var thumb = '<div class="activity-thumb-wrapper">' + thumbContent + badge + '</div>' |
244 | 343 | var links = |
245 | 344 | (mapsUrl ? '<a href="' + mapsUrl + '" target="_blank">Google Maps</a>' : '') + |
246 | 345 | (a.url ? '<a href="' + a.url + '" target="_blank">Source</a>' : '') |
|
0 commit comments