JavaScript and Jupyter references

JavaScript is the most important language you need to learn as a frontend developer. Jupyter Notebooks is a convenient way to learn the language without the overhead of creating a full Website. Jupyter Notebooks had ChatGPT plugins to assist with design and troubleshooting problems. This Notebook has colors on HTML pages that were designed with a dark mode background.

%%js

// Class representing a Formula One driver
class F1Driver {
  // Constructor to initialize driver data
  constructor(name, team, number, nationality) {
    this.name = name;
    this.team = team;
    this.number = number;
    this.nationality = nationality;
  }

  // Method to get the driver's name
  getName() {
    return this.name;
  }

  // Method to get the driver's team
  getTeam() {
    return this.team;
  }

  // Method to get the driver's number
  getNumber() {
    return this.number;
  }

  // Method to get the driver's nationality
  getNationality() {
    return this.nationality;
  }

  // Method to update the driver's team
  setTeam(newTeam) {
    this.team = newTeam;
  }
}

// Example usage of the F1Driver class
const driver = new F1Driver("Lewis Hamilton", "Mercedes", 44, "British");
console.log(driver.getName()); // Output: Lewis Hamilton
console.log(driver.getTeam()); // Output: Mercedes
console.log(driver.getNumber()); // Output: 44
console.log(driver.getNationality()); // Output: British

driver.setTeam("Red Bull Racing");
console.log(driver.getTeam()); // Output: Red Bull Racing
%%html
<div id="table-container">

</div>

<script>
// Class representing a Formula One driver
class F1Driver {
  // Constructor to initialize driver data
  constructor(name, team, number, nationality) {
    this.name = name;
    this.team = team;
    this.number = number;
    this.nationality = nationality;
  }

  // Method to get the driver's name
  getName() {
    return this.name;
  }

  // Method to get the driver's team
  getTeam() {
    return this.team;
  }

  // Method to get the driver's number
  getNumber() {
    return this.number;
  }

  // Method to get the driver's nationality
  getNationality() {
    return this.nationality;
  }

  // Method to update the driver's team
  setTeam(newTeam) {
    this.team = newTeam;
  }
}

// Function to fetch data from the API
async function fetchData() {
  const url = 'https://f1-live-motorsport-data.p.rapidapi.com/drivers/2020';
  const options = {
    method: 'GET',
    headers: {
      'X-RapidAPI-Key': '9275b62a1fmsh3b832340dafb492p1abc77jsn58ef554feee6',
      'X-RapidAPI-Host': 'f1-live-motorsport-data.p.rapidapi.com'
    }
  };

  try {
    const response = await fetch(url, options);
    const result = await response.json();
    console.log(result["results"])
    return result["results"]
  } catch (error) {
    console.error(error);
  }
}

// Function to create driver objects from the fetched data
async function createDriverObjects() {
  const data = await fetchData();

  if (data && data.length > 0) {
    let drivers = [];

    // Iterate over the data and create driver objects
    for (const item of data) {
      const driver = new F1Driver(
        item["driver_name"],
        item["team_name"],
        item["driver_id"],
        item["nationality"],
      );
      drivers.push(driver);
    }

    return drivers;
  }
}

// Function to generate an HTML table from the driver objects
async function generateTable() {
  const drivers = await createDriverObjects();

  if (drivers && drivers.length > 0) {
    const table = document.createElement("table");

    // Create table header
    const headerRow = table.insertRow();
    const headers = ["Name", "Team", "Number", "Nationality"];

    // Create sorting buttons and column headers
    for (const header of headers) {
      const th = document.createElement("th");
      const button = document.createElement("button");
      button.textContent = header;
      button.addEventListener("click", sortTable.bind(null, header.toLowerCase()));
      th.appendChild(button);
      headerRow.appendChild(th);
    }

    // Create table rows with driver data
    for (const driver of drivers) {
      const row = table.insertRow();
      const rowData = [
        driver.getName(),
        driver.getTeam(),
        driver.getNumber(),
        driver.getNationality(),
      ];
      for (const data of rowData) {
        const cell = row.insertCell();
        cell.textContent = data;
      }
    }

    // Append the table to a container element
    const container = document.getElementById("table-container");
    container.appendChild(table);
  }
}

// Function to sort the table based on the selected column
function sortTable(column) {
  const table = document.querySelector("table");
  const rows = Array.from(table.rows).slice(1); // Exclude the header row
  const columnIndex = ["name", "team", "number", "nationality"].indexOf(column);

  // Sort the rows based on the selected column
  rows.sort((a, b) => {
    const aValue = a.cells[columnIndex].textContent;
    const bValue = b.cells[columnIndex].textContent;
    return aValue.localeCompare(bValue, undefined, { numeric: true, sensitivity: "base" });
  });

  // Remove existing rows from the table
  while (table.rows.length > 1) {
    table.deleteRow(1);
  }

  // Reinsert sorted rows into the table
  for (const row of rows) {
    table.appendChild(row);
  }
}

