This is a quick tutorial. It's a 2 parter, the first part explaining the concept, how I got the data, and other misc things. The second part is going to be technical. I'll walk you through launching your own PDXLiveBus, and then building it from scratch. Hopefully this can help you implemnet one for your own city.
#The Concept The concept was actually built from SFLiveBus and I just happened to see it and said I could do that. It also helped that I took TriMet and was a little frustrated in that the bus was always late and all I ever wanted to know was where it was at.
#The Vehicles TLDR; Buses send updates via shortwave radio roughly every 30 seconds of how far they've driven, not GPS coordinates. Trains are tracked as they cross track sgements. It's sort of accurate and updates kinda frequently.
I had a COMPLETE misunderstanding of how GPS data is generated and how vehicle positioning actually works with TriMet and in general. After talking with the TriMet guys that actually build the system and API I got the run down. Here is the gist. TriMet recently upgraded to a new CAD system. Buses are using short wave radios to transmit there position. They currently send updates every 30 seconds, and TriMet sees the update about 3 seconds later. Each bus gets a turn sending it's position and works like a tolken ring network. Previously it took 90 - 130 seconds and if a bus missed it's turn then it would be double that time (meaning for 1-5 minutes they would not know the position of a bus)
Buses do not actually send GPS coordinates back, what they do send is distance traveled along their trip. They do use GPS but primarily they are using the odometer for tracking position. There is also a door sensor, to verify that a bus is at a stop. There are all sorts of calibration issues with the odometer and drivers have reported that the vehicle is not updating its schedule adherence until the door opens.
Trains are completely different and obviously do not need short wave radios. There are signals (and I imagine if you have ridden the max you've seen them) that are at various track segments. Once the train passes these segments they update their position to TriMet. Rather than explaining it I will just post the quote from the PDX Transit Developers google group. "For rail car expiration times we look at their next scheduled stop time, which may be on their next trip, add some time, and use that as the expiration time. In places where the rail car layover for a while that could be 37 minutes. Like Hatfield station for example."
At any given point a bus position is accurate to within 30 seconds - 7 minutes and trains are accurate to within 30 seconds - 37 minutes.
#The Data The data was pulled in from a fairly well hidden private API. Shortly after the release of PDXLiveBus I was contacted by TriMet and they quickly pushed out a new vehicle API. I sort of forced their hand a bit. They were planning on releasing it in a few months but needed time to test. The end point just returns json( or XML but cmonnn) of vehicle information. There are other streams of information. Including gtfs real-time. And gtfs alerts real-time. There is a set gtfs schedule that is a bunch of standard CSV files. There isn't anything that interesting really. It's a cluster of data.
Every 10 seconds it requests all vehicle data from TriMet's API. It parses the JSON sends it to FireBase. This is all the backend does. This means that only one call is being made to the TriMet, and not multiplied by every user connected.
The front end is where most everything takes place. Upon first visit to the website the client (your browser) loads up an empty map, it then connects to FireBase via web sockets. It establishes 3 events with FireBase, one for once it receives values (first load), another for updated values, and finally one for deleted data. The even for first load is called and it then loops through all the bus data that FireBase sends, creates a bus on screen, and sets the markers to an array.
Once FireBase receives updated data it then sends out only the updated data nodes to the front end. Now the update values event triggers the function we bound to it. It checks the array of buses to see if it exists, if it doesn't then it adds the bus to the map. If it finds it in the array it gets the updated latitude and longitude, using LeafLet it converts it to a point on the map, and animates the bus to it. However the power of LeafLet is that the buses are just div icons, meaning you can attach real DOM events, and also use CSS3. How it should work is to set the new latitude and longitude and let CSS3 handle the animations.
Finally once a bus expires, hasn't changed position, or data is manually cleared from FireBase then the function bound to the deleted data event is triggered. The marker is removed from the map, and the bus is removed from the array.