require 'postrunner/ViewWidgets' module PostRunner class ChartView include ViewWidgets def initialize(activity) @activity = activity end def head(doc) [ 'jquery/jquery-2.1.1.min.js', 'flot/jquery.flot.js', 'flot/jquery.flot.time.js' ].each do |js| doc.script({ 'language' => 'javascript', 'type' => 'text/javascript', 'src' => js }) end doc.style(style) doc.script(java_script) end def div(doc) chart_div(doc, 'pace', 'Pace (min/km)') chart_div(doc, 'altitude', 'Elevation (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, 'stance_time', 'Ground Contact Time (ms)') end private def style < 20.0 value = nil else value = (value * 3600.0 * 1000).to_i end end s << "[ #{((r.timestamp.to_i - start_time) * 1000).to_i}, " + "#{value ? value : 'null'} ]" end s << <<"EOT" ]; $.plot("##{field}_chart", [ { data: #{field}_data, #{color ? "color: \"#{color}\"," : ''} lines: { show: true#{field == 'pace' ? '' : ', fill: true'} } } ], { xaxis: { mode: "time" } EOT if field == 'pace' s << ", yaxis: { mode: \"time\",\n" + " transform: function (v) { return -v; },\n" + " inverseTransform: function (v) { return -v; } }" end s << "});\n" end def point_graph(field, colors, multiplier = 1) # 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. # Initialize the data sets. The key for data_sets is the corresponding # index in colors. data_sets = {} colors.each.with_index { |cp, i| data_sets[i] = [] } # Now we can split the field values into the sets. 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)) value *= multiplier # Find the right set by looking at the maximum allowed values for each # color. colors.each.with_index do |col_max_value, i| col, max_value = col_max_value if max_value.nil? || value < max_value # A max_value of nil means all values allowed. The value is in the # 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 ] # Abort the color loop since we've found the right set already. break end end end # Now generate the JS variable definitions for each set. s = '' data_sets.each do |index, ds| s << "var #{field}_data_#{index} = [\n" s << ds.map { |dp| "[ #{dp[0]}, #{dp[1]} ]" }.join(', ') s << " ];\n" end s << "$.plot(\"##{field}_chart\", [\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 end def chart_div(doc, field, title) frame(doc, title) { doc.div({ 'id' => "#{field}_chart", 'class' => 'chart-placeholder'}) } end end end