/* set up the circle packing layout */ var w = 1000 , h = 600; var pack = d3.layout.pack() .size([w, h]) .sort(function(a, b) { return b.value - a.value; }) .padding(1) var unchecked = []; // positions get saved here when they're unchecked var svg = d3.select('body').append('svg') .attr('width', w).attr('height', h); var options = { 'fill' : { 'positions' : 'steelblue', 'QB' : 'blue', 'RB' : 'red', 'WR' : 'green', 'TE' : 'grey', 'D/ST' : 'purple', 'K' : 'orange', }, } /* load the data in */ d3.json('data.json', function(data) { var positions = ['QB', 'RB', 'WR', 'TE', 'D/ST', 'K']; var cutoffs = {}; var nodes = pack.nodes(data) positions.forEach(function(pos) { cutoffs[pos] = getPosition(pos).children.slice(); }) var node = svg.selectAll('g') .data(nodes); function enterCircles() { var groups = node.enter().append('g') .attr('class', function(d) { return d.children ? '' : d.stats.POS; }) .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }) .on('click', function(d) { /* d3.select(this).select('div') .style('display', 'block') .style('position', 'absolute') .style('left', d.x + 'px') .style('top', d.y + 'px')*/ }) groups.append('circle') .attr('id', function(d) { return d.name; }) .attr('r', function(d) { return d.r; }) .attr('fill', getFill) .attr('opacity', function(d) { return d.children ? (d.name == 'positions' ? .1 : .25) : 1; }) .on('click', function(d) { console.log(d.stats) alert(JSON.stringify(d.stats, null, 4)) }) .style('cursor', function(d) { return d.children ? '' : 'pointer'; }) groups.append('foreignObject') .attr('class', 'popup') //.attr('height', '100px') //.attr('width', '100px') .append('xhtml:body') .append('div') .style('display', 'none') // start out hidden .style('width', '100px') .style('height', '100px') .style('background', 'black') .style('position', 'relative') .style('right', '0px') .style('bottom', '0px') groups.style('opacity', 0) // fade in .transition() .style('opacity', 1) } enterCircles(); function refresh() { console.log(data) nodes = pack.nodes(data); node = svg.selectAll('g').data(nodes, function(d) { return d.children ? d.name : JSON.stringify(d.stats); // unique identifier }); node.exit().transition() // fade out then remove .style('opacity', 0) .each('end', function() { d3.select(this).remove(); }) node.transition().delay(250).duration(1000) // once exit circles have been removed adjust circles .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }) .selectAll('circle') .attr('r', function(d) { return d.r; }) setTimeout(enterCircles, 1000) // start fading in new circles while update circles are moving } /* set up the checkbox for controls */ d3.select('body').append('form') .style('position', 'absolute').style('left', '0px').style('top', '0px') .append('fieldset') .style('border-radius', '10px') .call(function(fieldset) { fieldset.append('legend').text('Positions'); }) .datum('positions') .style('background', getColor) .append('table') .style('border-spacing', '0px') .selectAll('tr').data(positions).enter().append('tr') .style('background', getColor) .call(function(row) { row.append('td') .append('label') .call(function(label) { label .style('cursor', 'pointer') .append('input').attr('type', 'checkbox') .attr('id', function(d) { return d;}) .attr('name', function(d) { return d;}) .attr('checked', 'true') .style('cursor', 'pointer') .on('change', function() { var pos = d3.select(this).datum(); // tr > td > label > input d3.select(this.parentNode.parentNode.parentNode).select('select').attr('disabled', this.checked ? null : true) this.checked ? move(pos, unchecked, data.children) : move(pos, data.children, unchecked); refresh(); }) label.append('text').text(function(d) { return d;}) }) row.append('td').each(function(d) { var N = getPosition(d).children.length; var numbers = []; for (var i = N; i >= 1; i--) { numbers.push(i) } d3.select(this).append('select') .style('cursor', 'pointer') .call(function(select) { // add the options select .selectAll('option') .data(numbers).enter().append('option') .text(function(d) { return d; }); }) .on('change', function(d) { var players = getPosition(d).children; if (this.value < players.length) { players.splice(this.value, players.length - this.value); } else { getPosition(d).children = players.concat(cutoffs[d].slice(players.length, this.value)) } refresh(); }) }) }) function getFill(d) { return d.children ? options.fill[d.name] : d.stats.FILL; } /* helper method to move the object with id from a to b */ function move(id, a, b) { for (var i in a) { if (id === a[i].name) { b.push(a.splice(i, 1)[0]); break; } } } /* search the children array of data to find the object matching pos */ function getPosition(pos) { for (var i in data.children) { if (data.children[i].name === pos) { return data.children[i]; } } } /* return the appropriate color with alpha channel to match opacity */ function getColor(d) { var rgb = d3.rgb(options.fill[d]) return rgba(rgb.r, rgb.g, rgb.b, d === 'properties' ? .1 : .25); } /* stringify the color into rgba */ function rgba(r, g, b, a) { return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; } })