Kyogijo Stadiums競技場

Guides, the reference, a gallery of every picture it can draw, and how it compares: the pages are made from the package's own files when the site is built.

About the name

The pages are in English; this contents, the search and the buttons are in Japanese.

Gallery: data on a surface

Every kind of data layer, every heat layer, the ready-made charts, the team-shape layers and a frame of a replay, on made-up data that the code under each picture makes. The marks are in the surface's own frame, or a provider's. The pictures share one stylesheet, which is left out of each one's SVG here; drawKyogijo puts it in every drawing unless style: "none" says not to.

Data layers#

layers in the options of drawKyogijo: points, lines, arrows and text.

Points: the seven shapes

NHL hockey rinkDrawn as: an ice hockey rink, 200 by 85 feet with rounded corners, with its red and blue lines, face-off circles, creases and goal nets. Data: 7 shapes.7 shapescirclesquaretrianglediamondcrossxstar

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const shapes = ["circle", "square", "triangle", "diamond", "cross", "x", "star"];
const svg = drawKyogijo({
  sport: "nhl",
  layers: [{ kind: "points", name: "shapes", data: shapes.map((shape, i) => ({ x: 40 + i * 20, y: 42.5, shape, title: shape })), style: { size: 8 } }],
});

Points: outcomes, size and team

NHL hockey rinkDrawn as: an ice hockey rink, 200 by 85 feet with rounded corners, with its red and blue lines, face-off circles, creases and goal nets. Data: 36 shots. By outcome: shot 28, goal 8. By team: home 18, away 18. Values from 0.05 to 0.35.36 shotsBy outcome: shot 28, goal 8. By team: home 18, away 18. Values from 0.05 to 0.35.

A miss is open, a goal a star, and the size follows each mark's `value`.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const shots = Array.from({ length: 36 }, (_, i) => ({ x: 20 + ((i * 53) % 160), y: 8 + ((i * 29) % 70), team: i % 2 ? "away" : "home", outcome: i % 5 === 0 ? "goal" : "shot", value: 0.05 + (i % 7) / 20 }));
const svg = drawKyogijo({
  sport: "nhl",
  layers: [{ kind: "points", name: "shots", data: shots, style: { size: { range: [1.6, 4.6] }, outcomes: { shot: { hollow: true, shape: "x" } } } }],
});

Lines: straight, curved and wavy

NFL football fieldDrawn as: an American football field, 120 by 53 and a third yards with its end zones, with a yard line every 5 yards, hash marks, numbers and goal posts. Data: 1 straight. 1 curved. 1 wavy.1020304050403020100102030405040302011 straight1 curved1 wavy

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const svg = drawKyogijo({
  sport: "nfl",
  layers: [
    { kind: "lines", name: "straight", data: [{ x: 40, y: 12, x2: 80, y2: 12 }], style: { width: 1.4 } },
    { kind: "lines", name: "curved", data: [{ x: 40, y: 26, x2: 80, y2: 26, curve: 0.25 }], style: { width: 1.4 } },
    { kind: "lines", name: "wavy", data: [{ x: 40, y: 40, x2: 80, y2: 40 }], style: { width: 1.4, wavy: true } },
  ],
});

Arrows: heads, dashes and a comet

NFL football fieldDrawn as: an American football field, 120 by 53 and a third yards with its end zones, with a yard line every 5 yards, hash marks, numbers and goal posts. Data: 1 complete. By outcome: complete 1. 1 incomplete. By outcome: incomplete 1. 1 comet.1020304050403020100102030405040302011 completeBy outcome: complete 1.1 incompleteBy outcome: incomplete 1.1 comet

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const svg = drawKyogijo({
  sport: "nfl",
  layers: [
    { kind: "arrows", name: "complete", data: [{ x: 40, y: 12, x2: 80, y2: 16, outcome: "complete" }], style: { width: 1.4 } },
    { kind: "arrows", name: "incomplete", data: [{ x: 40, y: 26, x2: 80, y2: 30, outcome: "incomplete" }], style: { width: 1.4 } },
    { kind: "arrows", name: "comet", data: [{ x: 40, y: 40, x2: 100, y2: 44 }], style: { width: 1.4, comet: { taper: true } } },
  ],
});

Text: words on the surface

NBA basketball courtDrawn as: a basketball court, 94 by 50 feet, with its keys, three-point lines, free-throw circles and the centre circle. Data: 3 notes.3 notesCentreKeyKey

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const svg = drawKyogijo({
  sport: "nba",
  layers: [{ kind: "text", name: "notes", data: [{ x: 47, y: 25, text: "Centre" }, { x: 12, y: 25, text: "Key" }, { x: 82, y: 25, text: "Key" }], style: { size: 3 } }],
});

Heat layers#

Counts in cells, hexagons, named zones or a density, in a colour ramp.

Heat map

NHL hockey rinkDrawn as: an ice hockey rink, 200 by 85 feet with rounded corners, with its red and blue lines, face-off circles, creases and goal nets. Data: Heat map of 360 shots. Count in 220 cells, from 1 to 4. Highest: 150, 26.3 (4), 162, 30.4 (4), 130, 46.5 (4).Heat map of 360 shotsCount in 220 cells, from 1 to 4. Highest: 150, 26.3 (4), 162, 30.4 (4), 130, 46.5 (4).Legend: Shots in each 4 by 4 feetShots in each 4 by 4 feet1234

A count in each cell of a grid, in a ramp, cut to the boards.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const shots = Array.from({ length: 360 }, (_, i) => { const t = i * 2.399963; const r = 4 + 54 * Math.sqrt((i % 120) / 120); return { x: 189 - r * Math.abs(Math.cos(t)) * 1.1, y: 42.5 + r * Math.sin(t) * 0.7 }; });
const svg = drawKyogijo({
  sport: "nhl",
  layers: [{ kind: "heatmap", name: "shots", data: shots, bins: [50, 21], legend: { title: "Shots in each 4 by 4 feet" } }],
});

Hexagons

NHL hockey rinkDrawn as: an ice hockey rink, 200 by 85 feet with rounded corners, with its red and blue lines, face-off circles, creases and goal nets. Data: Hexagon map of 360 shots. Count in 74 hexagons, from 1 to 9. Highest: 173.2, 75 (9), 177.5, 7.5 (8), 173.2, 30 (8).Hexagon map of 360 shotsCount in 74 hexagons, from 1 to 9. Highest: 173.2, 75 (9), 177.5, 7.5 (8), 173.2, 30 (8).Legend: CountCount2468

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const shots = Array.from({ length: 360 }, (_, i) => { const t = i * 2.399963; const r = 4 + 54 * Math.sqrt((i % 120) / 120); return { x: 189 - r * Math.abs(Math.cos(t)) * 1.1, y: 42.5 + r * Math.sin(t) * 0.7 }; });
const svg = drawKyogijo({ sport: "nhl", layers: [{ kind: "hexbin", name: "shots", data: shots, size: 5, legend: true }] });

Zones: the slot

NHL hockey rinkDrawn as: an ice hockey rink, 200 by 85 feet with rounded corners, with its red and blue lines, face-off circles, creases and goal nets. Data: Zone chart of 360 shots. Count in 3 zones, from 15 to 328. Highest: Offensive zone (right end) (328), Outer slot (right end) (17), Inner slot (right end) (15).Zone chart of 360 shotsCount in 3 zones, from 15 to 328. Highest: Offensive zone (right end) (328), Outer slot (right end) (17), Inner slot (right end) (15).Offensive zone (left end) (0)Behind the goal line (left end) (0)Outer slot (left end) (0)Inner slot (left end) (0)Offensive zone (right end): 328 (328)Behind the goal line (right end) (0)Outer slot (right end): 17 (17)Inner slot (right end): 15 (15)3281715Legend: CountCount100200300

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const shots = Array.from({ length: 360 }, (_, i) => { const t = i * 2.399963; const r = 4 + 54 * Math.sqrt((i % 120) / 120); return { x: 189 - r * Math.abs(Math.cos(t)) * 1.1, y: 42.5 + r * Math.sin(t) * 0.7 }; });
const svg = drawKyogijo({ sport: "nhl", layers: [{ kind: "zones", name: "shots", zones: "nhl-slot", data: shots, labels: true, legend: true }] });

Zones: shot zones

NBA basketball courtDrawn as: a basketball court, 94 by 50 feet, with its keys, three-point lines, free-throw circles and the centre circle. Data: Zone chart of 160 shots. Success rate, % in 5 zones, from 25% to 50%. Highest: Left corner 3 (right end) (50%), Mid-range (right end) (34%), Above the break 3 (right end) (31.6%).Zone chart of 160 shotsSuccess rate, % in 5 zones, from 25% to 50%. Highest: Left corner 3 (right end) (50%), Mid-range (right end) (34%), Above the break 3 (right end) (31.6%).Above the break 3 (left end) (0)Right corner 3 (left end) (0)Left corner 3 (left end) (0)Mid-range (left end) (0)In the paint (non-RA) (left end) (0)Restricted area (left end) (0)Above the break 3 (right end): 31.6% (38)Left corner 3 (right end): 50% (8)Right corner 3 (right end): 25% (4)Mid-range (right end): 34% (103)In the paint (non-RA) (right end): 28.6% (7)Restricted area (right end) (0)50%34%31.6%28.6%25%Legend: Success rate, %Success rate, %30%40%50%

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const shots = Array.from({ length: 160 }, (_, i) => ({ x: ((i * 97) % 480) - 240, y: (i * 61) % 300, outcome: i % 3 === 0 ? "made" : "missed" }));
const svg = drawKyogijo({
  sport: "nba",
  layers: [{ kind: "zones", name: "shots", zones: "nba-shot", from: "nba-stats", data: shots, statistic: "rate", labels: true, legend: true }],
});

Zones: positional play

Soccer pitchDrawn as: a soccer pitch, 105 by 68 metres, with the halfway line, the centre circle, both penalty areas, goal areas, penalty marks and arcs, the corner arcs and the goals. Data: Zone chart of 220 touches. Share of all, % in 30 zones, from 1.8% to 6.4%. Highest: Centre, band 4 (6.4%), Centre, band 2 (5.5%), Centre, band 6 (5.5%).Zone chart of 220 touchesShare of all, % in 30 zones, from 1.8% to 6.4%. Highest: Centre, band 4 (6.4%), Centre, band 2 (5.5%), Centre, band 6 (5.5%).Left wing, band 1: 2.3% (5)Left half-space, band 1: 2.3% (5)Centre, band 1: 3.6% (8)Right half-space, band 1: 1.8% (4)Right wing, band 1: 2.3% (5)Left wing, band 2: 2.7% (6)Left half-space, band 2: 2.3% (5)Centre, band 2: 5.5% (12)Right half-space, band 2: 3.6% (8)Right wing, band 2: 4.1% (9)Left wing, band 3: 4.5% (10)Left half-space, band 3: 2.7% (6)Centre, band 3: 4.5% (10)Right half-space, band 3: 2.7% (6)Right wing, band 3: 2.7% (6)Left wing, band 4: 2.7% (6)Left half-space, band 4: 2.3% (5)Centre, band 4: 6.4% (14)Right half-space, band 4: 3.2% (7)Right wing, band 4: 3.6% (8)Left wing, band 5: 3.6% (8)Left half-space, band 5: 3.6% (8)Centre, band 5: 4.1% (9)Right half-space, band 5: 2.3% (5)Right wing, band 5: 3.6% (8)Left wing, band 6: 2.7% (6)Left half-space, band 6: 2.7% (6)Centre, band 6: 5.5% (12)Right half-space, band 6: 2.7% (6)Right wing, band 6: 3.2% (7)Legend: Share of all, %Share of all, %2%3%4%5%6%

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const touches = Array.from({ length: 220 }, (_, i) => ({ x: 6 + ((i * 41) % 93), y: 4 + ((i * 29) % 92) }));
const svg = drawKyogijo({ sport: "soccer", layers: [{ kind: "zones", name: "touches", zones: "soccer-positional", from: "opta", data: touches, statistic: "percent", legend: true }] });

Zones: passes

NFL football fieldDrawn as: an American football field, 120 by 53 and a third yards with its end zones, with a yard line every 5 yards, hash marks, numbers and goal posts. Data: Zone chart of 90 passes. Count in 6 zones, from 4 to 27. Highest: Deep, left (27), Deep, right (24), Short, right (15).102030405040302010010203040504030201Zone chart of 90 passesCount in 6 zones, from 4 to 27. Highest: Deep, left (27), Deep, right (24), Short, right (15).Short, left: 11 (11)Short, middle: 4 (4)Short, right: 15 (15)Deep, left: 27 (27)Deep, middle: 9 (9)Deep, right: 24 (24)2724151194Legend: CountCount510152025

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const passes = Array.from({ length: 90 }, (_, i) => ({ x: 62 + ((i * 17) % 45), y: 6 + ((i * 23) % 42) }));
const svg = drawKyogijo({ sport: "nfl", layers: [{ kind: "zones", name: "passes", zones: "football-pass", from: "nfl-tracking", los: 62, data: passes, labels: true, legend: true }] });

