Takeaways

  • Event handling in the browser
  • Manipulating the Document Object Model (DOM)
  • Client-side asynchronous HTTP requests
  • Using third-party client-side libraries

Relevant Resources

Delivery Track-inator

Norm is enamored with his new friend. They’re set to be married in the Spring. Dr. Doofenshmirtz has already placed reservations at Gunther Goat Cheese’s1 for the reception.

Our Story Continues

You realize after some time that you’ve been staring at the wall for quite a while2. As you slowly return to reality, you hear phones, a lot of phones, ringing in the distance. You approach your office door and attempt to figure out what’s happening.

Doofenshmirtz is on the phone. “YES, MA’AM!” you hear him say. He’s holding his hand over his other ear, so that he can here the person on the line. “We can rent the stress-inator until the beginning of December. Then there’s another reservation.” From where you’re standing, you can hear maniacal cackling from the receiver. “Well… it was designed to be used on graduate students, but I suppose you could stress out undergraduates with it, too.”

Minutes later, Doofenshmirtz approaches you. “This is incredible! Kevin was doing some outreach with his alma mater in Missouri, and now we’re overwhelmed with business! Apparently, this tiny engineering university has a huge demand for some very specific equipment3, and they want to rent every one of our inators! They told me it was for a Halloween thing, but I have my doubts4.”

“Anyway. We’re actually making money now, so I’m not asking questions5. Now we just need a way to keep an eye on our delivery guys…”

Your Task

Your task is to develop an interactive web page, so that Dr. Doofenshmirtz can monitor his -inator delivery service. Note that this is a client-side application. You are implementing logic in JavaScript which will run in a user’s browser. All server-side logic has been implemented, and a server6 is running at https://delivery-trackinator.appspot.com.

For this assignment, you are to do the following:

  • Finish implementing the Delivery Track-inator web page such that its behavior mimics that of the reference implementation.

Refer to this assignment’s rubric for further description of point values for completed tasks.

Application Description

You can simply use your browser 7 to open the index.html file included in your repository.

There is a helper script to install and run eslint, so that you can check your code’s style.

Remote Data

Your app will pull data from https://delivery-trackinator.appspot.com and display it in a friendly way. There is only one endpoint that you should be concerned about working with:

  • https://delivery-trackinator.appspot.com/position.json gives you the current positions of every delivery-minion
    • The positions are given to you as a JSON array.
    • Each element in the array is a JSON object with the following fields:
      • Lat: The minion’s latitude
      • Long: The minion’s longitude
      • Inator: The name of the -inator that is being delivered
      • Disposition: The current mood of the minion
        • The disposition ranges from 0 to 5.
        • A disposition of 0 is the least happy, while 5 is the most happy.
    • Example:

      [
        {
          "Long": -91.77355134921855,
          "Lat": 37.95290096855606,
          "Inator": "dodo-bird-incubatorinator",
          "Disposition": 3
        },
        {
          "Long": -91.77346904639805,
          "Lat": 37.9552281,
          "Inator": "boring-inator",
          "Disposition": 5
        },
        {
          "Long": -91.77368557983561,
          "Lat": 37.954959524594535,
          "Inator": "home-inator",
          "Disposition": 0
        },
        {
          "Long": -91.77397898975875,
          "Lat": 37.95246071251113,
          "Inator": "likely-inator",
          "Disposition": 2
        },
        {
          "Long": -91.77355289262732,
          "Lat": 37.95286557379505,
          "Inator": "blow-itself-up-inator",
          "Disposition": 1
        }
      ]
      

Since everyone (including the demo) refers to the same data source, you can compare your implementation to the sample. If your implementation shows the same data as the sample, that is a good sign.

Program Design

Your JavaScript program (tracker.js) is loaded by a browser when it loads index.html. Your implementation of tracker.js will require leaflet.js, jQuery, and the browser’s API. leaflet.js, jQuery, and bootstrap.js are all included for you in index.html. There is no reason to edit any file in the repository other than tracker.js.

In other words, you’re good to go - start coding.

You will be editing js/tracker.js and testing it using just the JavaScript engine in your browser. Do not modify index.html. Refer to the examples on leaflet.js’s website for an idea of how to work with it.

Error Handling and Input Validation

There aren’t really any error cases to handle. If your app cannot reach https://delivery-trackinator.appspot.com for some reason, don’t sweat it. Periodically, network lag may result in slow responses. If the minion pins hesitate, it’s no big deal.

Now… if the server responses are so delayed that it’s affecting your ability to do work, you should email your instructor. There’s a chance that the machine it’s running on will become bogged down. That’s a fixable problem.

Working on the Program

For this assignment, we will be running your app in Firefox on a Linux machine. You are welcome to develop your app with your favorite browser, but:

  • We will be grading your assignment using Firefox on a Linux machine.
  • You should check that your app works in Firefox on the campus Linux machines.

