-
Notifications
You must be signed in to change notification settings - Fork 1.8k
/
Copy pathbubble-chart.js
179 lines (154 loc) · 5.79 KB
/
bubble-chart.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/**
* 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/mbostock/d3/wiki/Selections#selecting-elements 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.
* @return {dc.bubbleChart}
*/
dc.bubbleChart = function (parent, chartGroup) {
var _chart = dc.bubbleMixin(dc.coordinateGridMixin({}));
var _elasticRadius = false;
var _sortBubbleSize = false;
_chart.transitionDuration(750);
_chart.transitionDelay(0);
var bubbleLocator = function (d) {
return 'translate(' + (bubbleX(d)) + ',' + (bubbleY(d)) + ')';
};
/**
* Turn on or off the elastic bubble radius feature, or return the value of the flag. If this
* feature is turned on, then bubble radii will be automatically rescaled to fit the chart better.
* @method elasticRadius
* @memberof dc.bubbleChart
* @instance
* @param {Boolean} [elasticRadius=false]
* @return {Boolean}
* @return {dc.bubbleChart}
*/
_chart.elasticRadius = function (elasticRadius) {
if (!arguments.length) {
return _elasticRadius;
}
_elasticRadius = elasticRadius;
return _chart;
};
/**
* Turn on or off the bubble sorting feature, or return the value of the flag. If enabled,
* bubbles will be sorted by their radius, with smaller bubbles in front.
* @method sortBubbleSize
* @memberof dc.bubbleChart
* @instance
* @param {Boolean} [sortBubbleSize=false]
* @return {Boolean}
* @return {dc.bubbleChart}
*/
_chart.sortBubbleSize = function (sortBubbleSize) {
if (!arguments.length) {
return _sortBubbleSize;
}
_sortBubbleSize = sortBubbleSize;
return _chart;
};
_chart.plotData = function () {
if (_elasticRadius) {
_chart.r().domain([_chart.rMin(), _chart.rMax()]);
}
_chart.r().range([_chart.MIN_RADIUS, _chart.xAxisLength() * _chart.maxBubbleRelativeSize()]);
var data = _chart.data();
if (_sortBubbleSize) {
// sort descending so smaller bubbles are on top
var radiusAccessor = _chart.radiusValueAccessor();
data.sort(function (a, b) { return d3.descending(radiusAccessor(a), radiusAccessor(b)); });
}
var bubbleG = _chart.chartBodyG().selectAll('g.' + _chart.BUBBLE_NODE_CLASS)
.data(data, function (d) { return d.key; });
if (_sortBubbleSize) {
// Call order here to update dom order based on sort
bubbleG.order();
}
renderNodes(bubbleG);
updateNodes(bubbleG);
removeNodes(bubbleG);
_chart.fadeDeselectedArea();
};
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);
dc.transition(bubbleG, _chart.transitionDuration(), _chart.transitionDelay())
.selectAll('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);
}
function updateNodes (bubbleG) {
dc.transition(bubbleG, _chart.transitionDuration(), _chart.transitionDelay())
.attr('transform', bubbleLocator)
.selectAll('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)) {
x = 0;
}
return x;
}
function bubbleY (d) {
var y = _chart.y()(_chart.valueAccessor()(d));
if (isNaN(y)) {
y = 0;
}
return y;
}
_chart.renderBrush = function () {
// override default x axis brush from parent chart
};
_chart.redrawBrush = function () {
// override default x axis brush from parent chart
_chart.fadeDeselectedArea();
};
return _chart.anchor(parent, chartGroup);
};