// Example usage
generateTable();
</script>
%%html
<body>

  <div style="display: flex; align-items: center; justify-content: center; flex-direction: column;">

    <canvas id="container" width="200" height="200">
    </canvas>

    <h1 id="pressure-header">
      P
    </h1>
    <input type="range" min="1" max="100" value="50" class="slider" id="pressure">

    <h1 id="volume-header">
      V
    </h1>
    <input type="range" min="1" max="100" value="50" class="slider" id="volume">

    <h1 id="collisions">
      # of Border Collisions: 
    </h1>

  </div>

  <style>
    #container {
      background-color: black;
      border-style: solid;
      border-width: 5px;
      border-color: white;
    }

    .slider {
      width: 500px;
      height: 25px;
      opacity: 0.7;
    }
  </style>

  <script>
    let container = document.getElementById("container")
    let pressure = document.getElementById("pressure")
    let volume = document.getElementById("volume")
    let collisions = document.getElementById("volume")
    let context = container.getContext("2d")

    let borderCollisions = 0

    let scaling = 200

    let particles = [],
      radius = 5,
      boundaryX = 200,
      boundaryY = 200,
      numberOfParticles = 10

    init()
    
    volume.oninput = () => { calculatePressure() }
    pressure.oninput = () => { calculateVolume() }
    
    // calculate the new volume & scale
    function calculateVolume() {
      let newVolume = (50 * 50) / pressure.value
      volume.value = newVolume

      scale()
    }

    // calculate the new pressure & scale
    function calculatePressure() {
      let newPressure = (50 * 50) / volume.value
      pressure.value = newPressure

      scale()
    }

    // find the scale factor & set the values
    function scale() {
      scaling = 200*volume.value/50

      context.clearRect(0, 0, 200, 200)

      container.width = scaling
      container.height = scaling

      boundaryX = scaling
      boundaryY = scaling
    }

    function init() {
      for (let i = 0; i < numberOfParticles; i++) {
        createParticle()
      }

      animate()
    }

    function createParticle() {
      let particle = {}, vx2, vy2
      particle.x = Math.random() * boundaryX
      particle.y = Math.random() * boundaryY

      particle.vx = 4 * Math.random()

      particle.vy = 4 * Math.random()

      particles.push(particle)
    }

    function drawParticle(x, y) {
      context.beginPath()
      context.arc(x, y, radius, 0, 2 * Math.PI, false)
      context.fillStyle = 'red'
      context.fill()
    }

    function resetVelocity(particle, axis) {
      // invert x or y velocity
      if (axis == 'x') {
        particle.vx = -1 * particle.vx
      } else {
        particle.vy = -1 * particle.vy
      }

      borderCollisions++
    }

    function draw() {
      for (let i = 0, l = particles.length; i < l; i++) {

        let particle = particles[i]
        
        // change particle position
        particle.x += particle.vx
        particle.y += particle.vy

        drawParticle(particle.x, particle.y)

        // reset velocity in the instance of a boundary contact
        if (particle.x < 0 + radius) {
          resetVelocity(particle, 'x')
        } else if (particle.x > boundaryX - radius) {
          resetVelocity(particle, 'x')
        } else if (particle.y < 0 + radius) {
          resetVelocity(particle, 'y')
        } else if (particle.y > boundaryY - radius) {
          resetVelocity(particle, 'y')
        }
      }
    }

    function animate() {
      context.clearRect(0, 0, scaling, scaling)
      draw()
      requestAnimationFrame(animate)
    }

    function update() {
      document.getElementById("pressure-header").innerHTML = "P1=50 | P2=" + pressure.value
      document.getElementById("volume-header").innerHTML = "V1=50 | V2=" + volume.value
      document.getElementById("collisions").innerHTML = "# of Border Collisions: " + borderCollisions
    }

    setInterval(update, 500)

  </script>

</body>

P

V

# of Border Collisions:

Hacks

One key to these hacks is to build confidence with me going into final grade, I would like to see each student adapt this frontend work in their final project. Second key is the finished work can serve as review for the course, notes for the future in relationship to frontend.

  • Adapt this tutorial to your own work
  • Consider what you need to work on to be stronger developer
  • Show something creative or unique, no cloning
  • Be ready to talk to Teacher for 5 to 10 minutes. Individually!!!
  • Show in Jupyter Notebook during discussion, show Theme and ChatGPT
  • Have a runtime final in GithHub Pages (or Fastpage)