-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ Allow dynamic height/width of IFAB soccer fields
- Loading branch information
Showing
12 changed files
with
1,317 additions
and
1,109 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
export function customCardSetup(s) { | ||
if (_.startsWith(s.id, "soccer-ifab")) { | ||
customSoccerCardSetup(s.id, s.appearance.width, s.appearance.height); | ||
} | ||
} | ||
|
||
function customSoccerCardSetup(id, width, height) { | ||
const card = d3.select(`#${id}`).attr("href", undefined); | ||
const dim = card.select(".card-text").select(".dimensions"); | ||
const inYards = _.endsWith(id, "-yd"); | ||
dim.selectAll("*").remove(); | ||
dim.append("div").attr("class", "bold").text("Dimensions: "); | ||
const widthField = dim.append("div"); | ||
widthField.append("label").attr("for", `${id}-width`).text("Width:"); | ||
const minWidth = inYards ? 100 : 90; | ||
const maxWidth = inYards ? 130 : 120; | ||
widthField | ||
.append("input") | ||
.attr("id", `${id}-width`) | ||
.attr("type", "number") | ||
.attr("name", `${id}-width`) | ||
.attr("min", minWidth) | ||
.attr("max", maxWidth) | ||
.attr("value", width); | ||
widthField.append("span").text(`(min: ${minWidth}, max: ${maxWidth})`); | ||
|
||
const heightField = dim.append("div"); | ||
heightField.append("label").attr("for", `${id}-height`).text("Height:"); | ||
const minHeight = inYards ? 50 : 45; | ||
const maxHeight = inYards ? 100 : 90; | ||
heightField | ||
.append("input") | ||
.attr("id", `${id}-height`) | ||
.attr("type", "number") | ||
.attr("name", `${id}-height`) | ||
.attr("min", minHeight) | ||
.attr("max", maxHeight) | ||
.attr("value", height); | ||
heightField.append("span").text(`(min: ${minHeight}, max: ${maxHeight})`); | ||
|
||
card.select("button").on("click", function () { | ||
const width = d3.select(`#${id}-width`).property("value"); | ||
const height = d3.select(`#${id}-height`).property("value"); | ||
console.log(width, height); | ||
let params = new URLSearchParams({ | ||
width: width, | ||
height: height, | ||
}); | ||
window.location.href = `./${id}?${params.toString()}`; | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
export function customConfigSetup(config) { | ||
if (_.startsWith(config.id, "soccer-ifab")) { | ||
return customSoccerConfigSetup(config); | ||
} | ||
} | ||
|
||
function customSoccerConfigSetup(config) { | ||
const urlParams = new URLSearchParams(window.location.search); | ||
const w = parseInt(urlParams.get("width")) || config.appearance.width; | ||
const h = parseInt(urlParams.get("height")) || config.appearance.height; | ||
config.appearance.width = w; | ||
config.appearance.height = h; | ||
config.goalCoords = [ | ||
[0, h / 2], | ||
[w, h / 2], | ||
]; | ||
|
||
const ice_hockey = { | ||
width: "200", | ||
circleR: "2", | ||
polyR: "2.75", | ||
fontSize: "0.15", //rem | ||
strokeWidth: "0.5", //px | ||
heatMapScale: 1.25, | ||
}; | ||
|
||
const scaleFactor = parseFloat(ice_hockey.width) / Math.max(w, h); | ||
for (const key in ice_hockey) { | ||
if (key === "heatMapScale") { | ||
config.appearance[key] = parseFloat(ice_hockey[key]) * scaleFactor; | ||
} else { | ||
const val = parseFloat(ice_hockey[key]) / scaleFactor; | ||
const suffix = | ||
key === "fontSize" ? "rem" : key === "strokeWidth" ? "px" : ""; | ||
config.appearance[key] = `${val.toFixed(3)}${suffix}`; | ||
} | ||
} | ||
return config; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import { sport, cfgSportA } from "../../setup.js"; | ||
|
||
export function customPlayingAreaSetup() { | ||
if (_.startsWith(sport, "soccer-ifab")) { | ||
customSoccerPlayingAreaSetup(); | ||
} | ||
} | ||
|
||
function customSoccerPlayingAreaSetup() { | ||
const inYards = _.endsWith(sport, "-yd"); | ||
|
||
const minWidth = inYards ? 100 : 90; | ||
const maxWidth = inYards ? 130 : 120; | ||
|
||
const minHeight = inYards ? 50 : 45; | ||
const maxHeight = inYards ? 100 : 90; | ||
|
||
let w = cfgSportA.width; | ||
w = w < minWidth || w > maxWidth ? 0 : w; | ||
let h = cfgSportA.height; | ||
h = h < minHeight || h > maxHeight || h >= w ? 0 : h; | ||
|
||
const halfw = w / 2; | ||
const halfh = h / 2; | ||
|
||
const goal = inYards ? 8 : 7.32; | ||
const halfgoal = goal / 2; | ||
const eighteenyd = inYards ? 18 : 16.5; | ||
const goalarea = inYards ? 6 : 5.5; | ||
const arc = inYards ? 8 : 7.312; | ||
|
||
const svg = d3.select(`#${sport}-svg`); | ||
svg.attr("viewBox", `-1 -1 ${w + 2} ${h + 2}`); | ||
|
||
const trans = svg.select("#transformations"); | ||
|
||
trans.select("clipPath").select("rect").attr("width", w).attr("height", h); | ||
trans.select("#background").attr("width", w).attr("height", h); | ||
|
||
trans.select("#halfway-line").attr("d", `M ${halfw} 0 L ${halfw} ${h}`); | ||
trans.select("#halfway-circle").attr("cx", halfw).attr("cy", halfh); | ||
|
||
trans.select("#outside-perimeter").attr("width", w).attr("height", h); | ||
|
||
for (const dir of ["left", "right"]) { | ||
const ga = trans.select(`#${dir}-goal`); | ||
if (dir === "right") { | ||
ga.attr("transform", `translate(${w} ${h}) rotate(180)`); | ||
} | ||
|
||
ga.select(`#${dir}-eighteen-yd-box`).attr( | ||
"d", | ||
`M 0 ${halfh - halfgoal - eighteenyd} | ||
L 18 ${halfh - halfgoal - eighteenyd} | ||
L 18 ${halfh + halfgoal + eighteenyd} | ||
L 0 ${halfh + halfgoal + eighteenyd}` | ||
); | ||
|
||
ga.select(`#${dir}-goal-area`).attr( | ||
"d", | ||
`M 0 ${halfh - halfgoal - goalarea} | ||
L 6 ${halfh - halfgoal - goalarea} | ||
L 6 ${halfh + halfgoal + goalarea} | ||
L 0 ${halfh + halfgoal + goalarea}` | ||
); | ||
|
||
ga.select(`#${dir}-penalty-kick-mark`).attr("cy", halfh); | ||
|
||
ga.select(`#${dir}-goal-arc`).attr( | ||
"d", | ||
`M 18 ${halfh - arc} | ||
A 10 10 1 0 1 18 ${halfh + arc} | ||
` | ||
); | ||
|
||
ga.select(`#${dir}-goal-line`).attr( | ||
"d", | ||
`M 0 ${halfh - halfgoal} | ||
L 0 ${halfh + halfgoal} | ||
` | ||
); | ||
|
||
ga.select(`#${dir}-bottom-corner`).attr( | ||
"d", | ||
`M 0 ${h - 1} | ||
A 1 1 0 0 1 1 ${h} | ||
` | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.