Contours: a density

NHL hockey rinkDrawn as: an ice hockey rink, 200 by 85 feet with rounded corners, with its red and blue lines, face-off circles, creases and goal nets. Data: Density contours of 360 shots. 6 density contours; the peak is near 143.4, 42.5.Density contours of 360 shots6 density contours; the peak is near 143.4, 42.5.Legend: Density, share of the peak, %Density, share of the peak, %10%25%40%55%70%85%

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const shots = Array.from({ length: 360 }, (_, i) => { const t = i * 2.399963; const r = 4 + 54 * Math.sqrt((i % 120) / 120); return { x: 189 - r * Math.abs(Math.cos(t)) * 1.1, y: 42.5 + r * Math.sin(t) * 0.7 }; });
const svg = drawKyogijo({ sport: "nhl", layers: [{ kind: "contour", name: "shots", data: shots, levels: 6, filled: true, legend: true }] });

A legend of its own

NHL hockey rinkDrawn as: an ice hockey rink, 200 by 85 feet with rounded corners, with its red and blue lines, face-off circles, creases and goal nets. Data: Heat map of 360 shots. Count in 169 cells, from 1 to 4. Highest: 167.5, 7.5 (4), 167.5, 17.5 (4), 182.5, 17.5 (4). Shots. 1 to 4Heat map of 360 shotsCount in 169 cells, from 1 to 4. Highest: 167.5, 7.5 (4), 167.5, 17.5 (4), 182.5, 17.5 (4).Shots1 to 4Count1234

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const shots = Array.from({ length: 360 }, (_, i) => { const t = i * 2.399963; const r = 4 + 54 * Math.sqrt((i % 120) / 120); return { x: 189 - r * Math.abs(Math.cos(t)) * 1.1, y: 42.5 + r * Math.sin(t) * 0.7 }; });
const svg = drawKyogijo({
  sport: "nhl",
  layers: [
    { kind: "heatmap", id: "heat", name: "shots", data: shots, bins: [40, 17] },
    { kind: "legend", for: "heat", title: "Shots", position: "bottom" },
  ],
});

Ready-made charts#

One call for a good chart: @johnmorrisdotca/kyogijo-stadiums/charts.

NBA shot chart

NBA shot chartDrawn as: a basketball court, 94 by 50 feet, with its keys, three-point lines, free-throw circles and the centre circle. Data: Zone chart of 140 shots. Field goals made, % in 5 zones, from 25% to 50%. Highest: Left corner 3 (50%), Mid-range (33.3%), Above the break 3 (32.4%). 140 shots. By outcome: Made 47, Missed 93. Key. Made, Missed Key.Zone chart of 140 shotsField goals made, % in 5 zones, from 25% to 50%. Highest: Left corner 3 (50%), Mid-range (33.3%), Above the break 3 (32.4%).Above the break 3: 32.4% (34)Left corner 3: 50% (8)Right corner 3: 25% (4)Mid-range: 33.3% (87)In the paint (non-RA): 28.6% (7)Restricted area (0)50%4/833.3%29/8732.4%11/3428.6%2/725%1/4Legend: Field goals made, %Field goals made, %30%40%50%60%140 shotsBy outcome: Made 47, Missed 93.KeyMade, MissedKeyMadeMissed

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { nbaShotChart } from "@johnmorrisdotca/kyogijo-stadiums/charts";

const shots = Array.from({ length: 140 }, (_, i) => ({ x: ((i * 97) % 480) - 240, y: (i * 61) % 300, made: i % 3 === 0 }));
const svg = nbaShotChart(shots, { league: 46, minShots: 2 }).draw();

NHL shot map

NHL shot mapDrawn as: an ice hockey rink, 200 by 85 feet with rounded corners, with its red and blue lines, face-off circles, creases and goal nets. Data: Zone chart of 40 shots. Expected goals (xG) in 3 zones, from 0.46 to 4.7. Highest: Offensive zone (4.7), Outer slot (1.1), Inner slot (0.46). 40 shots. By outcome: Goal 10, Saved 10, Off target 10, Blocked 10. The size of a mark shows its expected goals (xG). Key. Goal, Saved, Off target, Blocked Key. Size: xG, xG 6.2Zone chart of 40 shotsExpected goals (xG) in 3 zones, from 0.46 to 4.7. Highest: Offensive zone (4.7), Outer slot (1.1), Inner slot (0.46).Offensive zone: 4.7 (31)Behind the goal line (0)Outer slot: 1.1 (6)Inner slot: 0.46 (3)4.71.10.46Legend: Expected goals (xG)Expected goals (xG)123440 shotsBy outcome: Goal 10, Saved 10, Off target 10, Blocked 10. The size of a mark shows its expected goals (xG).KeyGoal, Saved, Off target, BlockedKeySize: xG, xG 6.2GoalSavedOff targetBlockedSize: xGxG 6.2

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { nhlShotMap } from "@johnmorrisdotca/kyogijo-stadiums/charts";

const shots = Array.from({ length: 40 }, (_, i) => ({ x: (i % 2 ? -1 : 1) * (50 + ((i * 11) % 38)), y: ((i * 23) % 60) - 30, outcome: ["goal", "saved", "missed", "blocked"][i % 4], xg: 0.03 + (i % 9) / 30, team: i % 2 ? "away" : "home" }));
const svg = nhlShotMap(shots, { fold: true, zones: true, statistic: "xg" }).draw();

MLB spray chart

Baseball spray chartDrawn as: a baseball field, with a 90-foot infield, the mound, the foul lines and the outfield fence. The outfield fence follows the figures published for Fenway Park. Data: Zone chart of 60 balls in play. Share of all, % in 6 zones, from 1.8% to 33.9%. Highest: Centre, outfield (33.9%), Opposite, outfield (28.6%), Pull, outfield (25%). 4 outside the grid or the zones. 60 balls in play. By outcome: Single 10, Double 10, Triple 10, Home run 10, Out 20. Key. Single, Double, Triple, Home run, Out Key.Zone chart of 60 balls in playShare of all, % in 6 zones, from 1.8% to 33.9%. Highest: Centre, outfield (33.9%), Opposite, outfield (28.6%), Pull, outfield (25%). 4 outside the grid or the zones.Pull, infield: 1.8% (1)Centre, infield: 5.4% (3)Opposite, infield: 5.4% (3)Pull, outfield: 25% (14)Centre, outfield: 33.9% (19)Opposite, outfield: 28.6% (16)33.9%28.6%25%5.4%5.4%1.8%Legend: Share of all, %Share of all, %10%20%30%60 balls in playBy outcome: Single 10, Double 10, Triple 10, Home run 10, Out 20.KeySingle, Double, Triple, Home run, OutKeySingleDoubleTripleHome runOut

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { mlbSprayChart } from "@johnmorrisdotca/kyogijo-stadiums/charts";

const types = ["single", "field_out", "double", "field_out", "home_run", "triple"];
const balls = Array.from({ length: 60 }, (_, i) => ({ x: 125.4 + (((i * 37) % 120) - 60), y: 198.27 - (30 + ((i * 53) % 110)), type: types[i % types.length] }));
const svg = mlbSprayChart(balls, { park: "fenway-park", zones: true }).draw();

NFL pass chart

NFL pass chartDrawn as: an American football field, 120 by 53 and a third yards with its end zones, with a yard line every 5 yards, hash marks, numbers and goal posts. Data: Zone chart of 40 passes. Completions, % in 5 zones, from 25% to 80%. Highest: Deep, middle (80%), Deep, left (64.3%), Deep, right (63.6%). 1 line of scrimmage. 40 passes. By outcome: complete 16, incomplete 8, touchdown 8, interception 8. 40 passes. By outcome: Complete 16, Incomplete 8, Touchdown 8, Interception 8. Air yards from 4 to 47. Key. Complete, Incomplete, Touchdown, Interception Key.102030405040302010010203040504030201Zone chart of 40 passesCompletions, % in 5 zones, from 25% to 80%. Highest: Deep, middle (80%), Deep, left (64.3%), Deep, right (63.6%).Short, left: 25% (4)Short, middle (1)Short, right: 60% (5)Deep, left: 64.3% (14)Deep, middle: 80% (5)Deep, right: 63.6% (11)80%4/564.3%9/1463.6%7/1160%3/525%1/4Legend: Completions, %Completions, %40%60%80%1 line of scrimmage40 passesBy outcome: complete 16, incomplete 8, touchdown 8, interception 8.40 passesBy outcome: Complete 16, Incomplete 8, Touchdown 8, Interception 8. Air yards from 4 to 47.KeyComplete, Incomplete, Touchdown, InterceptionKeyCompleteIncompleteTouchdownInterception

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { nflPassChart } from "@johnmorrisdotca/kyogijo-stadiums/charts";

const outcomes = ["complete", "complete", "incomplete", "touchdown", "interception"];
const passes = Array.from({ length: 40 }, (_, i) => ({ x: 66 + ((i * 13) % 44), y: 8 + ((i * 17) % 40), outcome: outcomes[i % outcomes.length], fromX: 60, fromY: 26 }));
const svg = nflPassChart(passes, { los: 62, arrows: true }).draw();

Soccer shot map

Soccer shot mapDrawn as: a soccer pitch, 105 by 68 metres, with the halfway line, the centre circle, both penalty areas, goal areas, penalty marks and arcs, the corner arcs and the goals. Half of it is shown. Data: 24 shots. By outcome: Goal 6, Saved 6, Off target 6, Blocked 6. The size of a mark shows its expected goals (xG). Key. Goal, Saved, Off target, Blocked Key. Size: xG, xG 5.1624 shotsBy outcome: Goal 6, Saved 6, Off target 6, Blocked 6. The size of a mark shows its expected goals (xG).KeyGoal, Saved, Off target, BlockedKeySize: xG, xG 5.16GoalSavedOff targetBlockedSize: xGxG 5.16

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { soccerShotMap } from "@johnmorrisdotca/kyogijo-stadiums/charts";

const outcomes = ["goal", "saved", "missed", "blocked"];
const shots = Array.from({ length: 24 }, (_, i) => ({ x: 84 + ((i * 7) % 30), y: 18 + ((i * 11) % 44), outcome: outcomes[i % 4], xg: 0.04 + (i % 8) / 20 }));
const svg = soccerShotMap(shots, { provider: "statsbomb", half: true }).draw();

Road to the final, card

Aurelia and Calvara: Northern Cup 2030, Road to the finalAurelia played 6 matches on the way to the final and Calvara played 6. The final: Aurelia 2-2 Calvara (4-3 pens). Aurelia won the final.Northern Cup 2030Road to the finalAureliaAURELIACalvaraCALVARAFinal2–24-3 pensSemi-finalAureliaNorvaneNRV2–1AETCalvaraValdorVAL1–3FTQuarter-finalAureliaGarroviaGAR1–15-4 pensCalvaraHelmaraHEL2–22-3 pensRound of 16AureliaFenlundFEN2–1FTCalvaraDornmarkDOR0–1FTGroup stageIsenmarkISE2–0LumeriaLUM1–1RovanaROV3–0EstriaEST4–1BoreaBOR0–1Kestrel IslesKES2–2Made-up teams, flags and results

1080 by 1350. The winner of each match is brighter; the final's loser is quiet.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { roadToFinal } from "@johnmorrisdotca/kyogijo-stadiums/charts";

