]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4952 Provide a new PieChart widget to display a measure filter
authorStas Vilchik <vilchiks@gmail.com>
Wed, 11 Dec 2013 11:17:16 +0000 (17:17 +0600)
committerStas Vilchik <vilchiks@gmail.com>
Wed, 11 Dec 2013 11:17:26 +0000 (17:17 +0600)
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/pie_chart.html.erb
sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_head.html.erb
sonar-server/src/main/webapp/javascripts/widgets/pie-chart.js
sonar-server/src/main/webapp/javascripts/widgets/widget.js [new file with mode: 0644]
sonar-server/wro.xml

index b83b65e351fd2d58c119b8309e864ac281422304..c0f2ae4220603f5298d3bbe42bfe6812931f9942 100644 (file)
@@ -1,11 +1,53 @@
+<%
+  containerId = 'pie-chart-widget' + widget.id.to_s
+  chartHeight = widget_properties["chartHeight"]
+  chartTitle = widget_properties["chartTitle"]
+  filterId = widget_properties["filter"].to_i
+%>
+
+<div class="pie-chart-widget" id="<%= containerId %>">
+  <!--[if lte IE 8 ]> <h3><%= message('widget.unsupported_browser_warning') -%></h3> <![endif]-->
+
+  <!--[if (gte IE 9)|!(IE)]><!-->
+  <% if chartTitle %>
+  <h3 style="text-align: center;"><%= h(chartTitle) -%></h3>
+  <% end %>
+  <!--<![endif]-->
+</div>
+
+<!--[if (gte IE 9)|!(IE)]><!-->
 <script>
-  var filterId = <%= widget_properties['filter'].to_i %>;
-  var chartTitle = <%= widget_properties['chartTitle'].to_s %>;
-  var chartHeight = <%= widget_properties['chartHeight'].to_s %>;
-  var mainMetric = <%= widget_properties['mainMetric'].to_s %>;
-  var extraMetric1 = <%= widget_properties['extraMetric1'].to_s %>;
-  var extraMetric2 = <%= widget_properties['extraMetric2'].to_s %>;
-  var extraMetric3 = <%= widget_properties['extraMetric3'].to_s %>;
+  (function () {
+    var metrics = [
+          '<%= widget_properties["mainMetric"].name %>',
+          '<%= widget_properties["extraMetric1"].name %>',
+          '<%= widget_properties["extraMetric2"].name %>',
+          '<%= widget_properties["extraMetric3"].name %>'
+        ],
+        query = [
+          'filter=<%= filterId %>',
+          'metrics=' + metrics.join(','),
+          'fields=name',
+          'pageSize=9',
+          'page=1',
+          'sort=metric:' + metrics[0],
+          'asc=false'
+        ].join('&');
+        widget = new SonarWidgets.Widget();
+
+    widget
+      .type('PieChart')
+      .source(baseUrl + '/measures/search_filter?' + query)
+      .metricsPriority(metrics)
+      .height(<%= chartHeight %>)
+      .render('#<%= containerId %>');
+
+    autoResize(500, function() {
+      widget.update('#<%= containerId %>');
+    });
+  })();
 </script>
+<!--<![endif]-->
+
 
 
index a1fd777877aaca6dce744f7224835d08c5db0fd5..cd405b7318fa73bedaf9c3e2c8a94c56c189cf55 100644 (file)
@@ -47,6 +47,7 @@
     <%= javascript_include_tag 'third-party/jquery.ba-throttle-debounce.min.js' %>
     <%= javascript_include_tag 'third-party/select2.min' %>
 
+    <%= javascript_include_tag 'widgets/widget' %>
     <%= javascript_include_tag 'widgets/bubble-chart' %>
     <%= javascript_include_tag 'widgets/timeline' %>
     <%= javascript_include_tag 'widgets/stack-area' %>
index 4bb174b4382193ff2270320d00f4e772553fb863..254b7db6ea9b48fb72772c55fc4f4e1e4d4377b9 100644 (file)
@@ -7,8 +7,9 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets;
 
   window.SonarWidgets.PieChart = function () {
     // Set default values
-    this._data = [];
+    this._components = [];
     this._metrics = [];
+    this._metricsPriority = [];
     this._width = window.SonarWidgets.PieChart.defaults.width;
     this._height = window.SonarWidgets.PieChart.defaults.height;
     this._margin = window.SonarWidgets.PieChart.defaults.margin;
@@ -16,15 +17,20 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets;
 
     this._lineHeight = 20;
 
-    // Export global variables
-    this.data = function (_) {
-      return param.call(this, '_data', _);
-    };
 
+    // Export global variables
     this.metrics = function (_) {
       return param.call(this, '_metrics', _);
     };
 
+    this.metricsPriority = function (_) {
+      return param.call(this, '_metricsPriority', _);
+    };
+
+    this.components = function (_) {
+      return param.call(this, '_components', _);
+    };
+
     this.width = function (_) {
       return param.call(this, '_width', _);
     };
@@ -60,6 +66,13 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets;
         .attr('transform', trans(this.margin().left, this.margin().top));
 
 
+    // Configure metrics
+    this.mainMetric = this.metricsPriority()[0];
+    this.getMainMetric = function(d) {
+      return d.measures[widget.mainMetric].val;
+    };
+
+
     // Configure scales
     this.color = d3.scale.category20();
 
@@ -72,12 +85,12 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets;
     // Configure pie
     this.pie = d3.layout.pie()
         .sort(null)
-        .value(function(d) { return d.metric; });
+        .value(function(d) { return widget.getMainMetric(d); });
 
 
     // Configure sectors
     this.sectors = this.plotWrap.selectAll('.arc')
-        .data(this.pie(this.data()))
+        .data(this.pie(this.components()))
         .enter().append('g').attr('class', 'arc');
 
     this.sectors.append('path')
@@ -89,8 +102,9 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets;
         .attr('width', this.legendWidth());
 
     this.legends = this.legendWrap.selectAll('.legend')
-        .data(this.pie(this.data()))
-        .enter().append('g')
+        .data(this.components());
+
+    this.legends.enter().append('g')
         .attr('class', 'legend')
         .attr('transform', function(d, i) { return trans(0, 10 + i * widget._lineHeight); });
 
@@ -102,7 +116,7 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets;
     this.legends.append('text')
         .attr('class', 'legend-text')
         .attr('transform', trans(10, 3))
-        .text(function(d) { return d.data.name; });
+        .text(function(d) { return d.name; });
 
 
     // Configure details
@@ -113,22 +127,16 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets;
 
     this.detailsColorIndicator = this.detailsWrap.append('rect')
         .classed('details-color-indicator', true)
+        .attr('transform', trans(-1, 0))
         .attr('x', 0)
         .attr('y', 0)
-        .attr('width', 4)
+        .attr('width', 3)
         .attr('height', this._detailsHeight)
         .style('opacity', 0);
 
-    this._detailsMetric = [
-      { name: 'Technical Dept', value: 8.5 },
-      { name: 'Lines of Code', value: 362 },
-      { name: 'Issues', value: 3 },
-      { name: 'Coverage', value: 86 }
-    ];
-
 
     // Configure events
-    var enterHandler = function(sector, legend, i) {
+    var enterHandler = function(sector, legend, d, i) {
           var scaleFactor = (widget.radius + 5) / widget.radius;
           d3.select(legend)
               .classed('legend-active', true);
@@ -136,12 +144,19 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets;
               .classed('arc-active', true)
               .style('-webkit-transform', 'scale(' + scaleFactor + ')');
 
-          updateMetrics(widget._detailsMetric);
+          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)
@@ -152,25 +167,28 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets;
           widget.detailsMetrics
               .style('opacity', 0);
         },
+
         updateMetrics = function(metrics) {
+
           widget.detailsMetrics = widget.detailsWrap.selectAll('.details-metric')
               .data(metrics);
 
-          widget.detailsMetrics
-              .enter().append('text')
-              .text(function(d) { return d.name + ': ' + d.value; });
-
-          widget.detailsMetrics
+          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')
+              .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, i);
+          return enterHandler(widget.sectors[0][i], this, d, i);
         })
         .on('mouseleave', function(d, i) {
           return leaveHandler(widget.sectors[0][i], this);
@@ -178,7 +196,7 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets;
 
     this.sectors
         .on('mouseenter', function(d, i) {
-          return enterHandler(this, widget.legends[0][i], i);
+          return enterHandler(this, widget.legends[0][i], d.data, i);
         })
         .on('mouseleave', function(d, i) {
           return leaveHandler(this, widget.legends[0][i]);
@@ -213,21 +231,22 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets;
 
 
     // Update radius
-    this.radius = Math.min(this.availableWidth - this.legendWidth(), this.availableHeight) / 2;
+    this.radius = Math.min(this.availableWidth, this.availableHeight) / 2;
 
 
     // Update plot
     this.plotWrap
-      .attr('transform', trans(this.radius, this.radius));
+        .attr('transform', trans(this.radius, this.radius));
 
 
     // Update arc
-    this.arc.outerRadius(this.radius);
+    this.arc
+        .outerRadius(this.radius);
 
 
     // Update legend
     this.legendWrap
-      .attr('transform', trans(20 + this.radius * 2, 0 ));
+        .attr('transform', trans(20 + this.radius * 2, 0 ));
 
 
     // Update details
@@ -239,9 +258,6 @@ window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets;
     this.sectors.selectAll('path')
         .transition()
         .attr('d', this.arc);
-
-    this.sectors.selectAll('text')
-        .attr('transform', function(d) { return 'translate(' + widget.arc.centroid(d) + ')'; });
   };
 
 
diff --git a/sonar-server/src/main/webapp/javascripts/widgets/widget.js b/sonar-server/src/main/webapp/javascripts/widgets/widget.js
new file mode 100644 (file)
index 0000000..f4db2b9
--- /dev/null
@@ -0,0 +1,70 @@
+/*global d3:false, SonarWidgets:false */
+/*jshint eqnull:true */
+
+window.SonarWidgets = window.SonarWidgets == null ? {} : window.SonarWidgets;
+
+(function () {
+
+  window.SonarWidgets.Widget = function () {
+    // Set default values
+    this._type = null;
+    this._source = null;
+    this._metricsPriority = null;
+    this._height = null;
+
+
+    // Export global variables
+    this.type = function (_) {
+      return param.call(this, '_type', _);
+    };
+
+    this.source = function (_) {
+      return param.call(this, '_source', _);
+    };
+
+    this.metricsPriority = function (_) {
+      return param.call(this, '_metricsPriority', _);
+    };
+
+    this.height = function (_) {
+      return param.call(this, '_height', _);
+    };
+  };
+
+
+  window.SonarWidgets.Widget.prototype.render = function(container) {
+    var that = this;
+
+    d3.json(this.source(), function(error, response) {
+      if (response && !error) {
+        that.widget = new SonarWidgets[that.type()]();
+        that.widget
+            .metrics(response.metrics)
+            .metricsPriority(that.metricsPriority())
+            .components(response.components)
+            .height(that.height());
+        that.widget.render(container);
+      }
+    });
+  };
+
+
+  window.SonarWidgets.Widget.prototype.update = function(container) {
+    return this.widget && this.widget.update(container);
+  };
+
+
+
+  // Some helper functions
+
+  // Gets or sets parameter
+  function param(name, value) {
+    if (value == null) {
+      return this[name];
+    } else {
+      this[name] = value;
+      return this;
+    }
+  }
+
+})();
index 11c1ba2ebe4c2ee28274491f2f3b37e5cd002edd..46f78721d2567a4feac1e9dd2fb89a3422e54831 100644 (file)
@@ -27,6 +27,7 @@
     <js>/javascripts/third-party/jquery.ba-throttle-debounce.min.js</js>
     <js>/javascripts/third-party/select2.min.js</js>
 
+    <js>/javascripts/widgets/widget.js</js>
     <js>/javascripts/widgets/bubble-chart.js</js>
     <js>/javascripts/widgets/timeline.js</js>
     <js>/javascripts/widgets/stack-area.js</js>