mirror of
https://github.com/mudabbir-ahmad/peworkshop.git
synced 2026-10-07 19:50:20 +00:00
FIXED CLUES! all that needs to be done is manually adding circle buttons and hiding/showing feature through API.. maybe fixing QR scanner
This commit is contained in:
1 parent
2236dceac9
commit
726121e105
18 files changed
+1504
-1192
No files matched your search
@@ -91,9 +91,23 @@ export function fixCluePointsRendering(svgElement) {
|
||||
|
||||
// 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",
|
||||
@@ -114,6 +128,12 @@ export function fixCluePointsRendering(svgElement) {
|
||||
// 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
|
||||
@@ -121,3 +141,63 @@ export function fixCluePointsRendering(svgElement) {
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
+128
-53
@@ -124,47 +124,39 @@ export async function populateMap(svgElement) {
|
||||
console.log(`Found ${allCircles.length} circles in SVG`);
|
||||
|
||||
if (allCircles.length === 0) {
|
||||
console.error("No circles found in SVG. Creating fallback circles.");
|
||||
|
||||
// Create some fallback circles at predefined positions
|
||||
const defs = document.createElementNS(
|
||||
"http://www.w3.org/2000/svg",
|
||||
"defs"
|
||||
console.error(
|
||||
"No circles found in SVG. Attempting to load from original map."
|
||||
);
|
||||
const positions = [
|
||||
{ x: 100, y: 100 },
|
||||
{ x: 200, y: 150 },
|
||||
{ x: 300, y: 200 },
|
||||
{ x: 400, y: 300 },
|
||||
{ x: 500, y: 400 },
|
||||
{ x: 600, y: 500 },
|
||||
];
|
||||
|
||||
positions.forEach((pos, i) => {
|
||||
const circle = document.createElementNS(
|
||||
"http://www.w3.org/2000/svg",
|
||||
"circle"
|
||||
);
|
||||
circle.setAttribute("cx", pos.x.toString());
|
||||
circle.setAttribute("cy", pos.y.toString());
|
||||
circle.setAttribute("r", "5");
|
||||
circle.setAttribute("fill", "transparent");
|
||||
defs.appendChild(circle);
|
||||
});
|
||||
// If no circles in current SVG, try to fetch circles from the original map SVG
|
||||
try {
|
||||
const mapResponse = await fetch("/images/map.svg");
|
||||
if (!mapResponse.ok) {
|
||||
throw new Error("Failed to load original map SVG");
|
||||
}
|
||||
|
||||
// Add the defs to the SVG
|
||||
svgElement.appendChild(defs);
|
||||
const mapText = await mapResponse.text();
|
||||
const parser = new DOMParser();
|
||||
const mapDoc = parser.parseFromString(mapText, "image/svg+xml");
|
||||
|
||||
// Now find all circles again
|
||||
const fallbackCircles = Array.from(defs.querySelectorAll("circle"));
|
||||
if (fallbackCircles.length > 0) {
|
||||
console.log(`Created ${fallbackCircles.length} fallback circles`);
|
||||
return await processCircles(svgElement, fallbackCircles);
|
||||
} else {
|
||||
return false;
|
||||
// Find circles in the original map
|
||||
const originalCircles = Array.from(mapDoc.querySelectorAll("circle"));
|
||||
console.log(`Found ${originalCircles.length} circles in original map`);
|
||||
|
||||
if (originalCircles.length > 0) {
|
||||
return await processCircles(svgElement, originalCircles, true);
|
||||
} else {
|
||||
console.error(
|
||||
"No circles found in original map either. Using fallback positions."
|
||||
);
|
||||
return await createFallbackCircles(svgElement);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to load circles from original map:", error);
|
||||
return await createFallbackCircles(svgElement);
|
||||
}
|
||||
} else {
|
||||
return await processCircles(svgElement, allCircles);
|
||||
return await processCircles(svgElement, allCircles, false);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error populating map:", error);
|
||||
@@ -172,16 +164,60 @@ export async function populateMap(svgElement) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create fallback circles at preset positions as a last resort
|
||||
* @param {SVGElement} svgElement - The SVG DOM element
|
||||
* @returns {Promise<boolean>} - Success flag
|
||||
*/
|
||||
async function createFallbackCircles(svgElement) {
|
||||
// Create some fallback circles at predefined positions
|
||||
const svgNamespace = "http://www.w3.org/2000/svg";
|
||||
const defs = document.createElementNS(svgNamespace, "defs");
|
||||
const positions = [
|
||||
{ x: 100, y: 100 },
|
||||
{ x: 200, y: 200 },
|
||||
{ x: 300, y: 300 },
|
||||
{ x: 400, y: 200 },
|
||||
{ x: 500, y: 100 },
|
||||
{ x: 600, y: 300 },
|
||||
];
|
||||
|
||||
positions.forEach((pos, i) => {
|
||||
const circle = document.createElementNS(svgNamespace, "circle");
|
||||
circle.setAttribute("cx", pos.x.toString());
|
||||
circle.setAttribute("cy", pos.y.toString());
|
||||
circle.setAttribute("r", "5");
|
||||
circle.setAttribute("fill", "transparent");
|
||||
defs.appendChild(circle);
|
||||
});
|
||||
|
||||
// Add the defs to the SVG
|
||||
svgElement.appendChild(defs);
|
||||
|
||||
// Now find all circles again
|
||||
const fallbackCircles = Array.from(defs.querySelectorAll("circle"));
|
||||
if (fallbackCircles.length > 0) {
|
||||
console.log(`Created ${fallbackCircles.length} fallback circles`);
|
||||
return await processCircles(svgElement, fallbackCircles, false);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process circles to create clue points
|
||||
* @param {SVGElement} svgElement - The SVG DOM element
|
||||
* @param {Array} circles - Array of circle elements
|
||||
* @param {boolean} isFromOriginalMap - Whether circles are from the original map
|
||||
* @returns {Promise<boolean>} - Success flag
|
||||
*/
|
||||
async function processCircles(svgElement, circles) {
|
||||
async function processCircles(svgElement, circles, isFromOriginalMap) {
|
||||
try {
|
||||
// Hide original circles
|
||||
circles.forEach((circle) => (circle.style.display = "none"));
|
||||
// Don't hide original circles if they are from the original map and not present in current SVG
|
||||
if (!isFromOriginalMap) {
|
||||
// Remove hiding originals so the new elements are clearly visible
|
||||
// circles.forEach((circle) => (circle.style.display = "none"));
|
||||
}
|
||||
|
||||
// Fetch the number of clues from the API
|
||||
const response = await fetch("/api/clues/count", {
|
||||
@@ -198,7 +234,7 @@ async function processCircles(svgElement, circles) {
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const clueCount = parseInt(data.count, 10) || 0;
|
||||
let clueCount = parseInt(data.count, 10) || 0;
|
||||
console.log(`API returned clue count: ${clueCount}`);
|
||||
|
||||
if (clueCount <= 0) {
|
||||
@@ -206,21 +242,17 @@ async function processCircles(svgElement, circles) {
|
||||
clueCount = 5; // Fallback to 5 clues if API returns invalid data
|
||||
}
|
||||
|
||||
// Sort circles by vertical position (top to bottom)
|
||||
const sortedCircles = circles.sort((a, b) => {
|
||||
const aY = parseFloat(a.getAttribute("cy") || "0");
|
||||
const bY = parseFloat(b.getAttribute("cy") || "0");
|
||||
return aY - bY;
|
||||
});
|
||||
|
||||
// Determine how many circles to show
|
||||
const circlesToShow = Math.min(sortedCircles.length, clueCount);
|
||||
console.log(`Will create ${circlesToShow} clue points from sorted circles`);
|
||||
// Use the circles exactly where they are - preserve original positions
|
||||
// Just limit how many we use based on clue count
|
||||
const circlesToShow = Math.min(circles.length, clueCount);
|
||||
console.log(
|
||||
`Will create ${circlesToShow} clue points from available circles`
|
||||
);
|
||||
|
||||
// Create the overlay element that will go on top of everything
|
||||
const svgNamespace = "http://www.w3.org/2000/svg";
|
||||
|
||||
// Remove any old overlay group
|
||||
// Remove any old overlay group (but leave persistent button layer intact)
|
||||
const oldOverlay = svgElement.querySelector(".clue-points-overlay");
|
||||
if (oldOverlay && oldOverlay.parentNode) {
|
||||
oldOverlay.parentNode.removeChild(oldOverlay);
|
||||
@@ -238,9 +270,9 @@ async function processCircles(svgElement, circles) {
|
||||
// Add the overlay group as the LAST element in the SVG to ensure proper rendering order
|
||||
svgElement.appendChild(overlayGroup);
|
||||
|
||||
// Create interactive clue points
|
||||
// Create interactive clue points based on the original circle positions
|
||||
for (let i = 0; i < circlesToShow; i++) {
|
||||
const originalCircle = sortedCircles[i];
|
||||
const originalCircle = circles[i];
|
||||
|
||||
// Get original circle attributes
|
||||
const cx = originalCircle.getAttribute("cx") || "0";
|
||||
@@ -299,7 +331,50 @@ async function processCircles(svgElement, circles) {
|
||||
// This ensures it's the last child of the SVG
|
||||
svgElement.appendChild(overlayGroup);
|
||||
|
||||
console.log(`Successfully created ${circlesToShow} clue points`);
|
||||
// Instead of appending button layer with absolute positioning,
|
||||
// create/update it as a child of overlayGroup using normal SVG positioning.
|
||||
let buttonGroup = svgElement.querySelector(".clue-button-layer");
|
||||
if (buttonGroup) {
|
||||
buttonGroup.innerHTML = "";
|
||||
} else {
|
||||
buttonGroup = document.createElementNS(svgNamespace, "g");
|
||||
buttonGroup.setAttribute("class", "clue-button-layer");
|
||||
// Remove absolute positioning; allow buttonGroup to inherit the overlay's coordinate system.
|
||||
buttonGroup.setAttribute(
|
||||
"style",
|
||||
"pointer-events: auto; z-index: 10000;"
|
||||
);
|
||||
}
|
||||
for (let i = 0; i < circlesToShow; i++) {
|
||||
const originalCircle = circles[i];
|
||||
const cx = originalCircle.getAttribute("cx") || "0";
|
||||
const cy = originalCircle.getAttribute("cy") || "0";
|
||||
const r = Math.max(
|
||||
parseFloat(originalCircle.getAttribute("r") || "5"),
|
||||
14
|
||||
);
|
||||
|
||||
const button = document.createElementNS(svgNamespace, "circle");
|
||||
button.setAttribute("cx", cx);
|
||||
button.setAttribute("cy", cy);
|
||||
button.setAttribute("r", r.toString());
|
||||
button.setAttribute("class", "clue-button");
|
||||
button.setAttribute(
|
||||
"style",
|
||||
"fill: #4caf50; stroke: #388e3c; stroke-width: 2px; cursor: pointer; opacity: 0.9; pointer-events: auto;"
|
||||
);
|
||||
button.addEventListener("click", () => {
|
||||
console.log(`Button for clue ${i + 1} clicked`);
|
||||
// ...add navigation or other logic here...
|
||||
});
|
||||
buttonGroup.appendChild(button);
|
||||
}
|
||||
// Append or re-append the buttonGroup into the overlayGroup so they appear together.
|
||||
overlayGroup.appendChild(buttonGroup);
|
||||
|
||||
console.log(
|
||||
`Successfully created ${circlesToShow} clue points and buttons`
|
||||
);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Error processing circles:", error);
|
||||
|
||||
Reference in new issue
Block a user