Friday, January 22, 2021

Hockey Experience Project - Part 3

 If you just happened to land here on this page by accident or without reading part 1 or 2, this multi-part blog is how to bring home an NHL experience to your living room, complete with goal light, horn, song, etc.  I would recommend going back and reading part 1 and 2 to get fully up-to-speed with where we are and why we chose to do things in this manner.


Carolina GOOOAAALLL!

So hopefully somewhere between part 2 and today you did a little research and obtained the mp3s for the goal horn, song, and maybe a few logos. I won't be uploading or sharing my files due to possible copyright issues, I don't own the rights to those so I'll only be using them for my personal at home enjoyment.


I did find a pretty cool hockey rink image that is freely available that would be perfect to use as the main background for our webapp. 


We will save this to our project as hockey_rink.jpg in the static/media folder along with any other media files for goal horns etc.  Since I want to ensure the goal song is played after the goal horn, I combined the two together into a single mp3, that way there are less media files to worry about and I'm guaranteed the effects I want. Obviously, I could have kept them separate and just queued them one after another, but I like the simple approach better.

Our project structure should now look like this.




Time to get on that ice and make something happen!

So at this point we have a functioning webapp, although it is kinda lame and boring at this point and we have our media files. So let's add our background image and some functionality to the page.

If you were wondering why we created an empty libs and templates folder, well now we shall add some files to them. The libs folder will hold any css (Cascading Style Sheets) and js (JavaScript) we write. This will make maintaining the webpage much easier and also it is best practice to not just throw everything in one file.

If you are not familiar, Flask uses the Jinja templating language which will allow us to create html pages with certain data as variables then when we render the page we can pass the values of those variables. Technically Jinja will provide so much more to us but since this is a simple webapp for our own personal use and won't be exposed to the Internet there isn't really a need to cover it all in this blog.

Why is this useful to us?

Let's say we want to add a banner at the top of the page that should display the teams playing, such as: "Hurricanes vs Red Wings".  We could add this directly to the page in html like such:

<h1>Hurricanes vs Red Wings</h1>

The problem with this approach is we will have to manually update the html everytime there is a new game and that can be a pain and if you are like me you will eventually forget to do it before game time, you'll be rushed to change it and probably make a mistake and miss the first goal of the game.

With jinja we can simply add the team names as variables from the APIs we explored in part 1. If you skipped part 1 this may be a good time to go review.  So now our html with jinja would look like:

<h1>{{ away_team }} at {{ home_team }}</h1>

We could do this with any bit of data we want to change dynamically on the page, team logos, scores, power play time, empty goal status, etc.  We could even use jinja to control the design of our page by using jinja in our css class names for the html, tags this would allow us to give the page a 'theme' for the home team or just our favorite team(s). If you follow more than one team this may be the approach you want to go with. I'll be using this approach in my examples so when I want to watch Marc-Andre Fleury play I can give the page a Vegas Golden Knights theme.


Every good website always has a default 'index.html' page that is usually used for the homepage. For our use that will pretty much be the only page we need. We can always add more later if we have a need to. So let's add a new page called index.html under templates and add the following markup to the file.

<!DOCTYPE html>
  <head>
    <title>{{ title }}</title>
    <link rel="icon" href={{ url_for('static', 
          filename='media/Carolina_Hurricanes.svg') }}>
    <link rel="stylesheet" href={{ url_for('static', 
          filename='libs/css/site.css') }}>
  </head>
  <body>
    <div class="header"></div>
    <div class="main__content">
      <form action="/" method="POST">
        <button type="submit" value="" class="btn__goal">
          <img src={{ url_for('static', 
  		filename='media/Carolina_Hurricanes.svg') }}>
        </button>
      </form>
     </div>
  </body>

Our html is pretty basic as you can see from above.  We will add more to it later to give it a better team theme.

The main important part in our markup above is the form section.

    <form action="/" method="POST">
       <button type="submit" value="" class="btn__goal">
          <img src={{ url_for('static', 
  		filename='media/Carolina_Hurricanes.svg') }}>
       </button>
    </form>
Our form action "/" tells our application to go to the root of the website, which is the index page. So essentially it will just refresh itself when the form is sent to the backend server. The HTTP method we will use is a POST method, this is what the web app will look for to determine if it should kick off our 'experience'.

You'll notice I've used an image for my button, in this case I'm using a team logo, so instead of  a cheezy "Click me" button we just touch the team logo to make magic happen.

Now that we have our index.html template completed, for now, we will want to add some design to it.  In the head section you'll notice I've already linked our main css (Cascading Style Sheets) file so lets go ahead and create that file and add some styles.

Under the directory 'libs' we will create a new subdirectory called "css", this css folder is where we will put all our styles for our web app.  Go ahead and create our main css file called 'site.css' and add the following to that file.


body, html {
height: 100%;
   margin: 0;
}
.main__content {
    background-color: white;
    background-image: url('../../media/hockey_rink.png');
    background-repeat: no-repeat;
    background-size: cover; height: 100%;
}
.header {
    height:10%; margin: 0;
    background-color: rgba(204, 0, 0);
}
form {
    position: fixed;
    top: 60%; left: 50%;
    transform: translate(-50%, -50%);
}
.btn__goal {
   background-color:rgba(255, 255, 255, 0.1); border: none;
}
In the above css we set the background color of the header section to one of the team's color of red, position the form that contains our button to be in the center of the screen, and add our hockey rink image as the background to the page. So when it is all put together what does the page look like?

 

Originally I thought about using a puck as the button icon, thought it would be more fitting but the logo is a nice size for someone to lean over and tap and still looks pretty good in my opinion.

Ok, so we have a basic page layout and some styling so that it is a little less boring, now we just need to add a bit more code to our main application file so that when the button is pushed and the post request is made we can tell the server to do something.

For this we will add the following code in our app.py file.

    from flask import Flask, render_template, request
    
    app = Flask(__name__)
    templateData = {
       'title': "Carolina Hurricanes"
    }
    
    @app.route('/', methods=['GET','POST'])
    def index():
        if request.method == 'POST':
           print("Play Horn!")    
        return render_template("index.html", **templateData)
    
    if __name__ == '__main__':
        app.run(debug=True, host='0.0.0.0')
    

Most of this should look familiar, we added the template data which is a json object to store the key: value pairs our template will render. Right now we are only setting the title of the page.
templateData = {
    'title': "Carolina Hurricanes"
}

We also modified the route to allow both GET and POST requests. 

To prevent the experience from kicking off everytime the page is loaded we added an if statement to check the request object's method, if the method was post then we know someone touched the logo aka button on the main page. To test this we will just print out "Play Horn!" anytime the button is pushed.

if request.method == 'POST':
   print("Play Horn!")

Once we save everything and run our app, if you forgot how from the command line or our terminal type in the following command:

python3 app.py
Now we should see our server come up, go to the server's ip and port 5000 in your browser and you should now see the page that looks similar to the one above, clicking the logo should also print the "Play Horn!" message to our console.

If your having issues or want to double-check your code you can go to my repo and pull or review the code for this section from my github repo.

In the next section Part 4 of our hockey experience will probably be the last section of this series where we put the rest of the solution together.

No comments:

Post a Comment