Creating Vertex and Graph Classes

  • class Vertex allows the coder to easily add in a new vertex on the graph by simply using JSON and writing {id: "", x: , y: }. This allows us to manipulate the points on the graph much more easily.
  • class Graph allows the coder to easily add in a graph. We added two graphs: one for allowing the user to draw their own line connections, another for displaying the shortest path using heuristic algorithm. Only one graph can be displayed on the canvas at a time.
    • calculateDistance() function is used to calculate distances in the heuristic graph.
    • calculateTotalDistance() function is used to calculate distances in the user interactive graph.
// Vertex class to represent each HTML element
class Vertex {
    constructor(id, x, y) {
        this.id = id; // id of the vertex
        this.x = x; // x-coordinate of the vertex
        this.y = y; // y-coordinate of the vertex
        this.adjacent = []; // array to store adjacent vertices
        this.connected = false; // flag to indicate if vertex is connected
    }
    // Function to add an adjacent vertex
    addAdjacent(vertex) {
        this.adjacent.push(vertex);
    }
    }
    // Graph class to hold all the vertices
    class Graph {
    constructor() {
        this.vertices = []; // array to store all vertices
        this.map = {}; // hash map to store vertices by their ids
    }
    // Function to add a vertex to the graph
    addVertex(vertex) {
        this.vertices.push(vertex);
        this.map[vertex.id] = vertex; // add vertex to the map
    }
    // Function to check if all vertices are connected
    checkAllVerticesConnected() {
        const visited = new Set(); // Set to store visited vertices
        const stack = []; // Stack for DFS traversal

        // Start DFS from the first vertex in the graph
        stack.push(graph.vertices[0]);

        while (stack.length > 0) {
        const vertex = stack.pop();
        visited.add(vertex);

        // Add all adjacent unvisited vertices to the stack
        for (const adjacentVertex of vertex.adjacent) {
            if (!visited.has(adjacentVertex)) {
            stack.push(adjacentVertex);
            }
        }
        }

    // Check if all vertices are visited
    return visited.size === graph.vertices.length;
    }
    // Function to calculate the Euclidean distance between two vertices
    calculateDistance(v1, v2) {
        const dx = v1.x - v2.x;
        const dy = v1.y - v2.y;
        return Math.sqrt(dx * dx + dy * dy);
    }
    // Function to calculate the total distance of all lines
    calculateTotalDistance() {
        let totalDistance = 0;
        for (const vertex of this.vertices) {
        for (const adjacentVertex of vertex.adjacent) {
            totalDistance += this.calculateDistance(vertex, adjacentVertex);
        }
        }
        return totalDistance;
    }
    }

Creating things using the Graph and Vertex classes

  • vertices array stores all of the points that are to be graphed on the canvas. The array can be manipulated based on user's menu selection(something that we will go over later in detail)
    • Note that points are still in the array but commented out, this allows the coder to know what locations are included in the game
  • const heuristic creates the graph of the shortest route among all points
  • const graph creates the graph where the user can interact and connect points using drag and drop lines
// Define the vertices as an array of objects, points are commented out since user picks these points, not us
let vertices = [
    // { id: "A", x: 150, y: 200 },
    // { id: "B", x: 90, y: 200 },
    // { id: "C", x: 95, y: 220 },
    // { id: "D", x: 165, y: 230 },
    // { id: "E", x: 316, y: 225 },
    // { id: "F", x: 100, y: 276 },
    // { id: "G", x: 235, y: 260 },
    // { id: "H", x: 265, y: 270 },
    // { id: "I", x: 360, y: 320 }, 
    // { id: "J", x: 370, y: 340 },
    // { id: "O", x: 330, y: 360 },
    // { id: "R", x: 310, y: 390 },
    // { id: "T", x: 360, y: 385 },
    // { id: "V", x: 360, y: 460 },
    // { id: "W", x: 270, y: 480 },
    // { id: "Z", x: 120, y: 530 },
    // { id: "MissionTrails", x: 640, y: 50},
    // { id: "Walmart", x: 500, y: 590},
    // { id: "Costco", x: 670, y: 190}
    
    // Add more vertices here as needed
    ];

// Create heuristic graph
const heuristic = new Graph();

// Create the user drawing graph
const graph = new Graph();

