xxxxxxxxxx
<head>
<title>hof-stacked-bar-iv</title>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: steelblue;
}
.x.axis path {
display: none;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<div class="sliders">
</div>
<script>
var current_key = 'rWar';
var minyr = 1899;
var maxyr = 9999;
var minwar = 48;
var maxwar = 10000;
var plid_font_size = 10;
var margin = {
top: 20,
right: 150,
bottom: 80,
left: 80
},
width = 960 - margin.left - margin.right,
height = 4500 - margin.top - margin.bottom;
var sliders;
var metric_keys = ['rWar', 'fWar', 'rwa2', 'rwa3', 'rwa4',
'rwa5', 'rwa7', 'rwb3', 'rwb5', 'rwb7'
];
var metric_d = ['career rWar (baseball reference)', 'career fWar (fangraphs)', 'career wins-above-2 rWar', 'career wins-above-3 rWar', 'career wins-above-4 rWar', 'career wins-above-5 rWar', 'career wins-above-7 rWar', 'best 3-year-rWar total', 'best 5-year-rWar total', 'best 7-year-rWar total'];
var metric_descriptions = {}
_.forEach(metric_keys, function(k, i) {
metric_descriptions[k] = metric_d[i];
});
var x = d3.scale.linear()
.rangeRound([0, width]);
var y = d3.scale.ordinal()
.rangeRoundBands([0, height], .1);
var opScale = d3.scale.linear()
.range([0.85, 0.85])
.domain([1901, 2000]);
var color;
if (metric_keys.length <= 11) {
color = d3.scale.ordinal()
.range(['#67001f', '#b2182b ', '#d6604d ', '#f4a582', '#fddbc7', '#f7f7f7', '#d1e5f0', '#92c5de', '#4393c3', '#2166ac', '#053061']);
} else {
color = d3.scale.category20b()
.domain(d3.range(metric_keys.length));
}
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var xAxis = d3.svg.axis()
.scale(x)
.orient("top")
.tickFormat(d3.format(".2s"));
var get_top = function(i) {
return 20 * i;
}
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var metric_weights = {};
var player_idx = {};
var stackedData = function(data) {
data.forEach(function(d) {
var x0 = 0;
d.metrics = color.domain().map(function(name) {
return {
name: name,
x0: x0,
x1: x0 += +d[name]
};
});
d.total = d.metrics[d.metrics.length - 1].x1;
});
};
/***************************************************************/
/***************************************************************/
d3.csv("HOF_metrics.csv", function(error, idata) {
var data;
var sort_by_total = function(data) {
data.sort(function(a, b) {
return b.wtotal - a.wtotal;
});
var oset;
_.forEach(data, function(d, i) {
if (typeof(d.idx) === typeof(undefined)) {
d.idx = i;
}
d.oldidx = d.idx;
d.idx = i;
player_idx[d.plid] = d.idx;
d.oset = 0;
});
};
var weighted_total = function(data, weights) {
_.forEach(data, function(d) {
var ss = 0.0;
var ww = 0.0;
_.mapObject(weights, function(val, key) {
ss += 1.0 * val * d[key];
ww += 1.0 * val;
})
if (ww > 0) {
d.wtotal = ss / ww;
} else {
d.wtotal = 0.0;
}
})
};
data = _.filter(idata, function(d) {
return (
(parseFloat(d.rWar) >= minwar && parseFloat(d.rWar) <= maxwar) && (parseFloat(d.minyr) >= minyr && parseFloat(d.minyr) <= maxyr)
);
});
metric_weights = {};
_.forEach(metric_keys, function(k) {
metric_weights[k] = 50.0;
});
color.domain(d3.keys(data[0]).filter(function(key) {
return _.contains(metric_keys, key);
}));
stackedData(data);
weighted_total(data, metric_weights);
sort_by_total(data);
x.domain([0, d3.max(data, function(d) {
return d.total;
})]);
y.domain(data.map(function(d, i) {
return i;
}));
sliders = d3.select("div.sliders")
.append('g')
.style('position', 'absolute')
.style('width', '240px')
.style('top', '20px')
.style('right', '20px');
sliders.selectAll('input')
.data(metric_keys)
.enter()
.append('input')
.attr('class', 'metric_slider')
.attr('id', function(d, i) {
return 'metric_slider_' + d;
})
.attr('type', 'range')
.attr('min', 0)
.attr('max', 100)
.attr('value', function(d) {
return d.value;
})
.style('top', function(d, i) {
return get_top(i) + "px";
})
.style('right', "10px")
.on('change', function(d, i) {
d.value = parseInt(this.value);
metric_weights[d] = this.value;
weighted_total(data, metric_weights);
sort_by_total(data);
do_sort(data);
});
svg.append('text')
.text('player-label')
.attr('id', 'player-label')
.attr('x', 800)
.attr('y', 20)
.attr('text-anchor', 'end')
.style('position', 'fixed')
.style('top', 100)
.style('right', 20)
.style('font-size', 18);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.style('text-anchor', 'end')
.attr("transform", "rotate(-65)")
.attr('font-size', '6px')
.attr('fint-family', 'sans-serif')
.attr('class', 'xaxis_label');
var ya = svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.selectAll("text")
.text(function(d, i) {
// return data[i].pname;
return i;
})
.attr("class", "ytext")
.attr("transform", "rotate(0)")
.attr("y", 6)
.attr("dy", ".71em")
.attr("font-size", "8px")
.style("text-anchor", "end");
var bar_containers = svg.selectAll(".bar_containers")
.data(data)
.enter().append("g")
.attr("class", "bar_containers")
.attr("transform", function(d, i) {
return "translate(0," + y(i) + ")";
});
var plid = svg.selectAll(".plid")
.data(data)
.enter().append("g")
.attr("class", "plid")
.attr("transform", function(d, i) {
return "translate(0," + y(i) + ")";
});
d3.selectAll(".bar_containers")
.selectAll("rect")
.data(function(d) {
return _.map(d.metrics, function(x) {
return {
'name': x.name,
'x0': x.x0,
'x1': x.x1,
'pname': d.pname,
'plid': d.plid,
'birthYear': d.birthYear,
'minyr': d.minyr,
'idx': d.idx,
'wtotal': d.wtotal
};
})
})
.enter()
.append("rect")
.attr("height", y.rangeBand())
.attr("x", function(d, i) {
return x(d.x0);
})
.attr("width", function(d, i) {
return x(d.x1) - x(d.x0);
})
.style("text-anchor", "end")
.style("fill", function(d) {
return color(d.name);
})
.style('opacity', function(d) {
return opScale(d.minyr);
})
.on('click', function(d, i) {
// current_key = metric_keys[i];
// sort_by_weight(data, metric_weights);
// do_sort(data);
;
})
.on('mouseover', function(d, i) {
d3.selectAll('#player-label')
.text(d.pname + " " + d.wtotal.toFixed(1))
.attr("y", function() {
return y(player_idx[d.plid]);
})
.style('opacity', 1)
})
.on('mouseout', function(d, i) {
d3.selectAll('#player-label')
.style('opacity', 0);
});
d3.selectAll(".bar_containers")
.append("text")
.text(function(d, i) {
return d.pname;
})
.style("font-size", plid_font_size)
.style("fill", "white")
.attr("transform", function(d, i) {
var x = parseFloat(y.rangeBand() / 2) + 0 * parseFloat(plid_font_size) + 3;
return "translate(20," + x.toString() + ")";
});
var do_sort = function(data) {
d3.selectAll(".bar_containers")
.transition()
.duration(1200)
.attr("transform", function(d, i) {
var dx = Math.random() * width * 0.1;
return "translate(" + dx + "," + y(d.oldidx) + ")";
})
.transition()
.duration(1800)
.attr("transform", function(d, i) {
return "translate(" + x(d.oset) + "," + y(d.idx) + ")";
})
};
var legend = svg.selectAll(".legend")
.data(color.domain().slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(0," + i * 20 + ")";
});
legend.append("rect")
.attr("x", width + margin.right - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color)
.on('click', function(d, i) {
current_key = d;
//sort_by_weight(data, metric_weights);
do_sort(data);
})
.on("mouseover", function(d, i) {;
d3.select('#legend-hover-text')
.text(function() {
return metric_descriptions[d];
})
.style("opacity", 1);
})
.on("mouseout", function(d, i) {;
d3.select('#legend-hover-text')
.style("opacity", 0);
});;
legend.append("text")
.attr("x", width + margin.right - 144)
.attr("y", 5)
.attr("dy", ".35em")
.attr('id', 'legend-hover-text')
.style("text-anchor", "end")
.text(function(d) {
return d;
})
.style('opacity', 0);
legend.append("text")
.attr("x", width + margin.right - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) {
return d;
});
});
</script>
https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js
https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js