function circleLegend(selection) { var instance = {} // set some defaults var api = { domain: [0, 100], // the values min and max range: [0, 80], // the circle area/size mapping values: [8, 34, 89], // values for circles width: 500, height: 500, suffix:'', // ability to pass in a suffix circleColor: '#888', textPadding: 40, textColor: '#454545' } var sqrtScale = d3.scaleSqrt() .domain(api.domain) .range(api.range) instance.render = function () { var s = selection.append('g') .attr('class', 'legend-wrap') // push down to radius of largest circle .attr('transform', 'translate(0,' + sqrtScale(d3.max(api.values)) + ')') // append the values for circles s.append('g') .attr('class', 'values-wrap') .selectAll('circle') .data(api.values) .enter().append('circle') .attr('class', function (d) { return 'values values-' + d; }) .attr('r', function (d) { return sqrtScale(d); }) .attr('cx', api.width/2) .attr('cy', function (d) { return api.height/2 - sqrtScale(d); }) .style('fill', 'none') .style('stroke', api.circleColor) .style('opacity', 0.5) // append some lines based on values s.append('g') .attr('class', 'values-line-wrap') .selectAll('.values-labels') .data(api.values) .enter().append('line') .attr('x1', function (d) { return api.width/2 + sqrtScale(d); }) .attr('x2', api.width/2 + sqrtScale(api.domain[1]) + 10) .attr('y1', function (d) { return api.height/2 - sqrtScale(d); }) .attr('y2', function (d) { return api.height/2 - sqrtScale(d); }) .style('stroke', api.textColor) .style('stroke-dasharray', ('2,2')) // append some labels from values s.append('g') .attr('class', 'values-labels-wrap') .selectAll('.values-labels') .data(api.values) .enter().append('text') .attr('x', api.width/2 + sqrtScale(api.domain[1]) + api.textPadding) .attr('y', function (d) { return (api.height/2 - sqrtScale(d)) + 5; }) .attr('shape-rendering', 'crispEdges') .style('text-anchor', 'end') .style('fill', api.textColor) .text(function (d) { return d + api.suffix; }) return instance } for (var key in api) { instance[key] = getSet(key, instance).bind(api) } return instance // https://gist.github.com/gneatgeek/5892586 function getSet(option, component) { return function (_) { if (! arguments.length) { return this[option]; } this[option] = _; return component; } } }