Storing vertices into each graph

  • The vertices array is stored into both graphs in order to allow the graphs to be able to plot specific points.
    • Because both graphs will be using the same points at all times, two for loops are used to iterate through and store each point in the array vertices in each graph.
// Loop through the vertices array and create a new Vertex object for each one
for (const vertex of vertices) {
    const newVertex = new Vertex(vertex.id, vertex.x, vertex.y);
    graph.addVertex(newVertex);
    }

    
    // Loop through the vertices array and create a new Vertex object for each one
    for (const vertex of vertices) {
        const newVertex = new Vertex(vertex.id, vertex.x, vertex.y);
        heuristic.addVertex(newVertex);
    }

Heuristic Calculation Method

  • function generatePaths() is responsible for calculating the shortest route between all vertices.
    • This function partially uses a heuristic and requires a significant amount of computer calculations.
// Function to generate all possible paths that visit all vertices exactly once
function generatePaths(graph) {
    const paths = [];
    const visited = new Set();
    
    function dfs(path) {
    if (path.length === graph.vertices.length) {
    paths.push(path);
    return;
    }

    graph.vertices.forEach((vertex) => {
    if (!visited.has(vertex)) {
    visited.add(vertex);
    dfs([...path, vertex]);
    visited.delete(vertex);
    }
    });
    }

    graph.vertices.forEach((vertex) => {
    visited.add(vertex);
    dfs([vertex]);
    visited.delete(vertex);
    });

    return paths;
}

Heuristic Calculations Continued

  • function getPathDistance() calculates the distance of the heuristic path. This is eventually used to display the shortest distance in a form as an answer at the end.
// Function to calculate the total distance of heuristic path
function getPathDistance(path) {
    let distance = 0;
    for (let i = 0; i < path.length - 1; i++) {
    distance += heuristic.calculateDistance(path[i], path[i+1]);
    }
    return distance;
    }

Drawing the Heuristic Graph

  • function drawShortestPath() is a function that is used to draw the shortest route between all points on the canvas.
    • This is a very convenient function as drawShortestPath() can be called anytime you want to display the shortest route between any points you create.
// Function to draw the shortest path on the canvas
function drawShortestPath(graph) {
    const canvas = document.getElementById("canvas");
    const ctx = canvas.getContext("2d");

    ctx.clearRect(0, 0, canvas.width, canvas.height); // clear the canvas
    
    // Generate all possible paths and find the shortest one
    const paths = generatePaths(heuristic);
    let shortestPath = null;
    let shortestDistance = Infinity;
    paths.forEach((path) => {
    const distance = getPathDistance(path);
    if (distance < shortestDistance) {
    shortestPath = path;
    shortestDistance= distance;
    }
    });

    // Store the pixel length in a global variable called path_length
    const path_length = shortestDistance;

    // Log the pixel length to the console
    console.log("Pixel length of shortest path:", path_length);

    shortestDistanceResult.textContent = ((path_length*2)/54).toFixed(2);
    dummyCalcD = ((path_length*2)/54).toFixed(2);
    
    // Draw all vertices as black circles
    graph.vertices.forEach((vertex) => {
    ctx.beginPath();
    ctx.arc(vertex.x, vertex.y, 10, 0, 2 * Math.PI);
    ctx.fillStyle = "#000000";
    ctx.fill();
    ctx.closePath();

    });

    // Draw the path as a red line
    ctx.beginPath();
    ctx.strokeStyle = "#FF0000";
    ctx.lineWidth = 3;

    for (let i = 0; i < shortestPath.length - 1; i++) {
    const current = shortestPath[i];
    const next = shortestPath[i+1];
    ctx.moveTo(current.x, current.y);
    ctx.lineTo(next.x, next.y);
    }

    ctx.stroke();
    ctx.closePath();
}

// Draw the shortest path on the canvas
// This is an example of how this function would be called. ***heuristic*** refers to the new Graph created using the Graph class
drawShortestPath(heuristic);

Moving onto the Game function

The game() function is a function that encloses all of the action that the user does. This includes multiple event handlers that are responsible for the lines dragging and dropping. It is also reponsible for drawing the graph that the user interacts with. This is essentially a separate dimension from the heuristic diagram which is not able to interact with users.

  • We enclosed all of the user actions into one function in order to allow the user to first select their points and draw the graph using the user's selected points.
    • Without game() the user would be unable to see the points they selected on the menu selection page.

For a time we will be explaining code from the game() function

Initialization of Variables

Many variables are initialized in order to store different kinds of data for the functionality of multiple functions. The user's graph is also drawn so that the user is able to see their points on the canvas.

// Initialize variables
let selectedVertex = null;
let lineStartX = null;
let lineStartY = null;
let lineEndX = null;
let lineEndY = null;
let allVerticesConnected = graph.checkAllVerticesConnected();
// Draw the user drawing graph
drawGraph(graph);

Defining Adjacency Relationships for the Heuristic Graph

  • This algorithm allows for calculation of a heuristic - It essentially finds the closest point from one starting point(vertex) to another. Then, it does the same thing again with the end point becoming the start point in the calculation.
    • This defining of adjacency relationships is what gives the heuristic graph its heuristic characteristics.
// Define adjacency relationships
heuristic.vertices.forEach((vertex) => {
    const closestPoints = vertices
        .filter((p) => p.id !== vertex.id)
        .sort((a, b) => heuristic.calculateDistance(vertex, a) - heuristic.calculateDistance(vertex, b))
        .slice(0, 2);

    closestPoints.forEach((point) => {
        const adjacentVertex = heuristic.map[point.id];
        vertex.addAdjacent(adjacentVertex);
    });
    });

Drawing the User's Graph

  • function drawGraph() is very similar to function drawShortestPath() for the heuristic graph. It essentially draws out the user's interactive graph onto the canvas.
    • It is as convenient as drawShortestPath() and can be called multiple times to the coder's desire without problems occuring.
// Function to draw the graph on the canvas
function drawGraph(graph) {
    const canvas = document.getElementById("canvas");
    const ctx = canvas.getContext("2d");
    ctx.clearRect(0, 0, canvas.width, canvas.height); // clear the canvas
    // Draw all vertices as black circles
    graph.vertices.forEach((vertex) => {
        ctx.beginPath();
        ctx.arc(vertex.x, vertex.y, 10, 0, 2 * Math.PI);
        ctx.fillStyle = vertex.connected ? "#00FF00" : "#000000";
        ctx.fill();
        ctx.closePath();
    });
    // Draw the connected lines
    ctx.beginPath();
    ctx.strokeStyle = "#0000FF";
    ctx.lineWidth = 3;
    graph.vertices.forEach((vertex) => {
        vertex.adjacent.forEach((adjacentVertex) => {
        ctx.moveTo(vertex.x, vertex.y);
        ctx.lineTo(adjacentVertex.x, adjacentVertex.y);
        });
    });
    ctx.stroke();
    ctx.closePath();
}

// Draw the user drawing graph
// This is an example of how this function would be called. ***graph*** refers to the new Graph created using the Graph class
drawGraph(graph);

Handling Mouse Event functions

We will next be talking about how the user is able to interact using mouse moving and clicking. We are using event handlers and event listeners to be able to track down mouse interactions.

  • We will be handling the following mouse events:
    • Mouse Down
    • Mouse Move
    • Mouse Up
    • What to do if reset button is clicked

Mouse Down

Mouse Down event is handled in the handleMouseDown() function.

  • The function first checks if all vertices are connected. If all vertices are connected(allVerticesConnected === true) then this function is disabled(which can prevent the user from interacting with the graph once it is completed)
    • This function's main functionality is to record down the coordinates of the vertex(point) in which the user clicked down on as a starting point.
// Function to handle the mouse down event
function handleMouseDown(e) {
    if (allVerticesConnected) {
            return; // Return early if all vertices are already connected
        }
        const canvas = e.target;
        const rect = canvas.getBoundingClientRect();
        const mouseX = e.clientX - rect.left;
        const mouseY = e.clientY - rect.top;
        // Find the vertex that the user clicked on (if any)
        const vertex = graph.vertices.find((vertex) => {
            const dx = vertex.x - mouseX;
            const dy = vertex.y - mouseY;
            return dx * dx + dy * dy <= 100; // check if the click is within the vertex's radius
        });
        if (vertex) {
            // Store the selected vertex and the starting position of the line
            selectedVertex = vertex;
            lineStartX = vertex.x;
            lineStartY = vertex.y;
            // Add mouse move and mouse up event listeners
            canvas.addEventListener("mousemove", handleMouseMove);
            canvas.addEventListener("mouseup", handleMouseUp);
        }
    }

