Skip to content

Instantly share code, notes, and snippets.

@agware
Last active March 5, 2017 11:05
Show Gist options
  • Save agware/147d4e4cf78f42379459a05ad0ac6763 to your computer and use it in GitHub Desktop.
Save agware/147d4e4cf78f42379459a05ad0ac6763 to your computer and use it in GitHub Desktop.
WAFL Goalkickers
license: gpl-3.0

The challenge for this project was to see what I could produce about the league goal kickers in a single day.

The animated goals and points are selected randomly from all goals and points kicked by that team across the season so far.

To change teams, just mouse over the logo and select the team you would like to see.

Credit

All logos used are property of the AFL, please don't sue me.

All statistics were taken AFL Women's Stats page.

Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
{
"Adelaide": [
{"name": "Sarah Perkins", "number": 28, "goals": 6, "points": 4},
{"name": "Erin Phillips", "number": 13, "goals": 5, "points": 6},
{"name": "Jenna McCormick", "number": 5, "goals": 3, "points": 1},
{"name": "Jessica Sedunary", "number": 17, "goals": 2, "points": 3},
{"name": "Abbey Holmes", "number": 1, "goals": 2, "points": 2},
{"name": "Kellie Gibson", "number": 2, "goals": 2, "points": 2},
{"name": "Sally Riley", "number": 8, "goals": 2, "points": 0},
{"name": "Rachael Killian", "number": 7, "goals": 1, "points": 2},
{"name": "Angela Foley", "number": 3, "goals": 1, "points": 0},
{"name": "Deni Varnhagen", "number": 9, "goals": 1, "points": 0},
{"name": "Chelsea Randall", "number": 26, "goals": 1, "points": 0},
{"name": "Ebony Marinoff", "number": 10, "goals": 0, "points": 2},
{"name": "Rhiannon Metcalfe", "number": 11, "goals": 0, "points": 1}
],
"Brisbane": [
{"name": "Kate McCarthy", "number": 9, "goals": 7, "points": 1},
{"name": "Sabrina Frederick-Traub", "number": 14, "goals": 4, "points": 2},
{"name": "Tayla Harris", "number": 7, "goals": 2, "points": 7},
{"name": "Jessica Wuetschner", "number": 23, "goals": 2, "points": 3},
{"name": "Kaitlyn Ashmore", "number": 10, "goals": 2, "points": 2},
{"name": "Emma Zielke", "number": 8, "goals": 2, "points": 0},
{"name": "Kate Lutkins", "number": 13, "goals": 1, "points": 0},
{"name": "Jordan Membrey", "number": 27, "goals": 1, "points": 0},
{"name": "Shannon Campbell", "number": 20, "goals": 1, "points": 0},
{"name": "Emily Bates", "number": 1, "goals": 1, "points": 0},
{"name": "Brittany Gibson", "number": 25, "goals": 1, "points": 0},
{"name": "Alexandra Anderson", "number": 18, "goals": 0, "points": 1}
],
"Bulldogs": [
{"name": "Ellie Blackburn", "number": 2, "goals": 5, "points": 7},
{"name": "Kirsten McLeod", "number": 6, "goals": 3, "points": 7},
{"name": "Katie Brennan", "number": 3, "goals": 3, "points": 1},
{"name": "Jaimee Lambert", "number": 7, "goals": 2, "points": 2},
{"name": "Kirsty Lamb", "number": 27, "goals": 2, "points": 0},
{"name": "Hayley Wildes", "number": 17, "goals": 1, "points": 3},
{"name": "Meg McDonald", "number": 15, "goals": 1, "points": 1},
{"name": "Courtney Clarkson", "number": 24, "goals": 1, "points": 0},
{"name": "Jess Gardner", "number": 33, "goals": 1, "points": 0},
{"name": "Brooke Lochland", "number": 1, "goals": 1, "points": 0},
{"name": "Aasta O'Connor", "number": 4, "goals": 1, "points": 0},
{"name": "Laura Bailey", "number": 13, "goals": 1, "points": 0},
{"name": "Emma Kearney", "number": 5, "goals": 0, "points": 3},
{"name": "Lauren Spark", "number": 11, "goals": 0, "points": 2},
{"name": "Angelica Gogos", "number": 36, "goals": 0, "points": 1},
{"name": "Ellyse Gamble", "number": 14, "goals": 0, "points": 1},
{"name": "Kate Tyndall", "number": 8, "goals": 0, "points": 1},
{"name": "Rebecca Neaves", "number": 25, "goals": 0, "points": 1}
],
"Carlton": [
{"name": "Darcy Vescio", "number": 3, "goals": 11, "points": 3},
{"name": "Isabella Ayre", "number": 22, "goals": 4, "points": 2},
{"name": "Bianca Jakobsson", "number": 35, "goals": 3, "points": 3},
{"name": "Kate Shierlaw", "number": 25, "goals": 2, "points": 1},
{"name": "Shae Audley", "number": 26, "goals": 2, "points": 1},
{"name": "Lauren Arnell", "number": 13, "goals": 1, "points": 2},
{"name": "Lauren Brazzale", "number": 12, "goals": 1, "points": 0},
{"name": "Gabriella Pound", "number": 6, "goals": 1, "points": 0},
{"name": "Alison Downie", "number": 30, "goals": 1, "points": 0},
{"name": "Sarah Hosking", "number": 10, "goals": 1, "points": 0},
{"name": "Brianna Davey", "number": 1, "goals": 1, "points": 0},
{"name": "Breann Moody", "number": 16, "goals": 1, "points": 0},
{"name": "Nat Exon", "number": 15, "goals": 0, "points": 3},
{"name": "Tilly Lucas-Rodd", "number": 18, "goals": 0, "points": 1},
{"name": "Katherine Gillespie-Jones", "number": 5, "goals": 0, "points": 1},
{"name": "Alison Brown", "number": 27, "goals": 0, "points": 1}
],
"Collingwood": [
{"name": "Moana Hope", "number": 23, "goals": 3, "points": 4},
{"name": "Jessica Cameron", "number": 27, "goals": 3, "points": 2},
{"name": "Jasmine Garner", "number": 43, "goals": 3, "points": 0},
{"name": "Sarah D'Arcy", "number": 4, "goals": 2, "points": 2},
{"name": "Alicia Eva", "number": 2, "goals": 2, "points": 0},
{"name": "Stephanie Chiocci", "number": 17, "goals": 1, "points": 1},
{"name": "Caitlyn Edwards", "number": 1, "goals": 1, "points": 1},
{"name": "Emma Grant", "number": 5, "goals": 1, "points": 0},
{"name": "Cecilia McIntosh", "number": 20, "goals": 1, "points": 0},
{"name": "Bree White", "number": 33, "goals": 1, "points": 0},
{"name": "Lauren Tesoriero", "number": 7, "goals": 0, "points": 1},
{"name": "Emma King", "number": 60, "goals": 0, "points": 1},
{"name": "Christina Bernardi", "number": 6, "goals": 0, "points": 1}
],
"Fremantle": [
{"name": "Ashley Sharp", "number": 1, "goals": 4, "points": 3},
{"name": "Stacey Barr", "number": 10, "goals": 2, "points": 5},
{"name": "Amy Lavell", "number": 7, "goals": 2, "points": 1},
{"name": "Kira Phillips", "number": 13, "goals": 2, "points": 1},
{"name": "Kara Donnellan", "number": 15, "goals": 2, "points": 0},
{"name": "Gabby O'Sullivan", "number": 22, "goals": 1, "points": 4},
{"name": "Gemma Houghton", "number": 27, "goals": 1, "points": 3},
{"name": "Kirby Bentley", "number": 23, "goals": 1, "points": 1},
{"name": "Melissa Caulfield", "number": 24, "goals": 1, "points": 0},
{"name": "Tayla Bresland", "number": 5, "goals": 1, "points": 0},
{"name": "Dana Hooker", "number": 17, "goals": 0, "points": 1},
{"name": "Stephanie Cain", "number": 20, "goals": 0, "points": 1},
{"name": "Ebony Antonio", "number": 12, "goals": 0, "points": 1},
{"name": "Hayley Miller", "number": 19, "goals": 0, "points": 1},
{"name": "Demi Okely", "number": 16, "goals": 0, "points": 1},
{"name": "Lara Filocamo", "number": 4, "goals": 0, "points": 1}
],
"GWS": [
{"name": "Phoebe McWilliams", "number": 3, "goals": 4, "points": 1},
{"name": "Jacinda Barclay", "number": 34, "goals": 3, "points": 2},
{"name": "Aimee Schmidt", "number": 11, "goals": 3, "points": 0},
{"name": "Rebecca Beeson", "number": 6, "goals": 1, "points": 2},
{"name": "Ellie Brush", "number": 10, "goals": 1, "points": 1},
{"name": "Kate Stanton", "number": 33, "goals": 1, "points": 1},
{"name": "Hannah Wallett", "number": 13, "goals": 1, "points": 1},
{"name": "Stephanie Walker", "number": 5, "goals": 1, "points": 0},
{"name": "Mai Nguyen", "number": 2, "goals": 1, "points": 0},
{"name": "Jess Dal Pos", "number": 7, "goals": 1, "points": 0},
{"name": "Maddy Collier", "number": 14, "goals": 0, "points": 2},
{"name": "Emma Swanson", "number": 17, "goals": 0, "points": 1},
{"name": "Britt Tully", "number": 16, "goals": 0, "points": 1},
{"name": "Alex Williams", "number": 20, "goals": 0, "points": 1}
],
"Melbourne": [
{"name": "Alyssa Mifsud", "number": 9, "goals": 6, "points": 3},
{"name": "Catherine Phillips", "number": 35, "goals": 3, "points": 1},
{"name": "Deanna Berry", "number": 7, "goals": 2, "points": 3},
{"name": "Shelley Scott", "number": 20, "goals": 2, "points": 2},
{"name": "Richelle Cranston", "number": 30, "goals": 1, "points": 3},
{"name": "Jessica Anderson", "number": 28, "goals": 1, "points": 3},
{"name": "Elise O'Dea", "number": 5, "goals": 1, "points": 1},
{"name": "Harriet Cordner", "number": 21, "goals": 1, "points": 1},
{"name": "Sarah Jolly", "number": 10, "goals": 1, "points": 0},
{"name": "Jasmine Grierson", "number": 19, "goals": 1, "points": 0},
{"name": "Mel Hickey", "number": 18, "goals": 1, "points": 0},
{"name": "Karen Paxman", "number": 4, "goals": 1, "points": 0},
{"name": "Lily Mithen", "number": 14, "goals": 0, "points": 2},
{"name": "Daisy Pearce", "number": 6, "goals": 0, "points": 1},
{"name": "Ainslie Kemp", "number": 36, "goals": 0, "points": 1},
{"name": "Lauren Pearce", "number": 15, "goals": 0, "points": 1},
{"name": "Sarah Lampard", "number": 8, "goals": 0, "points": 1}
]
}
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Goal Kickers</title>
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
<style>
text {
font-family: 'Open Sans', sans-serif;
font-size: 18px;
fill: #000;
}
.new {
stroke: #000;
}
.old {
stroke: #ADADAD;
stroke-dasharray: 5,5;
}
.interactive {
cursor: pointer;
}
</style>
</head>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
const margin = {'height': 500, 'width': 960};
const teams = ['Adelaide', 'Brisbane', 'Bulldogs', 'Carlton', 'Collingwood', 'Fremantle', 'GWS', 'Melbourne'];
const logo = {
'Adelaide': 'Adelaide.svg',
'Brisbane': 'Brisbane.svg',
'Bulldogs': 'Bulldogs.svg',
'Carlton': 'Carlton.svg',
'Collingwood': 'Collingwood.svg',
'Fremantle': 'Fremantle.svg',
'GWS': 'GWS.svg',
'Melbourne': 'Melbourne.svg'
};
const guernsey = [
{'x': 0, 'y': 0}, {'x': 10, 'y': 10}, {'x': 15, 'y': 5}, {'x': 15, 'y': 35},
{'x': 50, 'y': 35}, {'x': 50, 'y': 5}, {'x': 55, 'y': 10}, {'x': 65, 'y': 0},
{'x': 50, 'y': -15}, {'x': 45, 'y': -15}, {'x': 33, 'y': -3}, {'x': 21, 'y': -15},
{'x': 16, 'y': -15}, {'x': 0, 'y': 0}
];
const colour = {
'Adelaide': '#ffe303',
'Brisbane': '#b15928',
'Bulldogs': '#1f78b4',
'Carlton': '#253494',
'Collingwood': '#000',
'Fremantle': '#6a3d9a',
'GWS': '#ff7f00',
'Melbourne': '#e31a1c'
};
let svg = d3.select('body').append('svg')
.attr('height', margin.height)
.attr('width', margin.width);
let background = svg.append('g');
background.append('rect')
.attr('height', margin.height)
.attr('width', margin.width)
.style('fill', '#87CEEB');
let field = svg.append('g')
.attr('transform', 'translate(0,' + margin.height + ')');
field.append('ellipse')
.attr('cx', margin.width/2)
.attr('rx', margin.width/2)
.attr('ry', margin.height - 200)
.style('fill', '#01A611');
const postMargin = {'offsetHeight': 180, 'goalHeight': 300, 'pointHeight': 220, 'offsetWidth': 240, 'gapWidth': 150};
// goal posts
field.append('rect')
.attr('x', postMargin.offsetWidth)
.attr('y', -postMargin.pointHeight - postMargin.offsetHeight)
.attr('height', postMargin.pointHeight)
.attr('width', 10)
.style('fill', '#fff');
field.append('rect')
.attr('x', postMargin.offsetWidth + postMargin.gapWidth)
.attr('y', -postMargin.goalHeight - postMargin.offsetHeight)
.attr('height', postMargin.goalHeight)
.attr('width', 10)
.style('fill', '#fff');
// goal posts
field.append('rect')
.attr('x', postMargin.offsetWidth + postMargin.gapWidth*2)
.attr('y', -postMargin.goalHeight - postMargin.offsetHeight)
.attr('height', postMargin.goalHeight)
.attr('width', 10)
.style('fill', '#fff');
field.append('rect')
.attr('x', postMargin.offsetWidth + postMargin.gapWidth*3)
.attr('y', -postMargin.pointHeight - postMargin.offsetHeight)
.attr('height', postMargin.pointHeight)
.attr('width', 10)
.style('fill', '#fff');
let goals = svg.append('g')
.attr('transform', 'translate(' + margin.width/2 + ',' + (margin.height - 50) + ')');
let displayPoints = svg.append('g')
.attr('transform', 'translate(' + (margin.width - 190) + ',' + 75 + ')');
displayPoints.append('text')
.attr('id', 'teamScore')
.text('0.0')
.style('font-size', '60px')
.style('font-weight', 'bold');
let team = svg.append('g')
.attr('transform', 'translate(' + 20 + ',' + 20 + ')');
team.selectAll('image')
.data(teams)
.enter().append('image')
.attr('xlink:href', function(d) {return logo[d]; })
.classed('interactive', true)
.datum(function(d) {return d;})
.on('mouseover', scrollTeams)
.on('click', selectTeam);
let goalData;
let activeTeam = teams[teams.length - 1];
let activeShots;
let start = Date.now();
let paused = false;
let count = 0;
d3.timer(animate);
d3.json("goals.json", function(data) {
goalData = data;
generateActiveShots();
});
function animate() {
if (!paused) {
let duration = 3000;
if (activeShots.length < 1) {
goals.selectAll('ellipse').remove();
goals.selectAll('image').remove();
goals.selectAll('text').remove();
goals.selectAll('path').remove();
d3.select('#teamScore').text('0.0');
generateActiveShots();
start = Date.now();
count = 0;
}
let t = Date.now() - start;
if (count < t) {
goals.selectAll('ellipse').remove();
goals.selectAll('image').remove();
goals.selectAll('text').remove();
goals.selectAll('.new')
.classed('old', true)
.classed('new', false);
kickGoal(duration-50);
count += duration;
}
} else if(paused && count != 0) {
goals.selectAll('ellipse').remove();
goals.selectAll('image').remove();
goals.selectAll('text').remove();
goals.selectAll('path').remove();
d3.select('#teamScore').text('0.0');
count = 0;
}
}
function kickGoal(duration) {
let index = Math.floor(Math.random()*activeShots.length);
let player = activeShots[index][0];
let jumperNum = activeShots[index][1];
let score = activeShots[index][2];
activeShots.splice(index,1);
goals.append('path')
.datum(guernsey)
.classed('line', true)
.style('stroke', '#000')
.style('stroke-width', '2px')
.style('fill', colour[activeTeam])
.attr('transform', 'translate(' + 300 + ',' + (-340) + ')')
.attr('d', d3.line()
.curve(d3.curveLinear)
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
);
console.log(activeTeam);
goals.append('text')
.attr('x', 329.5 - jumperNum.toString().length*4.5)
.attr('y', -320)
.text(jumperNum)
.style('fill', (activeTeam == 'Collingwood' || activeTeam == 'Carlton') ? '#fff' : '#000')
.style('font-size', '22px')
.style('font-weight', 'bold');
goals.append('text')
.attr('x', 315 - player.length*3)
.attr('y', -280)
.text(player)
.style('fill', '#000')
.style('font-size', '18px')
.style('font-weight', 'bold');
let tempScore = d3.select('#teamScore').text();
let tempIndex = tempScore.indexOf('.');
let tempGoal = tempScore.substring(0,tempIndex);
let tempPoint = tempScore.substring(tempIndex + 1,tempScore.length);
if (score == 'point') {
tempPoint = tempPoint*1 + 1;
} else {
tempGoal = tempGoal*1 + 1;
}
d3.select('#teamScore')
.text(tempGoal + '.' + tempPoint);
// generate randomised end location within a specific range
let xRange = 100;
let randomX = (Math.random()*xRange) - (xRange/2);
let yRange = 100;
let randomY = (Math.random()*yRange) - (yRange/2);
if(score == 'point') {
let side = Math.random() < 0.5 ? 'left' : 'right';
randomX += postMargin.gapWidth*(side == 'left' ? -1 : 1);
}
randomX = randomX == 0 ? 0.0001 : randomX;
let pathData = [
{ "x": 0, "y": 0},
{ "x": randomX/2, "y": -350 + randomY},
{ "x": randomX, "y": -250 + randomY}
];
let path = goals.append('path')
.datum(pathData)
.classed('line', true)
.style('stroke-width', '2px')
.style('fill-opacity', 0)
.attr('d', d3.line()
.curve(d3.curveCardinal)
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
)
.classed('new', true);
let ball = goals.append('ellipse')
.attr('rx', 10)
.attr('ry', 15)
.style('fill', 'E3170D')
.classed('new', true);
transition();
function transition() {
ball.transition()
.duration(duration)
.attrTween('transform', translateAlong(path.node()));
}
}
function translateAlong(path) {
let l = path.getTotalLength();
return function(d, i, a) {
return function(t) {
let p = path.getPointAtLength(t*l);
return 'translate(' + p.x + ',' + p.y + ')';
};
};
}
d3.selection.prototype.moveToFront = function() {
return this.each(function(){
this.parentNode.appendChild(this);
});
};
function scrollTeams() {
paused = true;
team.selectAll('image')
.transition()
.attr('y', function(d,i) {return 60*i; })
}
function selectTeam() {
let selectedTeam = d3.select(this);
selectedTeam.moveToFront();
activeTeam = d3.select(this).datum();
generateActiveShots();
paused = false;
start = Date.now();
team.selectAll('image')
.transition()
.attr('y', 0);
}
function generateActiveShots() {
activeShots = [];
let teamData = goalData[activeTeam];
for(let i = 0; i < teamData.length; i++) {
let goalCount = teamData[i]['goals'];
let pointCount = teamData[i]['points'];
for(let j = 0; j < goalCount; j++) {
let temp = [teamData[i]['name'], teamData[i]['number'], 'goal'];
activeShots.push(temp);
}
for(let k = 0; k < pointCount; k++) {
let temp = [teamData[i]['name'], teamData[i]['number'], 'point'];
activeShots.push(temp);
}
}
}
</script>
</body>
</html>
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment