diff options
author | Chris Schlaeger <chris@linux.com> | 2014-08-28 20:23:38 +0200 |
---|---|---|
committer | Chris Schlaeger <chris@linux.com> | 2014-08-28 20:23:38 +0200 |
commit | 3c32e378c9ffc01c1ed994483571193127a4e6a4 (patch) | |
tree | aaf4d47e8162ca971dfb3e6d9b546f8ccc8f643b /lib | |
parent | a0e09bf3c5d9f78961239cc262d12c1af8d4cff4 (diff) | |
download | postrunner-3c32e378c9ffc01c1ed994483571193127a4e6a4.zip |
Adding support for metric and statute units.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/postrunner/ActivitiesDB.rb | 12 | ||||
-rw-r--r-- | lib/postrunner/Activity.rb | 10 | ||||
-rw-r--r-- | lib/postrunner/ActivityListView.rb | 27 | ||||
-rw-r--r-- | lib/postrunner/ActivitySummary.rb (renamed from lib/postrunner/ActivityReport.rb) | 73 | ||||
-rw-r--r-- | lib/postrunner/ActivityView.rb | 10 | ||||
-rw-r--r-- | lib/postrunner/ChartView.rb | 57 | ||||
-rw-r--r-- | lib/postrunner/Main.rb | 16 | ||||
-rw-r--r-- | lib/postrunner/RuntimeConfig.rb | 7 |
8 files changed, 155 insertions, 57 deletions
diff --git a/lib/postrunner/ActivitiesDB.rb b/lib/postrunner/ActivitiesDB.rb index 0e21e65..81f039a 100644 --- a/lib/postrunner/ActivitiesDB.rb +++ b/lib/postrunner/ActivitiesDB.rb @@ -248,6 +248,18 @@ module PostRunner end end + # This method can be called to re-generate all HTML reports and all HTML + # index files. + def generate_all_html_reports + Log.info "Re-generating all HTML report files..." + # Generate HTML views for all activities in the DB. + @activities.each { |a| a.generate_html_view } + Log.info "All HTML report files have been re-generated." + # (Re-)generate index files. + ActivityListView.new(self).update_html_index + Log.info "HTML index files have been updated." + end + private def sync diff --git a/lib/postrunner/Activity.rb b/lib/postrunner/Activity.rb index 70ab1ca..de4396b 100644 --- a/lib/postrunner/Activity.rb +++ b/lib/postrunner/Activity.rb @@ -12,7 +12,7 @@ require 'fit4ruby' -require 'postrunner/ActivityReport' +require 'postrunner/ActivitySummary' require 'postrunner/ActivityView' module PostRunner @@ -48,8 +48,7 @@ module PostRunner end def check - # Re-generate the HTML file for this activity - generate_html_view + @fit_activity = load_fit_file Log.info "FIT file #{@fit_file} is OK" end @@ -88,7 +87,7 @@ module PostRunner def summary @fit_activity = load_fit_file unless @fit_activity - puts ActivityReport.new(self).to_s + puts ActivitySummary.new(@fit_activity, name, @db.cfg[:unit_system]).to_s end def rename(name) @@ -110,7 +109,8 @@ module PostRunner def generate_html_view @fit_activity = load_fit_file unless @fit_activity - ActivityView.new(self, @db.predecessor(self), @db.successor(self)) + ActivityView.new(self, @db.cfg[:unit_system], @db.predecessor(self), + @db.successor(self)) end private diff --git a/lib/postrunner/ActivityListView.rb b/lib/postrunner/ActivityListView.rb index 5a37c26..61275da 100644 --- a/lib/postrunner/ActivityListView.rb +++ b/lib/postrunner/ActivityListView.rb @@ -42,6 +42,7 @@ module PostRunner def initialize(db) @db = db + @unit_system = @db.cfg[:unit_system] @page_size = 20 @page_no = -1 @last_page = (@db.activities.length - 1) / @page_size @@ -130,7 +131,7 @@ EOT end def generate_table - i = @page_no * @page_size + i = @page_no < 0 ? 0 : @page_no * @page_size t = FlexiTable.new t.head t.row(%w( Ref. Activity Start Distance Duration Pace ), @@ -151,9 +152,10 @@ EOT i += 1, ActivityLink.new(a), a.timestamp.strftime("%a, %Y %b %d %H:%M"), - "%.2f" % (a.total_distance / 1000), + local_value(a.total_distance, 'm', '%.2f', + { :metric => 'km', :statute => 'mi' }), secsToHMS(a.total_timer_time), - speedToPace(a.avg_speed) ]) + pace(a.avg_speed) ]) end t @@ -168,6 +170,25 @@ EOT Log.fatal "Cannot write activity index file '#{output_file}: #{$!}" end end + + def local_value(value, from_unit, format, units) + to_unit = units[@unit_system] + return '-' unless value + value *= conversion_factor(from_unit, to_unit) + "#{format % [value, to_unit]}" + end + + def pace(speed) + case @unit_system + when :metric + "#{speedToPace(speed)}" + when :statute + "#{speedToPace(speed, 1609.34)}" + else + Log.fatal "Unknown unit system #{@unit_system}" + end + end + end end diff --git a/lib/postrunner/ActivityReport.rb b/lib/postrunner/ActivitySummary.rb index f15ed91..c1f5771 100644 --- a/lib/postrunner/ActivityReport.rb +++ b/lib/postrunner/ActivitySummary.rb @@ -1,7 +1,7 @@ #!/usr/bin/env ruby -w # encoding: UTF-8 # -# = ActivityReport.rb -- PostRunner - Manage the data from your Garmin sport devices. +# = ActivitySummary.rb -- PostRunner - Manage the data from your Garmin sport devices. # # Copyright (c) 2014 by Chris Schlaeger <cs@taskjuggler.org> # @@ -17,25 +17,27 @@ require 'postrunner/ViewWidgets' module PostRunner - class ActivityReport + class ActivitySummary include Fit4Ruby::Converters include ViewWidgets - def initialize(activity) - @activity = activity + def initialize(fit_activity, name, unit_system) + @fit_activity = fit_activity + @name = name + @unit_system = unit_system end def to_s - session = @activity.fit_activity.sessions[0] + session = @fit_activity.sessions[0] summary(session).to_s + "\n" + laps.to_s end def to_html(doc) - session = @activity.fit_activity.sessions[0] + session = @fit_activity.sessions[0] - frame(doc, "Activity: #{@activity.name}") { + frame(doc, "Activity: #{@name}") { summary(session).to_html(doc) } frame(doc, 'Laps') { @@ -50,12 +52,17 @@ module PostRunner t.enable_frame(false) t.body t.row([ 'Date:', session.timestamp]) - t.row([ 'Distance:', "#{'%.2f' % (session.total_distance / 1000.0)} km" ]) + t.row([ 'Distance:', + local_value(session, 'total_distance', '%.2f %s', + { :metric => 'km', :statute => 'mi'}) ]) t.row([ 'Time:', secsToHMS(session.total_timer_time) ]) - t.row([ 'Avg. Pace:', - "#{speedToPace(session.avg_speed)} min/km" ]) - t.row([ 'Total Ascend:', "#{session.total_ascend} m" ]) - t.row([ 'Total Descend:', "#{session.total_descent} m" ]) + t.row([ 'Avg. Pace:', pace(session, 'avg_speed') ]) + t.row([ 'Total Ascent:', + local_value(session, 'total_ascent', '%.0f %s', + { :metric => 'm', :statute => 'ft' }) ]) + t.row([ 'Total Descent:', + local_value(session, 'total_descent', '%.0f %s', + { :metric => 'm', :statute => 'ft' }) ]) t.row([ 'Calories:', "#{session.total_calories} kCal" ]) t.row([ 'Avg. HR:', session.avg_heart_rate ? "#{session.avg_heart_rate} bpm" : '-' ]) @@ -67,17 +74,17 @@ module PostRunner session.avg_running_cadence ? "#{session.avg_running_cadence.round} spm" : '-' ]) t.row([ 'Avg. Vertical Oscillation:', - session.avg_vertical_oscillation ? - "#{'%.1f' % (session.avg_vertical_oscillation / 10)} cm" : '-' ]) + local_value(session, 'avg_vertical_oscillation', '%.1f %s', + { :metric => 'cm', :statute => 'in' }) ]) t.row([ 'Avg. Ground Contact Time:', session.avg_stance_time ? "#{session.avg_stance_time.round} ms" : '-' ]) t.row([ 'Avg. Stride Length:', - session.avg_stride_length ? - "#{'%.2f' % (session.avg_stride_length / 2)} m" : '-' ]) - rec_time = @activity.fit_activity.recovery_time + local_value(session, 'avg_stride_length', '%.2f %s', + { :metric => 'm', :statute => 'ft' }) ]) + rec_time = @fit_activity.recovery_time t.row([ 'Recovery Time:', rec_time ? secsToHMS(rec_time * 60) : '-' ]) - vo2max = @activity.fit_activity.vo2max + vo2max = @fit_activity.vo2max t.row([ 'VO2max:', vo2max ? vo2max : '-' ]) t @@ -90,13 +97,14 @@ module PostRunner 'Avg. HR', 'Max. HR' ]) t.set_column_attributes(Array.new(8, { :halign => :right })) t.body - @activity.fit_activity.sessions[0].laps.each.with_index do |lap, index| + @fit_activity.sessions[0].laps.each.with_index do |lap, index| t.cell(index + 1) t.cell(secsToHMS(lap.total_timer_time)) - t.cell('%.2f' % (lap.total_distance / 1000.0)) - t.cell(speedToPace(lap.avg_speed)) - t.cell(lap.total_strides ? - '%.2f' % (lap.total_distance / (2 * lap.total_strides)) : '') + t.cell(local_value(lap, 'total_distance', '%.2f', + { :metric => 'km', :statute => 'mi' })) + t.cell(pace(lap, 'avg_speed', false)) + t.cell(local_value(lap, 'avg_stride_length', '%.2f', + { :metric => 'm', :statute => 'ft' })) t.cell(lap.avg_running_cadence && lap.avg_fractional_cadence ? '%.1f' % (2 * lap.avg_running_cadence + (2 * lap.avg_fractional_cadence) / 100.0) : '') @@ -108,6 +116,25 @@ module PostRunner t end + def local_value(fdr, field, format, units) + unit = units[@unit_system] + value = fdr.get_as(field, unit) + return '-' unless value + "#{format % [value, unit]}" + end + + def pace(fdr, field, show_unit = true) + speed = fdr.get(field) + case @unit_system + when :metric + "#{speedToPace(speed)}#{show_unit ? ' min/km' : ''}" + when :statute + "#{speedToPace(speed, 1609.34)}#{show_unit ? ' min/mi' : ''}" + else + Log.fatal "Unknown unit system #{@unit_system}" + end + end + end end diff --git a/lib/postrunner/ActivityView.rb b/lib/postrunner/ActivityView.rb index 7cfe3fb..bde8d42 100644 --- a/lib/postrunner/ActivityView.rb +++ b/lib/postrunner/ActivityView.rb @@ -13,7 +13,7 @@ require 'fit4ruby' require 'postrunner/HTMLBuilder' -require 'postrunner/ActivityReport' +require 'postrunner/ActivitySummary' require 'postrunner/ViewWidgets' require 'postrunner/TrackView' require 'postrunner/ChartView' @@ -24,8 +24,9 @@ module PostRunner include ViewWidgets - def initialize(activity, predecessor, successor) + def initialize(activity, unit_system, predecessor, successor) @activity = activity + @unit_system = unit_system @predecessor = predecessor @successor = successor @output_dir = activity.html_dir @@ -39,9 +40,10 @@ module PostRunner private def generate_html(doc) - @report = ActivityReport.new(@activity) + @report = ActivitySummary.new(@activity.fit_activity, @activity.name, + @unit_system) @track_view = TrackView.new(@activity) - @chart_view = ChartView.new(@activity) + @chart_view = ChartView.new(@activity, @unit_system) doc.html { head(doc) diff --git a/lib/postrunner/ChartView.rb b/lib/postrunner/ChartView.rb index 3265aa1..5a68f0b 100644 --- a/lib/postrunner/ChartView.rb +++ b/lib/postrunner/ChartView.rb @@ -18,8 +18,9 @@ module PostRunner include ViewWidgets - def initialize(activity) + def initialize(activity, unit_system) @activity = activity + @unit_system = unit_system @empty_charts = {} end @@ -34,16 +35,29 @@ module PostRunner end def div(doc) - chart_div(doc, 'pace', 'Pace (min/km)') - chart_div(doc, 'altitude', 'Elevation (m)') + chart_div(doc, 'pace', "Pace (#{select_unit('min/km')})") + chart_div(doc, 'altitude', "Elevation (#{select_unit('m')})") chart_div(doc, 'heart_rate', 'Heart Rate (bpm)') - chart_div(doc, 'cadence', 'Run Cadence (spm)') - chart_div(doc, 'vertical_oscillation', 'Vertical Oscillation (cm)') + chart_div(doc, 'run_cadence', 'Run Cadence (spm)') + chart_div(doc, 'vertical_oscillation', + "Vertical Oscillation (#{select_unit('cm')})") chart_div(doc, 'stance_time', 'Ground Contact Time (ms)') end private + def select_unit(metric_unit) + case @unit_system + when :metric + metric_unit + when :statute + { 'min/km' => 'min/mi', 'm' => 'ft', 'cm' => 'in', + 'bpm' => 'bpm', 'spm' => 'spm', 'ms' => 'ms' }[metric_unit] + else + Log.fatal "Unknown unit system #{@unit_system}" + end + end + def style <<EOT .chart-container { @@ -77,22 +91,22 @@ EOT def java_script s = "$(function() {\n" - s << line_graph('pace', '#0A7BEE' ) - s << line_graph('altitude', '#5AAA44') - s << line_graph('heart_rate', '#900000') - s << point_graph('cadence', + s << line_graph('pace', 'min/km', '#0A7BEE' ) + s << line_graph('altitude', 'm', '#5AAA44') + s << line_graph('heart_rate', 'bpm', '#900000') + s << point_graph('run_cadence', 'spm', [ [ '#EE3F2D', 151 ], [ '#F79666', 163 ], [ '#A0D488', 174 ], [ '#96D7DE', 185 ], - [ '#A88BBB', nil ] ], 2) - s << point_graph('vertical_oscillation', - [ [ '#A88BBB', 6.7 ], - [ '#96D7DE', 8.4 ], - [ '#A0D488', 10.1 ], - [ '#F79666', 11.8 ], - [ '#EE3F2D', nil ] ], 0.1) - s << point_graph('stance_time', + [ '#A88BBB', nil ] ]) + s << point_graph('vertical_oscillation', 'cm', + [ [ '#A88BBB', 67 ], + [ '#96D7DE', 84 ], + [ '#A0D488', 101 ], + [ '#F79666', 118 ], + [ '#EE3F2D', nil ] ]) + s << point_graph('stance_time', 'ms', [ [ '#A88BBB', 208 ], [ '#96D7DE', 241 ], [ '#A0D488', 273 ], @@ -104,13 +118,13 @@ EOT s end - def line_graph(field, color = nil) + def line_graph(field, unit, color = nil) s = "var #{field}_data = [\n" data_set = [] start_time = @activity.fit_activity.sessions[0].start_time.to_i @activity.fit_activity.records.each do |r| - value = r.send(field) + value = r.get_as(field, select_unit(unit)) if field == 'pace' if value > 20.0 value = nil @@ -148,7 +162,7 @@ EOT s << "});\n" end - def point_graph(field, colors, multiplier = 1) + def point_graph(field, unit, colors) # We need to split the field values into separate data sets for each # color. The max value for each color determines which set a data point # ends up in. @@ -162,7 +176,6 @@ EOT @activity.fit_activity.records.each do |r| # Undefined values will be discarded. next unless (value = r.send(field)) - value *= multiplier # Find the right set by looking at the maximum allowed values for each # color. @@ -173,7 +186,7 @@ EOT # allowed range for this set, so add the value as x/y pair to the # set. x_val = (r.timestamp.to_i - start_time) * 1000 - data_sets[i] << [ x_val, value ] + data_sets[i] << [ x_val, r.get_as(field, select_unit(unit)) ] # Abort the color loop since we've found the right set already. break end diff --git a/lib/postrunner/Main.rb b/lib/postrunner/Main.rb index a2e6d11..25d9cd0 100644 --- a/lib/postrunner/Main.rb +++ b/lib/postrunner/Main.rb @@ -144,6 +144,9 @@ show [ <ref> ] summary <ref> Display the summary information for the FIT file. +units metric | statute + Change the unit system. + <fit file> An absolute or relative name of a .FIT file. @@ -200,6 +203,8 @@ EOT end when 'summary' process_activities(args, :summary) + when 'units' + change_unit_system(args) when nil Log.fatal("No command provided. " + "See 'postrunner -h' for more information.") @@ -292,6 +297,17 @@ EOT end end + def change_unit_system(args) + if args.length != 1 || !%w( metric statute ).include?(args[0]) + Log.fatal("You must specify 'metric' or 'statute' as unit system.") + end + + if @cfg[:unit_system].to_s != args[0] + @cfg.set_option(:unit_system, args[0].to_sym) + @activities.generate_all_html_reports + end + end + end end diff --git a/lib/postrunner/RuntimeConfig.rb b/lib/postrunner/RuntimeConfig.rb index 0cc3e05..2bb9cb0 100644 --- a/lib/postrunner/RuntimeConfig.rb +++ b/lib/postrunner/RuntimeConfig.rb @@ -31,6 +31,13 @@ module PostRunner load_options if File.exist?(@config_file) end + # Shortcut for get_option. + # @param name [Symbol] the name of the config option. + # @return [Object] the value of the config option. + def [](name) + get_option(name) + end + # Get a config option value. # @param name [Symbol] the name of the config option. # @return [Object] the value of the config option. |