filter.columns.clear
params[:columns].each do |colstring|
- filter.columns<<::FilterColumn.create_from_string(colstring)
+ column=::FilterColumn.create_from_string(colstring)
+ filter.columns<<column if column
end
filter.save
redirect_to :action => :edit, :id => filter.id
@width=(params[:width]||'800').to_i
@height=(params[:height]||'500').to_i
- @treemap=Sonar::Treemap.new(@filter_context.measures_by_snapshot, @width, @height, @size_metric, @color_metric)
+
+ treemap_options={:variation_index => @filter_context.variation_index}
+ @treemap=Sonar::Treemap.new(@filter_context.measures_by_snapshot, @width, @height, @size_metric, @color_metric, treemap_options)
render :action => "treemap", :layout => false
end
end
if filter.favourites
- java_filter.setFavouriteIds((filter_context.user ? user.favourite_ids : []).to_java(:Integer))
+ java_filter.setFavouriteIds((filter_context.user ? filter_context.user.favourite_ids : []).to_java(:Integer))
end
date_criterion=filter.criterion('date')
def treemap_metrics(filter)
metrics=filter.measure_columns.map{|col| col.metric}
size_metric=(metrics.size>=1 ? metrics[0] : Metric.by_key('ncloc'))
- color_metric=(metrics.size>=2 ? metrics[1] : Metric.by_key('violations_density'))
+ color_metric=nil
+ if metrics.size>=2
+ color_metric=metrics[1]
+ end
+ if color_metric.nil? || !color_metric.treemap_color?
+ color_metric=Metric.by_key('violations_density')
+ end
[size_metric, color_metric]
end
--- /dev/null
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2009 SonarSource SA
+# 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 MeasureColor
+
+ MIN_COLOR=Color::RGB.from_html("EE0000") # red
+ MEAN_COLOR=Color::RGB.from_html("FFEE00") # orange
+ MAX_COLOR=Color::RGB.from_html("00AA00") # green
+ NONE_COLOR=Color::RGB.from_html("DDDDDD") # gray
+
+ #
+ # Options :
+ # * min : min value, else the metric worst_value
+ # * max : max value, else the metric best_value
+ # * variation_index: integer between 1 and 5 if set, else nil
+ # * check_alert_status: true|false. Default is true.
+ #
+ def self.color(measure, options={})
+ return NONE_COLOR if measure.nil?
+
+ max_value = options[:max] || measure.metric.best_value
+ min_value = options[:min] || measure.metric.worst_value
+ percent=-1.0
+
+ if options[:variation_index]
+ if min_value && max_value
+ value=measure.variation(options[:variation_index])
+ percent = value_to_percent(value, min_value, max_value)
+ end
+ else
+ if !measure.alert_status.blank? && (options[:check_alert_status]||true)
+ case(measure.alert_status)
+ when Metric::TYPE_LEVEL_OK : percent=100.0
+ when Metric::TYPE_LEVEL_ERROR : percent=0.0
+ when Metric::TYPE_LEVEL_WARN : percent=50.0
+ end
+ elsif measure.metric.value_type==Metric::VALUE_TYPE_LEVEL
+ case(measure.text_value)
+ when Metric::TYPE_LEVEL_OK : percent=100.0
+ when Metric::TYPE_LEVEL_WARN : percent=50.0
+ when Metric::TYPE_LEVEL_ERROR : percent=0.0
+ end
+ elsif measure.value && max_value && min_value
+ percent = value_to_percent(measure.value, min_value, max_value)
+ end
+ end
+
+ if percent<0.0
+ NONE_COLOR
+ elsif (percent > 50.0)
+ MAX_COLOR.mix_with(MEAN_COLOR, (percent - 50.0) * 2.0)
+ else
+ MIN_COLOR.mix_with(MEAN_COLOR, (50.0 - percent) * 2.0)
+ end
+ end
+
+
+ def self.value_to_percent(value, min, max)
+ percent = 100.0 * (value.to_f - min.to_f) / (max.to_f - min.to_f)
+ percent=100.0 if percent>100.0
+ percent=0.0 if percent<0.0
+ percent
+ end
+end
'direction' => direction.to_i, 'val_type' => val_type.to_s, 'hidden' => hidden}
end
+ def treemap_color?
+ enabled && !hidden && ((numeric? && worst_value && best_value) || val_type==Metric::VALUE_TYPE_LEVEL)
+ end
+
+ def treemap_size?
+ enabled && !hidden && numeric? && !domain.blank?
+ end
+
def to_xml(options={})
xml = Builder::XmlMarkup.new
xml.metric do
end
end
-
- MIN_COLOR=Color::RGB.from_html("EE0000") # red
- MEAN_COLOR=Color::RGB.from_html("FFEE00") # orange
- MAX_COLOR=Color::RGB.from_html("00AA00") # green
-
def color
@color ||=
begin
- percent=-1.0
- if !alert_status.blank?
- case(alert_status)
- when Metric::TYPE_LEVEL_OK : percent=100.0
- when Metric::TYPE_LEVEL_ERROR : percent=0.0
- when Metric::TYPE_LEVEL_WARN : percent=50.0
- end
- elsif metric.value_type==Metric::VALUE_TYPE_LEVEL
- case(text_value)
- when Metric::TYPE_LEVEL_OK : percent=100.0
- when Metric::TYPE_LEVEL_WARN : percent=50.0
- when Metric::TYPE_LEVEL_ERROR : percent=0.0
- end
- elsif value && metric.worst_value && metric.best_value
- percent = 100.0 * (value.to_f - metric.worst_value.to_f) / (metric.best_value.to_f - metric.worst_value.to_f)
- percent=100.0 if percent>100.0
- percent=0.0 if percent<0.0
- end
- if percent<0.0
- nil
- elsif (percent > 50.0)
- MAX_COLOR.mix_with(MEAN_COLOR, (percent - 50.0) * 2.0)
- else
- MIN_COLOR.mix_with(MEAN_COLOR, (50.0 - percent) * 2.0)
- end
+ MeasureColor.color(self)
end
end
attr_accessor :color_metric, :size_metric, :width, :height
- def initialize(measures_by_snapshot, width, height, size_metric, color_metric)
+ def initialize(measures_by_snapshot, width, height, size_metric, color_metric, options={})
@measures_by_snapshot = measures_by_snapshot
@size_metric = size_metric
- @color_metric = color_metric
+ @color_metric = color_metric if color_metric && color_metric.treemap_color?
@width = width
@height = height
+
+ if options[:variation_index] && options[:variation_index]>0
+ @variation_index = options[:variation_index]
+ end
end
def generate_html
id_counter = 0
@measures_by_snapshot.each_pair do |snapshot, measures|
size_measure=measures[@size_metric]
- color_measure=measures[@color_metric]
+ color_measure=measures[@color_metric] if @color_metric
if size_measure
resource = snapshot.project
child = Treemap::Node.new( :id => (id_counter += 1),
- :size => size_measure.value.to_f||0,
+ :size => size_value(size_measure),
:label => resource.name(false),
:title => escape_javascript(resource.name(true)),
:tooltip => get_html_tooltip(snapshot, size_measure, color_measure),
:color => html_color(color_measure),
- :url => get_url(snapshot,color_measure))
+ :url => get_url(snapshot))
node.add_child(child)
end
end
end
- def get_url(snapshot,color_measure)
+ def get_url(snapshot)
if snapshot.display_dashboard?
"document.location='#{ApplicationController.root_context}/dashboard/index/#{snapshot.project.copy_resource_id || snapshot.project_id}'"
else
- "window.open('#{ApplicationController.root_context}/resource/index/#{snapshot.project_id}?viewer_metric_key=#{@color_metric.key}','resource','height=800,width=900,scrollbars=1,resizable=1');return false;"
+ color_metric_key=(@color_metric ? @color_metric.key : nil)
+ "window.open('#{ApplicationController.root_context}/resource/index/#{snapshot.project_id}?viewer_metric_key=#{color_metric_key}','resource','height=800,width=900,scrollbars=1,resizable=1');return false;"
end
end
def get_html_tooltip(snapshot, size_measure, color_measure)
html = "<table>"
html += "<tr><td align=left>#{escape_javascript(@size_metric.short_name)}</td><td align=right><b>#{escape_javascript(size_measure ? size_measure.formatted_value : '-')}</b></td></tr>"
- html += "<tr><td align=left>#{escape_javascript(@color_metric.short_name)}</td><td align=right><b>#{escape_javascript(color_measure ? color_measure.formatted_value : '-')}</b></td></tr>"
+ if color_measure
+ html += "<tr><td align=left>#{escape_javascript(@color_metric.short_name)}</td><td align=right><b>#{escape_javascript(color_measure ? color_measure.formatted_value : '-')}</b></td></tr>"
+ end
html += "</table>"
html
end
+
+ def size_value(measure)
+ if @variation_index
+ var=measure.variation(@variation_index)
+ var ? var.to_f.abs : 0.0
+ elsif measure.value
+ measure.value.to_f.abs||0.0
+ else
+ 0.0
+ end
+ end
def html_color(measure)
- measure ? measure.color.html : '#DDDDDD'
+ MeasureColor.color(measure).html
end
end
html = ""
html += "<div id=\"node-#{node.id}\" style=\""
- html += "overflow: hidden; position:absolute;"
- html += "left: #{node.bounds.x1}px; top: #{node.bounds.y1}px;"
- html += "width: #{node.bounds.width}px; height: #{node.bounds.height}px;"
- html += "background-color: #FFF;"
+ html += "overflow:hidden;position:absolute;"
+ html += "left:#{node.bounds.x1}px; top:#{node.bounds.y1}px;"
+ html += "width:#{node.bounds.width}px;height: #{node.bounds.height}px;"
+ html += "background-color:#FFF;"
html += "\" class=\"node\">"
html += "<div id=\"link_node-#{node.id}\" style='margin: 2px;background-color: #{node.color}; height: #{node.bounds.height-4}px; border: 1px solid #{node.color};' "
if node.url && @details_at_depth==node.depth
def self.size_metrics(options={})
exclude_user_managed=options[:exclude_user_managed]||false
Metric.all.select{ |metric|
- metric.enabled && !metric.hidden && metric.numeric? && !metric.domain.blank? && (!exclude_user_managed || !metric.user_managed?)
+ metric.treemap_size? && (!exclude_user_managed || !metric.user_managed?)
}.sort
end
def self.color_metrics
Metric.all.select{ |metric|
- metric.enabled && !metric.hidden && ((metric.numeric? && metric.worst_value && metric.best_value) || metric.val_type==Metric::VALUE_TYPE_LEVEL)
+ metric.treemap_color?
}.sort
end
<script>
var treemap_width = $('treemap').getDimensions().width - 15;
var treemap_height = document.viewport.getDimensions().height - 220;
-function load_treemap(size_metric, color_metric, hide_form) {
+function load_treemap(size_metric, color_metric, hide_form, variation_index) {
$('treemap_loading').show();
$('treemap').hide();
- <%= remote_function :update => 'treemap', :url => {:action => 'treemap', :id => @filter.id},
+ <%= remote_function :update => 'treemap', :url => {:action => 'treemap', :id => @filter.id, :show_periods => true},
:complete => "$('treemap_loading').hide();$('treemap').show();",
- :with => "'width=' + treemap_width + '&height=' + treemap_height + '&size_metric=' + size_metric + '&color_metric=' + color_metric + '&hide_form=' + hide_form" %>
+ :with => "'width=' + treemap_width + '&height=' + treemap_height + '&size_metric=' + size_metric + '&color_metric=' + color_metric + '&hide_form=' + hide_form + '&var=' + variation_index" %>
}
-load_treemap('<%= size_metric.key -%>', '<%= color_metric.key -%>', <%= edit_mode -%>);
+load_treemap('<%= size_metric.key -%>', '<%= color_metric.key -%>', <%= edit_mode -%>, <%= params[:var].to_i -%>);
</script>
\ No newline at end of file
<%= render :partial => 'filters/tabs', :locals => {:selected_tab=> (@active && @active.filter ? @active.filter.id : nil) } %>
<div class="tabs-panel">
-<%= render :partial => "filters/#{@filter.default_view}", :locals => {:edit_mode => false } if @filter %>
+<%= render :partial => "filters/#{@filter.default_view}", :locals => {:edit_mode => false} if @filter %>
</div>
\ No newline at end of file
<%= select_tag 'color_metric', options_grouped_by_domain(Sonar::TreemapBuilder.color_metrics, @color_metric.key),
:id => 'color_metric', :class => 'small', :onchange => "load_treemap(this.form.size_metric.value,this.form.color_metric.value, false);return false;" %>
</td>
+ <% if params[:show_periods]=='true' %>
+ <td class="sep"> </td>
+ <td>
+ <span class="comments">Period:</span>
+ <br/>
+ <select name="var" onchange="submit()" class="small">
+ <option value="">None</option>
+ <% period_names.each_with_index do |name, index| %>
+ <option value="<%= index+1 -%>" <%= 'selected' if params[:var].to_i==index+1 -%>><%= name -%></value>
+ <% end %>
+ </select>
+ </td>
+ <% end %>
</tr>
</table>
</form>