Mouse Move

Mouse Move event is handled in the handleMouseMove() function.

  • The function essentially creates the line dragging effect when the user drags his mouse. The starting point is on the point the user clicked on, and the end point of the line follows the user's cursor.
    • This line can also be customized, such as changing its color or width.
// Function to handle the mouse move event
function handleMouseMove(e) {
    const canvas = e.target;
    const rect = canvas.getBoundingClientRect();
    const mouseX = e.clientX - rect.left;
    const mouseY = e.clientY - rect.top;
    // Update the line end position
    lineEndX = mouseX;
    lineEndY = mouseY;
    // Redraw the canvas
    drawGraph(graph);
    // Draw the temporary line from the selected vertex to the mouse position
    const ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.strokeStyle = "#FF0000";
    ctx.lineWidth = 2;
    ctx.moveTo(lineStartX, lineStartY);
    ctx.lineTo(lineEndX, lineEndY);
    ctx.stroke();
    ctx.closePath();
    }

Mouse Up

Mouse Up event is handled in the handleMouseUp() function.

  • This function creates the "snapping effect," where the line finally connects onto another vertex(point) on the graph if the mouse is released.
    • It is able to do this by detecting if the line is within 20 pixels of a point once the mouse is released.
      • If the line is within 20 pixels of a point, the line snaps onto the corresponding point with the addAdjacent functions(addAdjacent function is found in class Vertex).
    • This function also detects to see if all points are connected.
      • If all points are connected, the status is updated in the console, and the user is allowed to finish the game.
      • The total distance of all the lines formed are also calculated
        • The total distance is converted to miles when displaying it in HTML.
// Function to handle the mouse up event
function handleMouseUp(e) {
    const canvas = e.target;
    // Find the vertex that the user released the mouse on (if any)
    const vertex = graph.vertices.find((vertex) => {
        const dx = vertex.x - lineEndX;
        const dy = vertex.y - lineEndY;
        const distance = Math.sqrt(dx * dx + dy * dy);
        return distance <= 20; // check if the release point is within 20 pixels of the vertex
    });
    if (vertex && !vertex.connected) {
        // Connect the line to the snapped vertex
        selectedVertex.addAdjacent(vertex);
        vertex.addAdjacent(selectedVertex);
        // Set the vertices as connected
        selectedVertex.connected = true;
        vertex.connected = true;
        // Redraw the canvas with the updated graph and line connection
        drawGraph(graph);
        // Check if all vertices are connected
        allVerticesConnected = graph.checkAllVerticesConnected();
        console.log("All vertices connected:", allVerticesConnected);
        // allows user to finish if all points connected
        if(allVerticesConnected === true){
        finishButton.style.display = "block";
        }
        // Calculate and update the total distance
        const totalDistance = graph.calculateTotalDistance();
        totalDistanceDisplay.textContent = (totalDistance/54).toFixed(2);
        dummyTotalD = (totalDistance/54).toFixed(2);
    }
    // Reset the line positions and remove the event listeners
    lineStartX = null;
    lineStartY = null;
    lineEndX = null;
    lineEndY = null;
    selectedVertex = null;
    canvas.removeEventListener("mousemove", handleMouseMove);
    canvas.removeEventListener("mouseup", handleMouseUp);
    }

Extra Handler: Handling the Reset Button

  • This event handler handleResetButtonClick() responds when the reset button is clicked on. When the reset button is clicked, all lines on the graph are erased and the total distance of all lines is reset to 0.
    • In addition, the function that checks for connection of all vertices is set to false so that the user can continue to draw lines after a reset.
    • The finish button is also hidden to prevent the user from submitting an unfinished route.
// Function to handle the reset button click event
function handleResetButtonClick() {
    // Clear the canvas
    const canvas = document.getElementById("canvas");
    const ctx = canvas.getContext("2d");
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    // Reset all vertices
    for (const vertex of graph.vertices) {
        vertex.connected = false;
        vertex.adjacent = [];
    }
    // Reset the total distance
    document.getElementById("totalDistance").textContent = "0.00";
    // Redraw the empty canvas
    drawGraph(graph);
    // Reset the allVerticesConnected flag
    allVerticesConnected = graph.checkAllVerticesConnected();
    // hides finish button if lines are reset
    finishButton.style.display = "none";
    }