const flag = (a, b, c) => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 20"><rect width="30" height="20" fill="' + a + '"/><path d="M15 2L27 10L15 18L3 10Z" fill="' + b + '"/><circle cx="15" cy="10" r="3.4" fill="' + c + '"/></svg>';
const stripes = (a, b, c) => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 20"><rect width="10.1" height="20" fill="' + a + '"/><rect x="10" width="10.1" height="20" fill="' + b + '"/><rect x="20" width="10" height="20" fill="' + c + '"/></svg>';
const aurelia = {
  name: "Aurelia", abbr: "AUR", color: "#0f7a7a", logo: flag("#0f7a7a", "#f4f0e4", "#e07a1f"),
  group: [
    { opponent: { name: "Isenmark", abbr: "ISE", color: "#3a2d6b", logo: stripes("#3a2d6b", "#f4f0e4", "#3a2d6b") }, score: [2, 0] },
    { opponent: { name: "Lumeria", abbr: "LUM", color: "#14233f", logo: flag("#14233f", "#f2c230", "#14233f") }, score: [1, 1] },
    { opponent: { name: "Rovana", abbr: "ROV", color: "#1f6b3c", logo: stripes("#f2c230", "#1f6b3c", "#f2c230") }, score: [3, 0] },
  ],
  path: [
    { round: "round-of-16", opponent: { name: "Fenlund", abbr: "FEN", color: "#1f6b3c", logo: flag("#1f6b3c", "#f2c230", "#1f6b3c") }, score: [2, 1] },
    { round: "quarter-final", opponent: { name: "Garrovia", abbr: "GAR", color: "#14233f", logo: stripes("#14233f", "#f2a900", "#14233f") }, score: [1, 1], decidedBy: "pens", pens: [5, 4] },
    { round: "semi-final", opponent: { name: "Norvane", abbr: "NRV", color: "#1f6b3c", logo: flag("#f4f0e4", "#1f6b3c", "#f4f0e4") }, score: [2, 1], decidedBy: "aet" },
  ],
};
const calvara = {
  name: "Calvara", abbr: "CAL", color: "#6b2d5c", logo: stripes("#6b2d5c", "#f2c230", "#14233f"),
  group: [
    { opponent: { name: "Estria", abbr: "EST", color: "#3a2d6b", logo: flag("#e8e2cf", "#3a2d6b", "#e8e2cf") }, score: [4, 1] },
    { opponent: { name: "Borea", abbr: "BOR", color: "#8a2d4b", logo: stripes("#8a2d4b", "#e8e2cf", "#2f7a67") }, score: [0, 1] },
    { opponent: { name: "Kestrel Isles", abbr: "KES", color: "#14233f", logo: flag("#14233f", "#e8e2cf", "#c2410c") }, score: [2, 2] },
  ],
  path: [
    { round: "round-of-16", opponent: { name: "Dornmark", abbr: "DOR", color: "#c2410c", logo: flag("#c2410c", "#14233f", "#c2410c") }, score: [1, 0] },
    { round: "quarter-final", opponent: { name: "Helmara", abbr: "HEL", color: "#7a2a8c", logo: stripes("#f2c230", "#7a2a8c", "#f2c230") }, score: [2, 2], decidedBy: "pens", pens: [3, 2] },
    { round: "semi-final", opponent: { name: "Valdor", abbr: "VAL", color: "#c2410c", logo: stripes("#c2410c", "#f4f0e4", "#c2410c") }, score: [3, 1] },
  ],
};
const svg = roadToFinal([aurelia, calvara], { title: "Northern Cup 2030", final: { score: [2, 2], decidedBy: "pens", pens: [4, 3] }, endnote: "Made-up teams, flags and results" }).draw();

Road to the final, wide

Aurelia and Calvara: Northern Cup 2030, Road to the finalAurelia played 6 matches on the way to the final and Calvara played 6. The final is still to be played.Northern Cup 2030Road to the finalAureliaAURELIACalvaraCALVARAFinalvSemi-finalAureliaNorvaneNRV2–1AETCalvaraValdorVAL1–3FTQuarter-finalAureliaGarroviaGAR1–15-4 pensCalvaraHelmaraHEL2–22-3 pensRound of 16AureliaFenlundFEN2–1FTCalvaraDornmarkDOR0–1FTGroup stageIsenmarkISE2–0LumeriaLUM1–1RovanaROV3–0EstriaEST4–1BoreaBOR0–1Kestrel IslesKES2–2

1200 by 675, before the final is played: the middle says v.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { roadToFinal } from "@johnmorrisdotca/kyogijo-stadiums/charts";

const flag = (a, b, c) => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 20"><rect width="30" height="20" fill="' + a + '"/><path d="M15 2L27 10L15 18L3 10Z" fill="' + b + '"/><circle cx="15" cy="10" r="3.4" fill="' + c + '"/></svg>';
const stripes = (a, b, c) => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 20"><rect width="10.1" height="20" fill="' + a + '"/><rect x="10" width="10.1" height="20" fill="' + b + '"/><rect x="20" width="10" height="20" fill="' + c + '"/></svg>';
const aurelia = {
  name: "Aurelia", abbr: "AUR", color: "#0f7a7a", logo: flag("#0f7a7a", "#f4f0e4", "#e07a1f"),
  group: [
    { opponent: { name: "Isenmark", abbr: "ISE", color: "#3a2d6b", logo: stripes("#3a2d6b", "#f4f0e4", "#3a2d6b") }, score: [2, 0] },
    { opponent: { name: "Lumeria", abbr: "LUM", color: "#14233f", logo: flag("#14233f", "#f2c230", "#14233f") }, score: [1, 1] },
    { opponent: { name: "Rovana", abbr: "ROV", color: "#1f6b3c", logo: stripes("#f2c230", "#1f6b3c", "#f2c230") }, score: [3, 0] },
  ],
  path: [
    { round: "round-of-16", opponent: { name: "Fenlund", abbr: "FEN", color: "#1f6b3c", logo: flag("#1f6b3c", "#f2c230", "#1f6b3c") }, score: [2, 1] },
    { round: "quarter-final", opponent: { name: "Garrovia", abbr: "GAR", color: "#14233f", logo: stripes("#14233f", "#f2a900", "#14233f") }, score: [1, 1], decidedBy: "pens", pens: [5, 4] },
    { round: "semi-final", opponent: { name: "Norvane", abbr: "NRV", color: "#1f6b3c", logo: flag("#f4f0e4", "#1f6b3c", "#f4f0e4") }, score: [2, 1], decidedBy: "aet" },
  ],
};
const calvara = {
  name: "Calvara", abbr: "CAL", color: "#6b2d5c", logo: stripes("#6b2d5c", "#f2c230", "#14233f"),
  group: [
    { opponent: { name: "Estria", abbr: "EST", color: "#3a2d6b", logo: flag("#e8e2cf", "#3a2d6b", "#e8e2cf") }, score: [4, 1] },
    { opponent: { name: "Borea", abbr: "BOR", color: "#8a2d4b", logo: stripes("#8a2d4b", "#e8e2cf", "#2f7a67") }, score: [0, 1] },
    { opponent: { name: "Kestrel Isles", abbr: "KES", color: "#14233f", logo: flag("#14233f", "#e8e2cf", "#c2410c") }, score: [2, 2] },
  ],
  path: [
    { round: "round-of-16", opponent: { name: "Dornmark", abbr: "DOR", color: "#c2410c", logo: flag("#c2410c", "#14233f", "#c2410c") }, score: [1, 0] },
    { round: "quarter-final", opponent: { name: "Helmara", abbr: "HEL", color: "#7a2a8c", logo: stripes("#f2c230", "#7a2a8c", "#f2c230") }, score: [2, 2], decidedBy: "pens", pens: [3, 2] },
    { round: "semi-final", opponent: { name: "Valdor", abbr: "VAL", color: "#c2410c", logo: stripes("#c2410c", "#f4f0e4", "#c2410c") }, score: [3, 1] },
  ],
};
const svg = roadToFinal([aurelia, calvara], { title: "Northern Cup 2030", size: "wide" }).draw();

Road to the final, phone, dark

Aurelia and Calvara: Northern Cup 2030, Road to the finalAurelia played 6 matches on the way to the final and Calvara played 6. The final is still to be played.Northern Cup 2030Road to the finalAureliaAURELIACalvaraCALVARAFinalvSemi-finalAureliaNorvaneNRV2–1AETCalvaraValdorVAL1–3FTQuarter-finalAureliaGarroviaGAR1–15-4 pensCalvaraHelmaraHEL2–22-3 pensRound of 16AureliaFenlundFEN2–1FTCalvaraDornmarkDOR0–1FTGroup stageIsenmarkISE2–0LumeriaLUM1–1RovanaROV3–0EstriaEST4–1BoreaBOR0–1Kestrel IslesKES2–2

390 wide and as tall as the rounds need, with each round's name over its row.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { roadToFinal } from "@johnmorrisdotca/kyogijo-stadiums/charts";

const flag = (a, b, c) => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 20"><rect width="30" height="20" fill="' + a + '"/><path d="M15 2L27 10L15 18L3 10Z" fill="' + b + '"/><circle cx="15" cy="10" r="3.4" fill="' + c + '"/></svg>';
const stripes = (a, b, c) => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 20"><rect width="10.1" height="20" fill="' + a + '"/><rect x="10" width="10.1" height="20" fill="' + b + '"/><rect x="20" width="10" height="20" fill="' + c + '"/></svg>';
const aurelia = {
  name: "Aurelia", abbr: "AUR", color: "#0f7a7a", logo: flag("#0f7a7a", "#f4f0e4", "#e07a1f"),
  group: [
    { opponent: { name: "Isenmark", abbr: "ISE", color: "#3a2d6b", logo: stripes("#3a2d6b", "#f4f0e4", "#3a2d6b") }, score: [2, 0] },
    { opponent: { name: "Lumeria", abbr: "LUM", color: "#14233f", logo: flag("#14233f", "#f2c230", "#14233f") }, score: [1, 1] },
    { opponent: { name: "Rovana", abbr: "ROV", color: "#1f6b3c", logo: stripes("#f2c230", "#1f6b3c", "#f2c230") }, score: [3, 0] },
  ],
  path: [
    { round: "round-of-16", opponent: { name: "Fenlund", abbr: "FEN", color: "#1f6b3c", logo: flag("#1f6b3c", "#f2c230", "#1f6b3c") }, score: [2, 1] },
    { round: "quarter-final", opponent: { name: "Garrovia", abbr: "GAR", color: "#14233f", logo: stripes("#14233f", "#f2a900", "#14233f") }, score: [1, 1], decidedBy: "pens", pens: [5, 4] },
    { round: "semi-final", opponent: { name: "Norvane", abbr: "NRV", color: "#1f6b3c", logo: flag("#f4f0e4", "#1f6b3c", "#f4f0e4") }, score: [2, 1], decidedBy: "aet" },
  ],
};
const calvara = {
  name: "Calvara", abbr: "CAL", color: "#6b2d5c", logo: stripes("#6b2d5c", "#f2c230", "#14233f"),
  group: [
    { opponent: { name: "Estria", abbr: "EST", color: "#3a2d6b", logo: flag("#e8e2cf", "#3a2d6b", "#e8e2cf") }, score: [4, 1] },
    { opponent: { name: "Borea", abbr: "BOR", color: "#8a2d4b", logo: stripes("#8a2d4b", "#e8e2cf", "#2f7a67") }, score: [0, 1] },
    { opponent: { name: "Kestrel Isles", abbr: "KES", color: "#14233f", logo: flag("#14233f", "#e8e2cf", "#c2410c") }, score: [2, 2] },
  ],
  path: [
    { round: "round-of-16", opponent: { name: "Dornmark", abbr: "DOR", color: "#c2410c", logo: flag("#c2410c", "#14233f", "#c2410c") }, score: [1, 0] },
    { round: "quarter-final", opponent: { name: "Helmara", abbr: "HEL", color: "#7a2a8c", logo: stripes("#f2c230", "#7a2a8c", "#f2c230") }, score: [2, 2], decidedBy: "pens", pens: [3, 2] },
    { round: "semi-final", opponent: { name: "Valdor", abbr: "VAL", color: "#c2410c", logo: stripes("#c2410c", "#f4f0e4", "#c2410c") }, score: [3, 1] },
  ],
};
const svg = roadToFinal([aurelia, calvara], { title: "Northern Cup 2030", size: "phone", theme: "dark" }).draw();

Road to the final: a series, with no flags

Northern Owls and Harbour City Gulls: Cup play-offs, Road to the finalNorthern Owls played 3 matches on the way to the final and Harbour City Gulls played 3. The final is still to be played.Cup play-offsRoad to the finalNorthern OwlsNOWNORTHERN OWLSHarbour City GullsHCGHARBOUR CITY GULLSCup finalvConference finalNorthern OwlsNOWPrairie Ridge BisonPRBPRB4–3Game 7Harbour City GullsHCGValley StarsVALVAL2–4Game 6Second roundNorthern OwlsNOWLakeshore AnchorsLSALSA4–2Game 6Harbour City GullsHCGSummit PeaksSMTSMT3–4Game 7First roundNorthern OwlsNOWCoastal PinesCPNCPN4–0Game 4Harbour City GullsHCGMetro BoltsMTBMTB1–4Game 5

A team with no flag or logo is its initials on its colour; the rounds are named by the caller and the scores are games won.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { roadToFinal } from "@johnmorrisdotca/kyogijo-stadiums/charts";

