var SAMPLE_COUNT = 13; var NAME_AREA_WIDTH = 450; function initialize(elementId) { var margin = {top: 150, bottom: 50, left: 25, right: 50}; var svgWidth = $(elementId).width(); var svgHeight = $(elementId).height(); var width = svgWidth - (margin.left + margin.right); var height = svgHeight - (margin.top + margin.bottom); var data = getData(); data.sort(function(a, b) { return b.score - a.score }); var allScores = data.reduce(function(p, c) { return p.concat(c.scores.map(function(d, i) {return {name: c.name, score: d, idx: i}})); }, []); var barName = function(bar) {return bar.name}; var barNames = data.map(barName); var x = d3.scale.ordinal() .domain(d3.range(SAMPLE_COUNT)) .rangePoints([NAME_AREA_WIDTH, width], 1); var y = d3.scale.ordinal() .domain(barNames) .rangeBands([0, height], .25); var radius = d3.scale.linear() .domain([0, d3.max(allScores, function(d) {return d.score})]) .range([0, y.rangeBand() / 2]); var scoreRange = d3.scale.linear() .domain([0, d3.max(data, function(d) {return d.score})]) .range([0, y.rangeBand()]); var svg = d3.select(elementId) .append("svg") .attr("width", svgWidth) .attr("height", svgHeight); svg.append("image") .attr("xlink:href", "http://www.trebor.org/static/assets/icons/tat.png") .classed("tat", true) .attr("x", svgWidth - 75) .attr("y", svgHeight - 75) .attr("width", 60) .attr("height", 60) .on("click", function() { window.open("http://www.trebor.org", '_blank'); }); var dataArea = svg.append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); dataArea.append("text") .classed("title", true) .attr("x", width / 2 + "px") .attr("dy", "-.9em") .attr("text-anchor", "middle") .text("Matterport Chocolate Tasting"); dataArea.selectAll("circle") .data(allScores) .enter() .append("circle") .classed("score", true) .classed("bad", function(d) {return d.score < 0}) .attr("cx", function(d) {return x(d.idx)}) .attr("cy", function(d) {return y(barName(d)) + y.rangeBand() / 2}) .attr("r", 0) .append("title") .text(function(d) {return "Score: " + d.score}); dataArea.selectAll("circle") .transition() .duration(2000) .ease("elastic") .attr("r", function(d) {return radius(d.score < 0 ? -d.score : d.score)}); dataArea.selectAll("rect.back") .data(data, barName) .enter() .append("rect") .classed("back", true) .attr("x", NAME_AREA_WIDTH - 30) .attr("y", function(d) {return y(barName(d))}) .attr("width", 20) .attr("height", function(d) {return y.rangeBand()}) .append("title") .text(function(d) {return "Total Score: " + d.score}); dataArea.selectAll("rect.bar") .data(data, barName) .enter() .append("rect") .classed("bar", true) .attr("x", NAME_AREA_WIDTH - 30) .attr("y", function(d) {return y(barName(d)) + y.rangeBand() - scoreRange(0)}) .attr("width", 20) .attr("height", function(d) {return scoreRange(0)}) .append("title") .text(function(d) {return "Total Score: " + d.score}); dataArea.selectAll("rect.bar") .transition() .duration(2000) .attr("y", function(d) {return y(barName(d)) + y.rangeBand() - scoreRange(d.score)}) .attr("height", function(d) {return scoreRange(d.score)}); dataArea.selectAll("text.name") .data(data, barName) .enter() .append("text") .classed("name", true) .attr("x", NAME_AREA_WIDTH) .attr("y", function(d) {return y(barName(d)) + y.rangeBand() / 2}) .attr("dy", ".3em") .attr("dx", "-1.6em") .attr("text-anchor", "end") .text(function(d) {return d.name}); } $( document ).ready(function() { initialize(".chart"); }); function getData() { var raw = [ { "Name":"Green and Black - Milk", "s1":2, "s2":3, "s3":3, "s4":null, "s5":2, "s6":2, "s7":2, "s8":3, "s9":null, "s10":3, "s11":null, "s12":3, "s13":5 }, { "Name":"Green and Black - Maya Gold", "s1":3.5, "s2":2, "s3":2, "s4":null, "s5":2, "s6":5, "s7":3, "s8":3, "s9":null, "s10":2, "s11":null, "s12":2, "s13":null }, { "Name":"Green and Black - Ginger", "s1":3, "s2":3, "s3":null, "s4":null, "s5":4, "s6":3, "s7":1, "s8":4, "s9":5, "s10":4, "s11":null, "s12":4, "s13":null }, { "Name":"Scharffen Berger - Semisweet", "s1":3, "s2":2, "s3":5, "s4":null, "s5":2, "s6":3, "s7":1, "s8":4, "s9":null, "s10":4, "s11":null, "s12":5, "s13":3 }, { "Name":"Scharffen Berger - Extra Dark", "s1":2.5, "s2":2, "s3":4, "s4":null, "s5":5, "s6":4, "s7":2, "s8":null, "s9":null, "s10":3, "s11":3, "s12":1, "s13":null }, { "Name":"L Amourette - 72%", "s1":4, "s2":4, "s3":3, "s4":4, "s5":2, "s6":4, "s7":1, "s8":3, "s9":null, "s10":3, "s11":null, "s12":1, "s13":null }, { "Name":"L Amourette - 91%", "s1":3, "s2":2, "s3":null, "s4":null, "s5":2, "s6":3, "s7":1, "s8":null, "s9":null, "s10":2, "s11":4, "s12":null, "s13":null }, { "Name":"Ritual - Novo Coffee", "s1":4, "s2":4, "s3":-10, "s4":5, "s5":5, "s6":5, "s7":3, "s8":5, "s9":null, "s10":3, "s11":null, "s12":0, "s13":null }, { "Name":"Ritual - Costa Rica", "s1":4, "s2":4, "s3":2, "s4":null, "s5":3, "s6":3, "s7":2, "s8":null, "s9":null, "s10":3, "s11":3.5, "s12":null, "s13":null }, { "Name":"Ritual - Belize", "s1":4, "s2":2, "s3":null, "s4":null, "s5":5, "s6":4, "s7":1, "s8":null, "s9":null, "s10":3, "s11":4, "s12":null, "s13":null }, { "Name":"Pacari - Lemongrass", "s1":3.5, "s2":4, "s3":5, "s4":5, "s5":5, "s6":2, "s7":1, "s8":5, "s9":null, "s10":4, "s11":4, "s12":3, "s13":5 }, { "Name":"Pacari Maca", "s1":2.5, "s2":2, "s3":4, "s4":4, "s5":4, "s6":1, "s7":1, "s8":4, "s9":null, "s10":2, "s11":3, "s12":null, "s13":null }, { "Name":"Raaka - Ecuador", "s1":1.5, "s2":1, "s3":null, "s4":null, "s5":2, "s6":3, "s7":1, "s8":null, "s9":null, "s10":2, "s11":5, "s12":null, "s13":null }, { "Name":"Raaka - Madagascar", "s1":2, "s2":3, "s3":2, "s4":null, "s5":3, "s6":1, "s7":1, "s8":null, "s9":null, "s10":3, "s11":5, "s12":null, "s13":null }, { "Name":"New Tree - Chili Pepper", "s1":2, "s2":2, "s3":4, "s4":4, "s5":5, "s6":3, "s7":0, "s8":3, "s9":null, "s10":4, "s11":null, "s12":null, "s13":null }, { "Name":"Blanxart - Milk", "s1":4, "s2":4, "s3":5, "s4":null, "s5":3, "s6":2, "s7":5, "s8":5, "s9":null, "s10":3, "s11":null, "s12":null, "s13":4 }, { "Name":"E. Guittard - 72%", "s1":3.5, "s2":4, "s3":4, "s4":null, "s5":4, "s6":5, "s7":1, "s8":null, "s9":null, "s10":3, "s11":null, "s12":null, "s13":null } ]; return raw.map(function(d) { var scores = d3.range(SAMPLE_COUNT).map(function(idx) { var value = d['s' + (idx + 1)]; return (value == null) ? 0 : value; }); return { name: d.Name, scores: scores, score: scores.reduce(function(p, c) {return c ? p + c : p}, 0) } }); }