diff options
-rw-r--r-- | README.md | 25 | ||||
-rw-r--r-- | lib/postrunner/ChartView.rb | 77 |
2 files changed, 84 insertions, 18 deletions
@@ -1,10 +1,13 @@ # PostRunner -PostRunner is an application to manage FIT files such as those produced by Garmin products like the Forerunner 620. It allows you to import the files from the device and inspect them. +PostRunner is an application to manage FIT files such as those +produced by Garmin products like the Forerunner 620 (FR620). It allows you to +import the files from the device and inspect them. ## Installation -PostRunner is a Ruby application. You need to have a Ruby 2.0 or later runtime environment installed. +PostRunner is a [http://www.ruby-lang.org](Ruby) application. You need +to have a Ruby 2.0 or later runtime environment installed. ``` $ gem install postrunner @@ -14,13 +17,20 @@ $ gem install postrunner ### Importing FIT files -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. +To get started you need to connect your device to your computer and +mount it as a disk 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/ ``` -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. +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. ### Viewing FIT file data on the console @@ -57,13 +67,16 @@ You can also get a full dump of the content of a FIT file. $ postrunner dump 1234568.FIT ``` -If the file is already in the data base you can also use the reference notation. +If the file is already in the data base you can also use the reference +notation. ``` $ 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. +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. ### Viewing FIT file data in your web browser diff --git a/lib/postrunner/ChartView.rb b/lib/postrunner/ChartView.rb index 5a68f0b..c0aac30 100644 --- a/lib/postrunner/ChartView.rb +++ b/lib/postrunner/ChartView.rb @@ -91,22 +91,23 @@ EOT def java_script s = "$(function() {\n" - 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', + s << tooltip_div + s << line_graph('pace', 'Pace', 'min/km', '#0A7BEE' ) + s << line_graph('altitude', 'Elevation', 'm', '#5AAA44') + s << line_graph('heart_rate', 'Heart Rate', 'bpm', '#900000') + s << point_graph('run_cadence', 'Run Cadence', 'spm', [ [ '#EE3F2D', 151 ], [ '#F79666', 163 ], [ '#A0D488', 174 ], [ '#96D7DE', 185 ], [ '#A88BBB', nil ] ]) - s << point_graph('vertical_oscillation', 'cm', + s << point_graph('vertical_oscillation', 'Vertical Oscillation', 'cm', [ [ '#A88BBB', 67 ], [ '#96D7DE', 84 ], [ '#A0D488', 101 ], [ '#F79666', 118 ], [ '#EE3F2D', nil ] ]) - s << point_graph('stance_time', 'ms', + s << point_graph('stance_time', 'Ground Contact Time', 'ms', [ [ '#A88BBB', 208 ], [ '#96D7DE', 241 ], [ '#A0D488', 273 ], @@ -118,7 +119,35 @@ EOT s end - def line_graph(field, unit, color = nil) + def tooltip_div + <<"EOT" + function timeToHMS(usecs) { + var secs = parseInt(usecs / 1000.0); + var s = secs % 60; + var mins = parseInt(secs / 60); + var m = mins % 60; + var h = parseInt(mins / 60); + s = (s < 10) ? "0" + s : s; + if (h == 0) { + return ("" + m + ":" + s); + } else { + m = (m < 10) ? "0" + m : m; + return ("" + h + ":" + m + ":" + s); + } + }; + $("<div id='tooltip'></div>").css({ + position: "absolute", + display: "none", + border: "1px solid #888", + padding: "2px", + "background-color": "#EEE", + opacity: 0.90, + "font-size": "8pt" + }).appendTo("body"); +EOT + end + + def line_graph(field, y_label, unit, color = nil) s = "var #{field}_data = [\n" data_set = [] @@ -144,15 +173,17 @@ EOT "[ #{set[0]}, #{set[1] ? set[1] : 'null'} ]" end.join(', ') + chart_id = "#{field}_chart" s << <<"EOT" ]; - $.plot("##{field}_chart", + $.plot(\"##{chart_id}\", [ { data: #{field}_data, #{color ? "color: \"#{color}\"," : ''} lines: { show: true#{field == 'pace' ? '' : ', fill: true'} } } ], - { xaxis: { mode: "time" } + { xaxis: { mode: "time" }, + grid: { hoverable: true } EOT if field == 'pace' s << ", yaxis: { mode: \"time\",\n" + @@ -160,9 +191,10 @@ EOT " inverseTransform: function (v) { return -v; } }" end s << "});\n" + s << hover_function(chart_id, y_label, unit) + "\n" end - def point_graph(field, unit, colors) + def point_graph(field, y_label, 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. @@ -207,14 +239,17 @@ EOT s << " ];\n" end - s << "$.plot(\"##{field}_chart\", [\n" + chart_id = "#{field}_chart" + s << "$.plot(\"##{chart_id}\", [\n" s << data_sets.map do |index, ds| "{ data: #{field}_data_#{index},\n" + " color: \"#{colors[index][0]}\",\n" + " points: { show: true, fillColor: \"#{colors[index][0]}\", " + " fill: true, radius: 2 } }" end.join(', ') - s << "], { xaxis: { mode: \"time\" } });\n" + s << "], { xaxis: { mode: \"time\" }, + grid: { hoverable: true } });\n" + s << hover_function(chart_id, y_label, unit) s end @@ -228,6 +263,24 @@ EOT } end + def hover_function(chart_id, y_label, y_unit) + <<"EOT" + $("##{chart_id}").bind("plothover", function (event, pos, item) { + if (item) { + var x = timeToHMS(item.datapoint[0]); + var y = #{y_label == 'Pace' ? 'timeToHMS(item.datapoint[1] / 60)' : + 'item.datapoint[1].toFixed(0)'}; + $("#tooltip").html("<b>#{y_label}:</b> " + y + " #{y_unit}<br/>" + + "<b>Time:</b> " + x + " h:m:s") + .css({top: item.pageY-20, left: item.pageX+15}) + .fadeIn(200); + } else { + $("#tooltip").hide(); + } + }); +EOT + end + end end |