Utilizing Event Handlers

Event listeners are added in order to use these different event handlers. Multiple buttons and the canvas are assigned specific event listeners that call specific event handlers.

// Add event listeners
canvas.addEventListener("mousedown", handleMouseDown);
resetButton.addEventListener("click", handleResetButtonClick);
submitButton.addEventListener("click", handleResetButtonClick);

Page Transitions

  • We are now outside of function game() and will now explore the code for page transitions.
    • function gameScreen() has a parameter which can help indicate the status of the page(whether the user is playing, on the start screen, or on the end screen, etc.)
    • Different pages will appear and disappear corresponding to which button the user presses on.
      • If the Finish Game button is pressed, the heuristic graph is drawn onto the canvas.
      • In this place we added our scoring algorithm to be able to display the score of the user.
        • The scoring is in accordance to how far away the user is from the shortest distance possible. The closer the route is to the shortest route, the higher the score.
        • The list of locations are also displayed using a for loop, and are shown on the form.
// Initially hides end page and game page and finish button
endPage.style.display = "none";
gamePage.style.display = "none";
finishButton.style.display = "none";
finishForm.style.display = "none";
menuPage.style.display = "none";
// Function switches screen based on status parameter
function gameScreen(status){
    if(status === 1){
    startPage.style.display = "none";
    menuPage.style.display = "block";
    }
    if(status === 2){
    finishForm.style.display = "block";
    resetButton.style.display = "none";
    finishButton.style.display = "none";
    // Draw the shortest path on the canvas
    drawShortestPath(heuristic);
    // Calculates the score
    let intShortestDistance=parseInt(shortestDistanceResult.innerHTML);
    let intUserDistance=parseInt(totalDistanceDisplay.innerHTML);
    let score = (Math.pow(2,vertices.length)*1000*Math.pow(Math.E,(2*(Math.log(intUserDistance/intShortestDistance))))).toFixed(2);
    // Invalidates score in case distance is less than shortest distance. Displays score if otherwise
    if(intShortestDistance>intUserDistance){
        totalDistanceDisplay.textContent = "**error**";
        scoreDisplay.textContent = "NA";
    } else{
        // Adds bonus score if user chooses more points(since more points means higher difficulty)
        if(vertices.length > 5){
            score = (score*(1+0.12*(vertices.length-5))).toFixed(2);
        }
        scoreDisplay.textContent = score.toString();
        dummyScore = score;
    }
    // for loop to display locations on the form
    locationDisplay = "";
    for(let i=0; i<(locationNames.length-1); i++){
        locationDisplay += locationNames[i] + ", ";
    }
    locationDisplay += locationNames[locationNames.length-1];
    locationList.textContent = locationDisplay;
    }
    if(status === 3){
    window.location.reload();
    }
}

Page Transitions in HTML

  • We will now show how page transitions are created to ensure a smooth user experience.
    • Multiple divs are used to separate the start, playing, menu, and end screens.
    • Liquid is used to utilize the menu selection page and functionality(which is in a separate file). Liquid makes the code more clear with less clutter. It also reduces the hassle of copying and pasting and having to reformat the code.
<div id="start-page">
    <div class="button-container">
    <button class="gen-button" onclick="gameScreen(1)" id="start-button">Start Game</button>
    </div>
  </div>
  <div id="menu-selection-page">
    <h2 style="color:white; text-align: center;">Please select 2-10 locations you would like to visit.</h2>
    <p style="color:white; text-align: center;">Selection of locations is limited to 10 locations.</p>
    <!-- Use liquid to incorporate menu code for easier access, removed so that fastpages will not have an error -->
    <!-- ***liquid goes here*** -->
  </div>
  <div id="end-page">
    <h1>Thank you for playing!</h1>
    <p>If you would like to play another round, please click the button below.</p>
    <div class="button-container">
      <button class="gen-button" onclick="gameScreen(3)">Return to Game Page</button>
    </div>
    <h3>If you would like to return to the home page, please click <span id="linked-gametohome"><a href="/VSCode-Fastpages/index">here</a></span>.</h3>
  </div>
