mirror of
https://github.com/mudabbir-ahmad/peworkshop.git
synced 2026-10-07 19:50:20 +00:00
map WIP
This commit is contained in:
1 parent
c5f2c0a98a
commit
25e877cc3a
6 files changed
+490
-154
No files matched your search
@@ -85,6 +85,7 @@
|
||||
height: fit-content; /* Allow natural height */
|
||||
display: block; /* Change to block for proper scrolling */
|
||||
overflow: visible; /* Show content beyond boundaries */
|
||||
z-index: 5; /* Ensure it's above the background */
|
||||
}
|
||||
|
||||
.svg-container svg {
|
||||
@@ -95,7 +96,12 @@
|
||||
object-fit: none; /* Don't constrain the SVG */
|
||||
}
|
||||
|
||||
/* Map background - display as full-page map */
|
||||
/* Remove the default map background when we have the processed SVG */
|
||||
.svg-container + .map-background {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Map background - only shown when SVG is loading */
|
||||
.map-background {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -106,7 +112,7 @@
|
||||
background-size: auto; /* Don't resize the background */
|
||||
background-position: top right; /* Position at top right */
|
||||
background-repeat: no-repeat;
|
||||
z-index: 5;
|
||||
z-index: 3; /* Lower z-index than the processed SVG */
|
||||
}
|
||||
|
||||
/* Circle elements in the SVG map - attach to a container class */
|
||||
@@ -119,6 +125,70 @@
|
||||
fill: #ffb74d !important; /* Only change color on hover, no movement */
|
||||
}
|
||||
|
||||
/* Circle elements in the SVG map - attach to a container class */
|
||||
.svg-container circle.clue-point {
|
||||
cursor: pointer;
|
||||
transition: fill 0.3s ease, stroke-width 0.3s ease;
|
||||
pointer-events: all; /* Ensure clicks are detected */
|
||||
stroke-width: 2px;
|
||||
r: 8; /* Set a minimum radius for all clue points */
|
||||
}
|
||||
|
||||
/* Improve circle visibility and interactivity */
|
||||
.svg-container circle.clue-point {
|
||||
cursor: pointer !important;
|
||||
transition: all 0.3s ease;
|
||||
pointer-events: all !important;
|
||||
stroke-width: 2px;
|
||||
r: 12px; /* Larger radius for better visibility and easier clicks */
|
||||
z-index: 10;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Enhance hover effect */
|
||||
.svg-container circle.clue-point:hover {
|
||||
fill: #ffb74d !important; /* Orange hover color */
|
||||
stroke: #ff6d00 !important;
|
||||
stroke-width: 4px !important;
|
||||
transform: scale(1.2);
|
||||
z-index: 20;
|
||||
filter: drop-shadow(0px 0px 4px rgba(0, 0, 0, 0.5));
|
||||
}
|
||||
|
||||
/* Invisible click areas for easier interaction */
|
||||
.svg-container circle.clue-point-click-area {
|
||||
pointer-events: all !important;
|
||||
cursor: pointer !important;
|
||||
opacity: 0.01; /* Nearly invisible but still interactive */
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
/* Create custom animation for the current clue */
|
||||
@keyframes clue-point-pulse {
|
||||
0% {
|
||||
stroke-width: 3px;
|
||||
transform: scale(1);
|
||||
filter: drop-shadow(0px 0px 2px rgba(255, 152, 0, 0.7));
|
||||
}
|
||||
50% {
|
||||
stroke-width: 5px;
|
||||
transform: scale(1.2);
|
||||
filter: drop-shadow(0px 0px 8px rgba(255, 152, 0, 0.9));
|
||||
}
|
||||
100% {
|
||||
stroke-width: 3px;
|
||||
transform: scale(1);
|
||||
filter: drop-shadow(0px 0px 2px rgba(255, 152, 0, 0.7));
|
||||
}
|
||||
}
|
||||
|
||||
.svg-container circle.clue-point:hover {
|
||||
fill: #ffb74d !important; /* Orange hover color */
|
||||
stroke: #ff6d00;
|
||||
stroke-width: 3px;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
/* Remaining styles unchanged */
|
||||
.map-svg {
|
||||
width: 100% !important; /* Override Next.js Image default width */
|
||||
@@ -133,8 +203,13 @@
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 50;
|
||||
background-color: rgba(105, 181, 168, 0.8);
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
|
||||
+79
-49
@@ -127,6 +127,74 @@ export default function MapPage() {
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Enhanced function to populate the map with clue points
|
||||
const enhanceSvgMap = useCallback(() => {
|
||||
if (!mapContainerRef.current) return;
|
||||
|
||||
// Find the SVG element inside the map container
|
||||
const svgElement = mapContainerRef.current.querySelector("svg");
|
||||
if (!svgElement) {
|
||||
console.error("No SVG element found in map container");
|
||||
setMapError(true);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("SVG element found, starting enhancement process");
|
||||
|
||||
// Clear out any existing map-background elements to ensure we only show one map
|
||||
const existingMapBgs = document.querySelectorAll(
|
||||
`.${styles["map-background"]}`
|
||||
);
|
||||
existingMapBgs.forEach((bg) => (bg.style.display = "none"));
|
||||
|
||||
// First populate the map with basic clue points
|
||||
populateMap(svgElement)
|
||||
.then((success) => {
|
||||
if (success) {
|
||||
console.log("Map populated with clue points successfully");
|
||||
|
||||
// Process the clues to determine which are available
|
||||
const processedClues = clues.map((clue, index, arr) => {
|
||||
// Find the first unfound clue's index
|
||||
const firstUnfoundIndex = arr.findIndex((c) => !c.found);
|
||||
|
||||
// A clue is available if:
|
||||
// 1. It's already found, OR
|
||||
// 2. It's the next unfound clue in the sequence
|
||||
const available = clue.found || index === firstUnfoundIndex;
|
||||
|
||||
return { ...clue, available };
|
||||
});
|
||||
|
||||
// Debug info about clue statuses
|
||||
processedClues.forEach((clue, index) => {
|
||||
console.log(
|
||||
`Clue ${clue.id} (index ${index}): Available: ${clue.available}, Found: ${clue.found}`
|
||||
);
|
||||
});
|
||||
|
||||
// Update the clue point appearances based on their statuses
|
||||
updateCluePointStatus(svgElement, processedClues);
|
||||
|
||||
// Define a direct navigation function that will be used for click handling
|
||||
const navigateToClue = (clueId) => {
|
||||
console.log(`Navigating to clue ${clueId}`);
|
||||
router.push(`/clue/${clueId}`);
|
||||
};
|
||||
|
||||
// Attach click handlers to all clue points and click areas
|
||||
attachClueClickHandlers(svgElement, processedClues, navigateToClue);
|
||||
} else {
|
||||
console.error("Failed to populate map with clue points");
|
||||
setMapError(true);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error enhancing SVG map:", error);
|
||||
setMapError(true);
|
||||
});
|
||||
}, [clues, router, styles]);
|
||||
|
||||
// Function to load and enhance the SVG map
|
||||
const loadAndEnhanceMap = useCallback(async () => {
|
||||
try {
|
||||
@@ -143,7 +211,7 @@ export default function MapPage() {
|
||||
}
|
||||
|
||||
const svgText = await response.text();
|
||||
console.log("SVG loaded, length:", svgText.length);
|
||||
console.log(`SVG loaded, length: ${svgText.length} characters`);
|
||||
|
||||
// Ensure SVG has correct namespaces and viewBox
|
||||
let fixedSvg = svgText.replace(
|
||||
@@ -174,42 +242,6 @@ export default function MapPage() {
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Enhanced function to populate the map with clue points
|
||||
const enhanceSvgMap = useCallback(() => {
|
||||
if (!mapContainerRef.current) return;
|
||||
|
||||
// Find the SVG element inside the map container
|
||||
const svgElement = mapContainerRef.current.querySelector("svg");
|
||||
if (!svgElement) {
|
||||
console.error("No SVG element found in map container");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("SVG element found, starting enhancement");
|
||||
|
||||
// Use our utility to populate the map with clue points
|
||||
populateMap(svgElement)
|
||||
.then((success) => {
|
||||
if (success) {
|
||||
console.log("Map populated successfully");
|
||||
|
||||
// After populating the map, update the status of each clue point
|
||||
updateCluePointStatus(svgElement, clues);
|
||||
|
||||
// Attach click handlers for navigation
|
||||
attachClueClickHandlers(svgElement, clues, (clueId) => {
|
||||
router.push(`/clue/${clueId}`);
|
||||
});
|
||||
} else {
|
||||
console.error("Failed to populate map");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error enhancing SVG map:", error);
|
||||
setMapError(true);
|
||||
});
|
||||
}, [clues, router]);
|
||||
|
||||
// Function to check hunt status and timer
|
||||
async function checkHuntAndTimer() {
|
||||
if (!isMounted.current) return;
|
||||
@@ -538,23 +570,23 @@ export default function MapPage() {
|
||||
// Only try to enhance the map if both the SVG and clues are loaded
|
||||
if (!mapSvg || !clues.length) return;
|
||||
|
||||
console.log("Both SVG and clues loaded, enhancing map");
|
||||
console.log("Both SVG and clues are loaded, preparing to enhance map");
|
||||
|
||||
// Use requestAnimationFrame to ensure the DOM has been updated with the SVG
|
||||
// Ensure the SVG is fully loaded in the DOM before enhancing
|
||||
requestAnimationFrame(() => {
|
||||
// Short timeout to ensure the SVG is fully rendered in the DOM
|
||||
// Longer timeout to ensure the SVG is fully rendered in the DOM
|
||||
setTimeout(() => {
|
||||
if (
|
||||
mapContainerRef.current &&
|
||||
mapContainerRef.current.querySelector("svg")
|
||||
) {
|
||||
console.log("SVG found in DOM, enhancing map");
|
||||
console.log("SVG found in DOM, enhancing map now");
|
||||
enhanceSvgMap();
|
||||
} else {
|
||||
console.error("SVG not found in DOM after rendering");
|
||||
console.error("SVG not found in DOM after rendering timeout");
|
||||
setMapError(true);
|
||||
}
|
||||
}, 100);
|
||||
}, 500); // Increased timeout for better reliability on slower devices
|
||||
});
|
||||
}, [mapSvg, clues, enhanceSvgMap]);
|
||||
|
||||
@@ -627,14 +659,12 @@ export default function MapPage() {
|
||||
<div
|
||||
className={styles["svg-container"]}
|
||||
dangerouslySetInnerHTML={{ __html: mapSvg }}
|
||||
onLoad={() => console.log("SVG container loaded")}
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
className={styles["map-background"]}
|
||||
role="img"
|
||||
aria-label="Treasure Map"
|
||||
></div>
|
||||
<div className={styles["loading-container"]}>
|
||||
<div className={styles["loading-spinner"]}></div>
|
||||
<div>Loading map...</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user