HTML of slide carousel

A slide carousel was used to display the menu for selecting points.

  • Each slide contains an image, name, description, and checkbox.
<html>
  <head>
    <title>Location Selector</title>
    <!-- <link rel="stylesheet" href="yuristyle.scss"> -->
    <!-- Fontawesome Link for Icons -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css">
  </head>
  <br>
  <br>
  <body>
    <div class="carousel-wrapper">
      <i id="left" class="fa-solid fa-angle-left"></i>
      <ul class="carousel">
        <li class="card">
          <div class="img"><img src="(image link)" alt="img" draggable="false"></div>
          <h2>Mission Bay</h2>
          <p style = "text-align: center;">a human-made saltwater bay located south of the Pacific Beach community of San Diego. The bay is part of the recreational Mission Bay Park, the largest man-made aquatic park in the United States.</p>
          <form> 
          <input id = "missionbay" type="checkbox">
          </form>
        </li>
        <li class="card">
          <div class="img"><img src="(image link)" alt="img" draggable="false"></div>
          <h2>Ocean Front Walk</h2>
          <p style = "text-align: center;">a two-and-a-half-mile (4 km) pedestrian promenade that features performers, fortune-tellers, and vendors.
          </p>
          <form> 
          <input id = "OceanFrontWalk" type="checkbox">
          </form>
        </li>
        <li class="card">
          <div class="img"><img src="(image link)" alt="img" draggable="false"></div>
          <h2>Belmont Park</h2>
          <p style = "text-align: center;">An oceanfront historic amusement park located in the Mission Beach area of San Diego, California.</p>
          <form> 
          <input id = "Belmont" type="checkbox">
          </form>
        </li>
        <li class="card">
          <div class="img"><img src="(image link)" alt="img" draggable="false"></div>
          <h2>Sea World</h2>
          <p style = "text-align: center;">An animal theme park, oceanarium, outside aquarium and marine mammal park that rovides education and outreach on marine issues to the general public, including information in park exhibits</p>
          <form> 
          <input id = "seaworld" type="checkbox">
          </form>
        </li>
        <li class="card">
          <div class="img"><img src="(image link)" alt="img" draggable="false"></div>
          <h2>Fashion valley</h2>
          <p style = "text-align: center;">an upscale, open-air shopping mall, the largest mall in San Diego and one of the largest in California.</p>
          <form> 
          <input id = "fashionvalley" type="checkbox">
          </form>
        </li>
        <li class="card">
          <div class="img"><img src="(image link)" alt="img" draggable="false"></div>
          <h2>Ocean Beach</h2>
          <p style = "text-align: center;">A beachfront neighborhood of San Diego, California, featuring a sandy beach and a famous pier.</p>
          <form> 
          <input id = "oceanbeach" type="checkbox">
          </form>
        </li>
        <li class="card">
            <div class="img"><img src="(image link)" alt="img" draggable="false"></div>
            <h2>Bazaar Del Mundo</h2>
            <p style = "text-align: center;">A collection of arts and crafts shops in San Diego featuring vibrant artworks from all over the world.
            </p>
          <form> 
          <input id = "bazaar" type="checkbox">
          </form>
        </li>
          <li class="card">
            <div class="img"><img src="(image link)" alt="img" draggable="false"></div>
            <h2>The Whaley House</h2>
            <p style = "text-align: center;">An 1857 Greek Revival style residence, former home of Thomas Whaley and his family. Used to also house Whaley's general store, San Diego's second county courthouse, and the first commercial theater in San Diego.</p>
            <form> 
            <input id = "whaley" type="checkbox">
          </form>
          </li>
          <li class="card">
            <div class="img"><img src="(image link)" alt="img" draggable="false"></div>
            <h2>San Diego Zoo</h2>
            <p style = "text-align: center;">A zoo housing 4,000 animals of more than 650 species, featuring open-air, cageless exhibits that recreate natural animal habitats. SanDiego Zoo is the most visited zoo in the United States.
            </p>
            <form> 
          <input id = "zoo" type="checkbox">
          </form>
          </li>
          <li class="card">
            <div class="img"><img src="(image link)" alt="img" draggable="false"></div>
            <h2>El Prado</h2>
            <p style = "text-align: center;">The main Spanish national art museum, housing one of the world's best collections of European art, dating from the 12th century to the early 20th century, based on the former Spanish royal collection, and the single best collection of Spanish art.
            </p>
            <form> 
            <input id = "prado" type="checkbox">
            </form>
          </li>
          <li class="card">
            <div class="img"><img src="(image link)" alt="img" draggable="false"></div>
            <h2>Firehouse Museum</h2>
            <p style = "text-align: center;">A museum which shows the history of our firedepartments.</p>
            <form> 
           <input id = "museum" type="checkbox">
           </form>
          </li>
          <li class="card">
            <div class="img"><img src="(image link)" alt="img" draggable="false"></div>
            <h2>USS Midway Carrier</h2>
            <p style = "text-align: center;">a historical naval aircraft carrier museum, featuring the aircraft carrier Midway.</p>
            <form> 
           <input id = "midway" type="checkbox">
           </form>
          </li>
          <li class="card">
            <div class="img"><img src="(image link)" alt="img" draggable="false"></div>
            <h2>Gaslamp Quarter</h2>
            <p style = "text-align: center;">a 16½-block neighborhood, including 94 historic buildings, most of which were constructed in the Victorian Era, the site of several events and festivals</p>
            <form> 
           <input id = "gaslamp" type="checkbox">
           </form>
          </li>
          <li class="card">
            <div class="img"><img src="(image link)" alt="img" draggable="false"></div>
            <h2>Cornado Bridge</h2>
            <p style = "text-align: center;">a prestressed concrete/steel girder bridge crossing over San Diego Bay, connecting San Diego to Coronado
            </p>
          <form> 
          <input id = "bridge" type="checkbox">
          </form>
          </li>
          <li class="card">
            <div class="img"><img src="(image link)" alt="img" draggable="false"></div>
            <h2>Cornado Beach</h2>
            <p style = "text-align: center;">a beach on the Coronado, featuring a long beach with a vast sand area, rated the sixth-best beach in America
            </p>
          <form> 
          <input id = "beach" type="checkbox">
          </form>
          </li>
          <li class="card">
            <div class="img"><img src="(image link)" alt="img" draggable="false"></div>
            <h2> Point Loma Lighthouse</h2>
            <p style = "text-align: center;">A historic lighthouse that serves as a museum, containinng an ocean view and detailing the history of hte location.
            </p>
            <form> 
          <input id = "pointloma" type="checkbox">
          </form>
          </li>
          <li class="card">
            <div class="img"><img src="(image link)" alt="img" draggable="false"></div>
            <h2>MissionTrails</h2>
            <p style = "text-align: center;">Mission Trails Regional Park encompasses more than 8,000 acres of both natural anddeveloped recreational areas.</p>
            <form> 
          <input id = "missiontrails" type="checkbox">
          </form>
          </li>
          <li class="card">
            <div class="img"><img src="(image link)" alt="img" draggable="false"></div>
            <h2>Walmart</h2>
            <p style = "text-align: center;">Walmart Inc (Walmart) is a retailer that operates grocery stores, supermarkets, hypermarkets, department and discount stores, and neighborhood markets.</p>
            <form> 
          <input id = "walmart" type="checkbox">
          </form>
          </li>
          <li class="card">
            <div class="img"><img src="(image link)" alt="img" draggable="false"></div>
            <h2>Costco</h2>
            <p style = "text-align: center;">Costco is a membership warehouse club, dedicated to bringing our members the best possible prices on quality brand-name merchandise</p>
            <form> 
            <input id = "costco" type="checkbox">
          </form>
          </li>
        </ul>
        <i id="right" class="fa-solid fa-angle-right"></i>
      </div>

The Slide Carousel's Functionality with Javascript

  • The Javascript used for the table is essentially meant to allow the user to interact with the carousel.
    • The user can drag their mouse to move the slide carousel to the next cards.
    • The user can also press buttons on the side to scroll through the cards.
    • If the user is inactive, the slide carousel autoplays and scrolls through cards automatically for the user.
  • Like the event handlers and listeners in the code for game functionality, this carousel also utilizes event listeners to track the user's mouse clicks and drags, as well as other mouse interactions.
let isDragging = false, isAutoPlay = true, startX, startScrollLeft, timeoutId;

// Get the number of cards that can fit in the carousel at once
let cardPerView = Math.round(carousel.offsetWidth / firstCardWidth);

// Insert copies of the last few cards to beginning of carousel for infinite scrolling
carouselChildrens.slice(-cardPerView).reverse().forEach(card => {
    carousel.insertAdjacentHTML("afterbegin", card.outerHTML);
});

// Insert copies of the first few cards to end of carousel for infinite scrolling
carouselChildrens.slice(0, cardPerView).forEach(card => {
    carousel.insertAdjacentHTML("beforeend", card.outerHTML);
});

// Scroll the carousel at appropriate postition to hide first few duplicate cards on Firefox
carousel.classList.add("no-transition");
carousel.scrollLeft = carousel.offsetWidth;
carousel.classList.remove("no-transition");

// Add event listeners for the arrow buttons to scroll the carousel left and right
arrowBtns.forEach(btn => {
    btn.addEventListener("click", () => {
        carousel.scrollLeft += btn.id == "left" ? -firstCardWidth : firstCardWidth;
    });
});

const dragStart = (e) => {
    isDragging = true;
    carousel.classList.add("dragging");
    // Records the initial cursor and scroll position of the carousel
    startX = e.pageX;
    startScrollLeft = carousel.scrollLeft;
}

const dragging = (e) => {
    if(!isDragging) return; // if isDragging is false return from here
    // Updates the scroll position of the carousel based on the cursor movement
    carousel.scrollLeft = startScrollLeft - (e.pageX - startX);
}

const dragStop = () => {
    isDragging = false;
    carousel.classList.remove("dragging");
}

const infiniteScroll = () => {
    // If the carousel is at the beginning, scroll to the end
    if(carousel.scrollLeft === 0) {
        carousel.classList.add("no-transition");
        carousel.scrollLeft = carousel.scrollWidth - (2 * carousel.offsetWidth);
        carousel.classList.remove("no-transition");
    }
    // If the carousel is at the end, scroll to the beginning
    else if(Math.ceil(carousel.scrollLeft) === carousel.scrollWidth - carousel.offsetWidth) {
        carousel.classList.add("no-transition");
        carousel.scrollLeft = carousel.offsetWidth;
        carousel.classList.remove("no-transition");
    }

    // Clear existing timeout & start autoplay if mouse is not hovering over carousel
    clearTimeout(timeoutId);
    if(!wrapper.matches(":hover")) autoPlay();
}

const autoPlay = () => {
    if(window.innerWidth < 800 || !isAutoPlay) return; // Return if window is smaller than 800 or isAutoPlay is false
    // Autoplay the carousel after every 2500 ms
    timeoutId = setTimeout(() => carousel.scrollLeft += firstCardWidth, 2500);
}
autoPlay();

carousel.addEventListener("mousedown", dragStart);
carousel.addEventListener("mousemove", dragging);
document.addEventListener("mouseup", dragStop);
carousel.addEventListener("scroll", infiniteScroll);
wrapper.addEventListener("mouseenter", () => clearTimeout(timeoutId));
wrapper.addEventListener("mouseleave", autoPlay);

Creation of vertices

  • The creation of specific vertices are shown in this code below.
    • The array locationSelected stores the vertex data of all the locations selected by the user, and puts all of its data into the list vertices once the user finishes selecting their points.
    • The array locationNames stores the names of each location which can be put in as info into the POST request to the backend. It can also be used to display the names of locations the user selected.
