Shot Charts
Visualize shot data with customizable markers, colors, and interactive tooltips. These examples can all be generalized for any type(s) of game event, but in these examples we will use shots.
Basic Shot Chart
Plot shot locations with simple circles.
import { Rink } from "d3-hockey";
const shots = [
{ coordinates: { x: 70, y: 15 }, player: "McDavid" },
{ coordinates: { x: 65, y: -10 }, player: "Draisaitl" },
{ coordinates: { x: 80, y: 0 }, player: "Hyman" },
];
new Rink("#container").render().addEvents(shots, {
id: "shots",
color: "#FF4C00",
radius: 5,
});Different Symbol Types
Use different symbols to distinguish between event types. By default the goals are stars, shots are circles, and blocks are crosses (the default selections can all be overwritten).
import { Rink, colorByCategory } from "d3-hockey";
const events = [
{ coordinates: { x: 85, y: 5 }, type: "goal", player: "Matthews" },
{ coordinates: { x: 75, y: -8 }, type: "shot", player: "Marner" },
{ coordinates: { x: 70, y: 12 }, type: "shot", player: "Nylander" },
{ coordinates: { x: 60, y: -15 }, type: "blocked", player: "Tavares" },
];
new Rink("#container").render().addEvents(events, {
id: "events",
color: colorByCategory("type", {
colors: {
goal: "#00ff00",
shot: "#0088ff",
blocked: "#ff6600",
},
}),
symbolSize: 100,
});Dynamic Sizing
Size events based on data properties, larger circles for higher shot danger or expected goals.
import { Rink, scaleRadiusByProperty } from "d3-hockey";
const shotsWithDanger = [
{ coordinates: { x: 85, y: 2 }, xG: 0.35, player: "Kane" },
{ coordinates: { x: 70, y: 15 }, xG: 0.12, player: "DeBrincat" },
{ coordinates: { x: 80, y: -5 }, xG: 0.28, player: "Toews" },
{ coordinates: { x: 55, y: 8 }, xG: 0.05, player: "Johnson" },
];
new Rink("#container").render().addEvents(shotsWithDanger, {
id: "xg-shots",
color: "#c8102e",
radius: scaleRadiusByProperty("xG", {
min: 3,
max: 23,
domain: [0, 1],
}),
opacity: 0.7,
});Color by Data
Use color gradients to represent continuous data like shot danger or distance from goal.
import { Rink, colorByProperty } from "d3-hockey";
const shots = [
{ coordinates: { x: 85, y: 3 }, xG: 0.32, player: "Pastrnak" },
{ coordinates: { x: 75, y: -12 }, xG: 0.15, player: "Marchand" },
{ coordinates: { x: 88, y: -2 }, xG: 0.38, player: "Bergeron" },
{ coordinates: { x: 65, y: 18 }, xG: 0.08, player: "Coyle" },
];
new Rink("#container").render().addEvents(shots, {
id: "heat-shots",
// Built-in shotQuality scale
color: colorByProperty("xG", {
scale: "shotQuality",
domain: [0, 0.4],
}),
radius: 8,
stroke: "#fff",
strokeWidth: 1.5,
opacity: 0.7,
});Custom Tooltips
Create rich, informative tooltips with custom formatting and styling.
import { Rink, colorByCategory } from "d3-hockey";
const detailedShots = [
{
coordinates: { x: 82, y: 8 },
player: "Ovechkin",
shotType: "Wrist Shot",
type: "goal",
speed: 98,
},
{
coordinates: { x: 68, y: -15 },
player: "Backstrom",
shotType: "Snap Shot",
type: "shot",
speed: 85,
},
];
new Rink("#container").render().addEvents(detailedShots, {
id: "detailed-shots",
color: colorByCategory("type", {
colors: {
goal: "#00ff00",
shot: "#0088ff",
},
}),
radius: 5,
tooltip: (d) => `<strong>${d.player}</strong><br/>
${d.shotType} - ${d.type}<br/>
Speed: ${d.speed} MPH<br/>
Location: (${d.coordinates.x.toFixed(1)}, ${d.coordinates.y.toFixed(1)})
`,
});Animation Control
Control animation timing and easing for smooth, professional transitions.
import { Rink } from "d3-hockey";
const shots = [
{ coordinates: { x: 75, y: 10 }, player: "Crosby" },
{ coordinates: { x: 82, y: -5 }, player: "Malkin" },
{ coordinates: { x: 68, y: 12 }, player: "Rust" },
];
new Rink("#container").render().addEvents(shots, {
id: "animated-shots",
color: "#FCB514",
radius: 5,
animate: true,
animationDuration: 800,
animationEasing: "easeElasticOut",
});Multiple Event Layers
Combine multiple event layers to show different data sets simultaneously, home vs. away, different periods, or multiple players.
import { Rink } from "d3-hockey";
const homeShots = [
{ coordinates: { x: 75, y: 8 }, team: "home" },
{ coordinates: { x: 82, y: -3 }, team: "home" },
{ coordinates: { x: 68, y: 15 }, team: "home" },
];
const awayShots = [
{ coordinates: { x: -78, y: -10 }, team: "away" },
{ coordinates: { x: -85, y: 5 }, team: "away" },
{ coordinates: { x: -70, y: 12 }, team: "away" },
];
const rink = new Rink("#container").render();
// Add home team shots
rink.addEvents(homeShots, {
id: "home",
color: "#003e7e",
radius: 5,
opacity: 0.7,
});
// Add away team shots
rink.addEvents(awayShots, {
id: "away",
color: "#c8102e",
radius: 5,
opacity: 0.7,
});