const owls = {
  name: "Northern Owls", abbr: "NOW", color: "#3a2d6b",
  path: [
    { round: "first-round", opponent: { name: "Coastal Pines", abbr: "CPN", color: "#1f6b3c" }, score: "4-0", note: "Game 4" },
    { round: "second-round", opponent: { name: "Lakeshore Anchors", abbr: "LSA", color: "#0f7a7a" }, score: "4-2", note: "Game 6" },
    { round: "conference-final", opponent: { name: "Prairie Ridge Bison", abbr: "PRB", color: "#a8452c" }, score: "4-3", note: "Game 7" },
  ],
};
const gulls = {
  name: "Harbour City Gulls", abbr: "HCG", color: "#1d4f91",
  path: [
    { round: "first-round", opponent: { name: "Metro Bolts", abbr: "MTB", color: "#c2410c" }, score: "4-1", note: "Game 5" },
    { round: "second-round", opponent: { name: "Summit Peaks", abbr: "SMT", color: "#14233f" }, score: "4-3", note: "Game 7" },
    { round: "conference-final", opponent: { name: "Valley Stars", abbr: "VAL", color: "#c8102e" }, score: "4-2", note: "Game 6" },
  ],
};
const labels = { "first-round": "First round", "second-round": "Second round", "conference-final": "Conference final", final: "Cup final" };
const svg = roadToFinal([owls, gulls], { title: "Cup play-offs", labels, size: "square" }).draw();

Team shape#

Pass networks, formations, space control, triangulations, hulls, flow fields and sonars, as on the Team shape page. Made-up players and passes from a fixed formula.

Pass network

Soccer pitchDrawn as: a soccer pitch, 105 by 68 metres, with the halfway line, the centre circle, both penalty areas, goal areas, penalty marks and arcs, the corner arcs and the goals. Data: Pass network: 11 players, 44 links from 240 passes. Most touches: 2, 46. Strongest link: 1 and 2, 6 passes. Links of fewer than 3 passes are left out.Pass network: 11 players, 44 links from 240 passesMost touches: 2, 46. Strongest link: 1 and 2, 6 passes. Links of fewer than 3 passes are left out.1 and 2: 6 passes1 and 8: 6 passes4 and 7: 6 passes11 and 2: 6 passes7 and 8: 6 passes3 and 7: 6 passes10 and 2: 6 passes6 and 8: 6 passes2 and 3: 6 passes2 and 9: 6 passes5 and 8: 6 passes1 and 3: 6 passes8 and 9: 6 passes4 and 8: 6 passes11 and 3: 6 passes7 and 9: 6 passes3 and 4: 6 passes10 and 3: 6 passes6 and 9: 6 passes2 and 4: 6 passes10 and 9: 5 passes5 and 9: 5 passes1 and 4: 5 passes10 and 8: 5 passes4 and 5: 5 passes11 and 4: 5 passes10 and 7: 5 passes3 and 5: 5 passes10 and 11: 5 passes10 and 6: 5 passes2 and 5: 5 passes11 and 9: 5 passes5 and 6: 5 passes1 and 5: 5 passes11 and 8: 5 passes4 and 6: 5 passes1 and 11: 5 passes11 and 7: 5 passes3 and 6: 5 passes1 and 10: 5 passes6 and 7: 5 passes2 and 6: 5 passes1 and 9: 5 passes5 and 7: 5 passes1: 43 touches (22 passes made, 21 received)2: 46 touches (22 passes made, 24 received)8: 46 touches (22 passes made, 24 received)4: 44 touches (22 passes made, 22 received)7: 44 touches (22 passes made, 22 received)11: 42 touches (22 passes made, 20 received)3: 46 touches (22 passes made, 24 received)10: 42 touches (22 passes made, 20 received)6: 42 touches (22 passes made, 20 received)9: 44 touches (21 passes made, 23 received)5: 41 touches (21 passes made, 20 received)1284711310695

A node at the average place of each player's passes, sized by his touches; a link for each pair, wider the more passes between them.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const passes = Array.from({ length: 240 }, (_, i) => { const a = (i * 7) % 11; const b = (a + 1 + ((i * 3) % 4)) % 11; return { from: a + 1, to: b + 1, x: 14 + a * 6 + (i % 5), y: 12 + ((a * 17) % 76) + (i % 7), x2: 14 + b * 6, y2: 12 + ((b * 17) % 76), team: "home", fromNumber: a + 1, toNumber: b + 1 }; });
const svg = drawKyogijo({ sport: "soccer", layers: [{ kind: "network", from: "opta", data: passes, minPasses: 3 }] });

Pass network, directed

Soccer pitchDrawn as: a soccer pitch, 105 by 68 metres, with the halfway line, the centre circle, both penalty areas, goal areas, penalty marks and arcs, the corner arcs and the goals. Data: Pass network: 11 players, 20 links from 240 passes. Most touches: 2, 46. Strongest link: 1 to 2, 6 passes. Links of fewer than 6 passes are left out.Pass network: 11 players, 20 links from 240 passesMost touches: 2, 46. Strongest link: 1 to 2, 6 passes. Links of fewer than 6 passes are left out.1 to 2: 6 passes8 to 1: 6 passes4 to 7: 6 passes11 to 2: 6 passes7 to 8: 6 passes3 to 7: 6 passes10 to 2: 6 passes6 to 8: 6 passes2 to 3: 6 passes9 to 2: 6 passes5 to 8: 6 passes1 to 3: 6 passes8 to 9: 6 passes4 to 8: 6 passes11 to 3: 6 passes7 to 9: 6 passes3 to 4: 6 passes10 to 3: 6 passes6 to 9: 6 passes2 to 4: 6 passes1: 43 touches (22 passes made, 21 received)2: 46 touches (22 passes made, 24 received)8: 46 touches (22 passes made, 24 received)4: 44 touches (22 passes made, 22 received)7: 44 touches (22 passes made, 22 received)11: 42 touches (22 passes made, 20 received)3: 46 touches (22 passes made, 24 received)10: 42 touches (22 passes made, 20 received)6: 42 touches (22 passes made, 20 received)9: 44 touches (21 passes made, 23 received)5: 41 touches (21 passes made, 20 received)1284711310695

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const passes = Array.from({ length: 240 }, (_, i) => { const a = (i * 7) % 11; const b = (a + 1 + ((i * 3) % 4)) % 11; return { from: a + 1, to: b + 1, x: 14 + a * 6 + (i % 5), y: 12 + ((a * 17) % 76) + (i % 7), x2: 14 + b * 6, y2: 12 + ((b * 17) % 76), team: "home", fromNumber: a + 1, toNumber: b + 1 }; });
const svg = drawKyogijo({ sport: "soccer", layers: [{ kind: "network", from: "opta", data: passes, minPasses: 6, directed: true, labels: "id" }] });

Pass network chart

Pass networkDrawn as: a soccer pitch, 105 by 68 metres, with the halfway line, the centre circle, both penalty areas, goal areas, penalty marks and arcs, the corner arcs and the goals. Data: Pass network: 11 players, 44 links from 240 passes. Most touches: 2, 46. Strongest link: 1 and 2, 6 passes. Links of fewer than 4 passes are left out. Key. Key. Node size: touches, Link width: passesPass network: 11 players, 44 links from 240 passesMost touches: 2, 46. Strongest link: 1 and 2, 6 passes. Links of fewer than 4 passes are left out.1 and 2: 6 passes1 and 8: 6 passes4 and 7: 6 passes11 and 2: 6 passes7 and 8: 6 passes3 and 7: 6 passes10 and 2: 6 passes6 and 8: 6 passes2 and 3: 6 passes2 and 9: 6 passes5 and 8: 6 passes1 and 3: 6 passes8 and 9: 6 passes4 and 8: 6 passes11 and 3: 6 passes7 and 9: 6 passes3 and 4: 6 passes10 and 3: 6 passes6 and 9: 6 passes2 and 4: 6 passes10 and 9: 5 passes5 and 9: 5 passes1 and 4: 5 passes10 and 8: 5 passes4 and 5: 5 passes11 and 4: 5 passes10 and 7: 5 passes3 and 5: 5 passes10 and 11: 5 passes10 and 6: 5 passes2 and 5: 5 passes11 and 9: 5 passes5 and 6: 5 passes1 and 5: 5 passes11 and 8: 5 passes4 and 6: 5 passes1 and 11: 5 passes11 and 7: 5 passes3 and 6: 5 passes1 and 10: 5 passes6 and 7: 5 passes2 and 6: 5 passes1 and 9: 5 passes5 and 7: 5 passes1: 43 touches (22 passes made, 21 received)2: 46 touches (22 passes made, 24 received)8: 46 touches (22 passes made, 24 received)4: 44 touches (22 passes made, 22 received)7: 44 touches (22 passes made, 22 received)11: 42 touches (22 passes made, 20 received)3: 46 touches (22 passes made, 24 received)10: 42 touches (22 passes made, 20 received)6: 42 touches (22 passes made, 20 received)9: 44 touches (21 passes made, 23 received)5: 41 touches (21 passes made, 20 received)1284711310695KeyKeyNode size: touches, Link width: passesNode size: touchesLink width: passes

With the key and the totals; `table()` lists the players and the links.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { passNetwork } from "@johnmorrisdotca/kyogijo-stadiums/charts";

const passes = Array.from({ length: 240 }, (_, i) => { const a = (i * 7) % 11; const b = (a + 1 + ((i * 3) % 4)) % 11; return { from: a + 1, to: b + 1, x: 14 + a * 6 + (i % 5), y: 12 + ((a * 17) % 76) + (i % 7), x2: 14 + b * 6, y2: 12 + ((b * 17) % 76), team: "home", fromNumber: a + 1, toNumber: b + 1 }; });
const svg = passNetwork(passes, { provider: "opta", minPasses: 4 }).draw();

Formations: 4-4-2 against 4-3-3

Soccer pitchDrawn as: a soccer pitch, 105 by 68 metres, with the halfway line, the centre circle, both penalty areas, goal areas, penalty marks and arcs, the corner arcs and the goals. Data: Formation 4-4-2: 11 positions. Positions: Goalkeeper, Right back, Right centre-back, Left centre-back, Left back, Right midfielder, Right central midfielder, Left central midfielder, Left midfielder, Right striker, Left striker. Four defenders, four midfielders in a flat line and two strikers. Formation 4-3-3: 11 positions. Positions: Goalkeeper, Right back, Right centre-back, Left centre-back, Left back, Right central midfielder, Central midfielder, Left central midfielder, Right winger, Striker, Left winger. Four defenders, three midfielders and a front three of two wingers and a striker.Formation 4-4-2: 11 positionsPositions: Goalkeeper, Right back, Right centre-back, Left centre-back, Left back, Right midfielder, Right central midfielder, Left central midfielder, Left midfielder, Right striker, Left striker. Four defenders, four midfielders in a flat line and two strikers.GoalkeeperRight backRight centre-backLeft centre-backLeft backRight midfielderRight central midfielderLeft central midfielderLeft midfielderRight strikerLeft strikerGKRBRCBLCBLBRMRCMLCMLMRSLSFormation 4-3-3: 11 positionsPositions: Goalkeeper, Right back, Right centre-back, Left centre-back, Left back, Right central midfielder, Central midfielder, Left central midfielder, Right winger, Striker, Left winger. Four defenders, three midfielders and a front three of two wingers and a striker.GoalkeeperRight backRight centre-backLeft centre-backLeft backRight central midfielderCentral midfielderLeft central midfielderRight wingerStrikerLeft wingerGKRBRCBLCBLBRCMCMLCMRWSTLW

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const svg = drawKyogijo({
  sport: "soccer",
  layers: [
    { kind: "formation", formation: "4-4-2", team: "home" },
    { kind: "formation", formation: "4-3-3", team: "away", attacking: "left" },
  ],
});

A formation with its lineup

Soccer pitchDrawn as: a soccer pitch, 105 by 68 metres, with the halfway line, the centre circle, both penalty areas, goal areas, penalty marks and arcs, the corner arcs and the goals. Data: Formation 4-2-3-1: 11 positions. Positions: Goalkeeper, Right back, Right centre-back, Left centre-back, Left back, Right defensive midfielder, Left defensive midfielder, Right winger, Attacking midfielder, Left winger, Striker. Players: Okafor (Goalkeeper), Haas (Right back), Ito (Left back), Silva (Striker). Four defenders, two holding midfielders, three behind a lone striker.Formation 4-2-3-1: 11 positionsPositions: Goalkeeper, Right back, Right centre-back, Left centre-back, Left back, Right defensive midfielder, Left defensive midfielder, Right winger, Attacking midfielder, Left winger, Striker. Players: Okafor (Goalkeeper), Haas (Right back), Ito (Left back), Silva (Striker). Four defenders, two holding midfielders, three behind a lone striker.Goalkeeper: Okafor 1Right back: Haas 2Right centre-backLeft centre-backLeft back: Ito 3Right defensive midfielderLeft defensive midfielderRight wingerAttacking midfielderLeft wingerStriker: Silva 91Okafor2Haas3Ito9Silva

