1// EtherverseSVGMap class modified to use a list instead of an SVG map 2class EtherverseSVGMap { 3 constructor(containerId) { 4 this.container = document.getElementById(containerId); 5 this.currentView = 'overview'; 6 7 // Use the shared locations data 8 this.loadLocationsData(); 9 10 this.initMap(); 11 12 // Important: Comment out the internal interactions to avoid conflicts 13 // this.initInteractions(); 14 } 15 16 // Load the shared locations data and transform it for this class 17 loadLocationsData() { 18 // Transform the shared data to the format needed for the SVG map 19 this.locations = ETHERVERSE_LOCATIONS.locations.map(location => { 20 const mappedLocation = { 21 id: location.id, 22 name: location.name, 23 type: location.type, 24 description: location.description 25 }; 26 27 // Include landmarks if available 28 if (location.landmarks) { 29 mappedLocation.landmarks = location.landmarks.map(landmark => ({ 30 id: landmark.id, 31 name: landmark.name, 32 description: landmark.description 33 })); 34 } 35 36 return mappedLocation; 37 }); 38 39 // Use the shared color mappings 40 this.locationColors = ETHERVERSE_LOCATIONS.colors; 41 } 42 43 initMap() { 44 // Get the parent container of the svg element 45 const parentContainer = document.querySelector('.map-container'); 46 if (!parentContainer) { 47 console.error("Map container not found"); 48 return; 49 } 50 51 // Remove the SVG element completely 52 const svgElement = document.getElementById('svg-map'); 53 if (svgElement) { 54 svgElement.remove(); 55 } 56 57 // Create a div element to hold our list content 58 const listContainer = document.createElement('div'); 59 listContainer.id = 'location-list-container'; 60 listContainer.style.width = '100%'; 61 listContainer.style.height = '100%'; 62 63 // Add the list container to the parent 64 parentContainer.appendChild(listContainer); 65 66 // Set the container reference for our content 67 this.container = listContainer; 68 69 // Create our list content 70 if (this.currentView === 'overview') { 71 this.createLocationsList(); 72 } else if (this.currentView === 'detail') { 73 this.createLandmarksList(); 74 } 75 } 76 77 createLocationsList() { 78 // Create categories for organization 79 const categories = { 80 city: { title: 'Cities', items: [] }, 81 outskirts: { title: 'Outskirts', items: [] } 82 }; 83 84 // Organize locations by type 85 this.locations.forEach(location => { 86 if (categories[location.type]) { 87 categories[location.type].items.push(location); 88 } 89 }); 90 91 // First, clear the container 92 while (this.container.firstChild) { 93 this.container.removeChild(this.container.firstChild); 94 } 95 96 // Create the container for the list 97 const listContainer = document.createElement('div'); 98 listContainer.className = 'location-list'; 99 100 // Create each category section 101 Object.entries(categories).forEach(([type, category]) => { 102 if (category.items.length === 0) return; 103 104 const categorySection = document.createElement('div'); 105 categorySection.className = 'location-category'; 106 107 // Add section heading 108 const heading = document.createElement('h4'); 109 heading.textContent = category.title; 110 categorySection.appendChild(heading); 111 112 // Create items list 113 const itemsList = document.createElement('ul'); 114 115 // Add each location to the list
116 category.items.forEach(location => { 117 const listItem = document.createElement('li'); 118 listItem.className = 'location-item'; 119 listItem.setAttribute('id', location.id); 120 listItem.setAttribute('data-name', location.name); 121 listItem.setAttribute('data-type', location.type); 122 listItem.setAttribute('data-description', location.description); 123 124 // Create color dot indicator 125 const colorDot = document.createElement('div'); 126 colorDot.className = 'location-dot'; 127 colorDot.style.backgroundColor = this.locationColors[location.id] || '#8a2be2'; 128 129 // Create location name 130 const locationName = document.createElement('div'); 131 locationName.className = 'location-name'; 132 locationName.textContent = location.name; 133 134 // Assemble the list item 135 listItem.appendChild(colorDot); 136 listItem.appendChild(locationName); 137 itemsList.appendChild(listItem); 138 }); 139 140 categorySection.appendChild(itemsList); 141 listContainer.appendChild(categorySection); 142 }); 143 144 this.container.appendChild(listContainer); 145 146 // Signal that the location list has been created 147 if (window.locationListCreated) { 148 window.locationListCreated(); 149 } 150 } 151 152 createLandmarksList() { 153 // We're in detail view, focusing on BUIDL City 154 const buidlCity = this.locations.find(loc => loc.id === 'buidl-city'); 155 if (!buidlCity) { 156 console.error("Could not find BUIDL City data"); 157 return; 158 } 159 160 // First, clear the container 161 while (this.container.firstChild) { 162 this.container.removeChild(this.container.firstChild); 163 } 164 165 // Create the container 166 const listContainer = document.createElement('div'); 167 listContainer.className = 'location-list'; 168 169 // Add a back button 170 const backLink = document.createElement('div'); 171 backLink.className = 'back-link'; 172 173 const backButton = document.createElement('a'); 174 backButton.href = '#'; 175 backButton.id = 'back-to-overview'; 176 backButton.innerHTML = '« Back'; 177 178 backLink.appendChild(backButton); 179 listContainer.appendChild(backLink); 180 181 // Create main location section 182 const locationSection = document.createElement('div'); 183 locationSection.className = 'location-category selected-location'; 184 185 const locationHeading = document.createElement('h4'); 186 locationHeading.textContent = buidlCity.name; 187 locationSection.appendChild(locationHeading); 188 189 const locationDescription = document.createElement('p'); 190 locationDescription.className = 'location-description'; 191 locationDescription.textContent = buidlCity.description; 192 locationSection.appendChild(locationDescription); 193 194 listContainer.appendChild(locationSection); 195 196 // Create landmarks section 197 const landmarksSection = document.createElement('div'); 198 landmarksSection.className = 'location-category landmarks-category'; 199 200 const landmarksHeading = document.createElement('h4'); 201 landmarksHeading.textContent = 'Districts'; 202 landmarksSection.appendChild(landmarksHeading); 203 204 // Create items list 205 const itemsList = document.createElement('ul'); 206 207 // Add each landmark to the list 208 buidlCity.landmarks.forEach(landmark => { 209 const listItem = document.createElement('li'); 210 listItem.className = 'location-item'; 211 listItem.setAttribute('id', landmark.id); 212 listItem.setAttribute('data-name', landmark.name); 213 listItem.setAttribute('data-type', 'landmark'); 214 listItem.setAttribute('data-description', landmark.description); 215 216 // Create color dot indicator 217 const colorDot = document.createElement('div'); 218 colorDot.className = 'location-dot'; 219 colorDot.style.backgroundColor = this.locationColors[landmark.id] || '#8a2be2'; 220 221 // Create location name 222 const locationName = document.createElement('div'); 223 locationName.className = 'location-name'; 224 locationName.textContent = landmark.name; 225 226 // Assemble the list item 227 listItem.appendChild(colorDot); 228 listItem.appendChild(locationName); 229 itemsList.appendChild(listItem); 230 }); 231 232 landmarksSection.appendChild(itemsList); 233 listContainer.appendChild(landmarksSection); 234 235 // Add the list to the container 236 this.container.appendChild(listContainer); 237 238 // Signal that the landmarks list has been created 239 if (window.landmarksListCreated) { 240 window.landmarksListCreated(); 241 } 242 } 243 244 // Keep this method but we won't use it directly 245 initInteractions() { 246 // Event delegation - listen for clicks at container level 247 this.container.addEventListener('click', event => { 248 let target = event.target; 249 250 // If clicked on a child element, traverse up to find the location-item 251 while (target !== this.container) { 252 // Check for back button 253 if (target.id === 'back-to-overview') { 254 event.preventDefault(); 255 this.transitionToOverview(); 256 return; 257 } 258 259 // Check for location item 260 if (target.classList && target.classList.contains('location-item')) { 261 const locationId = target.id; 262 const locationName = target.getAttribute('data-name'); 263 const locationType = target.getAttribute('data-type'); 264 const locationDesc = target.getAttribute('data-description'); 265 266 // Update info panel 267 this.updateInfoPanel(locationName, locationDesc, locationType); 268 269 // Highlight the selected item 270 this.highlightLocationItem(target); 271 272 // If BUIDL City is clicked and we're in overview, transition to detail 273 if (locationId === 'buidl-city' && this.currentView === 'overview') {
274 this.transitionToDetailView(); 275 } 276 return; 277 } 278 279 // Move up the DOM tree 280 if (!target.parentElement || target.parentElement === this.container) { 281 break; 282 } 283 target = target.parentElement; 284 } 285 }); 286 } 287 288 highlightLocationItem(element) { 289 if (!element) return; 290 291 // Remove previous highlights 292 const highlightedItems = document.querySelectorAll('.location-item.selected'); 293 highlightedItems.forEach(item => item.classList.remove('selected')); 294 295 // Add highlight to the clicked item 296 element.classList.add('selected'); 297 } 298 299 updateInfoPanel(title, description, type) { 300 // Get the info panel 301 const infoPanel = document.querySelector('.info-panel'); 302 if (!infoPanel) return; 303 304 // Update content 305 infoPanel.innerHTML = ` 306 <h2>${title}</h2> 307 <p>${description}</p> 308 <p>Region: ${type === 'city' ? 'BUIDL City' : type === 'landmark' ? 'BUIDL City - District' : 'The Outskirts'}</p> 309 `; 310 } 311 312 transitionToDetailView() { 313 this.currentView = 'detail'; 314 315 // Directly call createLandmarksList to show detailed view 316 this.createLandmarksList(); 317 318 // Update info panel 319 const buidlCity = this.locations.find(loc => loc.id === 'buidl-city'); 320 if (buidlCity) { 321 this.updateInfoPanel( 322 buidlCity.name, 323 buidlCity.description + '<br><small>Explore the districts by clicking on them.</small>', 324 'city' 325 ); 326 } 327 } 328 329 transitionToOverview() { 330 this.currentView = 'overview'; 331 332 // Recreate the list with main locations 333 this.createLocationsList(); 334 335 // Reset info panel 336 this.updateInfoPanel( 337 'The Etherverse', 338 'Welcome to the digital realm where reality and imagination converge. Explore the vast landscapes and discover the wonders of this virtual world.', 339 'overview' 340 ); 341 342 // Trigger reset view in 3D map via a global function 343 if (window.resetMapView) { 344 window.resetMapView(); 345 } else { 346 // Fallback to clicking the button 347 const resetButton = document.getElementById('reset-view'); 348 if (resetButton) { 349 resetButton.click(); 350 } 351 } 352 } 353 354 getCurrentView() { 355 return this.currentView; 356 } 357}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.