diff options
-rw-r--r-- | README.md | 51 | ||||
-rw-r--r-- | lib/postrunner/ActivityView.rb | 24 | ||||
-rw-r--r-- | lib/postrunner/ChartView.rb | 34 | ||||
-rw-r--r-- | lib/postrunner/TrackView.rb | 19 |
4 files changed, 82 insertions, 46 deletions
@@ -6,35 +6,66 @@ PostRunner is an application to manage FIT files such as those produced by Garmi PostRunner is a Ruby application. You need to have a Ruby 2.0 or later runtime environment installed. - $ gem install postrunner +``` +$ gem install postrunner +``` ## Usage To get started you need to connect your device to your computer and mount it as a drive. Only devices that expose their data as FAT file system are supported. Older devices use proprietary drivers and are not supported by postrunner. Once the device is mounted find out the full path to the directory that contains your FIT files. You can then import all files on the device. - $ postrunner import /var/run/media/user/GARMIN/GARMIN/ACTIVITY/ +``` +$ postrunner import /var/run/media/user/GARMIN/GARMIN/ACTIVITY/ +``` The above command assumes that your device is mounted as /var/run/media/user. Please replace this with the path to your device. Files that have been imported previously will not be imported again. Now you can list all the FIT files in your data base. - $ postrunner list +``` +$ postrunner list +``` -The first column is the index you can use to reference FIT files. To get a summary of the most recent activity use the following command. +The first column is the index you can use to reference FIT files. To +get a summary of the most recent activity use the following command. +References to already imported activities start with a colon followed +by the index number. + +``` +$ postrunner summary :1 +``` + +Or you can view the full details of your activity in your browser. +This view includes a map (internet connection for map data required) +and charts. + +``` +$ postrunner show :1 +``` - $ postrunner summary :1 - To get a summary of the oldest activity you can use - $ postrunner summary :-1 - +``` +$ postrunner summary :-1 +``` + +To select multiple activities you can use a range. + +``` +$ postrunner summary :1-3 +``` + You can also get a full dump of the content of a FIT file. - $ postrunner dump 1234568.FIT +``` +$ postrunner dump 1234568.FIT +``` If the file is already in the data base you can also use the reference notation. - $ postrunner dump :1 +``` +$ postrunner dump :1 +``` This will provide you with a lot more information contained in the FIT files that is not available through Garmin Connect or most other tools. diff --git a/lib/postrunner/ActivityView.rb b/lib/postrunner/ActivityView.rb index 5d34ca0..ecb069c 100644 --- a/lib/postrunner/ActivityView.rb +++ b/lib/postrunner/ActivityView.rb @@ -104,24 +104,6 @@ module PostRunner float: right; width: 600px; } -.widget_container { - box-sizing: border-box; - width: 600px; - padding: 10px 15px 15px 15px; - margin: 15px auto 15px auto; - border: 1px solid #ddd; - background: #fff; - background: linear-gradient(#f6f6f6 0, #fff 50px); - background: -o-linear-gradient(#f6f6f6 0, #fff 50px); - background: -ms-linear-gradient(#f6f6f6 0, #fff 50px); - background: -moz-linear-gradient(#f6f6f6 0, #fff 50px); - background: -webkit-linear-gradient(#f6f6f6 0, #fff 50px); - box-shadow: 0 3px 10px rgba(0,0,0,0.15); - -o-box-shadow: 0 3px 10px rgba(0,0,0,0.1); - -ms-box-shadow: 0 3px 10px rgba(0,0,0,0.1); - -moz-box-shadow: 0 3px 10px rgba(0,0,0,0.1); - -webkit-box-shadow: 0 3px 10px rgba(0,0,0,0.1); -} EOT ) end @@ -150,7 +132,11 @@ EOT end def show_in_browser - system("firefox \"#{@output_file}\" &") + cmd = "#{ENV['BROWSER'] || 'firefox'} \"#{@output_file}\" &" + unless system(cmd) + Log.fatal "Failed to execute the following shell command: #{$cmd}\n" + + "#{$!}" + end end end diff --git a/lib/postrunner/ChartView.rb b/lib/postrunner/ChartView.rb index 1ccdc2d..9ec86bd 100644 --- a/lib/postrunner/ChartView.rb +++ b/lib/postrunner/ChartView.rb @@ -8,6 +8,7 @@ module PostRunner def initialize(activity) @activity = activity + @empty_charts = {} end def head(doc) @@ -94,14 +95,9 @@ EOT def line_graph(field, color = nil) s = "var #{field}_data = [\n" - first = true + data_set = [] start_time = @activity.fit_activity.sessions[0].start_time.to_i @activity.fit_activity.records.each do |r| - if first - first = false - else - s << ', ' - end value = r.send(field) if field == 'pace' if value > 20.0 @@ -110,9 +106,17 @@ EOT value = (value * 3600.0 * 1000).to_i end end - s << "[ #{((r.timestamp.to_i - start_time) * 1000).to_i}, " + - "#{value ? value : 'null'} ]" + data_set << [ ((r.timestamp.to_i - start_time) * 1000).to_i, value ] + end + + # We don't want to plot charts with all nil values. + unless data_set.find { |v| v[1] != nil } + @empty_charts[field] = true + return '' end + s << data_set.map do |set| + "[ #{set[0]}, #{set[1] ? set[1] : 'null'} ]" + end.join(', ') s << <<"EOT" ]; @@ -120,7 +124,8 @@ EOT $.plot("##{field}_chart", [ { data: #{field}_data, #{color ? "color: \"#{color}\"," : ''} - lines: { show: true#{field == 'pace' ? '' : ', fill: true'} } } ], + lines: { show: true#{field == 'pace' ? '' : + ', fill: true'} } } ], { xaxis: { mode: "time" } EOT if field == 'pace' @@ -144,7 +149,7 @@ EOT start_time = @activity.fit_activity.sessions[0].start_time.to_i @activity.fit_activity.records.each do |r| # Undefined values will be discarded. - next unless (value = r.instance_variable_get('@' + field)) + next unless (value = r.send(field)) value *= multiplier # Find the right set by looking at the maximum allowed values for each @@ -163,6 +168,12 @@ EOT end end + # We don't want to plot charts with all nil values. + if data_sets.values.flatten.empty? + @empty_charts[field] = true + return '' + end + # Now generate the JS variable definitions for each set. s = '' data_sets.each do |index, ds| @@ -184,6 +195,9 @@ EOT end def chart_div(doc, field, title) + # Don't plot frame for graph without data. + return if @empty_charts[field] + frame(doc, title) { doc.div({ 'id' => "#{field}_chart", 'class' => 'chart-placeholder'}) } diff --git a/lib/postrunner/TrackView.rb b/lib/postrunner/TrackView.rb index 50e314d..9976cd1 100644 --- a/lib/postrunner/TrackView.rb +++ b/lib/postrunner/TrackView.rb @@ -10,9 +10,13 @@ module PostRunner def initialize(activity) @activity = activity + @session = @activity.fit_activity.sessions[0] + @has_geo_data = @session.has_geo_data? end def head(doc) + return unless @has_geo_data + doc.link({ 'rel' => 'stylesheet', 'href' => 'openlayers/theme/default/style.css', 'type' => 'text/css' }) @@ -22,6 +26,8 @@ module PostRunner end def div(doc) + return unless @has_geo_data + frame(doc, 'Map') { doc.div({ 'id' => 'map', 'class' => 'trackmap' }) } @@ -52,11 +58,10 @@ function init() { var geographic = new OpenLayers.Projection("EPSG:4326"); EOT - session = @activity.fit_activity.sessions[0] - center_long = session.swc_long + - (session.nec_long - session.swc_long) / 2.0 - center_lat = session.swc_lat + - (session.nec_lat - session.swc_lat) / 2.0 + center_long = @session.swc_long + + (@session.nec_long - @session.swc_long) / 2.0 + center_lat = @session.swc_lat + + (@session.nec_lat - @session.swc_lat) / 2.0 last_lap = @activity.fit_activity.laps[-1] js << <<EOT @@ -84,8 +89,8 @@ EOT var size = new OpenLayers.Size(21,25); var offset = new OpenLayers.Pixel(-(size.w/2), -size.h); EOT - set_marker(js, 'marker-green', session.start_position_long, - session.start_position_lat) + set_marker(js, 'marker-green', @session.start_position_long, + @session.start_position_lat) @activity.fit_activity.laps[0..-2].each do |lap| set_marker(js, 'marker-blue', lap.end_position_long, lap.end_position_lat) |