// 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 = `