replay-table
Version:
Visualize sport seasons with interactive standings
400 lines (304 loc) • 16.2 kB
Markdown
Replay Table
=========
A library fo visualizing sport season results with interactive standings:

## Live Demos
* [English Premier League](https://replaytable.com#replay-english-premier-league-2016-2017)
* [Formula One](https://replaytable.com#replay-formula-one-drivers-2016)
* [NBA](https://replaytable.com#replay-nba-western-2015-2016)
## Quickstart
1. Prepare an [input file](#input) with season results or download one from our [examples](https://replaytable.com/#examples).
2. Put a `div` with `replayTable` class on your page and supply a link to the input file using `data-source` attribute:
```
<div class="replayTable"
data-source="/path/to/file.csv">
</div>
```
3. Include D3.js and Replay Table scripts (70+16 KB gzipped) and the stylesheet. Apply some magic to the body:
```
<head>
...
<script type="text/javascript" src="https://d3js.org/d3.v4.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/replay-table/dist/replay-table.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://unpkg.com/replay-table/dist/replay-table.css">
</head>
<body>
...
<script type="text/javascript">replayTable.magic()</script>
</body>
```
4. Enjoy!
The library is highly customizable via `data-` attributes. Check out [customization](#customization) for the details.
Also feel free to embed ready-to-use Replay Tables from our [gallery](https://replayTable.com/#examples).
## Library
`npm install -S replay-table`
The only dependency is [D3.js](d3js.org). D3 is not included with the library so don't forget to plug it up.
The library consists of 5 modules: configure → extract → transform → calculate → visualize.
Take a look at how we use them in the `magic` function:
```
return Array.from(document.getElementsByClassName('replayTable'))
.map(table => {
const config = replayTable.configure(table.id, table.dataset); //build a config from data- attributes
return Promise.resolve(replayTable.extract(config.extract)) //fetch the input
.then(raw => {
const transformed = replayTable.transform(raw, config.transform); //transform into predefined format
const calculated = replayTable.calculate(transformed, config.calculate); //calculate wins, goals, etc.
return replayTable.visualize(calculated, config.visualize); //render interactive standings
})
.catch(error => crash(error));
});
```
Sometimes you won't need all the modules: for example, feel free to omit `configure` if you already have a config.
A Replay Table is returned from the `visualize` module. It has methods like `play()` and `to(roundIndex)` so you can control its behaviour from code.
## Customization
* [Configure](#configure)
* [Presets](#presets)
* [Extract](#extract)
* [Transfrom](#transform)
* [List of Matches](#list-of-matches)
* [Points Table](#points-table)
* [Calculate](#calculate)
* [Visualize](#visualize)
* [Classic](#classic)
* [Sparklines](#sparklines)
## Configure
Makes configs for other modules based on the div `data-` attributes. The output looks like this:
```
extract: {
extractor: csv
},
transform: {
transformer: 'pointsTable',
changeToOutcome: {
25: 'win'
},
insertStartRound: 'Start →'
},
calculate: {
orderBy: ['points', 'wins']
},
visualize: {
columns: ['position', 'item', 'points', 'points.change'],
labels: ['#', 'Driver', 'Points']
}
```
### Presets
To save you some time and cognitive effort we've constructed presets
that you can use via `data-preset` attribute:
[matches](https://github.com/TargetProcess/replay-table/blob/master/src/configure/presets/matches.js),
[f1](https://github.com/TargetProcess/replay-table/blob/master/src/configure/presets/f1.js),
[winLoss](https://github.com/TargetProcess/replay-table/blob/master/src/configure/presets/win-loss.js),
[chgk](https://github.com/TargetProcess/replay-table/blob/master/src/configure/presets/chgk.js).
So this table:
```
<div class="replayTable"
data-source="/path/to/file.csv">
data-transformer="listOfMatches"
data-change-to-outcome="{ 1: 'win', 0: 'loss' }"
data-order-by="winningPercentage,wins"
data-visualizer="classic"
data-columns="position,item,rounds,wins,losses,winningPercentage,outcome,match"
data-labels="#,Team,G,W,L,Win %"
</div>
```
is identical to this:
```
<div class="replayTable"
data-source="/path/to/file.csv">
data-preset="winLoss"
</div>
```
## Extract
Fetches the input file, returns a promise.
| Parameter | Attribute | Required | Accepts | Default | Examples |
|-----------|-----------|----------|---------------|---------------|----------|
| source | `data-source` | yes | `string` | `null` | `/assets/data/football/2016-2017/english-premier-league.json` |
| extractor | `data-extractor` | no | [extractor](https://github.com/TargetProcess/replay-table/tree/master/src/extract/extractors) | `csv` | `csv`, `json` |
If extractor is not defined we try to guess it from the file extension.
## Transform
Transforms raw data into the predefined format:
```
[
{
name: 'round name',
results: {
[
{
change: 25,
extras: {
item: {
team: 'Mercedes'
}
},
item: 'Lewis Hamilton',
outcome: 'win'
},
{
...
},
...
]
}
},
{
...
},
...
]
```
| Parameter | Attribute | Accepts | Parses | Default | Examples |
|-----------|-----------|---------|--------|---------------|----------|
| transformer | `data-transformer` | [transformer](https://github.com/TargetProcess/replay-table/tree/master/src/transform/transformers) | | `listOfMatches` | `listOfMatches`, `pointsTable` |
| changeToOutcome | `data-change-to-outcome` | `object` | JSON object | `{ 3: 'win', 1: 'draw', 0: 'loss'}` | `{ 1: 'win', 0: 'loss'}` |
| filterItems | `data-filter-items` | `array of strings` | comma-separated string | `[]` | `['Golden State Warriors', 'San Antonio Spurs', ...]` |
| insertStartRound | `data-insert-start-round` | `string` | | `0` | `Start` |
### List of Matches
The structure looks like this:
| Round name | First Item | First Item Score | Second Item | Second Item Score |
|------------|------------|------------------|-------------|-------------------|
| Round | Item | Score | Item | Score |
List should be sorted by round.
Here is an example:
| Match Week | Home | Points | Away | Points |
|------|------|--------|------|--------|
| 1 | Bournemouth | 0 | Aston Villa | 1 |
| 1 | Chelsea | 2 | Swansea | 2 |
| 1 | Everton | 2 | Watford | 2 |
| ... | ... | ... | ... | ... |
Also works with [football-data.org fixtures](http://api.football-data.org/v1/competitions/426/fixtures).
| Parameter | Attribute | Accepts | Default | Examples |
|-----------|-----------|---------|---------------|----------|
| format | `data-format` | `csv` or `football-data.org` | `csv` | `csv`, `football-data.org` |
| locationFirst | `data-location-first` | `home` or `away` | `home` | `home`, `away` |
| collapseToRounds | `data-collapse-to-rounds` | `boolean` | `false` | `true`, `false` |
Use `collapseToRounds` when you've got dates instead of match weeks: it groups each team's 1st, 2nd, 3rd, ... games.
### Points Table
The structure looks like this:
| Item name | [1st extra column name] | [2nd extra column name] | [...] | 1st round name | 2nd round name | ... | last round name |
|-----------|-------------------------|-------------------------|-----|----------------|----------------|-----|-----------------|
| item | [1st piece of extra info] | [2nd piece of extra info] | [...] | 1st round points | 2nd round points | ... | last round points |
The Formula One example ([csv](https://replaytable.com/assets/data/formula-one/2016/formula-one-drivers.csv)):
| Driver | Team | Australia | Bahrain | ... | Abu Dhabi |
|------|---|---|---|-----|----|
| Lewis Hamilton | Mercedes | 18 | 15 | ... | 25 |
| Nico Rosberg | Mercedes | 25 | 25 | ... | 18 |
| Daniel Ricciardo | Red Bull | 12 | 12 | ... | 10 |
| ... | ... | .... | ... | ... | ... |
Watch the [live demo](https://replaytable.com/#replay-formula-one-drivers-2016).
| Parameter | Attribute | Accepts | Default | Examples |
|-----------|-----------|---------|---------------|----------|
| extraColumnsNumber | `data-extra-columns-number` | `int` | `0` | `1`, `2` |
## Calculate
Calculates wins, goals, points, etc. and adds metadata. The output looks like this:
```
{
meta: {
lastRound: 38
},
results: {
[
{
meta: {
index: 2,
isLast: false,
items: 20,
name: "2"
},
results: {
[
{
change: 3,
draws: {
change: 0,
total: 0
},
extras: {},
item: 'Leicester',
losses: {
change: 0,
total: 0
},
match: {
location: "away",
opponent: "West Ham",
opponentScore: 1,
score: 2
},
outcome: "win",
points: {
change: 3,
total: 6
},
position: {
highest: 1,
lowest: 4,
strict: 1
},
wins: {
change: 1,
total: 2
}
...//goalsFor, goalsAgainst, goalsDifference, rounds, winningPercentage
},
....
]
}
},
...
]
}
}
```
See the whole list of calculations in the [calculations.js](https://github.com/TargetProcess/replay-table/blob/master/src/calculate/calculations.js).
| Parameter | Attribute | Accepts | Parses | Default | Examples |
|-----------|-----------|---------|--------|---------------|----------|
| orderBy | `data-order-by` | `array` of calculations | comma-separated string | `['points']` | `['winningPercentage', 'wins']` |
## Visualize
Renders interactive standings out of calculated data.
Returns a class instance with useful methods:
* `first()`, `last()`, `next()`, `previous()` and `to(roundIndex)`
* `play()` and `pause()`
* `preview(roundIndex)` and `endPreview()`
* `drillDown(item)` and `endDrillDown()`
| Parameter | Attribute | Accepts | Parses | Default | Examples |
|-----------|-----------|---------|--------|---------------|----------|
| visualizer | `data-visualizer` | [visualizer](https://github.com/TargetProcess/replay-table/tree/master/src/visualize/visualizers) | | `classic` | `classic`, `sparklines` |
| controls | `data-conrols` | `array` of [controls](https://github.com/TargetProcess/replay-table/tree/master/src/visualize/controls) | comma-separated string | `['play', 'previous', 'next', 'slider']` | `['play', 'slider']` |
| startFromRound | `data-start-from-round` | `int` | | `null` | `0`, `15` |
| roundsTotalNumber | `data-rounds-total-number` | `int` | | `null` | `38`, `82` |
| positionWhenTied | `data-position-when-tied` | `int` | | `strict`, `highest`, `range` or `average` | `strict`, `highest` |
| animationSpeed | `data-animation-speed` | `float` | | `1.0` | `0.5`, `2.0` |
### Classic

[Formula One](https://replaytable.com#replay-formula-one-drivers-2016)
A simple table with controls on top. Works for any sport and is highly customizable.
| Parameter | Attribute | Accepts | Parses | Default | Examples |
|-----------|-----------|---------|--------|---------------|----------|
| columns | `data-columns` | `array` of columns | comma-separated string | `['position', 'item', 'points']` | `['position', 'item', 'points', 'outcome', 'points.change]` |
| labels | `data-labels` | `array of strings` | comma-separated string | `['#', 'Team', 'Points']` | `['Position', 'Driver', 'Points']` |
| colors | `data-colors` | `object` | JSON object | `{ 'win': '#ACE680', 'draw': '#B3B3B3', 'loss': '#E68080' }` | `{ 'win': 'green', 'draw': 'gray', 'loss': 'red' }` |
| durations | `data-durations` | `object` | JSON object | `{ move: 750, freeze: 750, outcomes: 200}` | `{ move: 500, freeze: 400, outcomes: 250}` |
### Sparklines

[English Premier League](https://replaytable.com#replay-english-premier-league-2016-2017)
A powerful interactive visualization for the sports with matches and points. Might be slow on old devices and in Firefox.
| Parameter | Attribute | Accepts | Parses | Default | Examples |
|-----------|-----------|---------|--------|---------------|----------|
| controls | `data-conrols` | `array` of [controls](https://github.com/TargetProcess/replay-table/tree/master/src/visualize/controls) | comma-separated string | `['play']` | `['play', 'previous', 'next']` |
| colors | `data-colors` | `object` | JSON object | `{ 'win': '#21c114', 'draw': '#828282', 'loss': '#e63131' }` | `{ 'win': 'green', 'draw': 'gray', 'loss': 'red' }` |
| sparkColors | `data-spark-colors` | `object` | JSON object | `{ 'win': '#D7E7C1', 'draw': '#F0F0F0', 'loss': '#EFCEBA' }` | `{ 'win': 'green', 'draw': 'gray', 'loss': 'red' }` |
| currentSparkColors | `data-current-spark-colors` | `object` | JSON object | `{ 'win': '#AAD579', 'draw': '#CCCCCC', 'loss': '#E89B77' }` | `{ 'win': 'green', 'draw': 'gray', 'loss': 'red' }` |
| durations | `data-durations` | `object` | JSON object | `{ move: 1000, freeze: 500, pre: 750}` | `{ move: 750, freeze: 750, pre: 375}` |
| pointsLabel | `data-points-label` | `string` | | `points` | `очков` |
| allLabel | `data-all-label` | `string` | | `All` | `Все` |
## Contribution
Please, post your suggestions and bugs via Github issues. PRs are also welcome!
If you own an API or a database with sports results we'd be happy to collaborate.
We'd also be happy to work with sport journalists to leverage Replay Table for a better season recap.
## Credits
The library was built using the [orange time](http://www.openwork.org/targetprocess/) at [Targetprocess](https://www.targetprocess.com/)
by Anton Iokov ([@antoniokov](https://github.com/antoniokov)) and Daria Krupenkina ([@dariak](https://github.com/dariak)).
[Sparklines](#sparklines) prototype was made by Vitali Yanusheuski.
## Contact
We're open to your ideas and are ready to help with integrating Replay Table into your website.
Please, write us an email to [anton.iokov@targetprocess.com](mailto:anton.iokov@targetprocess.com) or ping on Twitter at [@antoniokov](https://twitter.com/antoniokov).