A position nobody stands on is hollow.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const lineup = [["GK", 1, "Okafor"], ["RB", 2, "Haas"], ["LB", 3, "Ito"], ["ST", 9, "Silva"]].map(([position, number, name]) => ({ position, number, name }));
const svg = drawKyogijo({ sport: "soccer", layers: [{ kind: "formation", formation: "4-2-3-1", team: "home", data: lineup, names: true }] });

Formations: a rink

NHL hockey rinkDrawn as: an ice hockey rink, 200 by 85 feet with rounded corners, with its red and blue lines, face-off circles, creases and goal nets. Data: Formation Hockey, five skaters and the goaltender: 6 positions. Positions: Goaltender, Left defenceman, Right defenceman, Left wing, Centre, Right wing. The six players on the ice at even strength: the goaltender, two defencemen and a line of centre and two wings. Formation Hockey, 1-3-1 power play: 6 positions. Positions: Goaltender, Right defenceman, Left wing, Left defenceman, Right wing, Centre. A power-play set in the attacking zone: one at the point, three across the middle and one low. Which player takes which place varies by team.Formation Hockey, five skaters and the goaltender: 6 positionsPositions: Goaltender, Left defenceman, Right defenceman, Left wing, Centre, Right wing. The six players on the ice at even strength: the goaltender, two defencemen and a line of centre and two wings.GoaltenderLeft defencemanRight defencemanLeft wingCentreRight wingGLDRDLWCRWFormation Hockey, 1-3-1 power play: 6 positionsPositions: Goaltender, Right defenceman, Left wing, Left defenceman, Right wing, Centre. A power-play set in the attacking zone: one at the point, three across the middle and one low. Which player takes which place varies by team.GoaltenderRight defencemanLeft wingLeft defencemanRight wingCentreGRDLWLDRWC

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const svg = drawKyogijo({
  sport: "nhl",
  layers: [
    { kind: "formation", formation: "hockey-5v5", team: "home" },
    { kind: "formation", formation: "hockey-1-3-1", team: "away", attacking: "left" },
  ],
});

Formations: a court

NBA basketball courtDrawn as: a basketball court, 94 by 50 feet, with its keys, three-point lines, free-throw circles and the centre circle. Data: Formation Basketball, 1-4 high: 5 positions. Positions: Point guard, Power forward, Centre, Shooting guard, Small forward. The point guard at the top, two forwards at the elbows of the free-throw line and a guard on each wing.Formation Basketball, 1-4 high: 5 positionsPositions: Point guard, Power forward, Centre, Shooting guard, Small forward. The point guard at the top, two forwards at the elbows of the free-throw line and a guard on each wing.Point guardPower forwardCentreShooting guardSmall forwardPGPFCSGSF

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const svg = drawKyogijo({ sport: "nba", layers: [{ kind: "formation", formation: "basketball-high-post", team: "home" }] });

Formations: offence and defence

NFL football fieldDrawn as: an American football field, 120 by 53 and a third yards with its end zones, with a yard line every 5 yards, hash marks, numbers and goal posts. Data: Formation Football, shotgun: 11 positions. Positions: Centre, Left guard, Left tackle, Right guard, Right tackle, Quarterback, Halfback, Tight end, Wide receiver 1, Wide receiver 2, Wide receiver 3. Offence: the quarterback a few yards behind the centre with a halfback beside him, a tight end and three wide receivers. Formation Football, 4-3 defence: 11 positions. Positions: Left defensive end, Left defensive tackle, Right defensive tackle, Right defensive end, Left linebacker, Middle linebacker, Right linebacker, Left cornerback, Right cornerback, Free safety, Strong safety. Defence against an offence going right: four linemen, three linebackers, two cornerbacks and two safeties. Left and right are the defenders' own.102030405040302010010203040504030201Formation Football, shotgun: 11 positionsPositions: Centre, Left guard, Left tackle, Right guard, Right tackle, Quarterback, Halfback, Tight end, Wide receiver 1, Wide receiver 2, Wide receiver 3. Offence: the quarterback a few yards behind the centre with a halfback beside him, a tight end and three wide receivers.CentreLeft guardLeft tackleRight guardRight tackleQuarterbackHalfbackTight endWide receiver 1Wide receiver 2Wide receiver 3CLGLTRGRTQBHBTEWR1WR2WR3Formation Football, 4-3 defence: 11 positionsPositions: Left defensive end, Left defensive tackle, Right defensive tackle, Right defensive end, Left linebacker, Middle linebacker, Right linebacker, Left cornerback, Right cornerback, Free safety, Strong safety. Defence against an offence going right: four linemen, three linebackers, two cornerbacks and two safeties. Left and right are the defenders' own.Left defensive endLeft defensive tackleRight defensive tackleRight defensive endLeft linebackerMiddle linebackerRight linebackerLeft cornerbackRight cornerbackFree safetyStrong safetyLDELDTRDTRDELLBMLBRLBLCBRCBFSSS

The ball is on the 30-yard line (40 yards from the back of the left end zone).

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const svg = drawKyogijo({
  sport: "nfl",
  layers: [
    { kind: "formation", formation: "football-shotgun", team: "home", los: 40 },
    { kind: "formation", formation: "football-4-3", team: "away", los: 40 },
  ],
});

Formations: a ballpark and a shift

Baseball fieldDrawn as: a baseball field, with a 90-foot infield, the mound, the foul lines and the outfield fence. Data: Formation Baseball, infield shift against a left-handed pull hitter: 9 positions. Positions: Pitcher, Catcher, First baseman, Second baseman, Shortstop, Third baseman, Left fielder, Centre fielder, Right fielder. Three infielders on the right side of second base and the outfield turned the same way. Since 2023 MLB's Rule 5.02 requires two infielders on each side of second base, so this shift is not allowed there.Formation Baseball, infield shift against a left-handed pull hitter: 9 positionsPositions: Pitcher, Catcher, First baseman, Second baseman, Shortstop, Third baseman, Left fielder, Centre fielder, Right fielder. Three infielders on the right side of second base and the outfield turned the same way. Since 2023 MLB's Rule 5.02 requires two infielders on each side of second base, so this shift is not allowed there.PitcherCatcherFirst basemanSecond basemanShortstopThird basemanLeft fielderCentre fielderRight fielderPC1B2BSS3BLFCFRF

An infield shift against a left-handed pull hitter. Not allowed in MLB since 2023.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const svg = drawKyogijo({ sport: "mlb", layers: [{ kind: "formation", formation: "baseball-shift", team: "away" }] });

Lineups: 4-2-3-1 against 4-4-2

Soccer pitchDrawn as: a soccer pitch, 105 by 68 metres, with the halfway line, the centre circle, both penalty areas, goal areas, penalty marks and arcs, the corner arcs and the goals. Data: Lineup in 4-2-3-1: 11 players. Players: Okafor (Goalkeeper), Silva (Right back), Mbeki (Right centre-back), Rossi (Left centre-back), Ito (Left back), Nakamura (Right defensive midfielder), Costa (Left defensive midfielder), Dubois (Right winger), Haddad (Attacking midfielder), Kowalski (Left winger), Eze (Striker). Captain: Mbeki. Four defenders, two holding midfielders, three behind a lone striker. Lineup in 4-4-2: 3 players. Players: Meyer (Goalkeeper), Moreau (Right striker), Eze (Left striker). Four defenders, four midfielders in a flat line and two strikers.Lineup in 4-2-3-1: 11 playersPlayers: Okafor (Goalkeeper), Silva (Right back), Mbeki (Right centre-back), Rossi (Left centre-back), Ito (Left back), Nakamura (Right defensive midfielder), Costa (Left defensive midfielder), Dubois (Right winger), Haddad (Attacking midfielder), Kowalski (Left winger), Eze (Striker). Captain: Mbeki. Four defenders, two holding midfielders, three behind a lone striker.Goalkeeper: Okafor 1Right back: Silva 2Right centre-back: Mbeki 3Left centre-back: Rossi 4Left back: Ito 5Right defensive midfielder: Nakamura 6Left defensive midfielder: Costa 7Right winger: Dubois 8Attacking midfielder: Haddad 9Left winger: Kowalski 10Striker: Eze 11Captain1Okafor2Silva3MbekiC4Rossi5Ito6Nakamura7Costa8Dubois9Haddad10Kowalski11EzeLineup in 4-4-2: 3 playersPlayers: Meyer (Goalkeeper), Moreau (Right striker), Eze (Left striker). Four defenders, four midfielders in a flat line and two strikers.Goalkeeper: Meyer 1Right backRight centre-backLeft centre-backLeft backRight midfielderRight central midfielderLeft central midfielderLeft midfielderRight striker: Moreau 9Left striker: Eze 101MeyerRBRCBLCBLBRMRCMLCMLM9Moreau10Eze

The home team has no formation: the best fit is chosen. The visitors attack the other way.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const home = ["Okafor", "Silva", "Mbeki", "Rossi", "Ito", "Nakamura", "Costa", "Dubois", "Haddad", "Kowalski", "Eze"];
const codes = ["GK", "RB", "CB", "CB", "LB", "DM", "DM", "RW", "AM", "LW", "ST"];
const players = home.map((name, i) => ({ pos: codes[i], name, number: i + 1, captain: i === 2 }));
const svg = drawKyogijo({
  sport: "soccer",
  layers: [
    { kind: "lineup", side: "home", players },
    { kind: "lineup", side: "away", formation: "4-4-2", shape: "jersey", players: [{ pos: "GK", name: "Meyer", number: 1 }, { pos: "ST", name: "Moreau", number: 9 }, { pos: "ST", name: "Eze", number: 10 }] },
  ],
});

Lineups: a rink with a second line

NHL hockey rinkDrawn as: an ice hockey rink, 200 by 85 feet with rounded corners, with its red and blue lines, face-off circles, creases and goal nets. Data: Lineup in Hockey, two lines: 9 players. Players: Hellebuyck (Goaltender), Josi (Left defenceman), Makar (Right defenceman), Marner (Left wing), McDavid (Centre), Rantanen (Right wing), Hyman (Left wing on the second line), Draisaitl (Centre on the second line), Kane (Right wing on the second line). Captain: Josi. The six on the ice and, in a row along the bench side, the next forward line and defence pair, each marked as the second unit. The codes of the second unit end in 2.Lineup in Hockey, two lines: 9 playersPlayers: Hellebuyck (Goaltender), Josi (Left defenceman), Makar (Right defenceman), Marner (Left wing), McDavid (Centre), Rantanen (Right wing), Hyman (Left wing on the second line), Draisaitl (Centre on the second line), Kane (Right wing on the second line). Captain: Josi. The six on the ice and, in a row along the bench side, the next forward line and defence pair, each marked as the second unit. The codes of the second unit end in 2.Goaltender: Hellebuyck 37Left defenceman: Josi 59Right defenceman: Makar 8Left wing: Marner 16Centre: McDavid 97Right wing: Rantanen 96Left defenceman on the second pairRight defenceman on the second pairLeft wing on the second line: Hyman 18Centre on the second line: Draisaitl 29Right wing on the second line: Kane 93Captain37Hellebuyck59JosiC8Makar16Marner97McDavid96RantanenLD2RD218Hyman29Draisaitl93Kane

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const svg = drawKyogijo({
  sport: "nhl",
  layers: [
    {
      kind: "lineup",
      side: "home",
      players: [
        { pos: "G", name: "Hellebuyck", number: 37 }, { pos: "D", name: "Josi", number: 59, captain: true }, { pos: "D", name: "Makar", number: 8 },
        { pos: "LW", name: "Marner", number: 16 }, { pos: "C", name: "McDavid", number: 97 }, { pos: "RW", name: "Rantanen", number: 96 },
        { pos: "LW", name: "Hyman", number: 18, line: 2 }, { pos: "C", name: "Draisaitl", number: 29, line: 2 }, { pos: "RW", name: "Kane", number: 93, line: 2 },
      ],
    },
  ],
});

Lineups: a ballpark with the designated hitter