Whenever you make a change to your tracker.js, you will need to refresh your browser to pull in the new changes. If it appears as though your page is not updating, use your browser’s developer tools to find out if it’s pulling your changes to tracker.js. It may be necessary to tell your browser to disable caching temporarily. That process varies from browser to browser. Additionally, if you’re not seeing your changes take effect, it may be because an error occurred, so always check the developer console for error output.

Running it

If you’re sitting at a campus Linux machine, you can open your app like this:

$ firefox index.html

If you’re working remotely (through PuTTY or whatever), you can forward your X session over SSH and use the campus installation of Firefox from home. You’re on your own to figure how to X forward, though. Maybe get it working on your own, then check it on a campus machine before you submit.

You can also pull up the app on a Windows machine and work on it there.

Automated Tests

There are no automated tests provided to you for this assignment. Ensure that your code behaves in the same manner as the reference implementation.

Proper JavaScript Style

ESLint is a code style checker and linter that we’ve configured to check your JavaScript code style. You should use it to your advantage to check the style of your code.

NOTE: ESLint will let some funny8 code slide. You should use ESLint to check your style, but you should also make an effort to make you code look nice. Just because ESLint says it passes doesn’t mean that it looks nice.

We’ve included a helper script (eslint.sh) in the starter code to make it a little easier to setup and invoke eslint. The script will perform some sanity checks to ensure that Node.js and NPM are installed. Then, it will install the correct version of eslint if it needs to. You can learn more about eslint.sh by reading its annotated source.

# This is install the correct version of ESLint and invoke it for us.
$ ./eslint.sh js/tracker.js

Further Details

Approaching this Assignment

You should tackle this assignment as follows:

  • Read this entire posting and docs (you’ll likely do this more than once).
  • Clone the code.
  • Open index.html in your browser (preferably Firefox or Chrome) to see what it looks like right now.
  • Implement tracker.js, so that your app behaves in the same way as the reference implementation. There are no automated unit tests this time around.
  • Check your style with ESLint.
  • Do one final commit/push to GitLab.
  • ENSURE THAT THE CODE LOOKS RIGHT IN GITLAB.

Important Notes

  • Make sure your app works in Firefox on a campus Linux machine. We will use a similar environment to grade it.
  • All of your changes will be to js/tracker.js. There is no reason to change index.html or any other file.
  • eslint.sh installs the right version of ESLint. However, the version of Node.js that’s already on the campus Linux machines is too old. You’ll need to run setup.sh to set up Node.js. Make sure to check your style on a campus Linux machine prior to submission.
  • Do not go nuts with jQuery. You only need it for $.getJSON(). Make sure you’re abiding by expectations in the rubric.

Point Value

This assignment is worth 100 points. It will be graded according to the following rubric:

Feature Points Possible Mostly or completely incorrect (0% of points possible) Needs improvement (50% of points possible) Adequate, but still some deficiencies (75% of points possible) Mostly or completely correct (100% of points possible)
Unit Testing          
Student passes instructor automated UI tests 10 -10 -5 -3 0
Implementation          
Demonstrates understanding of getElementById() 10 -10 -5 -3 0
Demonstrates understanding of addEventListener() 10 -10 -5 -3 0
Demonstrates understanding of $.getJSON() 10 -10 -5 -3 0
Demonstrates understanding of periodic function invocation using setTimeout() 10 -10 -5 -3 0
Demonstrates understanding of leaflet.js 10 -10 -5 -3 0
Functionality          
Program runs without runtime/syntax errors 10 -10 0
Behavior matches sample implementation 10 -10 -5 -3 0
Style          
ESLint outputs no suggestions for improvement for tracker.js 10 -10 0
Code Review (well-documented, implementation is straightforward, etc.) 10 -10 -5 -3 0
Points possible 100        

Each cell indicates how many points out of the available points will be awarded for that feature (row) and assessment level (column).

Cells marked -- cannot be achieved.

Submission

Deadline

  • 11:59:59 pm CDT – Monday, October 30, 2017

Submission Procedure

Refer to the assignment submission page on the course website for details on submitting your code to GitLab.

Grading Procedure

When we grade your assignment, we will do the following (roughly).

# Check your style
$ ./eslint.sh js/tracker.js

# Open your app on a Linux box.
$ firefox index.html

# Then we're going to try it out.

Hints and Tips

  • tracker.js can be written, fully documented, in 100 lines of JavaScript. You can use more, but don’t overthink your implementation.
  • Use OpenStreetMaps (osm.org) to setup your leaflet map. Don’t sign up for MapBox or something like that.
  • Use the constants that have been provided to you.
  • Make sure you include the OpenStreetMaps attribution. Give credit where credit is due.
  • Use $.getJSON for making requests for remote data.
  • Although your JavaScript code will manipulate the loaded page, you should not edit index.html yourself. Use the id attributes in the HTML and getElementById to find relevant elements and work with them.
  • The sample…
    • requests a new position 500 milliseconds after receiving its last position.
    • allows a maximum zoom of 18.
    • has a default zoom of 16 for the S&T area.
    • scales the minion pins to 31px by 48px.
    • anchors the minion pins at (15px, 48px).
    • anchors popups for minion pins at (0px, -48px) (relative to the pin anchor).
  • Each minion’s Disposition ranges from 0 to 5. Its marker icon should match its disposition (images/0.png through images/5.png)
  • The date is formatted as an ISO 8601 string. You can use this method of the Date object to format your time appropriately.

