From: Stas Vilchik Date: Fri, 13 Dec 2013 06:47:15 +0000 (+0600) Subject: SONAR-4952 Provide a new PieChart widget to display a measure filter X-Git-Tag: 4.2~996 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=13ed98d0490bbc37a306765f0bca69591b7a6b15;p=sonarqube.git SONAR-4952 Provide a new PieChart widget to display a measure filter Convert to donut chart, update layout --- diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/pie_chart.html.erb b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/pie_chart.html.erb index 04f414a5465..2e9ae043948 100644 --- a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/pie_chart.html.erb +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/pie_chart.html.erb @@ -20,14 +20,16 @@ (function () { var metrics = [ '<%= widget_properties["mainMetric"].name %>', - '<%= widget_properties["extraMetric1"].name %>', - '<%= widget_properties["extraMetric2"].name %>' + '<%= widget_properties["extraMetric1"].name %>' + <% if (widget_properties["extraMetric2"]) %> + , '<%= widget_properties["extraMetric2"].name %>' + <% end %> ], query = [ 'filter=<%= filterId %>', 'metrics=' + metrics.join(','), 'fields=name', - 'pageSize=9', + 'pageSize=10', 'page=1', 'sort=metric:' + metrics[0], 'asc=false' diff --git a/sonar-server/src/main/webapp/javascripts/widgets/pie-chart.js b/sonar-server/src/main/webapp/javascripts/widgets/pie-chart.js index 254b7db6ea9..90f799d0607 100644 --- a/sonar-server/src/main/webapp/javascripts/widgets/pie-chart.js +++ b/sonar-server/src/main/webapp/javascripts/widgets/pie-chart.js @@ -14,6 +14,8 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets; this._height = window.SonarWidgets.PieChart.defaults.height; this._margin = window.SonarWidgets.PieChart.defaults.margin; this._legendWidth = window.SonarWidgets.PieChart.defaults.legendWidth; + this._legendMargin = window.SonarWidgets.PieChart.defaults.legendMargin; + this._detailsWidth = window.SonarWidgets.PieChart.defaults.detailsWidth; this._lineHeight = 20; @@ -46,6 +48,14 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets; this.legendWidth = function (_) { return param.call(this, '_legendWidth', _); }; + + this.legendMargin = function (_) { + return param.call(this, '_legendMargin', _); + }; + + this.detailsWidth = function (_) { + return param.call(this, '_detailsWidth', _); + }; }; window.SonarWidgets.PieChart.prototype.render = function (container) { @@ -60,7 +70,8 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets; .attr('class', 'sonar-d3'); this.gWrap = this.svg.append('g'); - this.plotWrap = this.gWrap.append('g'); + this.plotWrap = this.gWrap.append('g') + .classed('plot', true); this.gWrap .attr('transform', trans(this.margin().left, this.margin().top)); @@ -71,10 +82,22 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets; this.getMainMetric = function(d) { return d.measures[widget.mainMetric].val; }; + this.fm = function(value, name) { + var type = this.metrics()[name].type; + + switch (type) { + case 'FLOAT': + return d3.format('.1f')(value); + case 'INT': + return d3.format('d')(value); + default : + return value; + } + }; // Configure scales - this.color = d3.scale.category20(); + this.color = d3.scale.category10(); // Configure arc @@ -88,39 +111,9 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets; .value(function(d) { return widget.getMainMetric(d); }); - // Configure sectors - this.sectors = this.plotWrap.selectAll('.arc') - .data(this.pie(this.components())) - .enter().append('g').attr('class', 'arc'); - - this.sectors.append('path') - .style('fill', function(d, i) { return widget.color(i); }); - - - // Configure legend - this.legendWrap = this.gWrap.append('g') - .attr('width', this.legendWidth()); - - this.legends = this.legendWrap.selectAll('.legend') - .data(this.components()); - - this.legends.enter().append('g') - .attr('class', 'legend') - .attr('transform', function(d, i) { return trans(0, 10 + i * widget._lineHeight); }); - - this.legends.append('circle') - .attr('class', 'legend-bullet') - .attr('r', 4) - .style('fill', function(d, i) { return widget.color(i); }); - - this.legends.append('text') - .attr('class', 'legend-text') - .attr('transform', trans(10, 3)) - .text(function(d) { return d.name; }); - - // Configure details - this._detailsHeight = this._lineHeight * 4; + this._metricsCount = Object.keys(this.metrics()).length + 1; + this._detailsHeight = this._lineHeight * this._metricsCount; this.detailsWrap = this.gWrap.append('g') .attr('width', this.legendWidth()); @@ -134,73 +127,10 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets; .attr('height', this._detailsHeight) .style('opacity', 0); - - // Configure events - var enterHandler = function(sector, legend, d, i) { - var scaleFactor = (widget.radius + 5) / widget.radius; - d3.select(legend) - .classed('legend-active', true); - d3.select(sector) - .classed('arc-active', true) - .style('-webkit-transform', 'scale(' + scaleFactor + ')'); - - var metrics = widget.metricsPriority().map(function(m) { - return { - name: widget.metrics()[m].name, - value: d.measures[m].val - }; - }); - updateMetrics(metrics); - - widget.detailsColorIndicator - .style('opacity', 1) - .style('fill', widget.color(i)); - }, - - leaveHandler = function(sector, legend) { - d3.select(legend).classed('legend-active', false); - d3.select(sector) - .classed('arc-active', false) - .style('-webkit-transform', 'scale(1)'); - widget.detailsColorIndicator - .style('opacity', 0); - widget.detailsMetrics - .style('opacity', 0); - }, - - updateMetrics = function(metrics) { - - widget.detailsMetrics = widget.detailsWrap.selectAll('.details-metric') - .data(metrics); - - widget.detailsMetrics.enter().append('text') - .classed('details-metric', true) - .classed('details-metric-main', function(d, i) { return i === 0; }) - .attr('transform', function(d, i) { return trans(10, i * widget._lineHeight); }) - .attr('dy', '1.2em'); - - widget.detailsMetrics - .text(function(d) { return d.name + ': ' + d.value; }) - .style('opacity', 1); - - widget.detailsMetrics.exit().remove(); - }; - - this.legends - .on('mouseenter', function(d, i) { - return enterHandler(widget.sectors[0][i], this, d, i); - }) - .on('mouseleave', function(d, i) { - return leaveHandler(widget.sectors[0][i], this); - }); - - this.sectors - .on('mouseenter', function(d, i) { - return enterHandler(this, widget.legends[0][i], d.data, i); - }) - .on('mouseleave', function(d, i) { - return leaveHandler(this, widget.legends[0][i]); - }); + this.donutLabel = this.plotWrap.append('text') + .attr('dy', '0.35em') + .style('text-anchor', 'middle') + .style('opacity', 0); // Update widget @@ -226,11 +156,9 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets; // Update available size - this.availableWidth = this.width() - this.margin().left - this.margin().right - this.legendWidth(); + this.availableWidth = this.width() - this.margin().left - this.margin().right - + this.legendWidth() - this.legendMargin(); this.availableHeight = this.height() - this.margin().top - this.margin().bottom; - - - // Update radius this.radius = Math.min(this.availableWidth, this.availableHeight) / 2; @@ -241,23 +169,93 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets; // Update arc this.arc + .innerRadius(this.radius / 2) .outerRadius(this.radius); - // Update legend - this.legendWrap - .attr('transform', trans(20 + this.radius * 2, 0 )); + // Configure sectors + this.sectors = this.plotWrap.selectAll('.arc') + .data(this.pie(this.components())); + + this.sectors + .enter() + .append('path') + .classed('arc', true) + .style('fill', function(d, i) { return widget.color(i); }); + + this.sectors + .transition() + .attr('d', this.arc); + + this.sectors + .exit().remove(); // Update details this.detailsWrap - .attr('transform', trans(20 + this.radius * 2, this.availableHeight - this._detailsHeight )); + .attr('width', this.legendWidth()) + .attr('transform', trans( + this.legendMargin() + 2 * this.radius, this.radius - this._detailsHeight / 2 + )); - - // Update sectors - this.sectors.selectAll('path') + this.donutLabel .transition() - .attr('d', this.arc); + .style('font-size', (this.radius / 6) + 'px'); + + + // Configure events + var enterHandler = function(sector, d, i) { + var metrics = widget.metricsPriority().map(function(m) { + return { + name: widget.metrics()[m].name, + value: widget.fm(d.measures[m].val, m) + }; + }); + metrics.unshift({ name: d.name }); + updateMetrics(metrics); + + widget.donutLabel + .style('opacity', 1) + .text(widget.fm(widget.getMainMetric(d), widget.mainMetric)); + + widget.detailsColorIndicator + .style('opacity', 1) + .style('fill', widget.color(i)); + }, + + leaveHandler = function() { + widget.detailsColorIndicator + .style('opacity', 0); + widget.detailsMetrics + .style('opacity', 0); + widget.donutLabel + .style('opacity', 0) + .text(''); + }, + + updateMetrics = function(metrics) { + + widget.detailsMetrics = widget.detailsWrap.selectAll('.details-metric') + .data(metrics); + + widget.detailsMetrics.enter().append('text') + .classed('details-metric', true) + .classed('details-metric-main', function(d, i) { return i === 0; }) + .attr('transform', function(d, i) { return trans(10, i * widget._lineHeight); }) + .attr('dy', '1.2em'); + + widget.detailsMetrics + .text(function(d) { return d.name + (d.value ? ': ' + d.value : ''); }) + .style('opacity', 1); + + widget.detailsMetrics.exit().remove(); + }; + + this.sectors + .on('mouseenter', function(d, i) { + return enterHandler(this, d.data, i); + }) + .on('mouseleave', leaveHandler); }; @@ -266,7 +264,8 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets; width: 350, height: 300, margin: { top: 10, right: 10, bottom: 10, left: 10 }, - legendWidth: 250 + legendWidth: 160, + legendMargin: 30 }; diff --git a/sonar-server/src/main/webapp/stylesheets/style.css b/sonar-server/src/main/webapp/stylesheets/style.css index ef70b94a716..a5150e840ed 100644 --- a/sonar-server/src/main/webapp/stylesheets/style.css +++ b/sonar-server/src/main/webapp/stylesheets/style.css @@ -2440,6 +2440,18 @@ textarea.width100 { fill: #444; } +.sonar-d3 .plot { + transition: all 0.2s ease; +} + +.sonar-d3 .plot:hover .arc { + opacity: 0.4; +} + +.sonar-d3 .plot .arc:hover { + opacity: 1; +} + .sonar-d3 .plot .line { fill: none; stroke: #000; @@ -2460,13 +2472,11 @@ textarea.width100 { .sonar-d3 .arc { cursor: pointer; + stroke: #fff; + stroke-width: 1px; transition: all 0.2s ease; } -.sonar-d3 .arc-active { - -webkit-transform: scale(1.05); -} - .sonar-d3 .legend { cursor: pointer; }