let locationNames = [];

function checkSelected(){
  // variables for all the inputs
  const missionbay = document.getElementById("missionbay");
  const OceanFrontWalk = document.getElementById("OceanFrontWalk");
  const belmontpark = document.getElementById("Belmont");
  const seaworld = document.getElementById("seaworld");
  const fashionvalley = document.getElementById("fashionvalley");
  const oceanbeach = document.getElementById("oceanbeach");
  const bazaar = document.getElementById("bazaar");
  const whaley = document.getElementById("whaley");
  const zoo = document.getElementById("zoo");
  const prado = document.getElementById("prado");
  const museum = document.getElementById("museum");
  const midway = document.getElementById("midway");
  const gaslamp = document.getElementById("gaslamp");
  const bridge = document.getElementById("bridge");
  const beach = document.getElementById("beach");
  const pointloma = document.getElementById("pointloma");
  const missiontrails = document.getElementById("missiontrails");
  const walmart = document.getElementById("walmart");
  const costco = document.getElementById("costco");

  // list of selected locations
  let locationSelected = [];

  // checks for if checked
  if (missionbay.checked == true){
    locationSelected.push({id: "missionbay", x: 150, y: 200 });
    locationNames.push("Mission Bay");
  }
  if (OceanFrontWalk.checked == true){
    locationSelected.push({ id: "OceanFrontWalk", x: 90, y: 200 });
    locationNames.push("Ocean Front Walk");
  }
  if (belmontpark.checked == true){
    locationSelected.push({id: "Belmont", x: 95, y: 220 });
    locationNames.push("Belmont Park");
  }
  if (seaworld.checked == true){
    locationSelected.push({id: "seaworld", x: 165, y: 230 });
    locationNames.push("Sea World");
  }
  if (fashionvalley.checked == true){
    locationSelected.push({id: "fashionvalley", x: 316, y: 225 });
    locationNames.push("Fashion Valley");
  }
  if (oceanbeach.checked == true){
    locationSelected.push({id: "oceanbeach", x: 100, y: 276 });
    locationNames.push("Ocean Beach");
  }
  if (bazaar.checked == true){
    locationSelected.push({id: "bazaar", x: 235, y: 260 });
    locationNames.push("Bazaar Del Mundo");
  }
  if (whaley.checked == true){
    locationSelected.push({id: "whaley", x: 265, y: 270 });
    locationNames.push("Whaley House");
  }
  if (zoo.checked == true){
    locationSelected.push({id: "zoo", x: 360, y: 320 });
    locationNames.push("San Diego Zoo");
  }
  if (prado.checked == true){
    locationSelected.push({id: "prado", x: 370, y: 340 });
    locationNames.push("El Prado");
  }
  if (museum.checked == true){
    locationSelected.push({id: "museum", x: 330, y: 360 });
    locationNames.push("Fire House Museum");
  }
  if (midway.checked == true){
    locationSelected.push({id: "midway", x: 310, y: 390 });
    locationNames.push("USS Midway Museum");
  }
  if (gaslamp.checked == true){
    locationSelected.push({id: "gaslamp", x: 360, y: 385 });
    locationNames.push("Gaslamp Quarter");
  }
  // fix this
  if (bridge.checked == true){
    locationSelected.push({id: "bridge", x: 360 , y: 460 });
    locationNames.push("Cornado Bridge")
  }
  if (beach.checked == true){
    locationSelected.push({id: "beach", x: 270, y: 480 });
    locationNames.push("Ocean Beach");
  }
  if (pointloma.checked == true){
    locationSelected.push({id: "pointloma", x: 120, y: 530 });
    locationNames.push("Point Loma Light House");
  }
  if (missiontrails.checked == true){
    locationSelected.push({id: "MissionTrails", x: 640, y: 50});
    locationNames.push("Mission Trails");
  }
  if (walmart.checked == true){
    locationSelected.push({id: "Walmart", x: 500, y: 590});
    locationNames.push("Walmart");
  }
  if (costco.checked == true){
    locationSelected.push({ id: "Costco", x: 670, y: 190});
    locationNames.push("Costco");
  }
  if (locationSelected.length <= 10 && locationSelected.length >= 2){
    console.log("Success");
    vertices.length = 0;
    vertices = locationSelected;
    console.log(vertices);
    menuPage.style.display = "none";
    gamePage.style.display = "block";
    resetButton.style.display = "block";
    finishButton.style.display = "none";
    game();
  }
  else {
    console.log("You've selected an invalid amount of locations");
    console.log(locationSelected);
    location.reload();
  }
}