</head>
<body>
    <div id="finish-form">
      <h3 style="color:white;">Game over, please record your score!</h3>
      <p style="color:white;">The shortest route is shown on the map with the red lines</p>
      <form action="javascript:userCreate()">
        <p><label>
            Username:
            <input type="text" name="username" id="username" placeholder="Enter username here" required>
        </label></p>
        <p><label>
            Total Distance of your route: <span id="totalDistance">0.00</span> miles
        </label></p>
        <p><label>
            Total Distance of shortest route: <span id="totalDistanceClosest">0.00</span> miles
        </label></p>
        <p><label>
            Calculated score: <span id="scoring">0</span>
        </label></p>
        <p><label>
            Locations visited: <span id="locationList">NA</span>
        </label></p>
        <p>
        <!-- Popup message on button click -->
            <button onclick="alert('Your score has been posted!')" id="form-submit-button">Submit</button>
        </p>
      </form>
    </div>
  <div id="game-page">
    <div class="button-container">
      <button id="game-finish-button" class="gen-button" onclick="gameScreen(2)">Finish Game</button>
      <button id="resetButton" class="gen-button">Reset</button>
    </div>
    <canvas id="canvas" width="1072" height="829"></canvas>
  </div>

POST Request

  • At the end of a game, the user is prompted to submit their data to a database. This is done through the POST request code.
    • Dummy variables for score, total distance, and calculated distance are created in order to prevent conflicts with the HTML strings from each element with the corresponding id.
      • These are automatic inputs, and the user does not need to input anything for these categories.
    • The list locationNames is added into body as it is without the need for input from the user.
    • Only the username requires input from the user in the form.
// prepare URL's to allow easy switch from deployment and localhost
// const url = "http://localhost:8086/api/leaderboardUser";
const url = "https://school.aipad-techs.com/api/leaderboardUser/api/leaderboardUser";
const createGame = url + '/addscore';

// Function creates POST request
function userCreate(){
        // Get the data
const body = {
    name: document.getElementById("username").value,
    score: Math.round(dummyScore),
    locations: locationNames,
    tot_distance: Math.round(dummyTotalD),
    calc_distance: Math.round(dummyCalcD)
};
console.log(body);
const requestOptions = {
    method: 'POST',
    body: JSON.stringify(body),
    mode: 'cors',
    cache: 'default',
    //credentials: 'include',
    headers: {
        "content-type": "application/json",
        'Authorization': 'Bearer my-token',
    },
};
// URL for Create API
// Fetch API call to the database to create a new user
fetch(createGame, requestOptions)
    .then(response => {
    // trap error response from Web API
    if (response.status !== 200) {
        const errorMsg = 'Database create error: ' + response.status;
        console.log(errorMsg);
        return;
    }
    // response contains valid result
    response.json().then(data => {
        console.log(data);
    })
})
    finishForm.style.display = "none";
    gamePage.style.display = "none";
    endPage.style.display = "block";
}

Styling

Additional styling is used to make the website look better, as well as adding the map picture onto the canvas.

#title-thing{
      text-align: center;
      color: white;
    }
    .button-container{
      width: fit-content;
      margin: 0 auto;
    }
    .gen-button{
      display: block;
      width: 200px;
      padding: 15px 0;
      text-align: center;
      margin: 20px 10px;
      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;
    }
    .gen-button:hover{
      background-color: #009614;
    }
    #canvas{
      border: 1px solid #000000;
      background-image: url('SDmap.png');
      background-position: center;
    }
    #linked-gametohome{
      background-color: yellow;
    }
    #end-page{
      text-align: center;
      color: white;
    }
    #game-page{
      text-align: center;
      color: white;
    }
    #finish-form{
      text-align: center;
      background-color: transparent;
    }

    form {
      background: transparent; /* Adjust the alpha value (0.5) to control the transparency */
    }

    label {
      display: block;
      color: white;
      font-family: Helvetica, arial;
    }

    p{
      width: 100%;
    }

    #username{
      background: transparent;
      border: none;
      outline: auto;
      font-size: 1em;
      padding:0 35px 0 5px;
      color: white;
    }

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

    #form-submit-button:hover{
      background-color: #009614;
    }

    .banner{
    width: 100%;
    height: 200% !important;
    background-image: linear-gradient(rgba(0,0,0,0.75), rgba(0,0,0,0.75)),url(homepg.jpg);
    background-size: cover;
    background-position: center !important ;
    }