From 83f1a6be23cc239d4d3790e57ff1fa24306a0a82 Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Mon, 26 Nov 2012 15:40:01 +0100 Subject: [PATCH] SONAR-3825 add treemap rendering --- .../WEB-INF/app/models/measure_filter.rb | 39 +++-- .../app/models/measure_filter_treemap.rb | 134 ++++++++++++++++++ .../views/measures/_display_treemap.html.erb | 4 + .../src/main/webapp/stylesheets/style.css | 3 - 4 files changed, 162 insertions(+), 18 deletions(-) create mode 100644 sonar-server/src/main/webapp/WEB-INF/app/models/measure_filter_treemap.rb diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/measure_filter.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/measure_filter.rb index 1312994d8e2..984ecc84b78 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/measure_filter.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/measure_filter.rb @@ -64,10 +64,10 @@ class MeasureFilter < ActiveRecord::Base def align @align ||= - begin - # by default is table cells are left-aligned - (@key=='name' || @key=='short_name' || @key=='description') ? '' : 'right' - end + begin + # by default is table cells are left-aligned + (@key=='name' || @key=='short_name' || @key=='description') ? '' : 'right' + end end def sort? @@ -110,6 +110,7 @@ class MeasureFilter < ActiveRecord::Base def load_links? @columns.index { |column| column.links? } end + end class TreemapDisplay < Display @@ -118,10 +119,18 @@ class MeasureFilter < ActiveRecord::Base KEY = :treemap def initialize(filter) - filter.set_criteria_default_value('columns', ['metric:ncloc', 'metric:violations']) + filter.set_criteria_default_value('columns', ['metric:ncloc', 'metric:violations_density']) @columns = filter.criteria['columns'].map { |column_key| Column.new(column_key) } @metric_ids = @columns.map { |column| column.metric.id if column.metric }.compact.uniq end + + def size_metric + @size_metric ||= Metric.by_key('ncloc') + end + + def color_metric + @color_metric ||= Metric.by_key('violations_density') + end end class CloudDisplay < Display @@ -223,15 +232,15 @@ class MeasureFilter < ActiveRecord::Base def display @display ||= - begin - display_class = nil - key = criteria['display'] - if key.present? - display_class = DISPLAYS.find { |d| d::KEY==key.to_sym } - end - display_class ||= DISPLAYS.first - display_class.new(self) + begin + display_class = nil + key = criteria['display'] + if key.present? + display_class = DISPLAYS.find { |d| d::KEY==key.to_sym } end + display_class ||= DISPLAYS.first + display_class.new(self) + end end @@ -301,7 +310,7 @@ class MeasureFilter < ActiveRecord::Base if display.metric_ids && !display.metric_ids.empty? measures = ProjectMeasure.find(:all, :conditions => - ['rule_priority is null and rule_id is null and characteristic_id is null and person_id is null and snapshot_id in (?) and metric_id in (?)', snapshot_ids, display.metric_ids] + ['rule_priority is null and rule_id is null and characteristic_id is null and person_id is null and snapshot_id in (?) and metric_id in (?)', snapshot_ids, display.metric_ids] ) measures.each do |measure| result = results_by_snapshot_id[measure.snapshot_id] @@ -328,7 +337,7 @@ class MeasureFilter < ActiveRecord::Base @base_result = Result.new(base_snapshot) if display.metric_ids && !display.metric_ids.empty? base_measures = ProjectMeasure.find(:all, :conditions => - ['rule_priority is null and rule_id is null and characteristic_id is null and person_id is null and snapshot_id=? and metric_id in (?)', base_snapshot.id, display.metric_ids] + ['rule_priority is null and rule_id is null and characteristic_id is null and person_id is null and snapshot_id=? and metric_id in (?)', base_snapshot.id, display.metric_ids] ) base_measures.each do |base_measure| @base_result.add_measure(base_measure) diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/measure_filter_treemap.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/measure_filter_treemap.rb new file mode 100644 index 00000000000..f2ea09a865a --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/measure_filter_treemap.rb @@ -0,0 +1,134 @@ +# +# Sonar, entreprise quality control tool. +# Copyright (C) 2008-2012 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 +# +class MeasureFilterTreemap + include ActionView::Helpers::UrlHelper + + attr_reader :filter, :height, :id, :size, :size_metric, :color_metric + + def initialize(filter, height, id) + @filter = filter + @height = height + @id = id + @size = 0 + @size_metric = filter.display.size_metric + @color_metric = filter.display.color_metric + end + + def html + root = Treemap::Node.new(:id => -1, :label => '') + build_tree(root) + + output = Sonar::HtmlOutput.new do |o| + # width in percents + o.width = 100 + o.height = @height + o.full_html = false + o.details_at_depth = 1 + end + html = output.to_html(root) + html + "" + end + + def empty? + @size==0 + end + + private + + def build_tree(node) + if @filter.results + @filter.results.each do |result| + size_measure=result.measure(@size_metric) + if size_measure + color_measure=(@color_metric ? result.measure(@color_metric) : nil) + resource = result.snapshot.resource + child = Treemap::Node.new(:id => "#{@id}-#{@size += 1}", + :size => size_value(size_measure), + :label => resource.name(false), + :title => escape_javascript(resource.name(true)), + :tooltip => tooltip(resource, size_measure, color_measure), + :color => html_color(color_measure), + :rid => resource.id, + :leaf => resource.source_code?) + node.add_child(child) + end + end + end + end + + def tooltip(resource, size_measure, color_measure) + html=CGI::escapeHTML(resource.name(true)) + html += " - #{CGI::escapeHTML(@size_metric.short_name)}: #{CGI::escapeHTML(size_measure.formatted_value)}" + if color_measure + html += " - #{CGI::escapeHTML(@color_metric.short_name)}: #{CGI::escapeHTML(color_measure.formatted_value)}" + end + html + end + + def size_value(measure) + if measure.value + measure.value.to_f.abs||0.0 + else + 0.0 + end + end + + def html_color(measure) + MeasureColor.color(measure).html + end + +end + +class Sonar::HtmlOutput < Treemap::HtmlOutput + + def draw_node(node) + return "" if node.bounds.nil? + + html = '' + html += "
" + html += "
0) + node.children.each do |c| + html += draw_node(c) + end + end + html + '
' + end + + def draw_label(node) + if node.leaf + "#{node_label(node)}" + else + "#{node_label(node)}" + end + end +end \ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/measures/_display_treemap.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/measures/_display_treemap.html.erb index e69de29bb2d..0f4f89108a4 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/measures/_display_treemap.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/measures/_display_treemap.html.erb @@ -0,0 +1,4 @@ +<% treemap = MeasureFilterTreemap.new(@filter, 600, @filter.id.to_s) %> +
+ <%= treemap.html() -%> +
\ No newline at end of file diff --git a/sonar-server/src/main/webapp/stylesheets/style.css b/sonar-server/src/main/webapp/stylesheets/style.css index 1260a280515..b6c02a430f7 100644 --- a/sonar-server/src/main/webapp/stylesheets/style.css +++ b/sonar-server/src/main/webapp/stylesheets/style.css @@ -274,9 +274,6 @@ h4, .h4 { text-decoration: none; font-size: 12px; padding: 1px; -} - -.treemap a:hover { text-decoration: underline; } -- 2.39.5