]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-2074 Improve timeline widget
authorFabrice Bellingard <bellingard@gmail.com>
Fri, 19 Aug 2011 13:57:22 +0000 (15:57 +0200)
committerFabrice Bellingard <bellingard@gmail.com>
Fri, 19 Aug 2011 16:27:44 +0000 (18:27 +0200)
- Improve JS code
- Sort the trends directly in the TrendsChart Ruby class
- Add optional title for graph
- Graph aware of differential view system

plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/TimelineWidget.java
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/timeline.html.erb
sonar-server/pom.xml
sonar-server/src/main/webapp/WEB-INF/app/models/trends_chart.rb
sonar-server/src/main/webapp/WEB-INF/app/views/layouts/_head.html.erb
sonar-server/src/main/webapp/javascripts/protovis-sonar.js

index c7c98054d888ef3ab024580ac25abfabaa6fea88..6faba17f93960b7baa7f24e8213b407d649f4e9e 100644 (file)
  */
 package org.sonar.plugins.core.widgets;
 
-import org.sonar.api.web.*;
+import org.sonar.api.web.AbstractRubyTemplate;
+import org.sonar.api.web.RubyRailsWidget;
+import org.sonar.api.web.WidgetProperties;
+import org.sonar.api.web.WidgetProperty;
+import org.sonar.api.web.WidgetPropertyType;
 
 @WidgetProperties(
     {
+        @WidgetProperty(key = "chartTitle", type = WidgetPropertyType.STRING),
         @WidgetProperty(key = "metric1", type = WidgetPropertyType.METRIC),
         @WidgetProperty(key = "metric2", type = WidgetPropertyType.METRIC),
         @WidgetProperty(key = "metric3", type = WidgetPropertyType.METRIC),
@@ -40,7 +45,7 @@ public class TimelineWidget extends AbstractRubyTemplate implements RubyRailsWid
 
   @Override
   protected String getTemplatePath() {
-    return "/org/sonar/plugins/core/widgets/timeline.html.erb";
-    //return "/Users/fbellingard/Documents/Sonar/repos/sonar/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/timeline.html.erb";
+    //return "/org/sonar/plugins/core/widgets/timeline.html.erb";
+    return "/Users/fbellingard/Documents/Sonar/repos/sonar/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/timeline.html.erb";
   }
 }
\ No newline at end of file
index d50e8ad94056faa01f21d36c2aa72c31703a0677..1c2f6ffc5203e46e78e09e21692e89bdf2b34aa1 100644 (file)
@@ -1,9 +1,4 @@
 <%= javascript_include_tag 'protovis-sonar' %>
-
-<div id="timeline-chart"></div>
-
-<script type="text/javascript+protovis">
-
 <%
   metric_data_map = {}
   (1..3).each do |index|
@@ -13,8 +8,13 @@
     end
   end
   
-  trends = TrendsChart.time_machine_measures(@resource, metric_data_map.keys, {}).sort { |t1, t2| t1["created_at"] <=> t2["created_at"] }
-  trends.each()  do |trend_item|
+  options = {}
+  from_date = dashboard_configuration.from_datetime
+  if from_date
+    options[:from] = from_date
+  end
+  
+  TrendsChart.time_machine_measures(@resource, metric_data_map.keys, options).each()  do |trend_item|
     metric_data_map[trend_item["metric_id"].to_i] << {:date => trend_item["created_at"], :value => trend_item["value"]}
   end
 
     js_data += "["
     metric_data_map[metric_id].each() do |metric_data|
       m_date = Time.parse(metric_data[:date])
-      js_data += "{\"x\":new Date("
-                 js_data +=  m_date.strftime("%Y,%m,%d")
-                 js_data +=  "),\"y\":\"" 
-                 js_data +=  metric_data[:value] 
-                 js_data +=  "\"},"
+      js_data += "{\"x\":d("
+                 js_data += m_date.year.to_s
+                 js_data += ","
+                 # Need to decrease by 1 the month as the JS Date object start months at 0 (= January)
+                 js_data += (m_date.month - 1).to_s
+                 js_data += ","
+                 js_data += m_date.day.to_s
+                 js_data +=  "),\"y\":" 
+                 js_data +=  sprintf( "%0.02f", metric_data[:value])
+                 js_data +=  "},"
     end
     js_data += "],"
   end
   js_data += "]"
    
 %>
-  var data = <%= js_data -%>;
-  
-  displayTrendChart('timeline-chart', data);
+
+<% if widget_properties["chartTitle"] %>
+<h3 style="text-align: center; margin-bottom: 10px"><%= h(widget_properties["chartTitle"]) -%></h3>
+<% end %>
+
+
+<div id="timeline-chart-<%= widget.id -%>"></div>
+<script type="text/javascript+protovis">
+  function d(y,m,d) {
+    return new Date(y,m,d);
+  }
+  var data = <%= js_data -%>;  
+  var timeline = new SonarWidgets.Timeline('timeline-chart-<%= widget.id -%>').data(data);
+  timeline.render();
 
 </script>
\ No newline at end of file
index ef0b4b3ffd76bf59e4e3900ff82d1035146fbf95..6cb65614c091c3ce94b76a30525c56dbbfacd712 100644 (file)
                 <include>**/prototip-min.js</include>
                 <include>**/dashboard-min.js</include>
                 <include>**/protovis-min.js</include>
+                <include>**/protovis-sonar-min.js</include>
               </includes>
               <output>${project.build.directory}/${project.build.finalName}/javascripts/sonar.js</output>
             </aggregation>
index 39497a9ed1851ea415c7c7f20ddbb55f7dbef381..00d2a31ab02021faa97451efc5b77b3fc328aa51 100644 (file)
@@ -25,7 +25,6 @@ class TrendsChart
     init_series(java_chart, metrics)
     metric_ids=metrics.map{|m| m.id}
     add_measures(java_chart, time_machine_measures(resource, metric_ids, options))
-    add_measures(java_chart, time_machine_reviews(resource, metric_ids, options))
     add_labels(java_chart, resource);
 
     export_chart_as_png(java_chart)
@@ -55,6 +54,7 @@ class TrendsChart
       if (options[:to])
         sql += ' and s.created_at<=?'
       end
+      sql += ' order by s.created_at ASC'
       conditions=[sql, Snapshot::STATUS_PROCESSED, resource.id, metric_ids]
       if (options[:from])
         conditions<<options[:from]
index 03ec71338e988666a4d9b20793d48de27d2d3a5d..50ee96547cb7fad47ab690c08d81ad71261e04c2 100644 (file)
@@ -28,6 +28,7 @@
 <%= javascript_include_tag 'prototip' %>
 <%= javascript_include_tag 'dashboard' %>
 <%= javascript_include_tag 'protovis' %>
+<%= javascript_include_tag 'protovis-sonar' %>
 <% end %>
 <!--[if lte IE 6]>
 <link href="<%= ApplicationController.root_context -%>/ie6/index" media="all" rel="stylesheet" type="text/css" />
index 12ebca3f7bef3de2acc105f3e01ad252dc8aa352..aa6e34e2ac957ac14a48a23db1ae93a1aa91a715 100755 (executable)
@@ -1,7 +1,20 @@
-function displayTrendChart(divId, data) {
+window.SonarWidgets = {}
 
+SonarWidgets.Timeline = function (divId) {
+       this.wDivId = divId;
+       this.wData;
+       this.data = function(data) {
+               this.wData = data;
+               return this;
+       }
+}
+
+SonarWidgets.Timeline.prototype.render = function() {
+       
+       var widgetDiv = document.getElementById(this.wDivId);
+       
        /* Sizing and scales. */
-       var w = 400 - 40, 
+       var w = widgetDiv.parentNode.clientWidth - 60, 
                h = 300 - 25,
                S=2;
 
@@ -15,24 +28,24 @@ function displayTrendChart(divId, data) {
 
        /* The root panel. */
        var vis = new pv.Panel()
-       .canvas(document.getElementById(divId))
-       .width(w)
-       .height(h)
-       .left(30)
-       .right(10)
-       .bottom(20)
-       .top(5)
-       .strokeStyle("#CCC");
+               .canvas(widgetDiv)
+               .width(w)
+               .height(h)
+               .left(30)
+               .right(20)
+               .bottom(20)
+               .top(5)
+               .strokeStyle("#CCC");
 
        /* X-axis */
        vis.add(pv.Rule)
-       .data(x.ticks())
-       .left(x)
-       .bottom(-5)
-       .height(5)
-       .anchor("bottom")
-       .add(pv.Label)
-       .text(x.tickFormat);
+               .data(x.ticks())
+               .left(x)
+               .bottom(-5)
+               .height(5)
+               .anchor("bottom")
+               .add(pv.Label)
+               .text(x.tickFormat);
 
        /* Y-axis and ticks. */
        var show_y_axis = (data.length==1)
@@ -48,43 +61,45 @@ function displayTrendChart(divId, data) {
 
        /* A panel for each data series. */
        var panel = vis.add(pv.Panel)
-       .data(data);
+               .data(this.wData);
 
        /* The line. */
        var line = panel.add(pv.Line)
-       .data(function(array) {return array;})
-       .left(function(d) {return x(d.x);})
-       .bottom(function(d) {return y[this.parent.index](d.y);})
-       .interpolate(function() {return interpolate;})
-       .lineWidth(2);
+               .data(function(array) {return array;})
+               .left(function(d) {return x(d.x);})
+               .bottom(function(d) {return y[this.parent.index](d.y);})
+               .interpolate(function() {return interpolate;})
+               .lineWidth(2);
 
        /* The mouseover dots and label. */
        line.add(pv.Dot)
-       .visible(function() {return idx >= 0;})
-       .data(function(d) {return [d[idx]];})
-       .fillStyle(function() {return line.strokeStyle();})
-       .strokeStyle("#000")
-       .size(20) 
-       .lineWidth(1)
-       .add(pv.Dot)
-       .left(10)
-       .bottom(function() {return this.parent.index * 12 + 10;})
-       .anchor("right").add(pv.Label)
-       .text(function(d) {return d.y.toFixed(2);});
+               .visible(function() {return idx >= 0;})
+               .data(function(d) {return [d[idx]];})
+               .fillStyle(function() {return line.strokeStyle();})
+               .strokeStyle("#000")
+               .size(20) 
+               .lineWidth(1)
+               .add(pv.Dot)
+               .left(10)
+               .bottom(function() {return this.parent.index * 12 + 10;})
+               .anchor("right").add(pv.Label)
+               .text(function(d) {return d.y.toFixed(2);});
 
 
        /* An invisible bar to capture events (without flickering). */
        vis.add(pv.Bar)
-       .fillStyle("rgba(0,0,0,.001)")
-       .event("mouseout", function() {
-               i = -1;
-               return vis;
-       })
-       .event("mousemove", function() {
-               var mx = x.invert(vis.mouse().x);
-               idx = pv.search(data[0].map(function(d) {return d.x;}), mx);
-               idx = idx < 0 ? (-idx - 2) : idx;
-               return vis;
-       });
+               .fillStyle("rgba(0,0,0,.001)")
+               .event("mouseout", function() {
+                       i = -1;
+                       return vis;
+               })
+               .event("mousemove", function() {
+                       var mx = x.invert(vis.mouse().x);
+                       idx = pv.search(data[0].map(function(d) {return d.x;}), mx);
+                       idx = idx < 0 ? (-idx - 2) : idx;
+                       return vis;
+               });
+       
        vis.render();
-};
\ No newline at end of file
+       
+}
\ No newline at end of file