Using Open Football Data - Get Ready for the World Cup in Brazil 2014 w/ JavaScript

Agenda

Let’s Build A World Cup Widget in JavaScript

World Cup in Brazil 2014 - The World’s Biggest (Sport) Event

When: 12 June - 13 July; Starts in:

43 days 3 hours 15 minutes

What:

32 teams 64 matches 25 matchdays 12 cities

Let’s Build A World Cup Widget in JavaScript

First let’s use an HTTP JSON API. Example:

GET /event/world.2014/teams

{
  "event": {
    "key":   "world.2014", "title": "World Cup 2014"
  },
  "teams": [
    { "key": "gre", "title": "Greece",      "code": "GRE" },
    { "key": "ned", "title": "Netherlands", "code": "NED" },
    { "key": "ger", "title": "Germany",     "code": "GER" },
    { "key": "por", "title": "Portugal",    "code": "POR" },
    ...
  ]
}

Let’s ask the intertubes (let’s google json world cup brazil or post a question on the open data stackexchange ‘Any Open Data Sets for the (Football) World Cup (in Brazil 2014)?’).

Nothing. Nada. Nichts. Niente. Zilch. Zero.

What’s football.db?

$ sportdb serve

Services available include:

GET /event/world.2014/round/1

{
  "event": { "key": "world.2014", "title": "World Cup 2014" },
  "round": { "pos": 1, "title": "Matchday 1" },
  "games": [
    {
      "team1_key": "bra",
      "team1_title": "Brazil",
      "team1_code": "BRA",
      "team2_key": "cro",
      "team2_title": "Croatia",
      "team2_code": "CRO",
      "play_at": "2014/06/12",
      "score1": null,
      "score2": null,
      "score1ot": null,
      "score2ot": null,
      "score1p": null,
      "score2p": null
    }
  ]
}

Basics - What’s Open Data? - Terms of Use

Open (Free) Data <=> Copyright © FIFA 2014. All Rights Reserved.

Example 1:

Basics - What’s Open Data? - Terms of Use (Cont.)

Open (Free) Data <=> Copyright © FIFA 2014. All Rights Reserved.

Example 2:

Q: Best “License” for Open Data?

A: Public Domain¹ (No License. No Copyright. No Rights Reserved.)

Q: Why?

A: Keep it simple².

________
¹ Also sometimes “rebranded” or known as Creative Commons Zero (CC0) or Unlicense.
² Full “License” Text Example: The data, schema n scripts are dedicated to the public domain. Use it as you please with no restrictions whatsoever.

Basics - What’s Structured Data? Ex. FIFA Web Page

Structured Data <=> Free-Style Text

Example 1:

Basics - What’s Structured Data? Ex. FIFA Web Page (Cont.)

Structured Data <=> Free-Style Text

Example 1:

Basics - What’s Structured Data? Ex. Wikipedia

Structured Data <=> Free-Style Text

Example 2:

Basics - What’s Structured Data? Ex. Wikipedia (Cont.)

Structured Data <=> Free-Style Text

Example 2:

Cut-n-Paste Text:

12 June 2014  17:00   Brazil    Match 1   Croatia    Arena de São Paulo, São Paulo
13 June 2014  13:00   Mexico    Match 2   Cameroon   Arena das Dunas, Natal
17 June 2014  16:00   Brazil    Match 17  Mexico     Estádio Castelão, Fortaleza
18 June 2014  19:00   Cameroon  Match 18  Croatia    Arena Amazônia, Manaus
23 June 2014  17:00   Cameroon  Match 33  Brazil     Estádio Nacional Mané Garrincha, Brasília
23 June 2014  17:00   Croatia   Match 34  Mexico     Arena Pernambuco, Recife

Wikipedia Source:

===Group A===
{{main|2014 FIFA World Cup Group A}}
{{Fb cl2 header navbar}}
{{{Fb cl2 team |t={{fb|BRA}} |w=0 |d=0 |l=0 |gf=0 |ga=0 |bc=}}}}
{{{Fb cl2 team |t={{fb|CRO}} |w=0 |d=0 |l=0 |gf=0 |ga=0 |bc=|border=green}}}}
{{{Fb cl2 team |t={{fb|MEX}} |w=0 |d=0 |l=0 |gf=0 |ga=0 |bc=}}}}
{{{Fb cl2 team |t={{fb|CMR}} |w=0 |d=0 |l=0 |gf=0 |ga=0 |bc=}}}}
|}

