Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

refactoring, changes in range, fixing range counting in different dat…

…abase adapters
  • Loading branch information...
commit c1c79c6f677fd0baaec6e933188c98afd9dab53d 1 parent 220f45b
@mszczytowski mszczytowski authored
View
27 app/controllers/charts_burndown_controller.rb
@@ -5,7 +5,7 @@ class ChartsBurndownController < ChartsController
protected
def get_data(conditions, grouping, range)
- from, to, labels, steps, sql, dates = RedmineCharts::RangeUtils.prepare_range(range, "start_date")
+ prepare_ranged = RedmineCharts::RangeUtils.prepare_range(range, "start_date")
estimated = []
logged = []
@@ -16,24 +16,24 @@ def get_data(conditions, grouping, range)
conditions_sql = "project_id = ? and (start_date <= ? or (start_date is null and created_on <= ?))"
- dates.each_with_index do |date,i|
- hours = Issue.sum(:estimated_hours, :conditions => [conditions_sql, conditions[:project_id], date, date])
+ prepare_ranged[:dates].each_with_index do |date,i|
+ hours = Issue.sum(:estimated_hours, :conditions => [conditions_sql, conditions[:project_id], date[1], date[1]])
estimated[i] = [hours, l(:charts_burndown_hint_estimated, hours)]
max = hours if max < hours
end
- dates.each_with_index do |date,i|
- hours = TimeEntry.sum(:hours, :conditions => ["project_id = ? and spent_on <= ?", conditions[:project_id], date])
+ prepare_ranged[:dates].each_with_index do |date,i|
+ hours = TimeEntry.sum(:hours, :conditions => ["project_id = ? and spent_on <= ?", conditions[:project_id], date[1]])
logged[i] = [hours, l(:charts_burndown_hint_logged, hours)]
max = hours if max < hours
end
- dates.each_with_index do |date,i|
+ prepare_ranged[:dates].each_with_index do |date,i|
hours = estimated[i][0]
- issues = Issue.find(:all, :conditions => [conditions_sql, conditions[:project_id], date, date])
+ issues = Issue.find(:all, :conditions => [conditions_sql, conditions[:project_id], date[1], date[1]])
total_ratio = 0
issues.each do |issue|
- journal = issue.journals.find(:first, :conditions => ["created_on <= ?", date], :order => "created_on desc", :select => "journal_details.value", :joins => "left join journal_details on journal_details.journal_id = journals.id and journal_details.prop_key = 'done_ratio'")
+ journal = issue.journals.find(:first, :conditions => ["created_on <= ?", date[1]], :order => "created_on desc", :select => "journal_details.value", :joins => "left join journal_details on journal_details.journal_id = journals.id and journal_details.prop_key = 'done_ratio'")
ratio = journal ? journal.value.to_i : 0
total_ratio += ratio
hours -= issue.estimated_hours.to_f * ratio.to_f / 100 if issue.estimated_hours
@@ -42,10 +42,10 @@ def get_data(conditions, grouping, range)
remaining[i] = [hours, l(:charts_burndown_hint_remaining, hours, done[i])]
end
- dates.each_with_index do |date,i|
+ prepare_ranged[:dates].each_with_index do |date,i|
hours = logged[i][0] + remaining[i][0]
if hours > estimated[i][0]
- predicted[i] = [hours, l(:charts_burndown_hint_predicted_over_estimation, hours, hours - estimated[i][0], labels[i]), true]
+ predicted[i] = [hours, l(:charts_burndown_hint_predicted_over_estimation, hours, hours - estimated[i][0], prepare_ranged[:labels][i]), true]
else
predicted[i] = [hours, l(:charts_burndown_hint_predicted, hours)]
end
@@ -59,7 +59,12 @@ def get_data(conditions, grouping, range)
[l(:charts_burndown_group_predicted), predicted],
]
- [labels, steps, max, sets]
+ {
+ :labels => prepare_ranged[:labels],
+ :count => prepare_ranged[:steps],
+ :max => max,
+ :sets => sets
+ }
end
def get_title
View
67 app/controllers/charts_controller.rb
@@ -55,29 +55,35 @@ def data
grouping = RedmineCharts::GroupingUtils.from_params(params)
conditions = RedmineCharts::ConditionsUtils.from_params(params, get_conditions_options)
- labels, count, max, sets = get_data(conditions, grouping, range)
+ data = get_data(conditions, grouping, range)
- get_converter.convert(chart, sets, labels)
+ get_converter.convert(chart, data)
if show_y_axis
y = YAxis.new
- y.set_range(0,max*1.2,max/get_y_axis_steps) if max
+ y.set_range(0,data[:max]*1.2,data[:max]/get_y_axis_labels) if data[:max]
chart.y_axis = y
end
if show_x_axis
x = XAxis.new
- x.set_range(0,count,1) if count
- if labels
- labels2 = []
- labels.each_with_index do |l,i|
- if i % get_x_axis_steps == 0
- labels2 << l
+ x.set_range(0,data[:count],1) if data[:count]
+ if data[:labels]
+ labels = []
+ if get_x_axis_labels > 0
+ step = (data[:labels].size/get_y_axis_labels).to_i
+ step = 1 if step == 0
+ else
+ step = 1
+ end
+ data[:labels].each_with_index do |l,i|
+ if i % step == 0
+ labels << l
else
- labels2 << ""
+ labels << ""
end
end
- x.set_labels(labels2)
+ x.set_labels(labels)
end
chart.x_axis = x
else
@@ -103,37 +109,6 @@ def data
render :text => chart.to_s
end
- # TODO Move it outside this class
- def get_sets(rows, grouping, count, flat = false)
- if rows.empty?
- [nil, {}]
- end
-
- sets = {}
- y_max = 0
- i = -1
-
- rows.each do |r|
- if flat
- group_name = ""
- else
- group_name = RedmineCharts::GroupingUtils.to_string(r.group_id, grouping)
- end
- sets[group_name] ||= Array.new(count, [0, get_hints])
-
- if r.respond_to?(:value_x) and r.value_x
- i += r.value_x.to_i
- else
- i += 1
- end
-
- sets[group_name][i] = [r.value_y.to_i, get_hints(r, grouping)]
- y_max = r.value_y.to_i if y_max < r.value_y.to_i
- end
-
- [y_max, sets.collect { |name, values| [name, values] }]
- end
-
protected
# Returns chart title
@@ -176,8 +151,8 @@ def show_x_axis
false
end
- # TODO
- def get_x_axis_steps
+ # Returns how many labels should be displayed on x axis. 0 means all labels.
+ def get_x_axis_labels
5
end
@@ -186,8 +161,8 @@ def show_y_axis
false
end
- # TODO
- def get_y_axis_steps
+ # Returns how many labels should be displayed on y axis. 0 means all labels.
+ def get_y_axis_labels
5
end
View
30 app/controllers/charts_deviation_controller.rb
@@ -75,9 +75,15 @@ def get_data(conditions, grouping, range)
end
# Project logged and remaining ratio.
- project_done_ratio = total_done_ratio.to_f/labels.size
- project_logged_ratio = total_logged_ratio.to_f/labels.size
- project_remaining_ratio = total_remaining_ratio.to_f/labels.size
+ if labels.size > 0
+ project_done_ratio = total_done_ratio.to_f/labels.size
+ project_logged_ratio = total_logged_ratio.to_f/labels.size
+ project_remaining_ratio = total_remaining_ratio.to_f/labels.size
+ else
+ project_done_ratio = 0
+ project_logged_ratio = 0
+ project_remaining_ratio = 0
+ end
hint = get_logged_hint(project_logged_ratio, project_remaining_ratio, project_done_ratio, total_logged_hours, total_estimated_hours)
project_logged_value = [project_logged_ratio, hint]
@@ -94,7 +100,13 @@ def get_data(conditions, grouping, range)
[l(:charts_deviation_group_remaining), remaining_values]
]
- [labels, labels.size, max, sets]
+ {
+ :labels => labels,
+ :count => labels.size,
+ :max => max,
+ :sets => sets,
+ :horizontal_line => 100
+ }
end
def get_title
@@ -121,8 +133,8 @@ def show_x_axis
true
end
- def get_x_axis_steps
- 1
+ def get_x_axis_labels
+ 0
end
def show_y_axis
@@ -176,10 +188,12 @@ def get_remaining_ratio(logged_ratio, done_ratio)
#
def get_remaining_hours(logged_hours, estimated_hours, logged_ratio, remaining_ratio)
if logged_ratio > 0
- Integer(logged_hours.to_f/logged_ratio.to_f*remaining_ratio) + 1
+ remaining_hours = Integer(logged_hours.to_f/logged_ratio.to_f*remaining_ratio)
else
- Integer(estimated_hours.to_f*remaining_ratio/100) + 1
+ remaining_hours = Integer(estimated_hours.to_f*remaining_ratio/100)
end
+ remaining_hours += 1 if remaining_hours == 0
+ remaining_hours
end
def get_remaining_hint(logged_ratio, remaining_ratio, done_ratio, logged_hours, remaining_hours, estimated_hours, row = nil)
View
9 app/controllers/charts_ratio_controller.rb
@@ -19,7 +19,7 @@ def get_data(conditions, grouping, range)
select << "#{group} as group_id"
select = select.join(", ")
- rows = TimeEntry.find(:all, :joins => "left join issues on issues.id = issue_id", :select => select, :conditions => conditions, :readonly => true, :group => group, :order => "sum(hours) asc")
+ rows = TimeEntry.find(:all, :joins => "left join issues on issues.id = issue_id", :select => select, :conditions => conditions, :readonly => true, :group => group, :order => "1 asc")
bigger_rows = []
total_hours = 0
@@ -62,7 +62,12 @@ def get_data(conditions, grouping, range)
end
end
- [labels, rows.size, 0, {"" => set}]
+ {
+ :labels => labels,
+ :count => rows.size,
+ :max => 0,
+ :sets => {"" => set}
+ }
end
def get_title
View
36 app/controllers/charts_timeline_controller.rb
@@ -5,12 +5,12 @@ class ChartsTimelineController < ChartsController
protected
def get_data(conditions, grouping , range)
- from, to, labels, steps, sql, dates = RedmineCharts::RangeUtils.prepare_range(range, "spent_on")
+ prepare_ranged = RedmineCharts::RangeUtils.prepare_range(range, "spent_on")
- conditions[:spent_on] = (from.to_date)...(to.to_date)
+ conditions[:spent_on] = (prepare_ranged[:date_from])...(prepare_ranged[:date_to])
group = []
- group << sql
+ group << prepare_ranged[:sql]
group << "user_id" if grouping == :users
group << "issue_id" if grouping == :issues
group << "project_id" if grouping == :projects
@@ -19,7 +19,7 @@ def get_data(conditions, grouping , range)
group = group.join(", ")
select = []
- select << "#{sql} as value_x"
+ select << "#{prepare_ranged[:sql]} as value_x"
select << "count(1) as count_y"
select << "sum(hours) as value_y"
select << "user_id as group_id" if grouping == :users
@@ -32,9 +32,33 @@ def get_data(conditions, grouping , range)
rows = TimeEntry.find(:all, :joins => "left join issues on issues.id = issue_id", :select => select, :conditions => conditions, :order => "1", :readonly => true, :group => group)
- max, sets = get_sets(rows, grouping, steps)
+ sets = {}
+ max = 0
- [labels, steps, max, sets]
+ if rows.size > 0
+ rows.each do |row|
+ group_name = RedmineCharts::GroupingUtils.to_string(row.group_id, grouping)
+ index = prepare_ranged[:keys].index(row.value_x)
+ if index
+ sets[group_name] ||= Array.new(prepare_ranged[:steps], [0, get_hints])
+ sets[group_name][index] = [row.value_y.to_i, get_hints(row, grouping)]
+ max = row.value_y.to_i if max < row.value_y.to_i
+ else
+ raise row.value_x.to_s
+ end
+ end
+ else
+ sets[""] ||= Array.new(prepare_ranged[:steps], [0, get_hints])
+ end
+
+ sets = sets.collect { |name, values| [name, values] }
+
+ {
+ :labels => prepare_ranged[:labels],
+ :count => prepare_ranged[:steps],
+ :max => max,
+ :sets => sets
+ }
end
def get_hints(record = nil, grouping = nil)
View
46 lib/redmine_charts/date_format.rb
@@ -3,47 +3,43 @@ module DateFormat
case ActiveRecord::Base.connection.adapter_name
when /mysql/i
- def format_date(format_in, column_name, diff_value)
- case format_in
+ def format_date(format, column)
+ case format
when :weeks
- format_in = "%u"
+ "(case when date_format(#{column}, '%d') < date_format(#{column}, '%w') then date_format(date_add(#{column}, interval - 7 day), '%Y%m%d') - date_format(#{column}, '%w') + 8 else date_format(#{column}, '%Y%m%d') - date_format(#{column}, '%w') + 1 end)"
when :months
- format_in = "%m"
+ "date_format(#{column}, '%Y%m01')"
else
- format_in = "%j"
+ "date_format(#{column}, '%Y%m%d')"
end
-
- "(DATE_FORMAT('#{format_in}', #{column_name}) + DATE_FORMAT('%Y', #{column_name}) - #{diff_value})"
end
- when /postgres.*/i
- def format_date(format_in, column_name, diff_value)
- case format_in
+ when /postgresql/i
+ def format_date(format, column)
+ case format
when :weeks
- format_in = "week"
+ "(case when date_part('days', #{column}) < date_part('dow', #{column}) then cast(to_char(#{column} - interval '7 days','YYYYMMDD') as integer) - date_part('dow', #{column}) + 8 else cast(to_char(#{column},'YYYYMMDD') as integer) - date_part('dow', #{column}) + 1 end)"
when :months
- format_in = "month"
+ "to_char(#{column},'YYYYMM01')"
else
- format_in = "doy"
+ "to_char(#{column},'YYYYMMDD')"
end
-
- "(date_part('#{format_in}', #{column_name}) + date_part('year', #{column_name}) - #{diff_value})"
end
- else
- def format_date(format_in, column_name, diff_value)
- case format_in
+ when /sqlite/i
+ def format_date(format, column)
+ case format
when :weeks
- format_in = '%W'
+ "(case when strftime('%d', #{column}) < strftime('%w', #{column}) then strftime('%Y%m%d', date(#{column}, '-7 day')) - strftime('%w', #{column}) + 8 else strftime('%Y%m%d', #{column}) - strftime('%w', #{column}) + 1 end)"
when :months
- format_in = '%m'
+ "strftime('%Y%m01', #{column})"
else
- format_in = '%j'
- end
-
- "(strftime('#{format_in}', #{column_name}) + strftime('%Y', #{column_name}) - #{diff_value})"
+ "strftime('%Y%m%d', #{column})"
+ end
end
+ else
+ raise "Unsupported adapter. Redmine Charts supports only SQLite, MySQL and PostgreSQL databases."
end
end
end
-ActiveRecord::Base.send(:extend, RedmineCharts::DateFormat)
+ActiveRecord::Base.send(:extend, RedmineCharts::DateFormat)
View
2  lib/redmine_charts/grouping_utils.rb
@@ -27,7 +27,7 @@ def self.to_string(id, grouping, default = nil)
elsif grouping == :users and user = User.find_by_id(id.to_i)
user.login.capitalize
elsif grouping == :issues and issue = Issue.find_by_id(id.to_i)
- issue.subject.capitalize
+ "##{issue.id} #{issue.subject.capitalize}"
elsif grouping == :activities and activity = Enumeration.find_by_id(id.to_i)
activity.name.capitalize
elsif default
View
6 lib/redmine_charts/line_data_converter.rb
@@ -3,10 +3,10 @@ module LineDataConverter
include GLoc
- def self.convert(chart, sets, labels)
+ def self.convert(chart, data)
index = 0
- sets.each do |set|
+ data[:sets].each do |set|
line = OpenFlashChart::LineDot.new
line.text = (set[0] == '0') ? l(:charts_group_all) : set[0]
line.width = 2
@@ -24,7 +24,7 @@ def self.convert(chart, sets, labels)
d.dot_size = 4
end
d.set_colour(RedmineCharts::Utils.color(index))
- d.set_tooltip("#{v[1]}<br>#{labels[j]}") unless v[1].nil?
+ d.set_tooltip("#{v[1]}<br>#{data[:labels][j]}") unless v[1].nil?
d
else
v
View
6 lib/redmine_charts/pie_data_converter.rb
@@ -1,13 +1,13 @@
module RedmineCharts
module PieDataConverter
- def self.convert(chart, sets, labels)
+ def self.convert(chart, data)
tooltip = OpenFlashChart::Tooltip.new
tooltip.set_hover()
chart.set_tooltip(tooltip)
- sets.each do |set|
+ data[:sets].each do |set|
pie = OpenFlashChart::Pie.new
pie.start_angle = 35
pie.animate = true
@@ -17,7 +17,7 @@ def self.convert(chart, sets, labels)
set[1].each_with_index do |v, index|
if v.is_a? Array
- d = OpenFlashChart::PieValue.new(v[0], labels[index])
+ d = OpenFlashChart::PieValue.new(v[0], data[:labels][index])
d.set_tooltip(v[1]) unless v[1].nil?
vals << d
else
View
124 lib/redmine_charts/range_utils.rb
@@ -23,85 +23,93 @@ def self.from_params(params)
}
end
- def self.count_range(range, first_time)
- case range[:in]
- when :weeks
- strftime_i = "%U"
- items_in_year = 52
- when :months
- strftime_i = "%m"
- items_in_year = 12
- else
- strftime_i = "%j"
- items_in_year = 366
- end
-
- first = first_time.strftime(strftime_i).to_i + first_time.strftime('%Y').to_i * items_in_year
- now = Time.now.strftime(strftime_i).to_i + Time.now.strftime('%Y').to_i * items_in_year
-
- range[:steps] = now - first + 4
- range[:offset] = 1
- range
- end
-
def self.prepare_range(range, column = "created_on")
- case range[:in]
- when :weeks
- strftime_i = "%U"
- when :months
- strftime_i = "%m"
- else
- strftime_i = "%j"
- end
+ dates = []
- from = times_ago(range[:steps],range[:offset],0,range[:in])
- to = times_ago(range[:steps],range[:offset]-1,0,range[:in])
+ range[:steps].times do |i|
+ dates[i] = get_times(range[:steps],range[:offset],i,range[:in])
+ end
- dates = []
+ keys = []
labels = []
range[:steps].times do |i|
- labels[i] = label(range[:steps],range[:offset],i,range[:in])
- dates[i] = times_ago(range[:steps],range[:offset],i+1,range[:in])
+ keys[i] = dates[i][0].strftime("%Y%m%d")
+ labels[i] = get_label(dates[i][0], dates[i][1], range[:in])
end
- diff = from.strftime(strftime_i).to_i + from.strftime('%Y').to_i
- sql = ActiveRecord::Base.format_date(range[:in], column, diff)
+ sql = ActiveRecord::Base.format_date(range[:in], column)
- [from, to, labels, range[:steps], sql, dates]
+ {
+ :date_from => dates[0][0].to_date,
+ :date_to => dates[dates.size-1][1].to_date,
+ :labels => labels,
+ :keys => keys,
+ :dates => dates,
+ :steps => range[:steps],
+ :sql => sql
+ }
end
- def self.label(steps, offset, i, type)
- time = times_ago(steps,offset,i,type)
+ private
+ def self.get_label(from, to, type)
if type == :months
- return time.strftime("%b %y")
+ return from.strftime("%b %y")
elsif type == :days
- return time.strftime("%d %b %y")
+ return from.strftime("%d %b %y")
else
- year = time.strftime("%y")
- month = time.strftime("%b")
- day = time.strftime("%d").to_i
-
- time2 = times_ago(steps,offset,i+1,type)
-
- year2 = time2.strftime("%y")
- month2 = time2.strftime("%b")
- day2 = time2.strftime("%d").to_i - 1
-
- if year2 != year
- return "#{day} #{month} #{year} - #{day2} #{month2} #{year2}"
- elsif month2 != month
- return "#{day} #{month} - #{day2} #{month2} #{year}"
+ year_from = from.strftime("%y")
+ month_from = from.strftime("%b")
+ day_from = from.strftime("%d").to_i
+
+ year_to = to.strftime("%y")
+ month_to = to.strftime("%b")
+ day_to = to.strftime("%d").to_i # - 1
+
+ if year_from != year_to
+ return "#{day_from} #{month_from} #{year_from} - #{day_to} #{month_to} #{year_to}"
+ elsif month_from != month_to
+ return "#{day_from} #{month_from} - #{day_to} #{month_to} #{year_from}"
else
- return "#{day} - #{day2} #{month} #{year}"
+ return "#{day_from} - #{day_to} #{month_from} #{year_from}"
end
end
end
- def self.times_ago(steps, offset, i, type)
- ((steps*offset)-i-1).send(type).ago
+ def self.get_times(steps, offset, i, type)
+ if type == :months
+ time = ((steps*offset)-i-1).send(type).ago
+ [
+ Time.mktime(time.year, time.month, 1, 0, 0, 0),
+ Time.mktime(time.year, time.month, get_days_in_month(time.year, time.month), 23, 59, 59)
+ ]
+ elsif type == :days
+ time = ((steps*offset)-i-1).send(type).ago
+ [
+ Time.mktime(time.year, time.month, time.day, 0, 0, 0),
+ Time.mktime(time.year, time.month, time.day, 23, 59, 59)
+ ]
+ else
+ time = ((steps*offset)-i-1).send(type).ago
+ day_of_week = time.strftime('%w').to_i - 1
+ day_of_week = 7 if day_of_week < 0
+ time -= day_of_week.days
+ time2 = time + 6.days
+ [
+ Time.mktime(time.year, time.month, time.day, 0, 0, 0),
+ Time.mktime(time2.year, time2.month, time2.day, 23, 59, 59)
+ ]
+ end
end
+ def self.get_days_in_month(year, month)
+ if month == 2 and ((year % 4 == 0 and year % 100 != 0) or (year % 400 == 0))
+ 29
+ else
+ [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month - 1]
+ end
+ end
+
end
end
View
24 lib/redmine_charts/stack_data_converter.rb
@@ -3,7 +3,7 @@ module StackDataConverter
include GLoc
- def self.convert(chart, sets, labels)
+ def self.convert(chart, data)
tooltip = OpenFlashChart::Tooltip.new
tooltip.set_hover()
@@ -15,7 +15,7 @@ def self.convert(chart, sets, labels)
keys = []
values = []
- sets.each_with_index do |set,i|
+ data[:sets].each_with_index do |set,i|
set[1].each_with_index do |v,j|
values[j] ||= []
values[j][i] = if v.is_a? Array
@@ -34,16 +34,18 @@ def self.convert(chart, sets, labels)
bar.values = values
bar.set_keys(keys)
- shape = OpenFlashChart::Shape.new(RedmineCharts::Utils.color(values.size))
- shape.values = [
- OpenFlashChart::ShapePoint.new(-0.45, 100),
- OpenFlashChart::ShapePoint.new(-0.55 + values.size, 100),
- OpenFlashChart::ShapePoint.new(-0.55 + values.size, 101),
- OpenFlashChart::ShapePoint.new(-0.45, 101),
- ]
-
chart.add_element(bar)
- chart.add_element(shape)
+
+ if data[:horizontal_line]
+ shape = OpenFlashChart::Shape.new(RedmineCharts::Utils.color(values.size))
+ shape.values = [
+ OpenFlashChart::ShapePoint.new(-0.45, data[:horizontal_line]),
+ OpenFlashChart::ShapePoint.new(-0.55 + values.size, data[:horizontal_line]),
+ OpenFlashChart::ShapePoint.new(-0.55 + values.size, data[:horizontal_line] + 1),
+ OpenFlashChart::ShapePoint.new(-0.45, data[:horizontal_line] + 1),
+ ]
+ chart.add_element(shape)
+ end
end
end
View
2  lib/redmine_charts/utils.rb
@@ -1,7 +1,7 @@
module RedmineCharts
module Utils
- @@colors = ['#80C31C', '#FF7900', '#00477F', '#DFC329', '#37414A', '#6363AC', '#4C88BE', '#5E4725', "#d01f3c", "#356aa0", "#C79810"]
+ @@colors = ['#80C31C', '#FF7900', '#6363AC', '#37414A', '#DFC329', '#00477F', '#d01f3c', '#356aa0', '#C79810', '#4C88BE', '#5E4725']
@@controllers = %w{burndown ratio timeline deviation}.collect { |name| [name.to_sym, "charts_#{name}".to_sym] }
Please sign in to comment.
Something went wrong with that request. Please try again.