Last active
August 29, 2015 13:56
-
-
Save wheaties/9157023 to your computer and use it in GitHub Desktop.
Playing around with making a reusable factory for sunburst d3 charts, inspired by a Backbone like View
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
| (function(window, d3){ | |
| var gb = window.gb = window.gb || {}; | |
| gb.arc = gb.arc || {}; | |
| gb.arc.radialScale = function(r, e, o){ | |
| var extent = e || 2 * Math.PI; | |
| var offset = o || 0; | |
| var radius = r || 350; | |
| var rScale = d3.scale.sqrt() | |
| .range([0, radius]); | |
| var thetaScale = d3.scale.linear() | |
| .range([0, extent]); | |
| var dispatch = d3.dispatch('extent', 'offset', 'radius'); | |
| var arc = d3.svg.arc() | |
| .startAngle(function(d){ return Math.max(offset, Math.min(offset + extent, thetaScale(d.x) + offset)); }) | |
| .endAngle(function(d){ return Math.max(offset, Math.min(offset + extent, thetaScale(d.x + d.dx) + offset)); }) | |
| .innerRadius(function(d){ return Math.max(0, rScale(d.y)); }) | |
| .outerRadius(function(d){ return Math.max(0, rScale(d.y + d.dy)); }); | |
| var out = function(d, i){ | |
| return arc(d, i); | |
| } | |
| out.extent = function(value){ | |
| if(!!value && value > 0){ | |
| extent = value; | |
| thetaScale.range([0, value]); | |
| dispatch.extent(value); | |
| return this; | |
| } | |
| else return extent; | |
| } | |
| out.offset = function(value){ | |
| if(!!value){ | |
| offset = value; | |
| dispatch.offset(value); | |
| return this; | |
| } | |
| else return offset; | |
| } | |
| out.radius = function(value){ | |
| if(!!value && radius > 0){ | |
| radius = value; | |
| rScale.range([0, value]); | |
| dispatch.radius(value); | |
| return this; | |
| } | |
| else return radius; | |
| } | |
| out.on = function(name, f){ | |
| if(!!name && !!f){ | |
| dispatch.on(name, f); | |
| return this; | |
| } | |
| else return dispatch.on(name); | |
| } | |
| out.off = function(name){ | |
| if(!!name){ | |
| dispatch.on(name, null); | |
| return this; | |
| } | |
| } | |
| out.arcTween = function(d, r){ | |
| var thetaInterp = d3.interpolate(thetaScale.domain(), [d.x, d.x + d.dx]), | |
| domainInterp = d3.interpolate(rScale.domain(), [d.y, 1]), | |
| rangeInterp = d3.interpolate(rScale.range(), [d.y ? (r || 20) : 0, radius]); | |
| var shift = function(x){ | |
| thetaScale.domain(thetaInterp(x)); | |
| rScale.domain(domainInterp(x)) | |
| .range(rangeInterp(x)); | |
| } | |
| return function(p, i){ | |
| return i ? | |
| function(t){ return arc(p); } : | |
| function(t){ | |
| shift(t); | |
| return arc(p); | |
| } | |
| } | |
| } | |
| out.centroid = function(d, i){ | |
| return arc.centroid(d, i); | |
| } | |
| return out; | |
| } | |
| })(window, d3) |
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
| (function(window, d3){ | |
| 'use strict'; | |
| var gb = window.gb = window.gb || {}; | |
| gb.color = gb.color || {} | |
| //TODO: is this reasonable? Does it depend on the size of the bands instead of the depth of the band? | |
| var radialScale = function(color){ | |
| return function(d){ return color(d.y); } | |
| } | |
| gb.color.constantRadial20 = function(){ | |
| return radialScale(d3.scale.category20()); | |
| } | |
| gb.color.constantRadial20c = function(){ | |
| return radialScale(d3.scale.category20c()); | |
| } | |
| gb.sunburst = function(el){ | |
| var dispatch = d3.dispatch('render', 'radius', 'partition', 'arc', 'style', 'attr'); | |
| var svg = d3.select(el).append('svg'); | |
| var g = svg.append('g'); | |
| var partition = d3.layout.partition() | |
| .sort(null) | |
| .value(d3.functor(1)); | |
| var chart = function(data){ | |
| return chart.render(data); | |
| } | |
| //Reset the 'children' function of the partition layout. Causes a 'partition' event to be fired. | |
| chart.children = function(f){ | |
| if(typeof(f) == 'string') f = function(d){ return d[f]; } | |
| if(typeof(f) != 'function') return; | |
| partition.children(f); | |
| dispatch.partition('children', f); | |
| return this; | |
| } | |
| //Reset the 'sort' function of the partition layout. Accepts 'null' argument. Causes a 'partition' event to be fired. | |
| chart.sort = function(f){ | |
| if(typeof(f) == 'string') f = function(d){ return d[f]; } | |
| if(!!f && typeof(f) != 'function') return; | |
| partition.sort(f); | |
| dispatch.partition('sort', f); | |
| return this; | |
| } | |
| chart.value = function(f){ | |
| if(typeof(f) == 'string') f = function(d){ return d[f]; } | |
| if(typeof(f) == 'number') f = d3.functor(f); | |
| if(typeof(f) != 'function') return; | |
| partition.value(f); | |
| dispatch.partition('value', f); | |
| return this; | |
| } | |
| var arc = gb.arc.radialScale(); | |
| chart.arc = function(f){ | |
| if(typeof(f) != 'function') return arc; | |
| arc = f; | |
| dispatch.arc(f); | |
| return this; | |
| } | |
| var radius = 350; | |
| chart.radius = function(r){ | |
| if(typeof(r) != 'number') return radius; | |
| radius = r; | |
| dispatch.radius(r); | |
| return this; | |
| } | |
| //TODO: Should be just an attribute of the 'chart.' Also need to be able to handle an object in 'name.' | |
| var style = function(enter){ | |
| for(var name in style){ | |
| enter.style(name, style[name]); | |
| } | |
| } | |
| style.stroke = '#fff'; | |
| style.fill = gb.color.constantRadial20c(); | |
| style['fill-rule'] = 'evenodd'; | |
| chart.style = function(name, f){ | |
| if(!arguments.length) return; | |
| if(!f) return style[name]; | |
| style[name] = f; | |
| dispatch.style(name, f); | |
| return this; | |
| } | |
| var attr = function(enter){ | |
| for(var name in attr){ | |
| enter.attr(name, attr[name]); | |
| } | |
| } | |
| chart.attr = function(name, f){ | |
| if(!arguments.length || name == 'd') return; | |
| if(!f) return attr[name]; | |
| attr[name] = f; | |
| dispatch.attr(name, f); | |
| return this; | |
| } | |
| chart.dispatchOn = function(name, f){ | |
| if(!arguments.length) return; | |
| if(!f) return display.on(name); | |
| dispatch.on(name, f); | |
| return this; | |
| } | |
| chart.dispatchOff = function(name){ | |
| if(!!name){ | |
| dispatch.on(name, null); | |
| return this; | |
| } | |
| } | |
| var on = function(enter){ | |
| for(var name in on){ | |
| enter.on(name, on[name]); | |
| } | |
| } | |
| chart.on = function(name, f){ | |
| if(!arguments.length) return; | |
| if(!f) return on[name]; | |
| on[name] = f; | |
| g.selectAll('path') | |
| .on(name, f); //TODO: make sure this works | |
| return this; | |
| } | |
| chart.off = function(name){ | |
| var paths = g.selectAll('path'); | |
| if(!name){ | |
| for(var name in on){ | |
| paths.on(name, null); | |
| on[name] = undefined; | |
| } | |
| } | |
| else{ | |
| paths.on(name, null); | |
| on[name] = undefined; | |
| } | |
| return this; | |
| } | |
| chart.render = function(data){ | |
| svg.attr('width', radius * 2) | |
| .attr('height', radius * 2); | |
| g.attr('transform', 'translate(' + radius + ', ' + radius + ')'); | |
| var paths = g.datum(data) | |
| .selectAll('path') | |
| .data(partition); | |
| paths.enter() | |
| .append('path') | |
| .attr('d', arc); | |
| attr(paths); | |
| style(paths); | |
| on(paths); | |
| paths.exit() | |
| .remove(); | |
| dispatch.render(); | |
| return this; | |
| } | |
| chart.transitionTo = function(f){ | |
| this.value(f); | |
| var tween = function(d){ | |
| var interpolate = d3.interpolate({x: d.x0, dx: d.dx0}, d); | |
| return function(s){ | |
| return arc(interpolate(s)); | |
| } | |
| } | |
| var backup = function(d){ | |
| d.x0 = d.x; | |
| d.dx0 = d.dx; | |
| } | |
| g.selectAll('path') | |
| .each(backup) | |
| .data(partition) | |
| .transition() | |
| .duration(750) | |
| .attrTween('d',tween); | |
| return this; | |
| } | |
| return chart; | |
| } | |
| })(window, d3); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment