Created
December 13, 2017 21:14
-
-
Save valex/1f8b0947acba6241ee4dfc8e7a659232 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
{ | |
"RECORDS": [ | |
{ | |
"name": "Corey Goldfarb", | |
"exitvelo": "48.996", | |
"vlaunch": "25.093", | |
"distance": "119.232", | |
"hlaunch": "13.671" | |
}, | |
{ | |
"name": "Corey Goldfarb", | |
"exitvelo": "57.342", | |
"vlaunch": "10.642", | |
"distance": "109.205", | |
"hlaunch": "33.076" | |
}, | |
{ | |
"name": "Corey Goldfarb", | |
"exitvelo": "64.148", | |
"vlaunch": "21.460", | |
"distance": "158.060", | |
"hlaunch": "-22.891" | |
}, | |
{ | |
"name": "Corey Goldfarb", | |
"exitvelo": "68.694", | |
"vlaunch": "24.660", | |
"distance": "205.239", | |
"hlaunch": "-38.423" | |
}, | |
{ | |
"name": "Corey Goldfarb", | |
"exitvelo": "58.100", | |
"vlaunch": "1.216", | |
"distance": "29.927", | |
"hlaunch": "6.950" | |
}, | |
{ | |
"name": "Corey Goldfarb", | |
"exitvelo": "45.542", | |
"vlaunch": "-1.435", | |
"distance": "38.432", | |
"hlaunch": "1.412" | |
}, | |
{ | |
"name": "Corey Goldfarb", | |
"exitvelo": "69.515", | |
"vlaunch": "16.342", | |
"distance": "185.072", | |
"hlaunch": "-27.972" | |
}, | |
{ | |
"name": "Corey Goldfarb", | |
"exitvelo": "66.590", | |
"vlaunch": "26.978", | |
"distance": "217.268", | |
"hlaunch": "-4.834" | |
}, | |
{ | |
"name": "Corey Goldfarb", | |
"exitvelo": "54.215", | |
"vlaunch": "-6.854", | |
"distance": "17.304", | |
"hlaunch": "-30.127" | |
}, | |
{ | |
"name": "Corey Goldfarb", | |
"exitvelo": "66.806", | |
"vlaunch": "31.138", | |
"distance": "215.927", | |
"hlaunch": "4.282" | |
} | |
] | |
} |
This file contains hidden or 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
<!DOCTYPE html> | |
<meta charset='utf-8'> | |
<html> | |
<head> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.11.0/d3.min.js"></script> | |
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta/css/bootstrap.min.css" rel="stylesheet"> | |
<link rel='stylesheet' href='style.css'> | |
</head> | |
<body> | |
<div id="page-container" class="row justify-content-center"> | |
<div class="col-sm-4" id="distance-module"></div> | |
<div class="col-sm-4" id="exit-launch-angle-module"></div> | |
<div class="col-sm-4" id="exit-direction-module"></div> | |
</div> | |
<div class="row justify-content-center"> | |
<div class="col-sm-4" id="table-module"></div> | |
</div> | |
<script type='text/javascript' src='script.js'></script> | |
</body> | |
</html> |
This file contains hidden or 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
var BASEBALL_ANIM_APP = { | |
url: 'batData.json', | |
data: [], | |
activeIndex: 0, | |
timer: null, | |
animation: { | |
duration: 1000, | |
delay: 4000 | |
}, | |
tableModuleOptions:{ | |
id: 'baseball-app-table', | |
appendToSelector: '#table-module', | |
rowActiveClass:"active", | |
}, | |
distanceModuleOptions: { | |
id: 'distance', | |
appendToSelector: '#distance-module', | |
margins: {top: 10, right: 10, bottom: 10, left: 10}, | |
width: 300, | |
height: 300, | |
defaultBallColor:'#b3b3b3', | |
ballActiveClass:"active", | |
ballHoverClass:"hovered", | |
radii: [350, 250, 150], | |
mainGroup: null, | |
schemeRadius: 0, | |
schemeBasePoint: {x:0, y:0}, | |
}, | |
exitLaunchAngleModuleOptions: { | |
id: 'exit-angle', | |
appendToSelector: '#exit-launch-angle-module', | |
margins: {top: 10, right: 10, bottom: 10, left: 10}, | |
width: 300, | |
height: 200, | |
mainGroup: null, | |
schemeRadius: 0, | |
vectorLength: 0, | |
vectorArcGenerator: null, | |
schemeBasePoint: {x:0, y:0}, | |
}, | |
exitDirectionModuleOptions: { | |
id: 'exit-dir', | |
appendToSelector: '#exit-direction-module', | |
margins: {top: 10, right: 10, bottom: 10, left: 10}, | |
width: 300, | |
height: 200, | |
mainGroup: null, | |
schemeRadius: 0, | |
schemeBasePoint: {x:0, y:0}, | |
vectorArcGenerator: null, | |
}, | |
mainColor: '#005d80', | |
mainLightColor: '#3bafda', | |
start: function(){ | |
this.loadData(); | |
}, | |
loadData: function(){ | |
var that = this; | |
d3.json(this.url, function (error, rawData) { | |
if (error) throw error; | |
that.data = rawData['RECORDS'].map(function (d) { | |
return { | |
exitSpeed: +d["exitvelo"], | |
vAngle: +d["vlaunch"], | |
hAngle: +d["hlaunch"], | |
distance: +d["distance"] | |
} | |
}); | |
that.initTableModule(); | |
that.initDistanceModule(); | |
that.initExitLaunchAngleModule(); | |
that.initExitDirectionModule(); | |
that.startTimer(); | |
}); | |
}, | |
initTableModule: function() { | |
var options = this.tableModuleOptions; | |
var columns = [ | |
{ | |
key: 'exitSpeed', | |
label: 'Exit velocity' | |
}, | |
{ | |
key: 'vAngle', | |
label: 'Vertical Launch' | |
}, | |
{ | |
key: 'hAngle', | |
label: 'Horiztonal Launch' | |
}, | |
{ | |
key: 'distance', | |
label: 'Distance' | |
}, | |
]; | |
var table = d3.select(options.appendToSelector).append('table') | |
.attr('id', options.id) | |
.attr('class', 'table'); | |
var thead = table.append('thead'); | |
var tbody = table.append('tbody'); | |
// append the header row | |
thead.append('tr') | |
.selectAll('th') | |
.data(columns) | |
.enter() | |
.append('th') | |
.text(function (column) { return column.label; }); | |
// create a row for each object in the data | |
var rows = tbody.selectAll('tr') | |
.data(this.data) | |
.enter() | |
.append('tr') | |
.attr('id', function(d,i){ return 'ball-'+i;}) | |
.on('click', function(d, i){ | |
BASEBALL_ANIM_APP.ballManuallySelected(i); | |
}); | |
// create a cell in each row for each column | |
var cells = rows.selectAll('td') | |
.data(function (row) { | |
return columns.map(function (column) { | |
return {value: row[column.key]}; | |
}); | |
}) | |
.enter() | |
.append('td') | |
.text(function (d) { return d.value; }); | |
return table; | |
}, | |
initDistanceModule: function(){ | |
var that = this; | |
var options = this.distanceModuleOptions; | |
var graphWidth = options.width - options.margins.left - options.margins.right, | |
graphHeight = options.height - options.margins.top - options.margins.bottom; | |
var svg = d3.select(options.appendToSelector) | |
.append("svg") | |
.attr("width", options.width) | |
.attr("height", options.height); | |
options.mainGroup = svg.append('g') | |
.attr('transform', 'translate(' + options.margins.left + ',' + options.margins.top + ')') | |
.attr('id', options.id); | |
// title text | |
options.mainGroup.append("text") | |
.attr("x", 0) | |
.attr("y", 0) | |
.attr("font-weight", "bold") | |
.attr("font-size", "14px") | |
.attr("alignment-baseline", "hanging") | |
.attr("dominant-baseline", "hanging") // for firefox | |
.attr("class", "title") | |
.style("fill", this.mainColor) | |
.text("DISTANCE"); | |
// ft label | |
options.mainGroup.append("text") | |
.attr("x", graphWidth) | |
.attr("y", 28) | |
.attr("font-size", "18px") | |
.attr("alignment-baseline", "baseline") | |
.attr("dominant-baseline", "baseline") // for firefox | |
.attr("text-anchor", "end") | |
.style("fill", this.mainColor) | |
.html("ft"); | |
// ft value | |
options.mainGroup.append("text") | |
.attr("id", "ft-value") | |
.attr("x", graphWidth - 14) | |
.attr("y", 28) | |
.attr("font-weight", "bold") | |
.attr("font-size", "28px") | |
.attr("alignment-baseline", "baseline") | |
.attr("dominant-baseline", "baseline") // for firefox | |
.attr("text-anchor", "end") | |
.style("fill", this.mainColor) | |
.html("0"); | |
// Define the div for the tooltip | |
var tooltip = d3.select("body") | |
.append("div") | |
.attr("class", "tooltip") | |
.style("opacity", 0); | |
options.schemeRadius = Math.round(0.5 * graphWidth / Math.cos(45 * Math.PI / 180)); | |
options.schemeBasePoint = { | |
x: Math.round(0.5 * graphWidth), | |
y: graphHeight | |
}; | |
var arcGen = d3.arc() | |
.startAngle(-45 * Math.PI / 180) | |
.endAngle(45 * Math.PI / 180); | |
var scaleRadius = d3.scaleLinear() | |
.domain([0, d3.max(options.radii)]) | |
.range([0, options.schemeRadius]); | |
// outfield | |
options.mainGroup.append('path') | |
.attr("d", arcGen({ | |
innerRadius: 0, | |
outerRadius: scaleRadius(d3.max(options.radii)) | |
})) | |
.attr("transform", 'translate('+options.schemeBasePoint.x+', '+options.schemeBasePoint.y+')') | |
.attr("fill", '#0a6d08'); | |
// infield | |
options.mainGroup.append('path') | |
.attr("d", arcGen({ | |
innerRadius: 0, | |
outerRadius: scaleRadius(d3.min(options.radii)) | |
})) | |
.attr("transform", 'translate('+options.schemeBasePoint.x+', '+options.schemeBasePoint.y+')') | |
.attr("fill", '#5e3d0b'); | |
var radii = options.radii; | |
var innerRadius, outerRadius; | |
for(var i=0; i < radii.length; i++){ | |
innerRadius = scaleRadius(radii[i]); | |
outerRadius = innerRadius; | |
if(i == 0){ | |
innerRadius = 0; | |
} | |
options.mainGroup.append('path') | |
.attr("d", arcGen({ | |
innerRadius: innerRadius, | |
outerRadius: outerRadius | |
})) | |
.attr("transform", 'translate('+options.schemeBasePoint.x+', '+options.schemeBasePoint.y+')') | |
.attr("fill", 'none') | |
.attr("stroke", '#777777') | |
.attr("stroke-width", '1'); | |
// labels left | |
options.mainGroup.append("text") | |
.attr("x", options.schemeBasePoint.x) | |
.attr("y", options.schemeBasePoint.y - scaleRadius(radii[i])) | |
.attr("transform", "translate(-3,0) rotate(-45,"+options.schemeBasePoint.x+", "+options.schemeBasePoint.y+")") | |
.attr("text-anchor", i == 0 ? "start" : "end") | |
.attr("font-size", "12px") | |
.attr("font-weight", "bold") | |
.attr("alignment-baseline", i == 0 ? "auto" : "middle") | |
.attr("dominant-baseline", i == 0 ? "auto" : "middle") // for firefox | |
.style("fill", '#777777') | |
.text(radii[i]); | |
// labels right | |
options.mainGroup.append("text") | |
.attr("x", options.schemeBasePoint.x) | |
.attr("y", options.schemeBasePoint.y - scaleRadius(radii[i])) | |
.attr("transform", "translate(3,0) rotate(45,"+options.schemeBasePoint.x+", "+options.schemeBasePoint.y+")") | |
.attr("text-anchor", i == 0 ? "end" : "start") | |
.attr("font-size", "12px") | |
.attr("font-weight", "bold") | |
.attr("alignment-baseline", i == 0 ? "auto" : "middle") | |
.attr("dominant-baseline", i == 0 ? "auto" : "middle") // for firefox | |
.style("fill", '#777777') | |
.text(radii[i]); | |
} | |
options.mainGroup.selectAll('circle') | |
.data(this.data) | |
.enter() | |
.append('circle') | |
.attr('id', function(d,i){return 'ball-'+i;}) | |
.attr('class', 'ball') | |
.attr('fill', options.defaultBallColor) | |
.attr('stroke', 'none') | |
.attr('r', 5) | |
.attr('cx', function(d, i){return options.schemeBasePoint.x + scaleRadius(d.distance * Math.sin(d.hAngle * Math.PI / 180))}) | |
.attr('cy', function(d, i){return options.schemeBasePoint.y - scaleRadius(d.distance * Math.cos(d.hAngle * Math.PI / 180))}) | |
.on('click', function(d, i) { | |
var el = d3.select(this); | |
that.ballManuallySelected(i); | |
}) | |
.on('mouseenter', function(d) { | |
var el = d3.select(this); | |
// tooltip | |
tooltip.transition() | |
.duration(200) | |
.style("opacity", .8); | |
tooltip.html(parseFloat(d.exitSpeed).toFixed(1)+' mph') | |
.style("left", (d3.event.pageX) + "px") | |
.style("top", (d3.event.pageY - 28) + "px"); | |
// classes | |
if(el.classed(options.ballActiveClass)) | |
return; | |
el.classed(options.ballHoverClass, true); | |
}) | |
.on('mouseout', function(d) { | |
var el = d3.select(this); | |
// tooltip | |
tooltip.transition() | |
.duration(500) | |
.style("opacity", 0); | |
// classes | |
if(el.classed(options.ballActiveClass)) | |
return; | |
el.classed(options.ballHoverClass, false); | |
}); | |
}, | |
initExitLaunchAngleModule: function(){ | |
var options = this.exitLaunchAngleModuleOptions; | |
var graphWidth = options.width - options.margins.left - options.margins.right, | |
graphHeight = options.height - options.margins.top - options.margins.bottom; | |
var svg = d3.select(options.appendToSelector) | |
.append("svg") | |
.attr("width", options.width) | |
.attr("height", options.height); | |
options.mainGroup = svg.append('g') | |
.attr('transform', 'translate(' + options.margins.left + ',' + options.margins.top + ')') | |
.attr('id', options.id); | |
// title text | |
options.mainGroup.append("text") | |
.attr("x", 0) | |
.attr("y", 0) | |
.attr("font-weight", "bold") | |
.attr("font-size", "14px") | |
.attr("alignment-baseline", "hanging") | |
.attr("dominant-baseline", "hanging") // for firefox | |
.attr("class", "title") | |
.style("fill", this.mainColor) | |
.text("EXIT LAUNCH ANGLE"); | |
// angle text | |
options.mainGroup.append("text") | |
.attr("id", "angle-label") | |
.attr("x", graphWidth) | |
.attr("y", 0) | |
.attr("font-weight", "bold") | |
.attr("font-size", "28px") | |
.attr("alignment-baseline", "hanging") | |
.attr("dominant-baseline", "hanging") // for firefox | |
.attr("class", "angle") | |
.attr("text-anchor", "end") | |
.style("fill", this.mainColor) | |
.html("0°"); | |
options.schemeRadius = Math.round((graphHeight - 30) * 0.5); | |
options.vectorLength = Math.round(options.schemeRadius * 0.85); | |
options.schemeBasePoint = { | |
x: Math.round(1/3 * graphWidth), | |
y: graphHeight - options.schemeRadius | |
}; | |
// outer arc | |
var outerArc = d3.arc() | |
.innerRadius(0) | |
.outerRadius(0.6 * options.schemeRadius) | |
.startAngle(0) | |
.endAngle(180 * Math.PI / 180); | |
options.mainGroup.append('path') | |
.attr("d", outerArc) | |
.attr("transform", 'translate('+options.schemeBasePoint.x+', '+options.schemeBasePoint.y+')') | |
.attr("fill", '#dee0df') | |
.attr("stroke-width", '0'); | |
// inner arc | |
var innerArc = d3.arc() | |
.innerRadius(0) | |
.outerRadius(0.44 * options.schemeRadius) | |
.startAngle(0) | |
.endAngle(180 * Math.PI / 180); | |
options.mainGroup.append('path') | |
.attr("d", innerArc) | |
.attr("transform", 'translate('+options.schemeBasePoint.x+', '+options.schemeBasePoint.y+')') | |
.attr("fill", this.mainLightColor) | |
.attr("stroke", this.mainColor) | |
.attr("stroke-width", 0); | |
// vector arc | |
options.vectorArcGenerator = d3.arc() | |
.innerRadius(0) | |
.outerRadius(0.44 * options.schemeRadius) | |
.startAngle(90 * Math.PI / 180) | |
.endAngle(function(d) { return (90 - d) * Math.PI / 180; }); | |
options.mainGroup.append('path') | |
.attr("id", "vector-arc") | |
.attr("d", options.vectorArcGenerator(0)) | |
.attr("transform", 'translate('+options.schemeBasePoint.x+', '+options.schemeBasePoint.y+')') | |
.attr("fill", this.mainColor); | |
// vector | |
options.mainGroup.append("line") | |
.style("stroke", this.mainColor) | |
.attr("id", "vector") | |
.attr("x1", options.schemeBasePoint.x) | |
.attr("y1", options.schemeBasePoint.y) | |
.attr("x2", options.schemeBasePoint.x + options.vectorLength) | |
.attr("y2", options.schemeBasePoint.y) | |
.attr("stroke-width", 1.5); | |
// x axis | |
options.mainGroup.append("line") | |
.style("stroke", this.mainColor) // colour the line | |
.attr("x1", options.schemeBasePoint.x) // x position of the first end of the line | |
.attr("y1", options.schemeBasePoint.y) // y position of the first end of the line | |
.attr("x2", options.schemeBasePoint.x + options.schemeRadius) // x position of the second end of the line | |
.attr("y2", options.schemeBasePoint.y) | |
.attr("stroke-width", 3); | |
// y axis | |
options.mainGroup.append("line") | |
.style("stroke", this.mainColor) // colour the line | |
.attr("x1", options.schemeBasePoint.x) // x position of the first end of the line | |
.attr("y1", options.schemeBasePoint.y + options.schemeRadius) // y position of the first end of the line | |
.attr("x2", options.schemeBasePoint.x) // x position of the second end of the line | |
.attr("y2", options.schemeBasePoint.y - options.schemeRadius) | |
.attr("stroke-width", 3); | |
}, | |
initExitDirectionModule: function(){ | |
var options = this.exitDirectionModuleOptions; | |
var graphWidth = this.exitDirectionModuleOptions.width - this.exitDirectionModuleOptions.margins.left - this.exitDirectionModuleOptions.margins.right, | |
graphHeight = this.exitDirectionModuleOptions.height - this.exitDirectionModuleOptions.margins.top - this.exitDirectionModuleOptions.margins.bottom; | |
var svg = d3.select(options.appendToSelector) | |
.append("svg") | |
.attr("width", options.width) | |
.attr("height", options.height); | |
options.mainGroup = svg.append('g') | |
.attr('transform', 'translate(' + options.margins.left + ',' + options.margins.top + ')') | |
.attr('id', options.id); | |
// Add the Title | |
options.mainGroup.append("text") | |
.attr("x", 0) | |
.attr("y", 0) | |
.attr("font-weight", "bold") | |
.attr("font-size", "14px") | |
.attr("alignment-baseline", "hanging") | |
.attr("dominant-baseline", "hanging") // for firefox | |
.attr("class", "title") | |
.style("fill", this.mainColor) | |
.text("EXIT DIRECTION"); | |
options.mainGroup.append("text") | |
.attr("id", "angle-label") | |
.attr("x", graphWidth) | |
.attr("y", 0) | |
.attr("font-weight", "bold") | |
.attr("font-size", "28px") | |
.attr("alignment-baseline", "hanging") | |
.attr("dominant-baseline", "hanging") // for firefox | |
.attr("class", "angle") | |
.attr("text-anchor", "end") | |
.style("fill", this.mainColor) | |
.html("0°"); | |
options.schemeRadius = Math.round(graphWidth * 0.5 * 0.66); | |
options.schemeBasePoint = { | |
x: Math.round(graphWidth / 2), | |
y: graphHeight | |
}; | |
// outer arc | |
var outerArc = d3.arc() | |
.innerRadius(0) | |
.outerRadius(4/5 * options.schemeRadius) | |
.startAngle(-45 * Math.PI / 180) | |
.endAngle(45 * Math.PI / 180); | |
options.mainGroup.append('path') | |
.attr("d", outerArc) | |
.attr("transform", 'translate('+options.schemeBasePoint.x+', '+options.schemeBasePoint.y+')') | |
.attr("fill", '#dee0df') | |
.attr("stroke-width", '0'); | |
// inner arc | |
var innerArc = d3.arc() | |
.innerRadius(0) | |
.outerRadius(4/7 * options.schemeRadius) | |
.startAngle(-45 * Math.PI / 180) | |
.endAngle(45 * Math.PI / 180); | |
options.mainGroup.append('path') | |
.attr("d", innerArc) | |
.attr("transform", 'translate('+options.schemeBasePoint.x+', '+options.schemeBasePoint.y+')') | |
.attr("fill", this.mainLightColor) | |
.attr("stroke", this.mainColor) | |
.attr("stroke-width", 2); | |
// vector arc | |
options.vectorArcGenerator = d3.arc() | |
.innerRadius(0) | |
.outerRadius(4/7 * options.schemeRadius) | |
.startAngle(0) | |
.endAngle(function(d) { return d * Math.PI / 180; }); | |
options.mainGroup.append('path') | |
.attr("id", "vector-arc") | |
.attr("d", options.vectorArcGenerator(0)) | |
.attr("transform", 'translate('+options.schemeBasePoint.x+', '+options.schemeBasePoint.y+')') | |
.attr("fill", this.mainColor); | |
options.mainGroup.append("line") | |
.style("stroke", this.mainColor) // colour the line | |
.attr("x1", options.schemeBasePoint.x) // x position of the first end of the line | |
.attr("y1", options.schemeBasePoint.y) // y position of the first end of the line | |
.attr("x2", options.schemeBasePoint.x + options.schemeRadius) // x position of the second end of the line | |
.attr("y2", options.schemeBasePoint.y - options.schemeRadius) | |
.attr("stroke-width", 3); | |
options.mainGroup.append("line") | |
.style("stroke", this.mainColor) // colour the line | |
.attr("x1", options.schemeBasePoint.x) // x position of the first end of the line | |
.attr("y1", options.schemeBasePoint.y) // y position of the first end of the line | |
.attr("x2", options.schemeBasePoint.x - options.schemeRadius) // x position of the second end of the line | |
.attr("y2", options.schemeBasePoint.y - options.schemeRadius) | |
.attr("stroke-width", 3); | |
// vector | |
options.mainGroup.append("line") | |
.style("stroke", this.mainColor) // colour the line | |
.attr("id", "vector") // x position of the first end of the line | |
.attr("x1", options.schemeBasePoint.x) // x position of the first end of the line | |
.attr("y1", options.schemeBasePoint.y) // y position of the first end of the line | |
.attr("x2", options.schemeBasePoint.x) // x position of the second end of the line | |
.attr("y2", options.schemeBasePoint.y - options.schemeRadius) | |
.attr("stroke-width", 1.5); | |
}, | |
animateExitLaunchAngleModule: function(){ | |
var options = this.exitLaunchAngleModuleOptions; | |
var data = this.data[this.activeIndex]; | |
options.mainGroup | |
.select('#'+options.id+' #vector') | |
.datum(data) | |
.transition() | |
.duration(this.animation.duration) | |
.tween("animations", function(d){ | |
var el = d3.select(this); | |
var angleLabel = d3.select('#'+options.id+' #angle-label'); | |
var vectorArc = d3.select('#'+options.id+' #vector-arc'); | |
var X2 = +el.attr("x2"); | |
var Y2 = +el.attr("y2"); | |
var fromAngle = 180 / Math.PI * Math.asin((options.schemeBasePoint.y - Y2) / options.vectorLength); | |
var toAngle = d['vAngle']; | |
var iAngle = d3.interpolateNumber(fromAngle, toAngle); | |
return function(t){ | |
el.attr("x2", options.schemeBasePoint.x + (options.vectorLength * Math.cos(iAngle(t) * Math.PI / 180))); | |
el.attr("y2", options.schemeBasePoint.y - (options.vectorLength * Math.sin(iAngle(t) * Math.PI / 180))); | |
angleLabel.html(Math.round(iAngle(t)) + "°"); | |
vectorArc.attr("d", options.vectorArcGenerator(iAngle(t))) | |
} | |
}) | |
}, | |
animateExitDirectionModule: function(){ | |
var options = this.exitDirectionModuleOptions; | |
var data = this.data[this.activeIndex]; | |
options.mainGroup | |
.select('#'+options.id+' #vector') | |
.datum(data) | |
.transition() | |
.duration(this.animation.duration) | |
.tween("animations", function(d){ | |
var el = d3.select(this); | |
var angleLabel = d3.select('#'+options.id+' #angle-label'); | |
var vectorArc = d3.select('#'+options.id+' #vector-arc'); | |
var X2 = +el.attr("x2"); | |
var Y2 = +el.attr("y2"); | |
var fromAngle = 180 / Math.PI * Math.asin((X2 - options.schemeBasePoint.x) / options.schemeRadius); | |
var toAngle = d['hAngle']; | |
var iAngle = d3.interpolateNumber(fromAngle, toAngle); | |
return function(t){ | |
el.attr("x2", options.schemeBasePoint.x + (options.schemeRadius * Math.sin(iAngle(t) * Math.PI / 180))); | |
el.attr("y2", options.schemeBasePoint.y - (options.schemeRadius * Math.cos(iAngle(t) * Math.PI / 180))); | |
var suffix = "°"; | |
if(iAngle(t) >= 0){ | |
suffix += 'R'; | |
}else{ | |
suffix += 'L'; | |
} | |
angleLabel.html(Math.round(iAngle(t)) + suffix); | |
vectorArc.attr("d", options.vectorArcGenerator(iAngle(t))) | |
} | |
}) | |
}, | |
animateDistanceModule: function(){ | |
var options = this.distanceModuleOptions; | |
var data = this.data[this.activeIndex]; | |
this.setBallActive(this.activeIndex); | |
}, | |
animateTableModule: function(){ | |
this.setRowActive(this.activeIndex); | |
}, | |
startTimer: function(){ | |
var that = this; | |
var animationDelay = this.animation.duration + this.animation.delay; | |
var dataLength = this.dataLength(); | |
var prevTickNum = null; | |
var tickNum; | |
this.timer = d3.timer(function(elapsed){ | |
tickNum = Math.floor(elapsed / animationDelay); | |
if(prevTickNum !== tickNum){ | |
prevTickNum = tickNum; | |
that.setActiveIndex(tickNum % dataLength); | |
that.updateModules(); | |
} | |
}) | |
}, | |
stopTimer: function(){ | |
this.timer.stop(); | |
}, | |
updateModules: function(){ | |
this.animateExitLaunchAngleModule(); | |
this.animateExitDirectionModule(); | |
this.animateDistanceModule(); | |
this.animateTableModule(); | |
}, | |
setActiveIndex:function(index){ | |
this.activeIndex = index; | |
}, | |
setRowActive: function(index){ | |
var options = this.tableModuleOptions; | |
var table = d3.select('#'+options.id); | |
var tr = table.select('#ball-'+index); | |
// only one active | |
var alreadyIsActive = tr.classed(options.rowActiveClass); | |
if(alreadyIsActive) | |
return; | |
table.selectAll('#'+options.id+' tr') | |
.classed(options.rowActiveClass, false); | |
tr.classed(options.rowActiveClass, !alreadyIsActive); | |
}, | |
ballManuallySelected: function(index){ | |
this.setBallActive(index); | |
this.stopTimer(); | |
this.setActiveIndex(index); | |
this.updateModules(); | |
}, | |
setBallActive:function(index){ | |
var options = this.distanceModuleOptions; | |
var el = d3.select('#'+options.id+' #ball-'+index); | |
var datum = el.datum(); | |
// update ft-value | |
options.mainGroup.select('#'+options.id+' #ft-value') | |
.text(Math.round(datum['distance'])); | |
// only one active | |
var alreadyIsActive = el.classed(options.ballActiveClass); | |
if(alreadyIsActive) | |
return; | |
options.mainGroup.selectAll('#'+options.id+' .ball') | |
.classed(options.ballActiveClass, false); | |
el.classed(options.ballActiveClass, !alreadyIsActive); | |
el.classed(options.ballHoverClass, false); | |
}, | |
isDataLoaded: function(){ | |
return this.dataLength(); | |
}, | |
dataLength: function(){ | |
return this.data.length; | |
} | |
}; | |
BASEBALL_ANIM_APP.start(); |
This file contains hidden or 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
circle.ball.active{ | |
fill: #ffffff; | |
} | |
circle.ball.hovered{ | |
fill: #c6c6c6; | |
} | |
table { | |
border-collapse: collapse; | |
} | |
.table { | |
width: 100%; | |
max-width: 100%; | |
margin-bottom: 1rem; | |
background-color: transparent; | |
font-size: 0.92rem; | |
} | |
.table thead th { | |
vertical-align: bottom; | |
border-bottom: 2px solid #e9ecef; | |
} | |
.table tr.active{ | |
background-color: #c5e8f5; | |
} | |
.table td, .table th { | |
padding: .3rem; | |
vertical-align: top; | |
border-top: 1px solid #e9ecef; | |
text-align: center; | |
} | |
.table td, .table th { | |
padding: .3rem; | |
vertical-align: top; | |
border-top: 1px solid #e9ecef; | |
} | |
div.tooltip { | |
position: absolute; | |
text-align: center; | |
width: 60px; | |
height: 28px; | |
line-height: 28px; | |
padding: 6px 2px 2px 2px; | |
font: 12px sans-serif; | |
background: black; | |
border: 0px; | |
-webkit-border-radius: 8px; | |
-moz-border-radius: 8px; | |
border-radius: 8px; | |
pointer-events: none; | |
color:white; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment