From 9001f7e14b547fc15fcbb1709466f7ce8de31a32 Mon Sep 17 00:00:00 2001 From: Fabrice Bellingard Date: Thu, 18 Aug 2011 17:47:18 +0200 Subject: [PATCH] SONAR-2074 New timeline widget: first basic version --- .../org/sonar/plugins/core/CorePlugin.java | 1 + .../plugins/core/widgets/TimelineWidget.java | 46 ++++++++++ .../plugins/core/widgets/timeline.html.erb | 41 +++++++++ .../resources/org/sonar/l10n/core.properties | 3 + .../main/webapp/javascripts/protovis-sonar.js | 92 +++++++++++++++++++ 5 files changed, 183 insertions(+) create mode 100644 plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/TimelineWidget.java create mode 100644 plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/timeline.html.erb create mode 100755 sonar-server/src/main/webapp/javascripts/protovis-sonar.js diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java index ebc5c48a4c1..4a30f0daac8 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java @@ -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 index 00000000000..c7c98054d88 --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/widgets/TimelineWidget.java @@ -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 index 00000000000..d50e8ad9405 --- /dev/null +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/timeline.html.erb @@ -0,0 +1,41 @@ +<%= javascript_include_tag 'protovis-sonar' %> + +
+ + \ No newline at end of file diff --git a/plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties b/plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties index 9f98474b8e2..f61dd520ddd 100644 --- a/plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties +++ b/plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties @@ -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 index 00000000000..edaa93ab6c2 --- /dev/null +++ b/sonar-server/src/main/webapp/javascripts/protovis-sonar.js @@ -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 -- 2.39.5