summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorChris Schlaeger <chris@linux.com>2014-08-28 20:23:38 +0200
committerChris Schlaeger <chris@linux.com>2014-08-28 20:23:38 +0200
commit3c32e378c9ffc01c1ed994483571193127a4e6a4 (patch)
treeaaf4d47e8162ca971dfb3e6d9b546f8ccc8f643b /lib
parenta0e09bf3c5d9f78961239cc262d12c1af8d4cff4 (diff)
downloadpostrunner-3c32e378c9ffc01c1ed994483571193127a4e6a4.zip
Adding support for metric and statute units.
Diffstat (limited to 'lib')
-rw-r--r--lib/postrunner/ActivitiesDB.rb12
-rw-r--r--lib/postrunner/Activity.rb10
-rw-r--r--lib/postrunner/ActivityListView.rb27
-rw-r--r--lib/postrunner/ActivitySummary.rb (renamed from lib/postrunner/ActivityReport.rb)73
-rw-r--r--lib/postrunner/ActivityView.rb10
-rw-r--r--lib/postrunner/ChartView.rb57
-rw-r--r--lib/postrunner/Main.rb16
-rw-r--r--lib/postrunner/RuntimeConfig.rb7
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.