NPR’s Election Party



NPR’s Election Party

0 0


elections14-slides

Slides for Hacks/Hackers Austin

On Github TylerFisher / elections14-slides

NPR’s Election Party

Tyler Fisher, NPR Visuals Team

We built an election app for TVs.

Elections at NPR

A brief history.

What does a passive election night app look like?

What we didn’t build

A hierarchical website

A liveblog (sort of)

Maps

Anything to interact with

What we built

Live audio

Big boards

A glance at everything on one screen

Scorecards

Interesting slices of the election

Yes, a liveblog

But for context, not just flash news updates

Recently called races

For a sense of timeliness

THIS IS FAKE DATA

State-specific results

How we built it

Started from the app template

Now we’re here

I’m so sorry.

The Moving Parts

  • Data from the Associated Press
  • Our own compiled data
  • Liveblog updates from Tumblr
  • A live-updating stack of slides, “DJ’ed” by a politics producer
  • A live radio show

We always build static websites.

How can you make a live website static?

We had a server!

Powered by our static site generating app template!

The two functions of the server

Run an admin to DJ the stack of slides Ingest new data and regenerate the entire website

The server-side tech stack

  • One EC2 server running Ubuntu
  • Two Flask apps
  • A PostgreSQL database on RDS
  • Two daemons running Fabric commands

One problem

Regenerating static sites is slow, even on big servers.

Multiprocessing!

slides = models.Slide.select()
slugs = [slide.slug for slide in slides if slide.slug not
    in ['state-senate-results', 'state-house-results'] and not 
    slide.slug.startswith('tumblr')]
slides.database.close()

Parallel(n_jobs=NUM_CORES)(delayed(_render_results_slide)
    (slug, output_path) for slug in slugs)
                    

The client-side app

What it had to do

  • Check to see if the user had a Chromecast
  • Geolocate the user
  • Inject HTML asynchronously on slide change
  • Check for new versions of the stack JSON

Chromecast

We might have built a library.

Simple tab mirroring wasn’t enough

Chromecasts are slow

if (IS_CAST_RECEIVER) {
    $newSlide.show();
    setTimer();
}
else {
    $newSlide.velocity('fadeIn', 800, setTimer);
}
                    

Interesting code

Responsive slideshows

The CSS

html {
    font-size:1vw;
}
body {
    margin:0;
}
 
#stack {
    box-sizing:border-box;
    margin: 0 auto;
 
    width: 100rem;
    height: 56.25rem;
}
                    

Everything else is in rems.

The JavaScript

var onWindowResize = function(){
    var aspect = window.innerWidth / window.innerHeight;
    if ( aspect > 16/9) {
        document.documentElement.style.fontSize = ((16/9) / aspect) 
            + 'vw';
    } else {
        document.documentElement.style.fontSize = '1vw';
    }
}
                    

How do you push hotfixes on a live streaming app?

Generate a timestamp file locally:

def reset_browsers():
    """
    Create a timestampped JSON file so the client will reset their page.
    """
    payload = {}
 
    # get current time and convert to epoch time
    now = datetime.now().strftime('%s')
    
    # set everything you want in the json file
    payload['timestamp'] = now
 
    with open('www/live-data/timestamp.json', 'w') as f:
        json.dump(now, f)
 
    deploy_json('www/live-data/timestamp.json', 'live-data/timestamp.json')
                    

Poll the timestamp file on the client. If the timestamp changed, refresh the page:

var reloadTimestamp = null;
 
var getTimestamp = function() {
    if (reloadTimestamp == null) {
        checkTimestamp();
    }
    setInterval(checkTimestamp, 180000);
}
 
var checkTimestamp = function() {
    $.ajax({
        'url': '/live-data/timestamp.json',
        'cache': false,
        'success': function(data) {
            var newTime = data['timestamp'];
            
            if (reloadTimestamp == null) {
                reloadTimestamp = newTime;
            }
            
            if (reloadTimestamp != newTime) {
                $.cookie('reload', true);
                
                window.location.reload(true);
            }
        }
    });
}
 
$(document).ready(function)() {
    getTimestamp();
    
    if ($.cookie('reload')) {

        $.removeCookie('reload');
    }
});
                    

Wanna dig deeper?

github.com/nprapps/elections14

Why we did this

Many news organiztions do elections well.

We targeted a different audience.

Our advantage is our radio and our live analysis.

Wait, why a party?

We can include our audience better.

This job isn’t any fun if you aren’t trying new things.

Questions?

@tylrfishr

elections.npr.org

tylerjfisher.com/elections14-slides