Skip to content

Commit

Permalink
interactive graphic
Browse files Browse the repository at this point in the history
  • Loading branch information
learyjk committed Aug 27, 2024
1 parent 622e5ec commit 6765365
Showing 1 changed file with 167 additions and 13 deletions.
180 changes: 167 additions & 13 deletions src/interactive/interactive-graphic.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,181 @@
const SELECTORS = {
touchpoint: '[interactive-el="touchpoint"]',
touchpoint: "[touchpoint-el]",
touchpointBase: ".interactive_touchpoint_base",
touchpointCard: ".interactive_touchpoint_card",
viewSolutionButton: "[solution-el]",
modal: "[modal-el]",
modalClose: "[close-el]",
modalCloseButton: "[close-button]",
};

const touchpoints = document.querySelectorAll(SELECTORS.touchpoint);
const modals = document.querySelectorAll(SELECTORS.modal);
const modalCloseEls = document.querySelectorAll(SELECTORS.modalClose);

touchpoints.forEach((touchpoint) => {
touchpoint.addEventListener("mouseover", () => {
// Do something when a touchpoint is hovered
console.log("Hovered over a touchpoint");
let activeIndex = 0;
let autoplayInterval;
let isAutoplaying = true;
let isModalOpen = false;
let previouslyFocusedElement; // Track the element that opened the modal

// Function to show the active card
function showActiveCard(index) {
touchpoints.forEach((touchpoint, i) => {
const card = touchpoint.querySelector(SELECTORS.touchpointCard);
card.classList.remove("hide");
const base = touchpoint.querySelector(SELECTORS.touchpointBase);

if (i === index) {
card.classList.remove("hide");
base.classList.add("is-active");
} else {
card.classList.add("hide");
base.classList.remove("is-active");
}
});
}

// Autoplay function
function startAutoplay() {
clearInterval(autoplayInterval);
if (!isModalOpen) {
autoplayInterval = setInterval(() => {
activeIndex = (activeIndex + 1) % touchpoints.length;
showActiveCard(activeIndex);
}, 2000);
}
}

// Stop autoplay function
function stopAutoplay() {
clearInterval(autoplayInterval);
isAutoplaying = false;
showActiveCard(-1);
}

// Function to trap focus within the modal
function trapFocus(modal) {
const focusableElements = modal.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];

modal.addEventListener("keydown", (event) => {
if (event.key === "Tab") {
if (event.shiftKey) {
// Shift + Tab
if (document.activeElement === firstElement) {
event.preventDefault();
lastElement.focus();
}
} else {
// Tab
if (document.activeElement === lastElement) {
event.preventDefault();
firstElement.focus();
}
}
}
});

// Set focus to the first element in the modal
firstElement.focus();
}

// Initial call to start autoplay
startAutoplay();

touchpoints.forEach((touchpoint, index) => {
const viewSolutionButton = touchpoint.querySelector(
SELECTORS.viewSolutionButton
);
const clickedIndex = parseInt(viewSolutionButton.getAttribute("solution-el"));
const matchingModal = modals[clickedIndex];
const closeEl = modalCloseEls[clickedIndex];
const closeButton = matchingModal.querySelector(SELECTORS.modalCloseButton);

// Reuse the mouseover effect for keyboard focus
const handleInteraction = () => {
if (isAutoplaying) {
stopAutoplay();
}
showActiveCard(index);
};

touchpoint.addEventListener("mouseover", handleInteraction);

touchpoint.addEventListener("focus", handleInteraction);

touchpoint.addEventListener("mouseout", () => {
// Do something when a touchpoint is no longer hovered
console.log("No longer hovering over a touchpoint");
const card = touchpoint.querySelector(SELECTORS.touchpointCard);
card.classList.add("hide");
if (!isAutoplaying && !isModalOpen) {
activeIndex = index;
startAutoplay();
isAutoplaying = true;
}
});

touchpoint.addEventListener("blur", () => {
if (!isAutoplaying && !isModalOpen) {
activeIndex = index;
startAutoplay();
isAutoplaying = true;
}
});

// Add keydown event listener to open modal on Enter or Space key
touchpoint.addEventListener("keydown", (event) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault(); // Prevent default behavior like scrolling
previouslyFocusedElement = document.activeElement;
matchingModal.classList.remove("hide");
isModalOpen = true;
stopAutoplay();
trapFocus(matchingModal); // Trap focus inside the modal
// stop body from scrolling
document.body.style.overflow = "hidden";
}
});

viewSolutionButton.addEventListener("click", () => {
previouslyFocusedElement = document.activeElement;
matchingModal.classList.remove("hide");
isModalOpen = true;
stopAutoplay();
trapFocus(matchingModal); // Trap focus inside the modal
// stop body from scrolling
document.body.style.overflow = "hidden";
});

closeEl.addEventListener("click", () => {
matchingModal.classList.add("hide");
isModalOpen = false;
startAutoplay();
isAutoplaying = true;
previouslyFocusedElement.focus(); // Return focus to the element that triggered the modal
// allow body to scroll
document.body.style.overflow = "auto";
});

closeButton.addEventListener("click", () => {
matchingModal.classList.add("hide");
isModalOpen = false;
startAutoplay();
isAutoplaying = true;
previouslyFocusedElement.focus(); // Return focus to the element that triggered the modal
// allow body to scroll
document.body.style.overflow = "auto";
});

touchpoint.addEventListener("click", () => {
// Do something when a touchpoint is clicked
console.log("Clicked on a touchpoint");
// Allow closing the modal with the Escape key
matchingModal.addEventListener("keydown", (event) => {
if (event.key === "Escape") {
matchingModal.classList.add("hide");
isModalOpen = false;
startAutoplay();
isAutoplaying = true;
previouslyFocusedElement.focus(); // Return focus to the element that triggered the modal
// allow body to scroll
document.body.style.overflow = "auto";
}
});
});

0 comments on commit 6765365

Please sign in to comment.