FAQ

Why are we supposed to use setTimeout()? Wouldn’t setInterval() be a better choice?

First off, I want to see that you are capable of solving the problem using setTimeout.

Secondly, we’re performing a network operation, so there’s a chance that we could experience a delay in receiving responses from the remote web server. By using setTimeout() instead of setInterval(), we can postpone starting the next timer until we’ve actually heard back from the server.

setInterval(), on the other hand, would continue submitting requests every 500ms, regardless of how quickly the server can respond. If the network is slow, we may end up with a bunch of pending requests, which really doesn’t help us out.


How do I know when a delivery has been completed?

Here are some facts that may be helpful:

  • Every minion can be uniquely identified by what it’s delivering (i.e., the Inator field of each object from position.json).
    • In other words, no two minions will be walking around with the same inator at the same time.
    • In other other words, position.json will never ever show two minions carrying the same inator.
  • Whenever one delivery is completed, another delivery begins.
    • The minions’ labor union limits DEInc to 5 concurrent deliveries.
    • If delivery for inator A completes, the next delivery to begin is guaranteed not to be A.
      • For example, if soupinator delivery completes, the next delivery to begin cannot be the soupinator.

Consider these two updates:

// The one on the left: received 12:05 PM                 // The one on the right: received 12:06 PM
[                                                         [
  {                                                         {
    "Long": -91.77357272449058,                               "Long": -91.77352221316632,
    "Lat": 37.954357154060304,                                "Lat": 37.953720972423675,
    "Inator": "if-a-tree-fell-in-the-forest-inator",          "Inator": "if-a-tree-fell-in-the-forest-inator",
    "Disposition": 4                                          "Disposition": 4
  },                                                        },
  {                                                         {
    "Long": -91.77379653007786,                               "Long": -91.7735495792724,
    "Lat": 37.95231321771992,                                 "Lat": 37.95294155846459,
    "Inator": "schmaltz-inator",                              "Inator": "schmaltz-inator",
    "Disposition": 0                                          "Disposition": 0
  },                                                        },
  {                                                         {
    "Long": -91.77479461584265,                               "Long": -91.77366246894366,
    "Lat": 37.95163553851054,                                 "Lat": 37.95231929077624,
    "Inator": "coolinator",                                   "Inator": "juice-inator",
    "Disposition": 1                                          "Disposition": 4
  },                                                        },
  {                                                         {
    "Long": -91.77350000106705,                               "Long": -91.77413787582556,
    "Lat": 37.9552281,                                        "Lat": 37.9551160202126,
    "Inator": "back-story-inator",                            "Inator": "underwear-inator",
    "Disposition": 3                                          "Disposition": 1
  },                                                        },
  {                                                         {
    "Long": -91.7744715518072,                                "Long": -91.77356682204183,
    "Lat": 37.95246493880621,                                 "Lat": 37.95254613263035,
    "Inator": "magnifinator",                                 "Inator": "magnifinator",
    "Disposition": 2                                          "Disposition": 2
  }                                                         }
]                                                         ]

The one on the left and the one on the right were received a minute apart. As shown, the if-a-tree-fell-in-the-forest-inator, schmaltz-inator, and magnifinator were in transit at 12:05, and they’re still in transit at 12:06. Our app should already have markers for those minions, so when we receive the 12:06 update, all we need to do is update their locations on the map.

The coolinator and the back-story-inator are present at 12:05, but they are not present at 12:06. This implies that the deliveries for these two inators have completed. When we receive the 12:06 update, we need to remove the markers for the minions who were delivering those inators.

Finally, the underwear-inator and juice-inator were not present at 12:05, but they are present at 12:06. This implies that these two inators have begun delivery. When we receive the 12:06 update, we need to add markers for those minions to the map.

Note that your app should retrieve updates every half second. This example considers minute-apart updates for the sake of clarity.

  1. “The goat-cheesiest place in all of Druselstein!” 

  2. As they say, “Time in front of a keyboard does not equate to time spent actually working”. 

  3. For “research”, obviously. 

  4. No one books the make-students-cry-inator for a whole month for a “Halloween thing”. 

  5. Don’t do this in real life. Don’t permit evil for the sake of turning a profit. 

  6. Everyone will use the same server. 

  7. You can develop with whatever browser you want, but make sure it works in Firefox on a campus Linux machine before you submit. 

  8. Funny as in “bad”, not funny as in “haha”. Goofy looking, silly style.