Styling with Sass

In addition to HTML and Javascript, lots of styling was also used using Sass. This styling is what allows the menu selection page to display nicely.

/* Import Google font - Poppins */
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap');
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: "Poppins", sans-serif;
}
// body {
//   display: block;
//   padding: 0 35px;
//   align-items: center;
//   justify-content: center;
//   min-height: 100vh;
// }
.carousel-wrapper {
  max-width: 1100px;
  width: 100%;
  position: relative;
  margin: auto;
}
.carousel-wrapper i {
  top: 50%;
  height: 50px;
  width: 50px;
  cursor: pointer;
  font-size: 1.25rem;
  position: absolute;
  text-align: center;
  line-height: 50px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 3px 6px rgba(0,0,0,0.23);
  transform: translateY(-50%);
  transition: transform 0.1s linear;
}
.carousel-wrapper i:active{
  transform: translateY(-50%) scale(0.85);
}
.carousel-wrapper i:first-child{
  left: -22px;
}
.carousel-wrapper i:last-child{
  right: -22px;
}
.carousel-wrapper .carousel{
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: calc((100% / 3) - 12px);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  gap: 16px;
  border-radius: 8px;
  scroll-behavior: smooth;
  scrollbar-width: none;
}
.carousel::-webkit-scrollbar {
  display: none;
}
.carousel.no-transition {
  scroll-behavior: auto;
}
.carousel.dragging {
  scroll-snap-type: none;
  scroll-behavior: auto;
}
.carousel.dragging .card {
  cursor: grab;
  user-select: none;
}
.carousel :where(.card, .img) {
  display: flex;
  justify-content: center;
  align-items: center;
}
.carousel .card {
  scroll-snap-align: start;
  height: 500px;
  list-style: none;
  background: #fff;
  cursor: pointer;
  padding-bottom: 15px;
  flex-direction: column;
  border-radius: 8px;
  padding: 15px;
}
.carousel .card .img {
  background: #388803;
  height: 148px;
  width: 148px;
  border-radius: 50%;
}
.card .img img {
  width: 140px;
  height: 140px;
  border-radius: 50%;
  object-fit: cover;
  border: 4px solid #fff;
}
.carousel .card h2 {
  font-weight: 500;
  font-size: 1.56rem;
  margin: 30px 0 5px;
}
.carousel .card span {
  color: #6A6D78;
  font-size: 1.31rem;
}

@media screen and (max-width: 900px) {
  .carousel-wrapper .carousel {
    grid-auto-columns: calc((100% / 2) - 9px);
  }
}

@media screen and (max-width: 600px) {
  .carousel-wrapper .carousel {
    grid-auto-columns: 100%;
  }
}
p {
    font-size: small;
}
input {
    margin-bottom: 20px;
}
form {
    background-color: transparent;
}

#finish_B{
  margin: auto;
  display: block;
  width: 200px;
  padding: 15px 0;
  text-align: center;
  background: transparent;
  border-radius: 25px;
  border: 2px solid #009614;
  color: #fff;
  font-weight: bold;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: all 0.6s;
  color: white;
}
#finish_B:hover{
  background-color: #009614;
}