{{{Football box
|date=12 June 2014
|time=17:00
|team1={{fb-rt|BRA}}
|score=[[2014 FIFA World Cup Group A#Brazil v Croatia|Match 1]]
|report=
|team2={{fb|CRO}}
|goals1=
|goals2=
|stadium=[[Arena Corinthians|Arena de São Paulo]], [[São Paulo]]
|attendance=
|referee=
}}}
{{{Football box
|date=13 June 2014
|time=13:00
|team1={{fb-rt|MEX}}
|score=[[2014 FIFA World Cup Group A#Mexico v Cameroon|Match 2]]
|report=
|team2={{fb|CMR}}
|goals1=
|goals2=
|stadium=[[Arena das Dunas]], [[Natal, Rio Grande do Norte|Natal]]
|attendance=
|referee=
}}}

Basics - What’s Structured Data? - “Classic” Format Options

Structured Data <=> Free-Style Text

“Classic” Structured Data Formats:

Basics - What’s Structured Data? - “New” Format Options

Structured Data <=> Free-Style Text

but also

“New” Structured Data Formats:

Example - Open Football Match Schedule Language:

(1) Thu Jun/12 17:00   Brazil - Croatia    @ Arena de São Paulo, São Paulo (UTC-3)
(2) Fri Jun/13 13:00   Mexico - Cameroon   @ Estádio das Dunas, Natal (UTC-3)

(Source: world-cup/2014/cup.txt)

Q: Why? Why invent yet another data format? Why?

A: Best of both worlds, that is, 1) looks n feels like free-form plain text - easy-to-read and easy-to-write - 2) but offers a 100-% data accuracy guarantee (when loading into SQL tables, for example).

Basics - What’s Structured Data? - “New” Format Options

Mini Languages for Structured Data

Example - Open Football Match Schedule Language:

############################
# World Cup 2014 Brazil

Group A  |  Brazil       Croatia              Mexico         Cameroon
Group B  |  Spain        Netherlands          Chile          Australia
Group C  |  Colombia     Greece               Côte d'Ivoire  Japan
Group D  |  Uruguay      Costa Rica           England        Italy
Group E  |  Switzerland  Ecuador              France         Honduras
Group F  |  Argentina    Bosnia-Herzegovina   Iran           Nigeria
Group G  |  Germany      Portugal             Ghana          United States
Group H  |  Belgium      Algeria              Russia         South Korea


Matchday 1  |  Thu Jun/12
Matchday 2  |  Fri Jun/13
Matchday 3  |  Sat Jun/14
...

(16) Round of 16            |  Sat Jun/28 - Tue Jul/1
(17) Quarter-finals         |  Fri Jul/4 - Sat Jul/5
(18) Semi-finals            |  Tue Jul/8 - Wed Jul/9
(19) Match for third place  |  Sat Jul/12
(20) Final                  |  Sun Jul/13


Group A:

(1) Thu Jun/12 17:00   Brazil - Croatia       @ Arena de São Paulo, São Paulo (UTC-3)
(2) Fri Jun/13 13:00   Mexico - Cameroon      @ Estádio das Dunas, Natal (UTC-3)

(17) Tue Jun/17 16:00   Brazil - Mexico        @ Estádio Castelão, Fortaleza (UTC-3)
(18) Wed Jun/18 18:00   Cameroon - Croatia     @ Arena Amazônia, Manaus (UTC-4)

(33) Mon Jun/23 17:00   Cameroon - Brazil      @ Brasília (UTC-3)
(34) Mon Jun/23 17:00   Croatia  - Mexico      @ Recife (UTC-3)


Group B:

(3) Fri Jun/13 16:00   Spain - Netherlands     @ Arena Fonte Nova, Salvador (UTC-3)
(4) Fri Jun/13 18:00   Chile - Australia       @ Arena Pantanal, Cuiabá (UTC-4)

(19) Wed Jun/18 16:00   Spain - Chile             @ Estádio do Maracanã, Rio de Janeiro (UTC-3)
(20) Wed Jun/18 13:00   Australia - Netherlands   @ Estádio Beira-Rio, Porto Alegre (UTC-3)

(35) Mon Jun/23 13:00   Australia - Spain         @ Curitiba (UTC-3)
(36) Mon Jun/23 13:00   Netherlands - Chile       @ São Paulo (UTC-3)
...

(Source: world-cup/2014/cup.txt)

More Basics - Terms of Use (Cont.)

Just Kidding. Let’s Dive into Code. Code. Code.

Matchday Widget Example - footballdb.widget.js

Use like:

<div id='world'¹></div>

<script>
  var widget = footballdb_widget_new( '#world'¹ );
  widget.update( 'world.2014'², '2'³  );   // world cup in brazil 2014, matchday 2
  widget.update( 'world.2014'², '20'³ );   // world cup in brazil 2014, final (e.g. round 20)
</script>

_________
¹ - selector id for div
² - event key for world cup in brazil 2014
³ - round 2 (e.g. matchday 2); round 20 (e.g. final)

Results in:

World Cup 2014 - Matchday 2

2014/06/13 | Mexico (MEX) - Cameroon (CMR)
2014/06/13 | Spain (ESP)  - Netherlands (NED)
2014/06/13 | Chile (CHI)  - Australia (AUS)

(Live: geraldb.github.io/football.js/samples/starter)

Matchday Widget Example - footballdb.widget.js - Source

var footballdb_widget_new = function( widget_id, api_path_prefix ) {
  
  var _api_path_prefix = '';
  var _$widget;
  
  function _init( widget_id, api_path_prefix )
  {
    _api_path_prefix = api_path_prefix;
    _$widget  = $( widget_id );
  }

  function _update( event_key, round_pos )
  {
    var api_link = _api_path_prefix + "/event/" + event_key + "/round/" + round_pos; 
    
    $.getJSON( api_link, function(json) {
    
      var snippet = "";  // build up a hypertext (html) snippet to add/append
  
      snippet += "<h3>";
      snippet += json.event.title;
      snippet += " - ";
      snippet += json.round.title;
      snippet += "</h3>";
  
      snippet += "<ul>";
  
      $.each( json.games, function( index, game ) {
        snippet += "<li>";
        snippet += game.play_at + " | ";
        snippet += game.team1_title + " (" + game.team1_code +")";

       if( game.score1 != null && game.score2 != null ) {
         if( game.score1et != null && game.score2et != null ) {
           if ( game.score1p != null && game.score2p != null ) {
             snippet += " " + game.score1p + "-" + game.score2p + " pen /";
           }
           snippet += " " + game.score1et + "-" + game.score2et + " a.e.t. /";
         }
         snippet += " " + game.score1 + "-" + game.score2;
      }
      else
        snippet += " - ";
      
      snippet += " " + game.team2_title + " (" + game.team2_code +")";
      snippet += "</li>";
    });

    snippet += "</ul>";
  
    _$widget.html( snippet );
    });  // getJSON
  }  // fn _update

  // call c'tor/constructor
  _init( widget_id, api_path_prefix );

  // return/export public api
  return {
     update: _update
  }
  
} // fn football_widget_new

(Source: github.com/geraldb/football.js)

Matchday Widget Example - footballdb.widget.js - v2.0

Matchday Widget Example - footballdb.widget.js - v2.0 - Templates

templates/events.html:

<h3>
 <%= event.title %>
   -  
 <%= round.title %>
</h3>

templates/games.html:

<table>
 <% _.each( games, function( game, index ) { %>
  <tr>
    <td>
      <%= game.play_at %>
     </td>
     <td style='text-align: right;'>
       <%= game.team1_title %> (<%= game.team1_code %>)
     </td>

     <td>
      <% if( game.score1 != null && game.score2 != null ) { %>
        <% if( game.score1ot != null && game.score2ot != null ) { %>
          <% if ( game.score1p != null && game.score2p != null ) { %>
             <%= game.score1p %> - <%= game.score2p %> pen /
          <% } %>
           <%= game.score1ot %> - <%= game.score2ot %> a.e.t. /
        <% } %>
        <%= game.score1 %> - <%= game.score2 %>
      <% } else { %>
        - 
      <% } %>
     </td>
     <td>
      <%= game.team2_title %> (<%= game.team2_code %>)
     </td>
   </tr>
  <% }); %>
</table>

Matchday Widget Example - footballdb.widget.js - v2.0 - Modules

Modules w/ require.js:

football/api.js
football/widget.js
football/templates/event.html
football/templates/games.html
football/templates/rounds.html

Template Usage in JavaScript (w/ require.js and underscore.js):

var gamesTpl     = require( 'text!football/templates/games.html' );
var renderGames  = _.template( gamesTpl );    // returns a fn for reuse
...
$games.html(  renderGames( { games: data.games } ) );

football/widget.js:

define( function(require) {

            require( 'utils' );
  var Api = require( 'football/api' );

  var eventTpl   = require( 'text!football/templates/event.html' ),
      roundsTpl  = require( 'text!football/templates/rounds.html' ),
      gamesTpl   = require( 'text!football/templates/games.html' );

  var renderEvent  = _.template( eventTpl ),
      renderRounds = _.template( roundsTpl ),
      renderGames  = _.template( gamesTpl );

  var Widget = {};

Widget.create = function( id, opts ) {

  var $el,
      $event,    // used for event header 
      $rounds,   // used for rounds
      $games;    // used for round details (matches/games)
  ...

Matchday Widget Example - footballdb.widget.js - v2.0 - API Wrapper Module

football/api.js:

define( function() {
  
  var Api = {};

Api.create = function( opts ) {

  var defaults = { baseUrl: 'http://footballdb.herokuapp.com/api/v1' };
  var settings;

  function init( opts )  {
    settings = _.extend( {}, defaults, opts );
  }

  function fetch( path, onsuccess )  {
    var url = settings.baseUrl + path + '?callback=?';
    $.getJSON( url, onsuccess );
  }

  function fetchRounds( event, onsuccess )  {
    fetch( '/event/' + event + '/rounds', onsuccess );
  }

  function fetchRound( event, round, onsuccess ) {
    fetch( '/event/' + event + '/round/' + round, onsuccess );
  }

  init( opts ); // call "c'tor/constructor"

  // return/export public api
  return {
     fetchRound:        fetchRound,
     fetchRounds:       fetchRounds,
  }
} // end fn Api.create

  return Api;

}); // end define

Matchday Widget Example - <football-js> - v3.0

The old way in JavaScript. Usage Example:

<script src='js/football.js'></script>

<div id='world'></div>

<script>
  var widget = footballdb_widget_new( '#world' );
  widget.update( 'world.2014', '2'  );   // world cup in brazil 2014, matchday 2
</script>

The new way:

<link rel='import' href='football-js.html'>     <!-- HTML Imports -->

<football-js event='world.2014'></football-js>  <!-- custom tag use -->

Web Components Machinery - New Web Standard Building Blocks

What’s X-Tag? What’s Polymer?

New Web Standard Building Blocks

Matchday Widget Example - <football-js> - v3.0 (Cont.)

football-js.html:

<polymer-element name='football-js' attributes='event'>
  <template>
     <style>
        ... [your styles here] ...
     </style>
     ... [your (model-driven) views here] ...
  </template>
  <script>
     ... [your scripts here] ...
  </script>
</polymer-element>

MDV (Model Driven Views):

<template>
  <div>
    <h3>
      {{ data.event.title }}  -  {{ data.round.title }}
    </h3>

   <table>
   <template repeat='{{data.games}}'>
   <tr>
    <td>
      {{ play_at }}
     </td>
     <td>
       {{ team1_title }} ({{ team1_code }})
     </td>

     <td>
       {{ score1 }} - {{ score2 }}
     </td>
     <td>
      {{ team2_title }} ({{ team2_code }})
     </td>
   </tr>
   </template>
   </table>  
</template>

Matchday Widget Example - <football-js> - v3.0

Usage:

<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'>
    <title>football.js</title>
    <script src='js/libs/polymer.min.js'></script>
    <link rel='import' href='football-js.html'>
  </head>
  <body>
    <football-js event='world.2014'></football-js>
  </body>
</html>

(Live: geraldb.github.io/football.js/samples/polymer)

That’s it. Thank you.

More Open Data Projects

Questions? Comments?

Bonus: Beer? Wine? Formula 1? Alpine Ski?

What’s beer.db?

A free open public domain beer database n schema for use in any (programming) language (e.g. uses plain text fixtures/data sets). Example:

### Brewery

guinness, St. James's Gate Brewery / Guinness Brewery, 1759, Dublin
### Beer

Guinness|Guinness Draught, 4.2%, irish_dry_stout|dry_stout|stout

Bonus: How to use the HTTP JSON API - GET /beer/guinness

Get beer by key /beer/:key

GET /beer/guinness

{
  "beer":
  {
    "key":"guinness",
    "title":"Guinness",
    "synonyms": "Guinness Draught",
    "abv":"4.2",
    "srm":null,
    "og":null,
    "tags":["irish_dry_stout","dry_stout","stout"],
    "brewery":
    {
      "key": "guinness",
      "title": "St. James's Gate Brewery / Guinness Brewery"
    },
    "country":
    {
      "key":"ie",
      "title":"Irland"
    }
  }
}