Skip to main content

Visualization Applications

The ScoringEngine serves as the data backbone for match visualization applications. Its structured state, episode system, and statistics API provide the data needed to build rich, interactive match visualizations.

Episode System

The getEpisodes() method transforms match state into a per-point timeline enriched with game/set/match context. Each episode represents a single point with its surrounding scoring context.

const engine = new ScoringEngine({ matchUpFormat: 'SET3-S:6/TB7' });

// ... score points ...

const episodes = engine.getEpisodes();
// Returns an array of Episode objects, one per point:
// {
// point, // Original point data (winner, server, result, etc.)
// gameScore, // Game score at this point
// setScore, // Set score at this point
// matchScore, // Match score at this point
// gameNumber, // Current game number within the set
// setNumber, // Current set number
// isBreakPoint, // Whether this point was a break point
// isGamePoint, // Whether this point was a game point
// isSetPoint, // Whether this point was a set point
// isMatchPoint, // Whether this point was a match point
// ...
// }

Episodes are the primary data source for building point-by-point visualizations. They provide the narrative arc of a match in a format ready for charting libraries.

Types of Visualizations

The ScoringEngine enables several categories of match visualization:

Point Progression

Visualize the flow of a match as a tree or Sankey diagram showing probability at each branching point. Each node represents a score state, and branches show outcomes.

const episodes = engine.getEpisodes();

// Build a tree structure from episodes
const tree = episodes.reduce((nodes, episode) => {
// Map each point to a node with game/set context
return buildProgressionNode(nodes, episode);
}, []);

Momentum Tracking

Plot point-by-point score differential to show momentum swings.

const episodes = engine.getEpisodes();
let cumulativeDiff = 0;

const momentumData = episodes.map((ep, i) => {
cumulativeDiff += ep.point.winner === 0 ? 1 : -1;
return { pointIndex: i, momentum: cumulativeDiff };
});

Grid-Based Point Layouts

Arrange points in a grid layout where cell size represents rally length and color represents the winner.

const episodes = engine.getEpisodes();

const grid = episodes.map((ep) => ({
size: ep.point.rallyLength || 1,
color: ep.point.winner === 0 ? 'blue' : 'red',
game: ep.gameNumber,
set: ep.setNumber,
}));

Statistics Dashboards

Combine getStatistics() with getEpisodes() to build multi-panel dashboards.

const stats = engine.getStatistics();
const set1Stats = engine.getStatistics({ setFilter: 1 });

// Render statistics panels
renderAceCount(stats);
renderBreakPointConversion(stats);
renderFirstServePercentage(stats);

Real-Time Score Display

Use event handlers to update visualizations in real-time as points are scored.

const engine = new ScoringEngine({
matchUpFormat: 'SET3-S:6/TB7',
eventHandlers: {
onPoint: ({ score }) => {
updateScoreDisplay(score);
updateMomentumChart(engine.getEpisodes());
},
onGameComplete: () => {
updateStatisticsPanel(engine.getStatistics());
},
onSetComplete: () => {
refreshAllCharts(engine);
},
onMatchComplete: ({ state }) => {
showFinalReport(state, engine.getStatistics());
},
},
});

Live Scoring Applications

The ScoringEngine's combination of state management, undo/redo, and event handlers makes it suitable for mobile match tracker applications.

A typical live scoring app architecture:

┌─────────────────────────────┐
│ Input UI (point buttons) │
├─────────────────────────────┤
│ ScoringEngine │
│ - addPoint / undo / redo │
│ - event handlers │
├─────────────────────────────┤
│ Visualization Layer │
│ - Scoreboard │
│ - Momentum chart │
│ - Statistics panel │
├─────────────────────────────┤
│ Persistence │
│ - getState / setState │
│ - getSupplementaryState │
└─────────────────────────────┘

The engine's persistence methods (getState, setState, getSupplementaryState, loadSupplementaryState) enable saving and restoring match state across app restarts, making it suitable for mobile applications where the app may be backgrounded.