};
};
- window.SonarWidgets.BubbleChart.prototype.render = function (container) {
- var widget = this,
- containerS = container;
- container = d3.select(container);
-
- var noInvalidEntry = true,
- atLeastOneValueOnX = false,
- atLeastOneValueOnY = false;
+ window.SonarWidgets.BubbleChart.prototype.hasValidData = function () {
+ var widget = this,
+ noInvalidEntry = true,
+ atLeastOneValueOnX = false,
+ atLeastOneValueOnY = false;
this.components().forEach(function(component) {
noInvalidEntry = noInvalidEntry &&
- !!component.measures[widget.metricsPriority()[0]] &&
- !!component.measures[widget.metricsPriority()[1]];
+ !!component.measures[widget.metricsPriority()[0]] &&
+ !!component.measures[widget.metricsPriority()[1]];
atLeastOneValueOnX = atLeastOneValueOnX ||
- (component.measures[widget.metricsPriority()[0]] || {}).fval !== '-';
+ (component.measures[widget.metricsPriority()[0]] || {}).fval !== '-';
atLeastOneValueOnY = atLeastOneValueOnY ||
- (component.measures[widget.metricsPriority()[1]] || {}).fval !== '-';
+ (component.measures[widget.metricsPriority()[1]] || {}).fval !== '-';
});
- var validData = !!noInvalidEntry && !!atLeastOneValueOnX && !!atLeastOneValueOnY;
-
- if (!validData) {
- container.text(this.options().noMainMetric);
- return;
- }
+ return !!noInvalidEntry && !!atLeastOneValueOnX && !!atLeastOneValueOnY;
+ };
+ window.SonarWidgets.BubbleChart.prototype.init = function (container) {
this.width(container.property('offsetWidth'));
this.svg = container.append('svg')
this.gWrap
.attr('transform', trans(this.margin().left, this.margin().top));
+ };
+
+ window.SonarWidgets.BubbleChart.prototype.initMetrics = function () {
+ var widget = this;
- // Configure metrics
this.xMetric = this.metricsPriority()[0];
this.getXMetric = function(d) {
return d.measures[widget.xMetric].val;
this.getSizeMetric = function(d) {
return !!d.measures[widget.sizeMetric] ? d.measures[widget.sizeMetric].val : 0;
};
+ };
- // Configure scales
+ window.SonarWidgets.BubbleChart.prototype.initScales = function () {
+ var widget = this;
this
.xLog(this.options().xLog)
.yLog(this.options().yLog);
this.y.domain([ym * 0.8, ym * 1.2]);
this.size.domain([sm * 0.8, sm * 1.2]);
}
+ };
+
+ window.SonarWidgets.BubbleChart.prototype.initBubbles = function () {
+ var widget = this;
// Create bubbles
this.items = this.plotWrap.selectAll('.item')
this.items.sort(function (a, b) {
return widget.getSizeMetric(b) - widget.getSizeMetric(a);
});
+ };
- // Set event listeners
+ window.SonarWidgets.BubbleChart.prototype.initBubbleEvents = function () {
+ var widget = this;
this.items
.on('click', function (d) {
window.location = widget.options().baseUrl + '?id=' + encodeURIComponent(d.key);
widget.infoDate.text('');
widget.infoMetrics.text('');
});
+ };
- // Configure axis
+ window.SonarWidgets.BubbleChart.prototype.initAxes = function () {
// X
this.xAxis = d3.svg.axis()
- .scale(widget.x)
+ .scale(this.x)
.orient('bottom');
this.gxAxisLabel = this.gxAxis.append('text')
// Y
this.yAxis = d3.svg.axis()
- .scale(widget.y)
+ .scale(this.y)
.orient('left');
this.gyAxis.attr('transform', trans(60 - this.margin().left, 0));
.text(this.metrics()[this.yMetric].name)
.style('font-weight', 'bold')
.style('text-anchor', 'middle');
+ };
- // Configure grid
- this.gxGridLines = this.gxGrid.selectAll('line').data(widget.x.ticks()).enter()
+ window.SonarWidgets.BubbleChart.prototype.initGrid = function () {
+ var widget = this;
+ this.gxGridLines = this.gxGrid.selectAll('line').data(this.x.ticks()).enter()
.append('line');
- this.gyGridLines = this.gyGrid.selectAll('line').data(widget.y.ticks()).enter()
+ this.gyGridLines = this.gyGrid.selectAll('line').data(this.y.ticks()).enter()
.append('line');
this.gGrid.selectAll('line')
.style('text-anchor', 'start')
.style('font-weight', 'bold');
- var metricLines = [widget.metrics().x, widget.metrics().y, widget.metrics().size];
- widget.infoMetrics = widget.infoWrap.selectAll('.metric')
+ var metricLines = [this.metrics().x, this.metrics().y, this.metrics().size];
+ this.infoMetrics = this.infoWrap.selectAll('.metric')
.data(metricLines);
- widget.infoMetrics.enter().append('text').attr('class', 'metric info-text-small')
+ this.infoMetrics.enter().append('text').attr('class', 'metric info-text-small')
.text(function(d) { return d; });
- widget.infoMetricWidth = [];
- widget.infoMetrics.each(function() {
+ this.infoMetricWidth = [];
+ this.infoMetrics.each(function() {
widget.infoMetricWidth.push(this.getComputedTextLength() + 140);
});
- widget.infoMetrics.text('');
+ this.infoMetrics.text('');
+ };
- // Update widget
+ window.SonarWidgets.BubbleChart.prototype.render = function (container) {
+ var containerS = container;
+
+ container = d3.select(container);
+
+ if (!this.hasValidData()) {
+ container.text(this.options().noMainMetric);
+ return;
+ }
+
+ this.init(container);
+ this.initMetrics();
+ this.initScales();
+ this.initBubbles();
+ this.initBubbleEvents();
+ this.initAxes();
+ this.initGrid();
+
this.update(containerS);
return this;
};
+ window.SonarWidgets.BubbleChart.prototype.adjustScalesAfterUpdate = function () {
+ // X
+ var minX = d3.min(this.components(), function (d) {
+ return widget.x(widget.getXMetric(d)) - widget.size(widget.getSizeMetric(d));
+ }),
+ maxX = d3.max(this.components(), function (d) {
+ return widget.x(widget.getXMetric(d)) + widget.size(widget.getSizeMetric(d));
+ }),
+ dMinX = minX < 0 ? this.x.range()[0] - minX : this.x.range()[0],
+ dMaxX = maxX > this.x.range()[1] ? maxX - this.x.range()[1] : 0;
+ this.x.range([dMinX, this.availableWidth - dMaxX]);
- window.SonarWidgets.BubbleChart.prototype.update = function(container) {
- container = d3.select(container);
-
- var widget = this,
- width = container.property('offsetWidth');
-
- this.width(width > 100 ? width : 100);
+ // Y
+ var minY = d3.min(this.components(), function (d) {
+ return widget.y(widget.getYMetric(d)) - widget.size(widget.getSizeMetric(d));
+ }),
+ maxY = d3.max(this.components(), function (d) {
+ return widget.y(widget.getYMetric(d)) + widget.size(widget.getSizeMetric(d));
+ }),
+ dMinY = minY < 0 ? this.y.range()[1] - minY: this.y.range()[1],
+ dMaxY = maxY > this.y.range()[0] ? maxY - this.y.range()[0] : 0;
+ this.y.range([this.availableHeight - dMaxY, dMinY]);
- // Update svg canvas
- this.svg
- .attr('width', this.width())
- .attr('height', this.height());
+ // Format improvement for log scales
+ // X
+ if (this.xLog()) {
+ this.xAxis.tickFormat(function (d) {
+ var ticksCount = widget.availableWidth / 50;
+ return widget.x.tickFormat(ticksCount, d3.format(',d'))(d);
+ });
+ }
+ // Y
+ if (this.yLog()) {
+ this.yAxis.tickFormat(function (d) {
+ var ticksCount = widget.availableHeight / 30;
+ return widget.y.tickFormat(ticksCount, d3.format(',d'))(d);
+ });
+ }
- // Update available size
- this.availableWidth = this.width() - this.margin().left - this.margin().right;
- this.availableHeight = this.height() - this.margin().top - this.margin().bottom;
+ // Make scale's domains nice
+ this.x.nice();
+ this.y.nice();
+ };
- // Update scales
+ window.SonarWidgets.BubbleChart.prototype.updateScales = function () {
+ var widget = this;
this.x.range([0, this.availableWidth]);
this.y.range([this.availableHeight, 0]);
this.size.domain([sm * 0.8, sm * 1.2]);
}
-
if (this.x.domain()[0] === 0 && this.x.domain()[1] === 0) {
this.x.domain([0, 1]);
}
-
if (this.y.domain()[0] === 0 && this.y.domain()[1] === 0) {
this.y.domain([0, 1]);
}
-
// Avoid zero values when using log scale
if (this.xLog) {
var xDomain = this.x.domain();
.domain([yDomain[0] > 0 ? yDomain[0] : 0.1, yDomain[1]])
.clamp(true);
}
+ };
- // Adjust the scale domain so the circles don't cross the bounds
- // X
- var minX = d3.min(this.components(), function (d) {
- return widget.x(widget.getXMetric(d)) - widget.size(widget.getSizeMetric(d));
- }),
- maxX = d3.max(this.components(), function (d) {
- return widget.x(widget.getXMetric(d)) + widget.size(widget.getSizeMetric(d));
- }),
- dMinX = minX < 0 ? this.x.range()[0] - minX : this.x.range()[0],
- dMaxX = maxX > this.x.range()[1] ? maxX - this.x.range()[1] : 0;
- this.x.range([dMinX, this.availableWidth - dMaxX]);
-
- // Y
- var minY = d3.min(this.components(), function (d) {
- return widget.y(widget.getYMetric(d)) - widget.size(widget.getSizeMetric(d));
- }),
- maxY = d3.max(this.components(), function (d) {
- return widget.y(widget.getYMetric(d)) + widget.size(widget.getSizeMetric(d));
- }),
- dMinY = minY < 0 ? this.y.range()[1] - minY: this.y.range()[1],
- dMaxY = maxY > this.y.range()[0] ? maxY - this.y.range()[0] : 0;
- this.y.range([this.availableHeight - dMaxY, dMinY]);
-
-
- // Format improvement for log scales
- // X
- if (this.xLog()) {
- this.xAxis.tickFormat(function (d) {
- var ticksCount = widget.availableWidth / 50;
- return widget.x.tickFormat(ticksCount, d3.format(',d'))(d);
- });
- }
-
- // Y
- if (this.yLog()) {
- this.yAxis.tickFormat(function (d) {
- var ticksCount = widget.availableHeight / 30;
- return widget.y.tickFormat(ticksCount, d3.format(',d'))(d);
- });
- }
-
-
- // Make scale's domains nice
- this.x.nice();
- this.y.nice();
-
-
- // Update bubbles position
+ window.SonarWidgets.BubbleChart.prototype.updateBubbles = function () {
+ var widget = this;
this.items
.transition()
.attr('transform', function (d) {
return trans(widget.x(widget.getXMetric(d)), widget.y(widget.getYMetric(d)));
});
+ };
- // Update axis
+ window.SonarWidgets.BubbleChart.prototype.updateAxes = function () {
// X
this.gxAxis.attr('transform', trans(0, this.availableHeight + this.margin().bottom - 40));
this.gyAxisLabel
.attr('transform', trans(-45, this.availableHeight / 2) + ' rotate(-90)');
+ };
- // Update grid
+ window.SonarWidgets.BubbleChart.prototype.updateGrid = function () {
+ var widget = this;
this.gxGridLines
.transition()
.attr({
};
+ window.SonarWidgets.BubbleChart.prototype.update = function (container) {
+ container = d3.select(container);
+
+ var width = container.property('offsetWidth');
+
+ this.width(width > 100 ? width : 100);
+
+ // Update svg canvas
+ this.svg
+ .attr('width', this.width())
+ .attr('height', this.height());
+
+ // Update available size
+ this.availableWidth = this.width() - this.margin().left - this.margin().right;
+ this.availableHeight = this.height() - this.margin().top - this.margin().bottom;
+
+ this.updateScales();
+ this.adjustScalesAfterUpdate();
+ this.updateBubbles();
+ this.updateAxes();
+ this.updateGrid();
+ };
+
+
window.SonarWidgets.BubbleChart.defaults = {
width: 350,