]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-2074 New timeline widget: first basic version
authorFabrice Bellingard <bellingard@gmail.com>
Thu, 18 Aug 2011 15:47:18 +0000 (17:47 +0200)
committerFabrice Bellingard <bellingard@gmail.com>
Thu, 18 Aug 2011 15:50:22 +0000 (17:50 +0200)
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/TimelineWidget.java [new file with mode: 0644]
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/timeline.html.erb [new file with mode: 0644]
plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties
sonar-server/src/main/webapp/javascripts/protovis-sonar.js [new file with mode: 0755]

index ebc5c48a4c14548a32d18c30d6f8efd117fc4183..4a30f0daac8e7f1d2211ab3be255d4e4702789f3 100644 (file)
@@ -214,6 +214,7 @@ public class CorePlugin extends SonarPlugin {
     extensions.add(SizeWidget.class);
     extensions.add(EventsWidget.class);
     extensions.add(CustomMeasuresWidget.class);
+    extensions.add(TimelineWidget.class);
 
     // chart
     extensions.add(XradarChart.class);
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/TimelineWidget.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/TimelineWidget.java
new file mode 100644 (file)
index 0000000..c7c9805
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.plugins.core.widgets;
+
+import org.sonar.api.web.*;
+
+@WidgetProperties(
+    {
+        @WidgetProperty(key = "metric1", type = WidgetPropertyType.METRIC),
+        @WidgetProperty(key = "metric2", type = WidgetPropertyType.METRIC),
+        @WidgetProperty(key = "metric3", type = WidgetPropertyType.METRIC),
+        @WidgetProperty(key = "displayEvents", type = WidgetPropertyType.BOOLEAN)
+    }
+)
+public class TimelineWidget extends AbstractRubyTemplate implements RubyRailsWidget {
+  public String getId() {
+    return "timeline";
+  }
+
+  public String getTitle() {
+    return "Timeline";
+  }
+
+  @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";
+  }
+}
\ No newline at end of file
diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/timeline.html.erb b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/timeline.html.erb
new file mode 100644 (file)
index 0000000..d50e8ad
--- /dev/null
@@ -0,0 +1,41 @@
+<%= javascript_include_tag 'protovis-sonar' %>
+
+<div id="timeline-chart"></div>
+
+<script type="text/javascript+protovis">
+
+<%
+  metric_data_map = {}
+  (1..3).each do |index|
+    metric=widget_properties["metric#{index}"]
+    if metric
+      metric_data_map[metric.id] = []
+    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|
+    metric_data_map[trend_item["metric_id"].to_i] << {:date => trend_item["created_at"], :value => trend_item["value"]}
+  end
+
+  js_data = "["
+  metric_data_map.keys.each() do |metric_id|
+    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 +=  "\"},"
+    end
+    js_data += "],"
+  end
+  js_data += "]"
+   
+%>
+  var data = <%= js_data -%>;
+  
+  displayTrendChart('timeline-chart', data);
+
+</script>
\ No newline at end of file
index 9f98474b8e27c1f85af7d42f3419e29f99878734..f61dd520dddd0852e9b87685e70791e6079615af 100644 (file)
@@ -508,6 +508,9 @@ widget.size.methods.suffix=\ methods
 widget.size.accessors.suffix=\ accessors
 widget.size.paragraphs.suffix=\ paragraphs
 
+widget.timeline.name=Timeline
+widget.timeline.description=Displays up to 3 metrics on a history chart.
+
 widget.ckjm.name=Chidamber & Kemerer
 widget.ckjm.description=Reports on LCOM4 and RFC average and distribution.
 widget.ckjm.lcom4=LCOM4
diff --git a/sonar-server/src/main/webapp/javascripts/protovis-sonar.js b/sonar-server/src/main/webapp/javascripts/protovis-sonar.js
new file mode 100755 (executable)
index 0000000..edaa93a
--- /dev/null
@@ -0,0 +1,92 @@
+function displayTrendChart(divId, data) {
+
+       /* Sizing and scales. */
+       var w = 400 - 40, 
+               h = 300 - 25,
+               S=2;
+
+
+       var x = pv.Scale.linear(pv.blend(pv.map(data, function(d) d)), function(d) d.x).range(0, w);
+       var y = new Array(data.length);
+       for(var i = 0; i < data.length; i++){ 
+               y[i]=pv.Scale.linear(data[i], function(d) d.y).range(0, h)
+       }
+       var interpolate = "linear"; /* cardinal or linear */
+       var idx = -1;
+
+       /* 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");
+
+       /* X-axis */
+       vis.add(pv.Rule)
+       .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)
+       if (show_y_axis) { 
+               vis.add(pv.Rule)
+               .data(y[0].ticks(5))
+               .bottom(y[0])
+               .strokeStyle(function(d) d ? "#eee" : "#000")
+               .anchor("left")
+               .add(pv.Label)
+               .text(y[0].tickFormat); 
+       }
+
+       /* A panel for each data series. */
+       var panel = vis.add(pv.Panel)
+       .data(data);
+
+       /* The line. */
+       var line = panel.add(pv.Line)
+       .data(function(array) array)
+       .left(function(d) x(d.x))
+       .bottom(function(d) y[this.parent.index](d.y))
+       .interpolate(function() interpolate)
+       .lineWidth(2);
+
+       /* The mouseover dots and label. */
+       line.add(pv.Dot)
+       .visible(function() idx >= 0)
+       .data(function(d) [d[idx]])
+       .fillStyle(function() line.strokeStyle())
+       .strokeStyle("#000")
+       .size(20) 
+       .lineWidth(1)
+       .add(pv.Dot)
+       .left(10)
+       .bottom(function() this.parent.index * 12 + 10)
+       .anchor("right").add(pv.Label)
+       .text(function(d) 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) d.x), mx);
+               idx = idx < 0 ? (-idx - 2) : idx;
+               return vis;
+       });
+       vis.render();
+
+}
\ No newline at end of file