/** * A concrete implementation of a general purpose bubble chart that allows data visualization using the * following dimensions: * - x axis position * - y axis position * - bubble radius * - color * * Examples: * - {@link http://dc-js.github.com/dc.js/ Nasdaq 100 Index} * - {@link http://dc-js.github.com/dc.js/vc/index.html US Venture Capital Landscape 2011} * @class bubbleChart * @memberof dc * @mixes dc.bubbleMixin * @mixes dc.coordinateGridMixin * @example * // create a bubble chart under #chart-container1 element using the default global chart group * var bubbleChart1 = dc.bubbleChart('#chart-container1'); * // create a bubble chart under #chart-container2 element using chart group A * var bubbleChart2 = dc.bubbleChart('#chart-container2', 'chartGroupA'); * @param {String|node|d3.selection} parent - Any valid * {@link https://github.com/d3/d3-selection/blob/master/README.md#select d3 single selector} specifying * a dom block element such as a div; or a dom element or d3 selection. * @param {String} [chartGroup] - The name of the chart group this chart instance should be placed in. * Interaction with a chart will only trigger events and redraws within the chart's group. * @returns {dc.bubbleChart} */ dc.bubbleChart = function (parent, chartGroup) { var _chart = dc.bubbleMixin(dc.coordinateGridMixin({})); _chart.transitionDuration(750); _chart.transitionDelay(0); var bubbleLocator = function (d) { return 'translate(' + (bubbleX(d)) + ',' + (bubbleY(d)) + ')'; }; _chart.plotData = function () { _chart.calculateRadiusDomain(); _chart.r().range([_chart.MIN_RADIUS, _chart.xAxisLength() * _chart.maxBubbleRelativeSize()]); var data = _chart.data(); var bubbleG = _chart.chartBodyG().selectAll('g.' + _chart.BUBBLE_NODE_CLASS) .data(data, function (d) { return d.key; }); if (_chart.sortBubbleSize()) { // update dom order based on sort bubbleG.order(); } removeNodes(bubbleG); bubbleG = renderNodes(bubbleG); updateNodes(bubbleG); _chart.fadeDeselectedArea(_chart.filter()); }; function renderNodes (bubbleG) { var bubbleGEnter = bubbleG.enter().append('g'); bubbleGEnter .attr('class', _chart.BUBBLE_NODE_CLASS) .attr('transform', bubbleLocator) .append('circle').attr('class', function (d, i) { return _chart.BUBBLE_CLASS + ' _' + i; }) .on('click', _chart.onClick) .attr('fill', _chart.getColor) .attr('r', 0); bubbleG = bubbleGEnter.merge(bubbleG); dc.transition(bubbleG, _chart.transitionDuration(), _chart.transitionDelay()) .select('circle.' + _chart.BUBBLE_CLASS) .attr('r', function (d) { return _chart.bubbleR(d); }) .attr('opacity', function (d) { return (_chart.bubbleR(d) > 0) ? 1 : 0; }); _chart._doRenderLabel(bubbleGEnter); _chart._doRenderTitles(bubbleGEnter); return bubbleG; } function updateNodes (bubbleG) { dc.transition(bubbleG, _chart.transitionDuration(), _chart.transitionDelay()) .attr('transform', bubbleLocator) .select('circle.' + _chart.BUBBLE_CLASS) .attr('fill', _chart.getColor) .attr('r', function (d) { return _chart.bubbleR(d); }) .attr('opacity', function (d) { return (_chart.bubbleR(d) > 0) ? 1 : 0; }); _chart.doUpdateLabels(bubbleG); _chart.doUpdateTitles(bubbleG); } function removeNodes (bubbleG) { bubbleG.exit().remove(); } function bubbleX (d) { var x = _chart.x()(_chart.keyAccessor()(d)); if (isNaN(x) || !isFinite(x)) { x = 0; } return x; } function bubbleY (d) { var y = _chart.y()(_chart.valueAccessor()(d)); if (isNaN(y) || !isFinite(y)) { y = 0; } return y; } _chart.renderBrush = function () { // override default x axis brush from parent chart }; _chart.redrawBrush = function (brushSelection, doTransition) { // override default x axis brush from parent chart _chart.fadeDeselectedArea(brushSelection); }; return _chart.anchor(parent, chartGroup); };