// Helper function to create location shape based on type function createLocationShape(locationId, loc) { const coords = loc.coordinates; const centerLatLng = [coords.x, coords.z]; // 7D2D coordinates (x, z) const dims = loc.dimensions || {}; const shape = loc.shape || 'circle'; const isEnabled = loc.is_enabled; const is3D = (shape === 'box' || shape === 'spherical'); // Color scheme const fillColor = isEnabled ? '#ff9900' : '#666666'; const strokeColor = isEnabled ? '#ffcc00' : '#999999'; const fillOpacity = isEnabled ? 0.3 : 0.15; let leafletShape; if (shape === 'circle') { const radius = parseFloat(dims.radius || 10); leafletShape = L.circle(centerLatLng, { radius: radius, fillColor: fillColor, color: strokeColor, weight: 2, opacity: 0.8, fillOpacity: fillOpacity }); } else if (shape === 'spherical') { const radius = parseFloat(dims.radius || 10); leafletShape = L.circle(centerLatLng, { radius: radius, fillColor: fillColor, color: strokeColor, weight: 2, opacity: 0.8, fillOpacity: fillOpacity, dashArray: '5, 5' // Dashed to indicate 3D }); } else if (shape === 'rectangular') { const width = parseFloat(dims.width || 10); const length = parseFloat(dims.length || 10); // Rectangle bounds: from center, extend width/length in both directions const bounds = [ [coords.x - width, coords.z - length], [coords.x + width, coords.z + length] ]; leafletShape = L.rectangle(bounds, { fillColor: fillColor, color: strokeColor, weight: 2, opacity: 0.8, fillOpacity: fillOpacity }); } else if (shape === 'box') { const width = parseFloat(dims.width || 10); const length = parseFloat(dims.length || 10); const bounds = [ [coords.x - width, coords.z - length], [coords.x + width, coords.z + length] ]; leafletShape = L.rectangle(bounds, { fillColor: fillColor, color: strokeColor, weight: 2, opacity: 0.8, fillOpacity: fillOpacity, dashArray: '5, 5' // Dashed to indicate 3D }); } else { // Fallback to circle leafletShape = L.circle(centerLatLng, { radius: 10, fillColor: fillColor, color: strokeColor, weight: 2, opacity: 0.8, fillOpacity: fillOpacity }); } // Build popup content const dimensionText = shape === 'circle' || shape === 'spherical' ? `Radius: ${dims.radius || 'N/A'}` : `Width: ${dims.width || 'N/A'}, Length: ${dims.length || 'N/A'}${shape === 'box' ? ', Height: ' + (dims.height || 'N/A') : ''}`; // Parse locationId to extract components // Format: {dataset}_{owner}_{identifier} const locationIdParts = locationId.split('_'); const dataset = locationIdParts.slice(0, -2).join('_'); // Handle datasets with underscores const owner = locationIdParts[locationIdParts.length - 2]; const identifier = locationIdParts[locationIdParts.length - 1]; const teleportEntry = loc.teleport_entry || {}; const hasTeleport = teleportEntry.x !== undefined && teleportEntry.y !== undefined && teleportEntry.z !== undefined; const teleportText = hasTeleport ? `TP: ${parseFloat(teleportEntry.x || 0).toFixed(0)}, ${parseFloat(teleportEntry.y || 0).toFixed(0)}, ${parseFloat(teleportEntry.z || 0).toFixed(0)}` : 'TP: Not set'; // Use template literal for clean HTML const popupContent = `
${loc.name}
${is3D ? '🎲 3D' : '⬜ 2D'} - ${shape}

Type: ${loc.type && loc.type.length > 0 ? loc.type.join(', ') : 'None'}
Owner: ${loc.owner}
Status: ${isEnabled ? '✅ Enabled' : '❌ Disabled'}
Position: ${coords.x.toFixed(0)}, ${coords.y.toFixed(0)}, ${coords.z.toFixed(0)}
Dimensions: ${dimensionText}
${teleportText}

`; leafletShape.bindPopup(popupContent); leafletShape.addTo(map); return leafletShape; } // Location shapes are now loaded dynamically via Socket.IO // Initial loading is handled by location_update events // See location_update_handler.html for shape creation logic