/** * Utility for debugging SVG rendering issues */ /** * Adds a visible debug overlay to the SVG to test z-index rendering * @param {SVGElement} svgElement - The SVG DOM element */ export function addDebugOverlay(svgElement) { if (!svgElement) return; const svgNS = "http://www.w3.org/2000/svg"; // Create a debug group at the highest level const debugGroup = document.createElementNS(svgNS, "g"); debugGroup.setAttribute("id", "debug-overlay"); debugGroup.setAttribute( "style", "pointer-events: none; z-index: 10000; position: relative;" ); // Add a semi-transparent rectangle across the entire SVG const svgWidth = svgElement.viewBox?.baseVal?.width || 1000; const svgHeight = svgElement.viewBox?.baseVal?.height || 1000; const rect = document.createElementNS(svgNS, "rect"); rect.setAttribute("x", "0"); rect.setAttribute("y", "0"); rect.setAttribute("width", svgWidth.toString()); rect.setAttribute("height", svgHeight.toString()); rect.setAttribute("fill", "rgba(255, 255, 0, 0.1)"); rect.setAttribute("stroke", "none"); // Add some test circles at fixed positions const testPositions = [ { x: 50, y: 50, color: "red" }, { x: 150, y: 150, color: "blue" }, { x: 250, y: 250, color: "green" }, { x: 350, y: 350, color: "purple" }, ]; testPositions.forEach((pos, i) => { const testCircle = document.createElementNS(svgNS, "circle"); testCircle.setAttribute("cx", pos.x.toString()); testCircle.setAttribute("cy", pos.y.toString()); testCircle.setAttribute("r", "20"); testCircle.setAttribute("fill", pos.color); testCircle.setAttribute("fill-opacity", "0.5"); testCircle.setAttribute("stroke", "black"); testCircle.setAttribute("stroke-width", "2"); testCircle.setAttribute("class", "debug-circle"); debugGroup.appendChild(testCircle); }); // Add the debug group to the SVG svgElement.appendChild(debugGroup); console.log("Debug overlay added to SVG"); } /** * Checks if clue points are visible and fixes rendering issues * @param {SVGElement} svgElement - The SVG DOM element */ export function fixCluePointsRendering(svgElement) { if (!svgElement) return; // Find the clue points overlay group let overlayGroup = svgElement.querySelector(".clue-points-overlay"); // If no overlay group exists, create one if (!overlayGroup) { console.log("No clue points overlay found, creating one"); overlayGroup = document.createElementNS("http://www.w3.org/2000/svg", "g"); overlayGroup.setAttribute("class", "clue-points-overlay"); overlayGroup.setAttribute( "style", "pointer-events: all !important; z-index: 9999 !important; position: relative !important;" ); svgElement.appendChild(overlayGroup); } // Find all clue points const cluePoints = svgElement.querySelectorAll(".clue-point"); const clickAreas = svgElement.querySelectorAll(".clue-click-area"); console.log( `Found ${cluePoints.length} clue points and ${clickAreas.length} click areas` ); // Ensure all clue points are in the overlay group and have proper styles cluePoints.forEach((point, i) => { // Get original coordinates if available const originalCx = point.getAttribute("data-original-cx") || point.getAttribute("cx"); const originalCy = point.getAttribute("data-original-cy") || point.getAttribute("cy"); // Clone the point to remove any existing event handlers and styling issues const newPoint = point.cloneNode(true); // Restore original coordinates if they were saved if (originalCx) newPoint.setAttribute("cx", originalCx); if (originalCy) newPoint.setAttribute("cy", originalCy); // Store original coordinates for future reference if (originalCx) newPoint.setAttribute("data-original-cx", originalCx); if (originalCy) newPoint.setAttribute("data-original-cy", originalCy); // Apply explicit styles to ensure visibility newPoint.setAttribute( "style", "fill: #ff9800; stroke: #e65100; stroke-width: 3px; " + "pointer-events: all !important; cursor: pointer !important; " + "z-index: 9999 !important; position: relative !important; " + "r: 14px; fill-opacity: 1; stroke-opacity: 1; " + "filter: drop-shadow(0px 0px 5px rgba(0, 0, 0, 0.7));" ); // Move to overlay group if (point.parentNode !== overlayGroup) { // Remove from current location if (point.parentNode) { point.parentNode.removeChild(point); } // Add to overlay group overlayGroup.appendChild(newPoint); } // Update the corresponding click area position too if (clickAreas[i]) { clickAreas[i].setAttribute("cx", originalCx || point.getAttribute("cx")); clickAreas[i].setAttribute("cy", originalCy || point.getAttribute("cy")); } }); // Move the overlay group to be the last child of the SVG svgElement.appendChild(overlayGroup); console.log("Clue points rendering fixed"); } // New function to ensure clue circles match original map export function fixCluePositionsFromOriginalMap(svgElement) { if (!svgElement) return; // Fetch the original map SVG to get circle positions fetch("/images/map.svg") .then((response) => response.text()) .then((svgText) => { const parser = new DOMParser(); const mapDoc = parser.parseFromString(svgText, "image/svg+xml"); // Get all circles from original map const originalCircles = Array.from(mapDoc.querySelectorAll("circle")); console.log( `Found ${originalCircles.length} circles in original map for position fixing` ); // Get current clue points const cluePoints = svgElement.querySelectorAll(".clue-point"); console.log(`Found ${cluePoints.length} clue points to fix positions`); // Only adjust positions if we have both original circles and clue points if (originalCircles.length > 0 && cluePoints.length > 0) { // Get the clue overlay group let overlayGroup = svgElement.querySelector(".clue-points-overlay"); if (!overlayGroup) return; // Update each clue point to match original circle position cluePoints.forEach((point, i) => { if (i < originalCircles.length) { const originalCircle = originalCircles[i]; const cx = originalCircle.getAttribute("cx") || "0"; const cy = originalCircle.getAttribute("cy") || "0"; // Update position point.setAttribute("cx", cx); point.setAttribute("cy", cy); point.setAttribute("data-original-cx", cx); point.setAttribute("data-original-cy", cy); // Update the corresponding click area const clickArea = svgElement.querySelector( `.clue-click-area[data-index="${i}"]` ); if (clickArea) { clickArea.setAttribute("cx", cx); clickArea.setAttribute("cy", cy); } } }); console.log("Clue positions fixed to match original map"); } }) .catch((error) => { console.error("Error fixing clue positions from original map:", error); }); }