Baseball fieldDrawn as: a baseball field, with a 90-foot infield, the mound, the foul lines and the outfield fence. Data: Lineup in Baseball, standard defence: 10 players. Players: Cole (Pitcher), Rutschman (Catcher), Alonso (First baseman), Albies (Second baseman), Witt (Shortstop), Ramirez (Third baseman), Soto (Left fielder), Trout (Centre fielder), Judge (Right fielder), Ohtani (Designated hitter). The nine fielders where they usually stand: a straight infield and the outfielders in their fields.Lineup in Baseball, standard defence: 10 playersPlayers: Cole (Pitcher), Rutschman (Catcher), Alonso (First baseman), Albies (Second baseman), Witt (Shortstop), Ramirez (Third baseman), Soto (Left fielder), Trout (Centre fielder), Judge (Right fielder), Ohtani (Designated hitter). The nine fielders where they usually stand: a straight infield and the outfielders in their fields.Pitcher: Cole 1Catcher: Rutschman 2First baseman: Alonso 3Second baseman: Albies 4Shortstop: Witt 5Third baseman: Ramirez 6Left fielder: Soto 7Centre fielder: Trout 8Right fielder: Judge 9Designated hitter: Ohtani 101Cole2Rutschman3Alonso4Albies5Witt6Ramirez7Soto8Trout9Judge10Ohtani

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const codes = ["P", "C", "1B", "2B", "SS", "3B", "LF", "CF", "RF", "DH"];
const names = ["Cole", "Rutschman", "Alonso", "Albies", "Witt", "Ramirez", "Soto", "Trout", "Judge", "Ohtani"];
const players = codes.map((pos, i) => ({ pos, name: names[i], number: i + 1 }));
const svg = drawKyogijo({ sport: "mlb", layers: [{ kind: "lineup", shape: "jersey", players }] });

Lineups: two rugby teams

Rugby union fieldDrawn as: a rugby union field, 120 by 70 metres with its in-goal areas, with the 22-metre lines, the half-way line, the dash lines and the goal posts. Data: Lineup in Rugby union, the fifteen: 15 players. Players: Player 1 (Loosehead prop), Player 2 (Hooker), Player 3 (Tighthead prop), Player 4 (Lock), Player 5 (Lock), Player 6 (Blindside flanker), Player 7 (Openside flanker), Player 8 (Number eight), Player 9 (Scrum-half), Player 10 (Fly-half), Player 12 (Inside centre), Player 13 (Outside centre), Player 11 (Left wing), Player 14 (Right wing), Player 15 (Full-back). The fifteen in their numbers, 1 to 15: the pack of eight bound as for a scrum, the scrum-half beside it, the fly-half and the centres in a line behind, the wings wide and the full-back deep. Lineup in Rugby union, the fifteen: 15 players. Players: Player 1 (Loosehead prop), Player 2 (Hooker), Player 3 (Tighthead prop), Player 4 (Lock), Player 5 (Lock), Player 6 (Blindside flanker), Player 7 (Openside flanker), Player 8 (Number eight), Player 9 (Scrum-half), Player 10 (Fly-half), Player 12 (Inside centre), Player 13 (Outside centre), Player 11 (Left wing), Player 14 (Right wing), Player 15 (Full-back). The fifteen in their numbers, 1 to 15: the pack of eight bound as for a scrum, the scrum-half beside it, the fly-half and the centres in a line behind, the wings wide and the full-back deep.Lineup in Rugby union, the fifteen: 15 playersPlayers: Player 1 (Loosehead prop), Player 2 (Hooker), Player 3 (Tighthead prop), Player 4 (Lock), Player 5 (Lock), Player 6 (Blindside flanker), Player 7 (Openside flanker), Player 8 (Number eight), Player 9 (Scrum-half), Player 10 (Fly-half), Player 12 (Inside centre), Player 13 (Outside centre), Player 11 (Left wing), Player 14 (Right wing), Player 15 (Full-back). The fifteen in their numbers, 1 to 15: the pack of eight bound as for a scrum, the scrum-half beside it, the fly-half and the centres in a line behind, the wings wide and the full-back deep.Loosehead prop: Player 1 1Hooker: Player 2 2Tighthead prop: Player 3 3Lock: Player 4 4Lock: Player 5 5Blindside flanker: Player 6 6Openside flanker: Player 7 7Number eight: Player 8 8Scrum-half: Player 9 9Fly-half: Player 10 10Inside centre: Player 12 12Outside centre: Player 13 13Left wing: Player 11 11Right wing: Player 14 14Full-back: Player 15 151Player 12Player 23Player 34Player 45Player 56Player 67Player 78Player 89Player 910Player 1012Player 1213Player 1311Player 1114Player 1415Player 15Lineup in Rugby union, the fifteen: 15 playersPlayers: Player 1 (Loosehead prop), Player 2 (Hooker), Player 3 (Tighthead prop), Player 4 (Lock), Player 5 (Lock), Player 6 (Blindside flanker), Player 7 (Openside flanker), Player 8 (Number eight), Player 9 (Scrum-half), Player 10 (Fly-half), Player 12 (Inside centre), Player 13 (Outside centre), Player 11 (Left wing), Player 14 (Right wing), Player 15 (Full-back). The fifteen in their numbers, 1 to 15: the pack of eight bound as for a scrum, the scrum-half beside it, the fly-half and the centres in a line behind, the wings wide and the full-back deep.Loosehead prop: Player 1 1Hooker: Player 2 2Tighthead prop: Player 3 3Lock: Player 4 4Lock: Player 5 5Blindside flanker: Player 6 6Openside flanker: Player 7 7Number eight: Player 8 8Scrum-half: Player 9 9Fly-half: Player 10 10Inside centre: Player 12 12Outside centre: Player 13 13Left wing: Player 11 11Right wing: Player 14 14Full-back: Player 15 151Player 12Player 23Player 34Player 45Player 56Player 67Player 78Player 89Player 910Player 1012Player 1213Player 1311Player 1114Player 1415Player 15

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const fifteen = () => Array.from({ length: 15 }, (_, i) => ({ pos: String(i + 1), number: i + 1, name: "Player " + (i + 1) }));
const svg = drawKyogijo({ sport: "rugby", layers: [{ kind: "lineup", side: "home", shape: "jersey", players: fifteen() }, { kind: "lineup", side: "away", shape: "jersey", players: fifteen() }] });

Lineups: an offence and a defence

NFL football fieldDrawn as: an American football field, 120 by 53 and a third yards with its end zones, with a yard line every 5 yards, hash marks, numbers and goal posts. Shows only the field between the 20-yard lines. Data outside it is not drawn. Data: Lineup in Football, I formation: 11 players. Players: 7 (Centre), 8 (Left guard), 10 (Left tackle), 9 (Right guard), 11 (Right tackle), 1 (Quarterback), 3 (Fullback), 2 (Halfback), 4 (Tight end), 5 (Wide receiver 1), 6 (Wide receiver 2). Offence: the quarterback under centre with the fullback and the halfback in a line behind him, a tight end and two wide receivers. Lineup in Football, 4-3 defence: 11 players. Players: 1 (Left defensive end), 2 (Left defensive tackle), 3 (Right defensive tackle), 4 (Right defensive end), 6 (Left linebacker), 5 (Middle linebacker), 7 (Right linebacker), 8 (Left cornerback), 9 (Right cornerback), 10 (Free safety), 11 (Strong safety). Defence against an offence going right: four linemen, three linebackers, two cornerbacks and two safeties. Left and right are the defenders' own.102030405040302010010203040504030201Lineup in Football, I formation: 11 playersPlayers: 7 (Centre), 8 (Left guard), 10 (Left tackle), 9 (Right guard), 11 (Right tackle), 1 (Quarterback), 3 (Fullback), 2 (Halfback), 4 (Tight end), 5 (Wide receiver 1), 6 (Wide receiver 2). Offence: the quarterback under centre with the fullback and the halfback in a line behind him, a tight end and two wide receivers.Centre: 7Left guard: 8Left tackle: 10Right guard: 9Right tackle: 11Quarterback: 1Fullback: 3Halfback: 2Tight end: 4Wide receiver 1: 5Wide receiver 2: 67810911132456Lineup in Football, 4-3 defence: 11 playersPlayers: 1 (Left defensive end), 2 (Left defensive tackle), 3 (Right defensive tackle), 4 (Right defensive end), 6 (Left linebacker), 5 (Middle linebacker), 7 (Right linebacker), 8 (Left cornerback), 9 (Right cornerback), 10 (Free safety), 11 (Strong safety). Defence against an offence going right: four linemen, three linebackers, two cornerbacks and two safeties. Left and right are the defenders' own.Left defensive end: 1Left defensive tackle: 2Right defensive tackle: 3Right defensive end: 4Left linebacker: 6Middle linebacker: 5Right linebacker: 7Left cornerback: 8Right cornerback: 9Free safety: 10Strong safety: 111234657891011

A football line stands shoulder to shoulder, so the picture is zoomed to the middle of the field.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const offence = ["QB", "HB", "FB", "TE", "WR", "WR", "C", "LG", "RG", "LT", "RT"];
const defence = ["DE", "DT", "DT", "DE", "LB", "LB", "LB", "CB", "CB", "S", "S"];
const of = (codes) => codes.map((pos, i) => ({ pos, number: i + 1 }));
const svg = drawKyogijo({
  sport: "nfl",
  range: "between-the-20s",
  layers: [{ kind: "lineup", side: "home", players: of(offence) }, { kind: "lineup", side: "away", players: of(defence) }],
});

Lineups: a fielding preset

Cricket groundDrawn as: a cricket ground, 150 by 150 yards, with its boundary, the pitch with its creases and wickets, and the fielding restriction's circle where the rules have one. Data: Lineup in Cricket, attacking field for a fast bowler: 11 players. Players: 1 (Bowler), 2 (Wicketkeeper), 3 (First slip), 4 (Second slip), 5 (Third slip), 6 (Gully), 7 (Point), 8 (Cover), 9 (Mid-off), 10 (Mid-on), 11 (Square leg). For a right-handed batter: three slips and a gully on the off side to catch an edge, point, cover, mid-off, mid-on and square leg all close, and the wicketkeeper standing back. Nobody is on the boundary.Lineup in Cricket, attacking field for a fast bowler: 11 playersPlayers: 1 (Bowler), 2 (Wicketkeeper), 3 (First slip), 4 (Second slip), 5 (Third slip), 6 (Gully), 7 (Point), 8 (Cover), 9 (Mid-off), 10 (Mid-on), 11 (Square leg). For a right-handed batter: three slips and a gully on the off side to catch an edge, point, cover, mid-off, mid-on and square leg all close, and the wicketkeeper standing back. Nobody is on the boundary.Bowler: 1Wicketkeeper: 2First slip: 3Second slip: 4Third slip: 5Gully: 6Point: 7Cover: 8Mid-off: 9Mid-on: 10Square leg: 111234567891011

For a right-handed batter with the striker at the right end: the off side is up the page.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const codes = ["BWL", "WK", "SL1", "SL2", "SL3", "GU", "PT", "CV", "MO", "MN", "SQ"];
const svg = drawKyogijo({ sport: "cricket", layers: [{ kind: "lineup", formation: "cricket-test-attacking", players: codes.map((pos, i) => ({ pos, number: i + 1 })) }] });

Lineups: a volleyball rotation

Volleyball courtDrawn as: a volleyball court, 18 by 9 metres, with its centre line, attack lines, the net and its antennae. Data: Lineup in Volleyball, the six places of the rotation: 6 players. Players: 5 (Position 4, left front), 4 (Position 3, centre front), 3 (Position 2, right front), 6 (Position 5, left back), 1 (Position 6, centre back), 2 (Position 1, right back). Rotation 2 of 6. The six places, numbered as the rules number them: 1 right back (the server), 2 right front, 3 centre front, 4 left front, 5 left back and 6 centre back. After each side-out the team moves one place clockwise. Lineup in Volleyball, the six places of the rotation: 6 players. Players: 4 (Position 4, left front), 3 (Position 3, centre front), 2 (Position 2, right front), 5 (Position 5, left back), 6 (Position 6, centre back), 1 (Position 1, right back). The six places, numbered as the rules number them: 1 right back (the server), 2 right front, 3 centre front, 4 left front, 5 left back and 6 centre back. After each side-out the team moves one place clockwise.Lineup in Volleyball, the six places of the rotation: 6 playersPlayers: 5 (Position 4, left front), 4 (Position 3, centre front), 3 (Position 2, right front), 6 (Position 5, left back), 1 (Position 6, centre back), 2 (Position 1, right back). Rotation 2 of 6. The six places, numbered as the rules number them: 1 right back (the server), 2 right front, 3 centre front, 4 left front, 5 left back and 6 centre back. After each side-out the team moves one place clockwise.Position 4, left front: 5Position 3, centre front: 4Position 2, right front: 3Position 5, left back: 6Position 6, centre back: 1Position 1, right back: 2543612Lineup in Volleyball, the six places of the rotation: 6 playersPlayers: 4 (Position 4, left front), 3 (Position 3, centre front), 2 (Position 2, right front), 5 (Position 5, left back), 6 (Position 6, centre back), 1 (Position 1, right back). The six places, numbered as the rules number them: 1 right back (the server), 2 right front, 3 centre front, 4 left front, 5 left back and 6 centre back. After each side-out the team moves one place clockwise.Position 4, left front: 4Position 3, centre front: 3Position 2, right front: 2Position 5, left back: 5Position 6, centre back: 6Position 1, right back: 1432561

The home team is on its second rotation: each player has moved one place clockwise.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const six = ["P1", "P2", "P3", "P4", "P5", "P6"].map((pos, i) => ({ pos, number: i + 1 }));
const svg = drawKyogijo({ sport: "volleyball", layers: [{ kind: "lineup", side: "home", rotation: 2, players: six }, { kind: "lineup", side: "away", players: six }] });

Voronoi: space control

Soccer pitchDrawn as: a soccer pitch, 105 by 68 metres, with the halfway line, the centre circle, both penalty areas, goal areas, penalty marks and arcs, the corner arcs and the goals. Data: Space control of 22 players. Share of the surface nearest each team's players: away 50.7%, home 49.3%.Space control of 22 playersShare of the surface nearest each team's players: away 50.7%, home 49.3%.1, home: 4.1%2, home: 2.7%3, home: 2.2%4, home: 3.2%5, home: 2.4%6, home: 1.9%7, home: 5.2%8, home: 3.9%9, home: 8.5%10, home: 10.1%11, home: 5.1%1, away: 6%2, away: 5.2%3, away: 6.3%4, away: 7.2%5, away: 4.2%6, away: 3.7%7, away: 2.8%8, away: 2.3%9, away: 3.6%10, away: 2.8%11, away: 6.4%

Each player's cell is the part of the pitch nearer him than any other player; the description gives each team's share.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const players = Array.from({ length: 22 }, (_, i) => ({ x: 8 + ((i * 37 + (i < 11 ? 3 : 17)) % 88), y: 8 + ((i * 53 + (i < 11 ? 5 : 11)) % 84), team: i < 11 ? "home" : "away", number: (i % 11) + 1 }));
const svg = drawKyogijo({ sport: "soccer", layers: [{ kind: "voronoi", from: "opta", data: players }] });

Delaunay triangles

Soccer pitchDrawn as: a soccer pitch, 105 by 68 metres, with the halfway line, the centre circle, both penalty areas, goal areas, penalty marks and arcs, the corner arcs and the goals. Data: Delaunay triangulation of 22 players. 25 triangles and 45 edges.Delaunay triangulation of 22 players25 triangles and 45 edges.home: 13 triangles and 23 edges.away: 12 triangles and 22 edges.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const players = Array.from({ length: 22 }, (_, i) => ({ x: 8 + ((i * 37 + (i < 11 ? 3 : 17)) % 88), y: 8 + ((i * 53 + (i < 11 ? 5 : 11)) % 84), team: i < 11 ? "home" : "away", number: (i % 11) + 1 }));
const svg = drawKyogijo({ sport: "soccer", layers: [{ kind: "delaunay", from: "opta", data: players, triangles: true }] });

Convex hulls

Soccer pitchDrawn as: a soccer pitch, 105 by 68 metres, with the halfway line, the centre circle, both penalty areas, goal areas, penalty marks and arcs, the corner arcs and the goals. Data: Convex hull of 22 players. home: 11 players, area 29568 square feet, away: 11 players, area 31308 square feet.Convex hull of 22 playershome: 11 players, area 29568 square feet, away: 11 players, area 31308 square feet.home: 11 players, area 29568 square feetaway: 11 players, area 31308 square feet

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const players = Array.from({ length: 22 }, (_, i) => ({ x: 8 + ((i * 37 + (i < 11 ? 3 : 17)) % 88), y: 8 + ((i * 53 + (i < 11 ? 5 : 11)) % 84), team: i < 11 ? "home" : "away", number: (i % 11) + 1 }));
const svg = drawKyogijo({ sport: "soccer", layers: [{ kind: "hull", from: "opta", data: players }] });

Space and shape, tall and dark

Soccer pitchDrawn as: a soccer pitch, 105 by 68 metres, with the halfway line, the centre circle, both penalty areas, goal areas, penalty marks and arcs, the corner arcs and the goals. Data: Space control of 22 players. Share of the surface nearest each team's players: away 50.7%, home 49.3%. Convex hull of 22 players. home: 11 players, area 29568 square feet, away: 11 players, area 31308 square feet.Space control of 22 playersShare of the surface nearest each team's players: away 50.7%, home 49.3%.1, home: 4.1%2, home: 2.7%3, home: 2.2%4, home: 3.2%5, home: 2.4%6, home: 1.9%7, home: 5.2%8, home: 3.9%9, home: 8.5%10, home: 10.1%11, home: 5.1%1, away: 6%2, away: 5.2%3, away: 6.3%4, away: 7.2%5, away: 4.2%6, away: 3.7%7, away: 2.8%8, away: 2.3%9, away: 3.6%10, away: 2.8%11, away: 6.4%Convex hull of 22 playershome: 11 players, area 29568 square feet, away: 11 players, area 31308 square feet.home: 11 players, area 29568 square feetaway: 11 players, area 31308 square feet

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const players = Array.from({ length: 22 }, (_, i) => ({ x: 8 + ((i * 37 + (i < 11 ? 3 : 17)) % 88), y: 8 + ((i * 53 + (i < 11 ? 5 : 11)) % 84), team: i < 11 ? "home" : "away", number: (i % 11) + 1 }));
const svg = drawKyogijo({
  sport: "soccer",
  orientation: "portrait",
  theme: "dark",
  layers: [{ kind: "voronoi", from: "opta", data: players }, { kind: "hull", from: "opta", data: players }],
});

Flow field

Soccer pitchDrawn as: a soccer pitch, 105 by 68 metres, with the halfway line, the centre circle, both penalty areas, goal areas, penalty marks and arcs, the corner arcs and the goals. Data: Flow of 400 movements in 53 cells. The mean movement of a cell is up to 54.6 feet long.Flow of 400 movements in 53 cellsThe mean movement of a cell is up to 54.6 feet long.

The mean direction of the passes that start in each cell.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const moves = Array.from({ length: 400 }, (_, i) => { const x = 5 + ((i * 13) % 90); const y = 5 + ((i * 29) % 90); return { x, y, x2: x + 8 + (i % 5) + (x > 50 ? 4 : 0), y2: y + ((i % 7) - 3) * 2.2, id: (i % 5) + 1 }; });
const svg = drawKyogijo({ sport: "soccer", layers: [{ kind: "flow", from: "opta", data: moves, bins: 12 }] });

Sonars: a rose for each player

Soccer pitchDrawn as: a soccer pitch, 105 by 68 metres, with the halfway line, the centre circle, both penalty areas, goal areas, penalty marks and arcs, the corner arcs and the goals. Data: Direction roses of 400 movements: 5 roses of 10 directions. Most common direction: 0 degrees, 62. 0 degrees points to the right end of the surface as drawn wide and 90 degrees to the top.Direction roses of 400 movements: 5 roses of 10 directionsMost common direction: 0 degrees, 62. 0 degrees points to the right end of the surface as drawn wide and 90 degrees to the top.1: 80 movements, most toward 0 degrees342 to 18 degrees: 4318 to 54 degrees: 18306 to 342 degrees: 192: 80 movements, most toward 0 degrees342 to 18 degrees: 5618 to 54 degrees: 13306 to 342 degrees: 113: 80 movements, most toward 0 degrees342 to 18 degrees: 6118 to 54 degrees: 10306 to 342 degrees: 94: 80 movements, most toward 0 degrees342 to 18 degrees: 6018 to 54 degrees: 11306 to 342 degrees: 95: 80 movements, most toward 0 degrees342 to 18 degrees: 6218 to 54 degrees: 9306 to 342 degrees: 9

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const moves = Array.from({ length: 400 }, (_, i) => { const x = 5 + ((i * 13) % 90); const y = 5 + ((i * 29) % 90); return { x, y, x2: x + 8 + (i % 5) + (x > 50 ? 4 : 0), y2: y + ((i % 7) - 3) * 2.2, id: (i % 5) + 1 }; });
const svg = drawKyogijo({ sport: "soccer", layers: [{ kind: "sonar", from: "opta", data: moves, by: "player", angles: 10 }] });

Sonars: a rose for each cell of a rink

NHL hockey rinkDrawn as: an ice hockey rink, 200 by 85 feet with rounded corners, with its red and blue lines, face-off circles, creases and goal nets. Data: Direction roses of 400 movements: 32 roses of 8 directions. Most common direction: 0 degrees, 22. 0 degrees points to the right end of the surface as drawn wide and 90 degrees to the top.Direction roses of 400 movements: 32 roses of 8 directionsMost common direction: 0 degrees, 22. 0 degrees points to the right end of the surface as drawn wide and 90 degrees to the top.25: 10 movements, most toward 0 degrees338 to 23 degrees: 1018: 14 movements, most toward 0 degrees338 to 23 degrees: 1411: 14 movements, most toward 0 degrees338 to 23 degrees: 144: 14 movements, most toward 0 degrees338 to 23 degrees: 1421: 18 movements, most toward 0 degrees338 to 23 degrees: 1814: 14 movements, most toward 0 degrees338 to 23 degrees: 147: 18 movements, most toward 0 degrees338 to 23 degrees: 1817: 10 movements, most toward 0 degrees338 to 23 degrees: 1010: 14 movements, most toward 0 degrees338 to 23 degrees: 143: 14 movements, most toward 0 degrees338 to 23 degrees: 1428: 9 movements, most toward 0 degrees338 to 23 degrees: 913: 22 movements, most toward 0 degrees338 to 23 degrees: 226: 13 movements, most toward 0 degrees338 to 23 degrees: 1331: 13 movements, most toward 0 degrees338 to 23 degrees: 139: 14 movements, most toward 0 degrees338 to 23 degrees: 142: 13 movements, most toward 0 degrees338 to 23 degrees: 1327: 17 movements, most toward 0 degrees338 to 23 degrees: 1720: 18 movements, most toward 0 degrees338 to 23 degrees: 185: 5 movements, most toward 0 degrees338 to 23 degrees: 530: 13 movements, most toward 0 degrees338 to 23 degrees: 1323: 13 movements, most toward 0 degrees338 to 23 degrees: 1326: 13 movements, most toward 0 degrees338 to 23 degrees: 1319: 13 movements, most toward 0 degrees338 to 23 degrees: 1312: 13 movements, most toward 0 degrees338 to 23 degrees: 1329: 13 movements, most toward 0 degrees338 to 23 degrees: 1322: 13 movements, most toward 0 degrees338 to 23 degrees: 1315: 13 movements, most toward 0 degrees338 to 23 degrees: 1332: 4 movements, most toward 0 degrees338 to 23 degrees: 424: 12 movements, most toward 0 degrees338 to 23 degrees: 121: 4 movements, most toward 0 degrees338 to 23 degrees: 416: 8 movements, most toward 0 degrees338 to 23 degrees: 88: 4 movements, most toward 0 degrees338 to 23 degrees: 4

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const moves = Array.from({ length: 400 }, (_, i) => { const x = 5 + ((i * 13) % 90); const y = 5 + ((i * 29) % 90); return { x, y, x2: x + 8 + (i % 5) + (x > 50 ? 4 : 0), y2: y + ((i % 7) - 3) * 2.2, id: (i % 5) + 1 }; }).map((m) => ({ x: m.x * 2 - 100, y: m.y * 0.85 - 42.5, x2: m.x2 * 2 - 100, y2: m.y2 * 0.85 - 42.5 }));
const svg = drawKyogijo({ sport: "nhl", layers: [{ kind: "sonar", from: "nhl-api", data: moves, by: "grid", bins: 8, angles: 8 }] });

Sonars: a rose for each zone

Soccer pitchDrawn as: a soccer pitch, 105 by 68 metres, with the halfway line, the centre circle, both penalty areas, goal areas, penalty marks and arcs, the corner arcs and the goals. Data: Direction roses of 400 movements: 3 roses of 8 directions. Most common direction: 0 degrees, 47. 0 degrees points to the right end of the surface as drawn wide and 90 degrees to the top.Direction roses of 400 movements: 3 roses of 8 directionsMost common direction: 0 degrees, 47. 0 degrees points to the right end of the surface as drawn wide and 90 degrees to the top.Defensive third: 131 movements, most toward 0 degrees338 to 23 degrees: 37.423 to 68 degrees: 33.8293 to 338 degrees: 34.2Middle third: 147 movements, most toward 0 degrees338 to 23 degrees: 44.923 to 68 degrees: 35.2293 to 338 degrees: 34.2Attacking third: 122 movements, most toward 0 degrees338 to 23 degrees: 47.323 to 68 degrees: 41.6

The bars are the mean length of the passes in each direction.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawKyogijo } from "@johnmorrisdotca/kyogijo-stadiums";

const moves = Array.from({ length: 400 }, (_, i) => { const x = 5 + ((i * 13) % 90); const y = 5 + ((i * 29) % 90); return { x, y, x2: x + 8 + (i % 5) + (x > 50 ? 4 : 0), y2: y + ((i % 7) - 3) * 2.2, id: (i % 5) + 1 }; });
const svg = drawKyogijo({ sport: "soccer", layers: [{ kind: "sonar", from: "opta", data: moves, by: "zone", zones: "soccer-thirds", angles: 8, statistic: "mean" }] });

Replay#

A frame of tracking data on a surface: drawFrame from @johnmorrisdotca/kyogijo-stadiums/replay. The same frame, played, is mountKyogijo(...).replay(...).

A frame of a replay: the rink

NHL hockey rinkDrawn as: an ice hockey rink, 200 by 85 feet with rounded corners, with its red and blue lines, face-off circles, creases and goal nets. Data: Replay, 0:10. 7 tracked objects. By team: home 3, away 3, puck 1. 2 events.Trail of the last 2 secondsPasses and shotsBy outcome: shot 1. By team: home 1.Shot, home, 0:07PlayersBy team: home 3, away 3.home 9home 17home 28away 4away 8away 31Shirt numbers917284831ball, puckpuck

Tracking data in the NHL API's frame, played on the rink: the players with their numbers, the puck with its trail, and the events that are on the surface at 7.8 seconds (the pass has gone, the shot is on its way). Played, with controls, it is mountKyogijo(...).replay(...).

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawFrame } from "@johnmorrisdotca/kyogijo-stadiums/replay";

const skater = (id, team, number, x, y, t) => ({ id, team, number, x: x + 6 * Math.sin(t / 1.4 + number), y: y + 4 * Math.cos(t / 1.1 + number) });
const frames = Array.from({ length: 51 }, (_, i) => {
  const t = i / 5;
  const objects = [skater("h9", "home", 9, 30, 0, t), skater("h17", "home", 17, 48, 18, t), skater("h28", "home", 28, 48, -18, t), skater("a4", "away", 4, 62, 8, t), skater("a8", "away", 8, 62, -8, t), skater("a31", "away", 31, 89, 0, 0)];
  const puck = objects[Math.min(2, Math.floor(t / 3.5))];
  return { t, objects: [...objects, { id: "puck", team: "puck", x: puck.x, y: puck.y }] };
});
const events = [
  { t: 3.5, kind: "pass", team: "home", by: "h9", to: "h17", until: 4 },
  { t: 7, kind: "shot", team: "home", by: "h28", x2: 89, y2: 2, until: 7.6 },
];
const svg = drawFrame({ sport: "nhl" }, { from: "nhl-api", frames, events }, 7.8);

A frame of a replay: the pitch

Soccer pitchDrawn as: a soccer pitch, 105 by 68 metres, with the halfway line, the centre circle, both penalty areas, goal areas, penalty marks and arcs, the corner arcs and the goals. Data: Replay, 0:08. 7 tracked objects. By team: home 4, away 2, ball 1. 2 events.Trail of the last 3 seconds1 eventBy outcome: goal 1. By team: home 1.Goal, home, 0:06PlayersBy team: home 4, away 2.home 1home 4home 8home 9away 5away 1Shirt numbers148951ball, puckball

The same on the pitch, in Opta's frame, with a trail of three seconds and the goal marked by a star.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawFrame } from "@johnmorrisdotca/kyogijo-stadiums/replay";

const spot = (id, team, number, x, y, t) => ({ id, team, number, x: x + 4 * Math.sin(t / 1.7 + number), y: y + 5 * Math.cos(t / 1.3 + number) });
const frames = Array.from({ length: 41 }, (_, i) => {
  const t = i / 5;
  const objects = [spot("h1", "home", 1, 4, 50, t), spot("h4", "home", 4, 30, 35, t), spot("h8", "home", 8, 50, 55, t), spot("h9", "home", 9, 72, 45, t), spot("a5", "away", 5, 66, 60, t), spot("a1", "away", 1, 96, 50, 0)];
  const ball = objects[Math.min(3, Math.floor(t / 2))];
  return { t, possession: ball.id, objects: [...objects, { id: "ball", team: "ball", x: ball.x, y: ball.y }] };
});
const events = [{ t: 2, kind: "pass", team: "home", by: "h4", to: "h8", until: 2.4 }, { t: 6, kind: "goal", team: "home", x: 100, y: 48 }];
const svg = drawFrame({ sport: "soccer" }, { from: "opta", frames, events }, 6.4, { trail: 3 });

Goals, the strike zone and the stumps#

A target seen end-on, with where each shot, pitch or delivery crossed it: @johnmorrisdotca/kyogijo-stadiums/target.

A hockey net with its zones

Goal mouth, Hockey net: where the shots crossed the goal lineThe Hockey net, 6 by 4 feet, seen from the front: the shooter's left is on the left. Data: 7 shots. By outcome: Goal 2, Saved 1, Post 1, Crossbar 1, Wide 1, High 1.Top left cornerTop left cornerTop shelfTop shelfTop right cornerTop right cornerLeft sideLeft sideCentreCentreRight sideRight sideBottom left cornerBottom left cornerFive-holeFive-holeBottom right cornerBottom right corner7 shotsBy outcome: Goal 2, Saved 1, Post 1, Crossbar 1, Wide 1, High 1.

The net is the NHL's 6 by 4 feet, seen from the front with the shooter's left on the left. A post and a crossbar are on the frame, a shot wide or high is outside it; the top shelf and the five-hole are hockey's names for the middle cells of the top and bottom rows.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawGoalMouth } from "@johnmorrisdotca/kyogijo-stadiums/target";

const shots = [
  { x: -2.4, z: 3.6, outcome: "goal" },
  { x: 0, z: 0.4, outcome: "saved" },
  { x: 1.5, z: 1.2, outcome: "goal" },
  { x: -3, z: 2.5, outcome: "post" },
  { x: 1, z: 4, outcome: "crossbar" },
  { x: 3.4, z: 2, outcome: "wide" },
  { x: 1.2, z: 4.6, outcome: "high" },
];
const svg = drawGoalMouth(shots, { sport: "nhl", zones: "labels" }).svg;

A soccer goal, dark

Goal mouth, Soccer goal: where the shots crossed the goal lineThe Soccer goal, 7.32 by 2.44 metres, seen from the front: the shooter's left is on the left. Data: 5 shots. By outcome: Goal 1, Saved 1, Post 1, Wide 1, High 1.Top left cornerTop centreTop right cornerLeft sideCentreRight sideBottom left cornerBottom centreBottom right corner5 shotsBy outcome: Goal 1, Saved 1, Post 1, Wide 1, High 1.

The Laws' 7.32 by 2.44 metres; the marks are sized by expected goals.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawGoalMouth } from "@johnmorrisdotca/kyogijo-stadiums/target";

const shots = [
  { x: -3.3, z: 2.2, outcome: "goal", value: 0.4 },
  { x: 1, z: 0.5, outcome: "saved", value: 0.1 },
  { x: 3.66, z: 1.2, outcome: "post", value: 0.05 },
  { x: 4.4, z: 1, outcome: "wide", value: 0.03 },
  { x: 0, z: 2.9, outcome: "high", value: 0.02 },
];
const svg = drawGoalMouth(shots, { sport: "soccer", theme: "dark", zones: true, sizeBy: "value" }).svg;

A lacrosse goal: 6 by 6 feet

Goal mouth, Lacrosse goal: where the shots crossed the goal lineThe Lacrosse goal, 6 by 6 feet, seen from the front: the shooter's left is on the left. Data: 3 shots. By outcome: Goal 1, Saved 1, Wide 1.Top left cornerTop centreTop right cornerLeft sideCentreRight sideBottom left cornerBottom centreBottom right corner3 shotsBy outcome: Goal 1, Saved 1, Wide 1.

World Lacrosse's 1.83 m and the NCAA's and the PLL's 6 feet are the same goal; the box floor's (`league: "nll"`) is 4 feet 9 inches by 4.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawGoalMouth } from "@johnmorrisdotca/kyogijo-stadiums/target";

const shots = [{ x: -2, z: 5, outcome: "goal" }, { x: 2.5, z: 1, outcome: "saved" }, { x: 3.4, z: 3, outcome: "wide" }];
const svg = drawGoalMouth(shots, { sport: "lacrosse", zones: true }).svg;

A water polo goal

Goal mouth, Water polo goal: where the shots crossed the goal lineThe Water polo goal, 3 by 0.9 metres, seen from the front: the shooter's left is on the left. Data: 3 shots. By outcome: Goal 1, Saved 1, Wide 1.Top left cornerTop centreTop right cornerLeft sideCentreRight sideBottom left cornerBottom centreBottom right corner3 shotsBy outcome: Goal 1, Saved 1, Wide 1.

3.0 metres between the posts, the crossbar's underside 0.9 m over the water.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawGoalMouth } from "@johnmorrisdotca/kyogijo-stadiums/target";

const svg = drawGoalMouth([{ x: -1.2, z: 0.7, outcome: "goal" }, { x: 0.4, z: 0.2, outcome: "saved" }, { x: 1.6, z: 0.5, outcome: "wide" }], { sport: "waterpolo", zones: true }).svg;

The strike zone: the catcher's view

Strike zone: where the pitches crossed the plateThe strike zone seen from the catcher's position: the plate 17 inches wide, the zone from 1.5 to 3.5 feet above the ground. The batter stands on the left. Data: 5 pitches. By outcome: Ball 1, Called strike 1, Swinging strike 1, Foul 1, In play 1. 5 pitch numbers.Zone 11Zone 22Zone 33Zone 44Zone 55Zone 66Zone 77Zone 88Zone 99Zone 11, high and leftZone 12, high and rightZone 13, low and leftZone 14, low and rightR5 pitchesBy outcome: Ball 1, Called strike 1, Swinging strike 1, Foul 1, In play 1.5 pitch numbers12345

Plate 17 inches across, a zone from the batter's knees to his belt, the nine cells and the four chase zones round them, the pitches numbered in order, coloured by result and shaped by what became of them.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawStrikeZone } from "@johnmorrisdotca/kyogijo-stadiums/target";

const pitches = [
  { x: 0.1, z: 2.6, outcome: "called-strike", type: "FF" },
  { x: 1.3, z: 1.1, outcome: "ball", type: "SL" },
  { x: -0.4, z: 2.0, outcome: "swinging-strike", type: "SL" },
  { x: 0.9, z: 3.9, outcome: "foul", type: "CH" },
  { x: -0.2, z: 2.4, outcome: "in-play", type: "FF" },
];
const svg = drawStrikeZone(pitches, { bats: "R", top: 3.5, bottom: 1.5 }).svg;

The strike zone, left-handed, by pitch type, dark

Strike zone: where the pitches crossed the plateThe strike zone seen from the catcher's position: the plate 17 inches wide, the zone from 1.6 to 3.6 feet above the ground. The batter stands on the right. Data: 3 pitches. By outcome: Ball 1, Called strike 1, Swinging strike 1. 3 pitch numbers.Zone 11Zone 22Zone 33Zone 44Zone 55Zone 66Zone 77Zone 88Zone 99Zone 11, high and leftZone 12, high and rightZone 13, low and leftZone 14, low and rightL3 pitchesBy outcome: Ball 1, Called strike 1, Swinging strike 1.3 pitch numbers123

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawStrikeZone } from "@johnmorrisdotca/kyogijo-stadiums/target";

const pitches = [
  { x: 0.3, z: 2.9, outcome: "called-strike", type: "FF" },
  { x: -1.1, z: 1.4, outcome: "ball", type: "CH" },
  { x: 0.5, z: 1.8, outcome: "swinging-strike", type: "SL" },
];
const svg = drawStrikeZone(pitches, { bats: "L", colorBy: "type", theme: "dark", top: 3.6, bottom: 1.6 }).svg;

The stumps from the bowler's end

Stumps: where the deliveries reached the wicketThe stumps seen from the bowler's end: three stumps across 9 inches (22.86 cm) and 28 inches (71.12 cm) high, with the bails. Data: 3 deliveries. By outcome: Wicket 1, Runs 1, Dot ball 1.Outside, left of the stumpsOn the stumpsOver the stumpsOutside, right of the stumpsWide right3 deliveriesBy outcome: Wicket 1, Runs 1, Dot ball 1.Good lengthShort of a lengthFull length

Three stumps across 9 inches and 28 inches high, with the bails; the line zones are the stumps' own width either side. The length of a delivery (where it pitched) names its length zone.

Open in a page loads the published package from jsDelivr, which serves only released versions.

Show the code
import { drawStumps } from "@johnmorrisdotca/kyogijo-stadiums/target";

const svg = drawStumps([
  { x: 0.02, z: 0.4, outcome: "wicket", length: 5.1 },
  { x: 0.3, z: 0.5, outcome: "dot", length: 7.4 },
  { x: -0.5, z: 0.2, outcome: "runs", length: 2 },
]).svg;