Private
Public Access
1
0

Merge branch 'feature/sliders' into develop

This commit is contained in:
sanderroosendaal
2016-10-31 15:36:12 +01:00
259 changed files with 228 additions and 21281 deletions

View File

@@ -1,16 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Change Workout {% endblock %}
{% block content %}
<div class="grid_12">
<h1>Page not found</h1>
<p>
We could not find the page on our server.
</p>
</div>
{% endblock %}

View File

@@ -1,16 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Change Workout {% endblock %}
{% block content %}
<div class="grid_12">
<h1>Bad Request</h1>
<p>
HTTP Error 400 Bad Request.
</p>
</div>
{% endblock %}

View File

@@ -1,16 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Change Workout {% endblock %}
{% block content %}
<div class="grid_12">
<h1>Page not found</h1>
<p>
We could not find the page on our server.
</p>
</div>
{% endblock %}

View File

@@ -1,16 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Change Workout {% endblock %}
{% block content %}
<div class="grid_12">
<h1>Internal Server Error</h1>
<p>
The site reported an internal server error. If this behavior repeats, please inform us by using the contact form at the bottom of this page. This allows us to improve the site's behaviour.
</p>
</div>
{% endblock %}

View File

@@ -1,123 +0,0 @@
{% extends "base.html" %}
{% block title %}About us{% endblock title %}
{% block content %}
<div class="grid_6 alpha">
<h2>Introduction</h2>
<p>This is a solution for the self-tracking rowers.</p>
<p>Some of us use Concept2 rowing machines. Some of us are On-The-Water
rowers. All of us will use smartphone apps, smart watches, fitness (GPS)
watches, etc. to track our activities.</p>
<p>Most of them will cross-train. Bike. Run. Skate.</p>
<p>That means, the Concept2 logbook is not a sufficient training logbook for us.</p>
<p>At the same time, the Concept2 logbook is used in rankings, for challenges,
and more. Many of us will want to log all our rowing on the Concept2 logbook.</p>
<p>So there are a couple of challenges here:</p>
<ul>
<li><p>How do I get my erg rows on Strava/SportTracks/Garmin Connect?</p>
<blockquote>
<ul>
<li>Use an ANT+ device, like explained here: <a href="https://dr3do.wordpress.com/2015/07/09/hurray/" rel="nofollow">https://dr3do.wordpress.com/2015/07/09/hurray/</a></li>
<li>Import from RowPro to SportTracks</li>
<li>There are many smartphone apps to capture data from the PM3/4/5 erg monitor. Not many of them export in a format that is suitable for upload to the above-mentioned sites.</li>
</ul>
</blockquote>
</li>
<li><p>How do I get all my rows (including OTW) into the Concept2 logbook</p>
<blockquote>
<ul>
<li>For On-Water and Erg: Add them manually</li>
<li>For erg: Upload from ErgData, RowPro, Concept2 utility</li>
</ul>
</blockquote>
</li>
</ul>
<p>This project aims at giving you ways to:</p>
<ul>
<li><p>Upload fitness data captured in TCX format to the Concept2 logbook (implemented)</p>
<blockquote>
<ul>
<li>This should cover all your On-Water activities, whether they are captured with a SpeedCoach, a GPS fitness watch, your phone, or any other device. As long as you are able to export a valid TCX file.</li>
</ul>
</blockquote>
</li>
<li><p>Get erg data captured with apps that have no <q>upload to Concept2</q> functionality and upload them to the Concept2 logbook (implemented)</p>
<blockquote>
<ul>
<li>For example: painsled</li>
</ul>
</blockquote>
<li><p>Create useful plots. Who wants to be limited to what the on-line logbooks plot. Get your data and create:</p>
<blockquote>
<ul>
<li>Color HR band charts or Pie Charts (implemented)</li>
<li>Plot drive length, drive time, and other erg related parameters as a function of time or distance (to be implemented)</li>
</ul>
</blockquote>
</li>
</ul>
</div>
<div class="grid_6 omega">
<div class="grid_6">
<h2>Credits</h2>
<p>The project is based on python plotting code by
Greg Smith (<a href="https://quantifiedrowing.wordpress.com/" rel="nofollow">https://quantifiedrowing.wordpress.com/</a>)
and inspired by the RowPro Dan Burpee spreadsheet
(<a href="http://www.sub7irc.com/RP_Split_Template.zip" rel="nofollow">http://www.sub7irc.com/RP_Split_Template.zip</a>).</p>
</div>
<div class="grid_6">
<h2>Pro Membership</h2>
<p>Donations are welcome to keep this web site going. To help cover the hosting
costs, I have created a <q>Pro</q> membership option (for only 5 EURO per year). Once I process your
donation, I will give you access to some <q>special</q> features on this
website. </p>
<p>Currently, the Pro membership will give you the following extra functionality (and more will follow):
<ul>
<li>More stroke metrics plots</li>
<li>Power curves for OTW rowing</li>
<li>Power histogram</li>
</ul>
</p>
<p>Click on the PayPal button to pay for your Pro membership. It will be valid for one year with automatic renewal which you can stop at any time.
You will be taken to the secure PayPal payment site.
<ul>
<li>Please mention the username you are registered under in "instructions to seller".</li>
</ul>
</p>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="964GLEXX3THAW">
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_subscribeCC_LG_global.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online.">
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
</form>
<h2>What's new?</h2>
<p>
<ul>
<li>2016-09-30 Stroke Analysis Plot - with date range filtering</li>
<li>2016-09-29 Improved Flex plot, Power Histogram and Ranking Pieces - with date range filtering</li>
<li>2016-09-20 Added the Power histogram</li>
<li>2016-08-31 Added the Ranking Piece summary and pace predictor</li>
<li>2016-08-02 Added support for the SpeedCoach GPS 2 CSV/FIT file export</li>
<li>2016-07-19 Added the possibility to download wind data from <a href="http://forecast.io">The Dark Sky / Forecast.io</a></li>
<li>2016-07-19 New Flexible interactive charts for OTE and OTW (pick your own axes parameters)</li>
<li>2016-07-07 Wind and Stream corrections for OTW (Pro functionality)</li>
<li>2016-06-23 Pro users can now compare workouts</li>
<li>2016-06-20 Fixed Strava upload and added SportTracks import and export. The export is not working reliably. We are debugging this,</li>
<li>2016-06-08 Added possibility to upload CrewNerd summary CSV file for Pro Members</li>
<li>2016-06-08 Added workout summaries</li>
<li>2016-06-05 Export to Strava is working</li>
<li>2016-06-01 We're approved on the Concept2 logbook!!!!
</ul>
</p>
</div>
</div>
{% endblock content %}

View File

@@ -1,9 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% block title %}Here's your result{% endblock %}
{% block content %}
Waiting for task with result {{ task }}
{% endblock %}

View File

@@ -1,158 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Advanced Features {% endblock %}
{% block content %}
<div id="workouts" class="grid_6 alpha">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<h1>Advanced Workout Editor</h1>
{% if user.rower.rowerplan == 'basic' %}
<p>This is a preview of the page with advanced functionality for Pro users. See <a href="/rowers/promembership">the page about Pro membership</a> for more information and to sign up for Pro Membership</a>
{% endif %}
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2 suffix_2 omega">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/export">Export</a>
</p>
</div>
<div class="grid_6 alpha">
<table width=100%>
<tr>
<th>Date:</th><td>{{ workout.date }}</td>
</tr><tr>
<th>Time:</th><td>{{ workout.starttime }}</td>
</tr><tr>
<th>Distance:</th><td>{{ workout.distance }}m</td>
</tr><tr>
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
</tr>
<th>Public link to this workout</th>
<td>
<a href="/rowers/workout/{{ workout.id }}">http://rowsandall.com/rowers/workout/{{ workout.id }}</a>
<td>
</table>
</div>
<div class="grid_6 alpha">
<div class="grid_2 alpha">
{% if user.rower.rowerplan == 'pro' %}
<a class="button blue small" href="/rowers/workout/compare/{{ workout.id }}">Compare Workouts</a>
{% else %}
<a class="button blue small" href="/rowers/promembership/">Compare Workouts</a>
{% endif %}
<p>
Compare this workout to other workouts. Plot HR, SPM, or pace vs time or distance for the two workouts.
</p>
</div>
<div class="grid_2">
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/flexchart">
Flexible Interactive Plot
</a>
<p>
Flexible Interactive plot. Pick your own X and Y axis parameters.
</p>
</div>
<div class="grid_2 omega tooltip">
<p>
{% if user.rower.rowerplan == 'pro' %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/editintervals">Edit Intervals</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Edit Intervals</a>
{% endif %}
</p>
<span class="tooltiptext">Enter or change the interval and summary data for your workout</span>
<p>
Enter or change the interval and summary data for your workout
</p>
</div>
</div>
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
{% if user.rower.rowerplan == 'pro' %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/adddistanceplot2">Dist Metrics Plot</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Dist Metrics Plot</a>
{% endif %}
</p>
<p>
Various advanced stroke metrics plotted versus distance.
</p>
</div>
<div class="grid_2">
<p>
{% if user.rower.rowerplan == 'pro' %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/addtimeplot2">Time Metrics Plot</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Time Metrics Plot</a>
{% endif %}
</p>
<p>
Various advanced stroke metrics plotted versus time.
</p>
</div>
<div class="grid_2 omega">
<p>
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/interactiveplot">Big Interactive Plot</a>
</p>
<p>
See (and save) the big interactive plot
</p>
</div>
</div>
</div>
<div id="advancedplots" class="grid_6 omega">
<div class="grid_6 alpha">
<script type="text/javascript" src="/static/js/bokeh-0.11.1.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, true, true);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="interactiveplot" class="grid_6 omega">
{{ the_div |safe }}
</div>
</div>
{% endblock %}

View File

@@ -1,208 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Advanced Features {% endblock %}
{% block content %}
<div id="workouts" class="grid_6 alpha">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<h1>Advanced OTW features</h1>
{% if user.rower.rowerplan == 'basic' %}
<p>This is a preview of the page with advanced functionality for Pro users. See <a href="/rowers/promembership">the page about Pro membership</a> for more information and to sign up for Pro Membership</a>
{% endif %}
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2 suffix_2 omega">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/export">Export</a>
</p>
</div>
<div class="grid_6 alpha">
<table width=100%>
<tr>
<th>Date:</th><td>{{ workout.date }}</td>
</tr><tr>
<th>Time:</th><td>{{ workout.starttime }}</td>
</tr><tr>
<th>Distance:</th><td>{{ workout.distance }}m</td>
</tr><tr>
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
</tr>
<th>Public link to this workout</th>
<td>
<a href="/rowers/workout/{{ workout.id }}">http://rowsandall.com/rowers/workout/{{ workout.id }}</a>
<td>
</table>
</div>
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
{% if user.rower.rowerplan == 'pro' %}
<a class="button blue small" href="/rowers/workout/compare/{{ workout.id }}">Compare Workouts</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Compare Workouts</a>
{% endif %}
</p>
<p>
Compare this workout to other workouts. Plot HR, SPM, or pace vs time or distance for the two workouts.
</p>
</div>
<div class="grid_2">
<p>
{% if user.rower.rowerplan == 'pro' %}
<a class="button blue small"href="/rowers/workout/{{ workout.id }}/smoothenpace">Smooth out Pace Data</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Smooth out Pace Data</a>
{% endif %}
</p>
<p>
This will reduce noise on your pace data (EWMA average). The smoothing is irreversible
but you can use the reset smoothing button.
</p>
</div>
<div class="grid_2 omega">
<p>
{% if user.rower.rowerplan == 'pro' %}
<a class="button blue small"href="/rowers/workout/{{ workout.id }}/undosmoothenpace">Raw Data</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Reset Smoothing</a>
{% endif %}
</p>
<p>
Reset pace data to values before smoothing (as originally imported/uploaded)
</p>
</div>
</div>
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
{% if user.rower.rowerplan == 'pro' %}
<a class="button blue small"href="/rowers/workout/{{ workout.id }}/crewnerdsummary">CrewNerd Summary</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">CrewNerd Summary</a>
{% endif %}
</p>
<p>
Upload a CrewNerd Summary (CSV file) to this workout.
</p>
</div>
<div class="grid_2">
<p>
{% if user.rower.rowerplan == 'pro' %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/geeky">Geeky Stuff</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Geeky Stuff</a>
{% endif %}
</p>
<p>
Add weather and current data and OTW power calculations.
</p>
</div>
<div class="grid_2 omega">
<p>
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/interactiveplot">Big Interactive Plot</a>
</p>
<p>
See (and save) the big interactive plot
</p>
</div>
</div>
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/flexchart">Flexible Interactive Plot</a>
</p>
<p>
Flexible Interactive plot. Pick your own X and Y axis parameters.
</p>
</div>
<div class="grid_2 tooltip">
<p>
{% if user.rower.rowerplan == 'pro' %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/addotwpowerplot">OTW Power Plot</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">OTW Power Plot</a>
{% endif %}
</p>
<span class="tooltiptext">Note: You must run the OTW calculations under Geeky Stuff first. Otherwise the plot will be empty</span>
<p>
Pace, wind corrected pace, power, equivalent erg power in a static plot
</p>
</div>
<div class="grid_2 omega tooltip">
<p>
{% if user.rower.rowerplan == 'pro' %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/editintervals">Edit Intervals</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Edit Intervals</a>
{% endif %}
</p>
<span class="tooltiptext">Enter or change the interval and summary data for your workout</span>
<p>
Enter or change the interval and summary data for your workout
</p>
</div>
</div>
</div>
<div id="advancedplots" class="grid_6 omega">
<div class="grid_6 alpha">
<script type="text/javascript" src="/static/js/bokeh-0.11.1.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, true, true);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="interactiveplot" class="grid_6 omega">
{{ the_div |safe }}
</div>
</div>
{% endblock %}

View File

@@ -1,76 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Analysis {% endblock %}
{% block content %}
<h1>Analysis</h1>
<p>Functionality to analyze multiple workouts.</p>
<div class="grid_12 alpha">
<div class="grid_6 alpha">
<h2>Basic</h2>
<div class="grid_2 alpha">
<p>
<a class="button blue small" href="/rowers/ote-bests">Ranking Pieces</a></p>
<p>Analyze your Concept2 ranking pieces over the past 12 months and predict your pace on other pieces.</p>
</div>
<div class="grid_2">
<p class="button white small">
Analysis Feature 2
</p>
<p>
Reserved for future functionality.
</p>
</div>
<div class="grid_2 omega">
<p class="button white small">
Analysis Feature 3
</p>
<p>
Reserved for future functionality.
</p>
</div>
</div>
<div class="grid_6 omega">
<h2>Pro</h2>
<div class="grid_2 alpha">
<p>
{% if user.rower.rowerplan == 'pro' %}
<a class="button blue small" href="/rowers/histo">Power Histogram</a>
{% else %}
<a class="button blue small" href="/rowers/about">Power Histogram</a>
{% endif %}
</p>
<p>
Plot a power histogram of all your strokes over the past 12 months.
</p>
</div>
<div class="grid_2">
<p class="button white small">
Pro Feature 2
</p>
<p>
Reserved for future functionality.
</p>
</div>
<div class="grid_2 omega">
<p class="button white small">
Pro Feature 3
</p>
<p>
Reserved for future functionality.
</p>
</div>
</div>
</div>
{% endblock %}

View File

@@ -1,182 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<link rel="stylesheet" href="/static/css/bokeh-0.12.3.min.css" type="text/css" />
<link rel="stylesheet" href="/static/css/bokeh-widgets-0.12.3.min.css" type="text/css" />
<link rel="shortcut icon" href="/static/img/myicon.png" />
<link rel="shortcut icon" href="/static/img/favicon.ico" />
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=0.67">
<title>Rowsandall</title>
<link rel="stylesheet" href="/static/css/reset.css" />
<link rel="stylesheet" href="/static/css/text.css" />
<link rel="stylesheet" href="/static/css/960_12_col.css" />
<link rel="stylesheet" href="/static/css/rowsandall.css" />
{% block meta %} {% endblock %}
</head>
<body>
<div class="container_12">
<div id="logo" class="grid_2">
{% if user.rower.rowerplan == 'pro' %}
<p><a href="/"><img src="/static/img/logocroppedpro.gif"
alt="Rowsandall logo" width="110" heigt="110"></a></p>
{% else %}
<p><a href="/"><img src="/static/img/logocropped.gif"
alt="Rowsandall logo" width="110" heigt="110"></a></p>
{% endif %}
</div>
<div class="grid_10 omega">
<div class="grid_8 alpha"><p>&nbsp</p></div>
<div class="grid_2 omega">
{% if user.is_authenticated %}
<p><a class="button gray small" href="/password_change/">Password Change</a></p>
{% else %}
<p><a class="button gray small" href="/password_reset/">Forgotten Password?</a></p>
{% endif %}
</div>
</div>
<div class="grid_10 omega">
<div class="grid_4 suffix_2 alpha">
<p>Free Data and Analysis. For Rowers. By Rowers.</p>
</div>
<div class="grid_3">
{% if user.rower.rowerplan == 'pro' %}
<h6>Pro Member</h6>
{% else %}
<p>&nbsp;</p>
{% endif %}
</div>
<div class="grid_1 omega">
{% if user.is_authenticated %}
<p><a class="button gray small" href="{% url 'logout' %}">logout</a></p>
{% else %}
<p>&nbsp</p>
{% endif %}
</div>
</div>
<div class="grid_10" omega>
<div class="grid_1 alpha tooltip">
{% if user.is_authenticated %}
<p><a class="button gray small" href="/rowers/workout/upload/">Upload</a></p>
<span class="tooltiptext">Upload CSV, TCX, FIT data files to rowsandall.com</span>
{% else %}
<p><a class="button green small" href="/rowers/register">Register (free)</a></p>
{% endif %}
</div>
<div class="grid_1 tooltip">
{% if user.is_authenticated %}
<p>
<a class="button gray small" href="/rowers/imports/">Import</a>
</p>
<span class="tooltiptext">Import workouts from Strava, SportTracks, and C2 logbook</span>
{% else %}
<p>&nbsp;</p>
{% endif %}
</div>
<div class="grid_2 tooltip">
{% if user.is_authenticated %}
<p>
<a class="button gray small" href="/rowers/list-workouts/">Workouts</a>
</p>
<span class="tooltiptext">See your list of workouts</span>
{% else %}
<p>&nbsp;</p>
{% endif %}
</div>
<div class="grid_2 tooltip">
{% if user.is_authenticated %}
<p>
<a class="button gray small" href="/rowers/list-graphs/">Graphs</a>
</p>
<span class="tooltiptext">See your most recent charts</span>
{% else %}
<p>&nbsp;</p>
{% endif %}
</div>
<div class="grid_2 suffix_1 tooltip">
{% if user.is_authenticated %}
<p>
<a class="button gray small" href="/rowers/analysis">Analysis</a>
</p>
<span class="tooltiptext">Analysis of workouts over a period of time</span>
{% else %}
<p>&nbsp;</p>
{% endif %}
</div>
<div class="grid_1 omega tooltip">
{% if user.is_authenticated %}
<p>
<a class="button gray small" href="/rowers/me/edit">{{ user.first_name }}</a>
</p>
<span class="tooltiptext">Edit user data, e.g. heart rate zones</span>
{% else %}
<p><a class="button gray small" href="{% url 'login' %}">login</a> </p>
{% endif %}
</div>
</div>
<div class="clear"></div>
<div class="grid_12">
{% block message %}
{% if message %}
<p class="message">
{{ message }}
</p>
{% endif %}
{% if successmessage %}
<p class="successmessage">
{{ successmessage }}
</p>
{% endif %}
{% endblock %}
</div>
<div class="grid_12">
{% load tz %}
{% block content %}{% endblock %}
</div>
<div class="clear"></div>
<div class="grid_12 omega" >
{% block footer %}
<p id="footer"
>{{ versionstring }}</p>
<div class="grid_3 alpha">
<p id="footer"><a href="/rowers/email/">&copy; Sander Roosendaal</a></p>
</div>
<div class="grid_1 suffix_1">
<p id="footer">
<a href="/rowers/about">About</a></p>
</div>
<div class="grid_1 suffix_1">
<p id="footer">
<a href="/rowers/legal">Legal</a></p>
</div>
<div class="grid_1">
<p id="footer">
<a href="/rowers/physics">Physics</a></p>
</div>
<div class="grid_2">
<p id="footer">
<a href="/rowers/videos">Videos</a></p>
</div>
<div class="grid_1 omega">
<p id="footer">
<a href="/rowers/email">Contact</a></p>
</div>
{% endblock %}
</div>
</div>
<!-- end container -->
</body>
</html>

View File

@@ -1,60 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}View Workout {% endblock %}
{% block content %}
<script type="text/javascript" src="/static/js/bokeh-0.11.1.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, false, false);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="workouts" class="grid_12 alpha">
<h1>Interactive Plot</h1>
{% if user.is_authenticated and mayedit %}
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2 suffix_2 omega">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/advanced">Advanced Edit</a>
</p>
</div>
{% endif %}
{{ the_div|safe }}
</div>
{% endblock %}

View File

@@ -1,48 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Workouts{% endblock %}
{% block content %}
<h1>Available on C2 Logbook</h1>
{% if data %}
<table width="70%" class="listtable">
<thead>
<tr>
<th> Distance </th>
<th> Duration </th>
<th> Date</th>
<th> Type</th>
<th> Import</th>
</tr>
</thead>
<tbody>
{% for workout in data %}
<tr>
{% for key,value in workout.items %}
{% if key == "date" %}
<td>{{ value }}</td>
{% endif %}
{% if key == "type" %}
<td>{{ value }}</td>
{% endif %}
{% if key == "distance" %}
<td>{{ value }}m</td>
{% endif %}
{% if key == "time_formatted" %}
<td>{{ value }}</td>
{% endif %}
{% if key == "id" %}
<td><a href="/rowers/workout/c2import/{{ value }}/">Import</a></td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p> No workouts found </p>
{% endif %}
{% endblock %}

View File

@@ -1,39 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Workouts{% endblock %}
{% block content %}
<h1>Available on C2 Logbook</h1>
{% if workouts %}
<table width="70%" class="listtable">
<thead>
<tr>
<th> Import </th>
<th> Date/Time </th>
<th> Duration </th>
<th> Total Distance</th>
<th> Type</th>
<th> Source</th>
</tr>
</thead>
<tbody>
{% for workout in workouts %}
<tr>
<td>
<a href="/rowers/workout/c2import/{{ workout|lookup:'id' }}/">Import</a></td>
<td>{{ workout|lookup:'starttime' }}</td>
<td>{{ workout|lookup:'duration' }}</td>
<td>{{ workout|lookup:'distance' }}</td>
<td>{{ workout|lookup:'rowtype' }}</td>
<td>{{ workout|lookup:'source' }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p> No workouts found </p>
{% endif %}
{% endblock %}

View File

@@ -1,20 +0,0 @@
{% extends "base.html" %}
{% block title %}Upload CrewNerd Summary CSV{% endblock title %}
{% block content %}
<div id="emailform" class="grid_6 alpha">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form method="post" action="/rowers/workout/{{ workout.id }}/crewnerdsummary">{% csrf_token %}
<table>
</table>
</form>
</div>
{% endblock content %}

View File

@@ -1,75 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Workouts{% endblock %}
{% block content %}
<div id="workouts" class="grid_4 alpha">
<h1>Workout {{ id }}</h1>
<table width=100%>
<tr>
<th>Rower:</th><td>{{ first_name }} {{ last_name }}</td>
</tr><tr>
<tr>
<th>Name:</th><td>{{ workout.name }}</td>
</tr><tr>
<tr>
<th>Date:</th><td>{{ workout.date }}</td>
</tr><tr>
<th>Time:</th><td>{{ workout.starttime }}</td>
</tr><tr>
<th>Distance:</th><td>{{ workout.distance }}m</td>
</tr><tr>
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
</tr><tr>
<th>Type:</th><td>{{ workout.workouttype }}</td>
</tr><tr>
<th>Weight Category:</th><td>{{ workout.weightcategory }}</td>
</tr>
</table>
</div>
<div id="comparison" class="grid_8 omega">
<h1>Compare this workout to:</h1>
{% if workouts %}
<table width="100%" class="listtable">
<thead>
<tr>
<th> Date</th>
<th> Time</th>
<th> Name</th>
<th> Type</th>
<th> Distance </th>
<th> Duration </th>
<th> Avg HR </th>
<th> Max HR </th>
<th> Compare</th>
</tr>
</thead>
</tbody>
{% for cworkout in workouts %}
{% if id != cworkout.id %}
<tr>
<td> {{ cworkout.date }} </td>
<td> {{ cworkout.starttime }} </td>
<td> <a href="/rowers/workout/{{ workout.id }}/edit">{{ cworkout.name }}</a> </td>
<td> {{ cworkout.workouttype }} </td>
<td> {{ cworkout.distance }}m</td>
<td> {{ cworkout.duration |durationprint:"%H:%M:%S.%f" }} </td>
<td> {{ cworkout.averagehr }} </td>
<td> {{ cworkout.maxhr }} </td>
<td> <a class="button blue small" href="/rowers/workout/compare/{{ id }}/{{ cworkout.id }}/time/hr">Compare</a> </td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
{% else %}
<p> No workouts found </p>
{% endif %}
</div>
{% endblock %}

View File

@@ -1,77 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Compare Workouts {% endblock %}
{% block content %}
<script type="text/javascript" src="/static/js/bokeh-0.11.1.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, true, false);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="other" class="grid_12 alpha">
<div class="grid_2 alpha suffix_10">
<a class="button blue small"
href="/rowers/workout/compare/{{ id2 }}/{{ id1 }}/{{ xparam }}/{{ yparam }}">Swap Workouts</a>
</div>
</div>
<p>&nbsp;</p>
<div id="plotbuttons" class="grid_12 alpha">
<div id="x-axis" class="grid_6 alpha">
<div class="grid_2 alpha">
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/time/{{ yparam }}">Time</a>
</div>
<div class="grid_2 suffix_2 omega">
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/distance/{{ yparam }}">Distance</a>
</div>
</div>
<div id="y-axis" class="grid_6 omega">
<div class="grid_2 alpha">
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/pace">Pace</a>
</div>
<div class="grid_2">
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/hr">Heart Rate</a>
</div>
<div class="grid_2 omega">
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/spm">SPM</a>
</div>
</div>
</div>
<div id="theplot" class="grid_12 alpha">
{{ the_div|safe }}
</div>
{% endblock %}

View File

@@ -1,146 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %} Comparison Plot {% endblock %}
{% block content %}
<script type="text/javascript" src="/static/js/bokeh-0.11.1.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, true, false);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="navigation" class="grid_12 alpha">
{% if user.is_authenticated and mayedit %}
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ id }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2 suffix_8 omega">
<p>
<a class="button gray small" href="/rowers/workout/compare/{{ id }}/advanced">Advanced Edit</a>
</p>
</div>
{% endif %}
</div>
<div id="other" class="grid_12 alpha">
<div class="grid_2 alpha">
<a class="button blue small"
href="/rowers/workout/compare/{{ id2 }}/{{ id1 }}/{{ xparam }}/{{ yparam }}/{{ plottype }}">Swap Workouts</a>
</div>
<div class="grid_2">
<a class="button blue small"
href="/rowers/workout/{{ id1 }}/edit">Edit Workout</a>
</div>
<div class="grid_2 suffix_6 omega">
<a class="button blue small"
href="/rowers/workout/{{ id1 }}/advanced">Advanced Edit</a>
</div>
</div>
<p>&nbsp;</p>
<div id="plotbuttons" class="grid_12 alpha">
<div id="x-axis" class="grid_6 alpha">
<div class="grid_2 alpha dropdown">
<button class="grid_2 alpha button blue small dropbtn">X-axis</button>
<div class="dropdown-content">
<a class="button blue small alpha" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/time/{{ yparam }}/{{ plottype }}">Time</a>
<a class="button blue small alpha" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/distance/{{ yparam }}/{{ plottype }}">Distance</a>
{% if promember %}
<a class="button blue small alpha" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/power/{{ yparam }}/scatter">Power</a>
<a class="button blue small alpha" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/hr/{{ yparam }}/scatter">HR</a>
<a class="button blue small alpha" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/spm/{{ yparam }}/scatter">SPM</a>
<a class="button blue small alpha" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/peakforce/{{ yparam }}/scatter">Peak Force</a>
<a class="button blue small alpha" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/averageforce/{{ yparam }}/scatter">Average Force</a>
<a class="button blue small alpha" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/drivelength/{{ yparam }}/scatter">Drive Length</a>
<a class="button blue small alpha" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/driveenergy/{{ yparam }}/scatter">Drive Energy</a>
<a class="button blue small alpha" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/drivespeed/{{ yparam }}/scatter">Drive Speed</a>
{% else %}
<a class="button rosy small" href="/rowers/promembership">Power (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">HR (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">SPM (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Length (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Energy (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Speed (Pro)</a>
{% endif %}
</div>
</div>
<div class="grid_2 suffix_2 omega dropdown">
<button class="grid_2 alpha button blue small dropbtn">Y-axis</button>
<div class="dropdown-content">
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/pace/{{ plottype }}">Pace</a>
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/hr/{{ plottype }}">HR</a>
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/spm/{{ plottype }}">SPM</a>
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/power/{{ plottype }}">Power</a>
{% if promember %}
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/peakforce/{{ plottype }}">Peak Force</a>
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/averageforce/{{ plottype }}">Average Force</a>
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/drivelength/{{ plottype }}">Drive Length</a>
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/driveenergy/{{ plottype }}">Drive Energy</a>
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/drivespeed/{{ plottype }}">Drive Speed</a>
{% else %}
<a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Length (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Energy (Pro)</a>
{% endif %}
</div>
</div>
</div>
<div id="y-axis" class="grid_6 omega">
<div class="grid_2 prefix_2 alpha">
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/{{ yparam }}/line">Line Plot</a>
</div>
<div class="grid_2 omega">
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/{{ yparam }}/scatter">Scatter Plot</a>
</div>
</div>
</div>
<div id="theplot" class="grid_12 alpha flexplot">
{{ the_div|safe }}
</div>
{% endblock %}

View File

@@ -1,55 +0,0 @@
body {
background: #123;
color: #333;
font-size: 11px;
height: auto;
padding-bottom: 20px;
}
a {
color: #fff;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
h1 {
font-family: Georgia, serif;
font-weight: normal;
padding-top: 20px;
text-align: center;
}
h2 {
padding-top: 20px;
text-align: center;
}
p {
border: 1px solid #666;
overflow: hidden;
padding: 10px 0;
text-align: center;
}
.container_12,
.container_16,
.container_24 {
background-color: #fff;
background-repeat: repeat-y;
margin-bottom: 20px;
}
.container_12 {
background-image: url(../img/12_col.gif);
}
.container_16 {
background-image: url(../img/16_col.gif);
}
.container_24 {
background-image: url(../img/24_col.gif);
}

View File

@@ -1,55 +0,0 @@
body {
background: #123;
color: #333;
font-size: 11px;
height: auto;
padding-bottom: 20px;
}
a {
color: #fff;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
h1 {
font-family: Georgia, serif;
font-weight: normal;
padding-top: 20px;
text-align: left;
}
h2 {
padding-top: 20px;
text-align: left;
}
p {
border: 1px solid #666;
overflow: hidden;
padding: 10px 0;
text-align: left;
}
.container_12,
.container_16,
.container_24 {
background-color: #fff;
background-repeat: repeat-y;
margin-bottom: 20px;
}
.container_12 {
background-image: url(../img/12_col.gif);
}
.container_16 {
background-image: url(../img/16_col.gif);
}
.container_24 {
background-image: url(../img/24_col.gif);
}

View File

@@ -6,28 +6,17 @@
{% block content %}
{{ js_res | safe }}
{{ css_res| safe }}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, false, false);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}

View File

@@ -1,173 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}View Workout {% endblock %}
{% block content %}
<script type="text/javascript" src="/static/js/bokeh-0.11.1.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, false, false);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="title" class="grid_12 alpha">
<h1>Indoor Rower Stroke Analysis</h1>
</div>
<div id="summary" class="grid_6 alpha">
<p>Summary for {{ theuser.first_name }} {{ theuser.last_name }}
between {{ startdate|date }} and {{ enddate|date }}</p>
<div id="plotbuttons" class="grid_6 alpha">
<div class="grid_2 alpha dropdown">
<button class="grid_2 alpha button blue small dropbtn">X-axis</button>
<div class="dropdown-content">
<a class="button blue small alpha" href="/rowers/flexall/time/{{ yparam1 }}/{{ yparam2 }}">Time</a>
<a class="button blue small alpha" href="/rowers/flexall/distance/{{ yparam1 }}/{{ yparam2 }}">Distance</a>
{% if promember %}
<a class="button blue small alpha" href="/rowers/flexall/power/{{ yparam1 }}/{{ yparam2 }}">Power</a>
<a class="button blue small alpha" href="/rowers/flexall/hr/{{ yparam1 }}/{{ yparam2 }}">HR</a>
<a class="button blue small alpha" href="/rowers/flexall/spm/{{ yparam1 }}/{{ yparam2 }}">SPM</a>
<a class="button blue small alpha" href="/rowers/flexall/peakforce/{{ yparam1 }}/{{ yparam2 }}">Peak Force</a>
<a class="button blue small alpha" href="/rowers/flexall/averageforce/{{ yparam1 }}/{{ yparam2 }}">Average Force</a>
<a class="button blue small alpha" href="/rowers/flexall/drivelength/{{ yparam1 }}/{{ yparam2 }}">Drive Length</a>
<a class="button blue small alpha" href="/rowers/flexall/driveenergy/{{ yparam1 }}/{{ yparam2 }}">Drive Energy</a>
<a class="button blue small alpha" href="/rowers/flexall/drivespeed/{{ yparam1 }}/{{ yparam2 }}">Drive Speed</a>
{% else %}
<a class="button rosy small" href="/rowers/promembership">Power (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">HR (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">SPM (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Length (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Energy (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Speed (Pro)</a>
{% endif %}
</div>
</div>
<div class="grid_2 dropdown">
<button class="grid_2 alpha button blue small dropbtn">Left</button>
<div class="dropdown-content">
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/pace/{{ yparam2 }}">Pace</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/hr/{{ yparam2 }}">HR</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/spm/{{ yparam2 }}">SPM</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/power/{{ yparam2 }}">Power</a>
{% if promember %}
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/peakforce/{{ yparam2 }}">Peak Force</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/averageforce/{{ yparam2 }}">Average Force</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/drivelength/{{ yparam2 }}">Drive Length</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/driveenergy/{{ yparam2 }}">Drive Energy</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/drivespeed/{{ yparam2 }}">Drive Speed</a>
{% else %}
<a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Length (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Energy (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Speed (Pro)</a>
{% endif %}
</div>
</div>
<div class="grid_2 dropdown omega">
<button class="grid_2 alpha button blue small dropbtn">Right</button>
<div class="dropdown-content">
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/hr">HR</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/spm">SPM</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/power">Power</a>
{% if promember %}
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/peakforce">Peak Force</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/averageforce">Average Force</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/drivelength">Drive Length</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/driveenergy">Drive Energy</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/drivespeed">Drive Speed</a>
{% else %}
<a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Length (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Energy (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Speed (Pro)</a>
{% endif %}
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/None">None</a>
</div>
</div>
</div>
<div class="grid_6 alpha">
<p>&nbsp;</p>
<p>Warning: Large date ranges may take a long time to load. Huge date ranges may crash your browser.</p>
</div>
</div>
<div id="form" class="grid_6 omega">
<p>Use this form to select a different date range:</p>
<p>
Select start and end date for a date range:
<div class="grid_4 alpha">
<form enctype="multipart/form-data" action="" method="post">
<table>
{{ form.as_table }}
</table>
{% csrf_token %}
</div>
<div class="grid_2 omega">
<input name='daterange' class="button green" type="submit" value="Submit"> </form>
</div>
<div class="grid_4 alpha">
<form enctype="multipart/form-data" action="" method="post">
Or use the last {{ deltaform }} days.
</div>
<div class="grid_2 omega">
{% csrf_token %}
<input name='datedelta' class="button green" type="submit" value="Submit">
</form>
</div>
</div>
<div id="graph" class="grid_12 alpha">
{{ the_div|safe }}
</div>
{% endblock %}

View File

@@ -1,114 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Graphs{% endblock %}
{% block content %}
<div id="workouts" class="grid_6 alpha">
<h1>Workouts</h1>
{% if workouts %}
<table class="listtable" width=100% >
<thead>
<tr>
<th> Date</th>
<th> Time</th>
<th> Name</th>
<th> Type</th>
<th> Edit</th>
<th> Delete</th>
<th> C2 upload</th>
</tr>
</thead>
<tbody>
{% for workout in workouts %}
<tr>
<td> {{ workout.date }} </td>
<td> {{ workout.starttime }} </td>
<td><a href="/rowers/workout/{{workout.id}}"> {{ workout.name }}</a> </td>
<td> {{ workout.workouttype }} </td>
<td> <a href="/rowers/workout/{{ workout.id }}/edit">E</td>
<td> <a href="/rowers/workout/{{ workout.id }}/deleteconfirm">D</td>
{% if not workout.uploadedtoc2 %}
<td> <a href="/rowers/workout/{{ workout.id }}/c2upload">C2</td>
{% else %}
<td> &nbsp; </td>
{% endif %}
</tr>
{% endfor %}
</table>
</tbody>
{% else %}
<p>No workouts found</p>
{% endif %}
</div>
<div id="graphs" class="grid_6 omega">
<h1>Recent Graphs</h1>
{% if graphs1 %}
{% for graph in graphs1 %}
{% if forloop.counter == 1 %}
<div id="thumb-container" class="grid_2 alpha">
<a href="/rowers/graph/{{ graph.id }}/">
<img src="/{{ graph.filename }}"
onerror="this.src='/static/img/waiting.png'"
alt="{{ graph.filename }}" width="120" height="100"></a>
</div>
{% elif forloop.counter == 3 %}
<div id="thumb-container" class="grid_2 omega">
<a href="/rowers/graph/{{ graph.id }}/">
<img src="/{{ graph.filename }}"
onerror="this.src='/static/img/waiting.png'"
alt="{{ graph.filename }}" width="120" height="100"></a>
</div>
{% else %}
<div id="thumb-container" class="grid_2">
<a href="/rowers/graph/{{ graph.id }}/">
<img src="/{{ graph.filename }}"
onerror="this.src='/static/img/waiting.png'"
alt="{{ graph.filename }}" width="120" height="100"></a>
</div>
{% endif %}
{% endfor %}
{% for graph in graphs2 %}
{% if forloop.counter == 1 %}
<div id="thumb-container" class="grid_2 alpha">
<a href="/rowers/graph/{{ graph.id }}/">
<img src="/{{ graph.filename }}"
onerror="this.src='/static/img/waiting.png'"
alt="{{ graph.filename }}" width="120" height="100"></a>
</div>
{% elif forloop.counter == 3 %}
<div id="thumb-container" class="grid_2 omega">
<a href="/rowers/graph/{{ graph.id }}/">
<img src="/{{ graph.filename }}"
onerror="this.src='/static/img/waiting.png'"
alt="{{ graph.filename }}" width="120" height="100"></a>
</div>
{% else %}
<div id="thumb-container" class="grid_2">
<a href="/rowers/graph/{{ graph.id }}/">
<img src="/{{ graph.filename }}"
onerror="this.src='/static/img/waiting.png'"
alt="{{ graph.filename }}" width="120" height="100"></a>
</div>
{% endif %}
{% endfor %}
{% else %}
<p> No graphs found </p>
{% endif %}
</div>
{% endblock %}

View File

@@ -1,50 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% block title %}File loading{% endblock %}
{% block content %}
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
<div id="left" class="grid_6 alpha">
<h1>Upload Workout File</h1>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<table>
{{ form.as_table }}
</table>
{% csrf_token %}
<div id="formbutton" class="grid_1 prefix_4 suffix_1">
<input class="button green" type="submit" value="Submit">
</div>
</div>
<div id="right" class="grid_6 omega">
<h1>Optional extra actions</h1>
<p>
<table>
{{ optionsform.as_table }}
</table>
</p>
<p>
Valid file types are:
<ul>
<li>Painsled iOS Stroke Export (CSV)</li>
<li>Painsled desktop version Stroke Export (CSV)</li>
<li>A TCX file with location data (lat,long) - with or without Heart Rate value, for example from RiM or CrewNerd</li>
<li>RowPro CSV export</li>
<li>SpeedCoach GPS and SpeedCoach GPS 2 CSV export</li>
<li>ErgData CSV export</li>
<li>ErgStick CSV export</li>
<li>A FIT file with location data (experimental)</li>
</ul>
</p>
</div>
</form>
{% endblock %}

View File

@@ -1,60 +0,0 @@
{% extends "base.html" %}
{% block title %}Contact Us{% endblock title %}
{% block content %}
<div id="emailform" class="grid_6 alpha">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form method="post" action="/rowers/email/send/">{% csrf_token %}
<table>
<tr><td>
<label class="label">Name <span class="required">*</span></label>
<span class="span">
</td><td>
<input name= "firstname" class="inputtext" maxlength="255" size="12" />
<label class="spanlabel">First</label>
</td></tr>
<tr><td>
</span>
<span class="span">
</td><td>
<input name= "lastname" class="inputtext" maxlength="255" size="18" />
<label class="spanlabel">Last</label>
</span>
</td></tr>
<tr><td>
<label class="label">Email Address <span class="required">*</span></label>
</td><td>
<input name="email" class="inputtext" type="text" maxlength="255" size="35" />
</td></tr>
<tr><td>
<label class="label">Subject <span class="required">*</span></label>
</td><td>
<input name="subject" class="inputtext" type="text" maxlength="255" size="45" />
</td></tr>
</table>
<label class="label">You must answer <u>YES</u> to the question below to approve sending this email. <span class="required">*</span></label>
<table>
<tr><td>
Do you want to send me an email?
</td><td>
<input name="botcheck" class="inputtext" type="text" maxlength="5" size="5" />
</td></tr>
<tr><td>
<label class="label">Message <span class="required">*</span></label>
</td><td>
<textarea name="message" class="inputtextarea" rows="11" cols="45"></textarea>
</td></tr>
<tr><td>
<input class="submitform" type="submit" name="submitform" value="Send Message" />
</td></tr>
</table>
</form>
</div>
{% endblock content %}

View File

@@ -1,115 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Export {% endblock %}
{% block content %}
<div id="exportbuttons" class="grid_6 alpha">
<h3>Export Workout</h3>
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2 suffix_2 omega">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/advanced">Advanced Edit</a>
</p>
</div>
<div class="grid_6 alpha">
<p>
Click on the icon to upload this workout to your site of choice. A checkmark indicates that the workout has already been uploaded. If the button is grayed out, click it to authorize the connection to that site. Use TCX export to email a TCX file of your workout to yourself.
</p>
</div>
{% if workout.uploadedtoc2 == 0 %}
{% if user.rower.c2token == None or user.rower.c2token == '' %}
<div class="grid_1 alpha">
<a href="/rowers/me/c2authorize">
<img src="/static/img/c2square_gray.png" alt="C2 icon" width="60" height="60"></a>
</div>
{% else %}
<div class="grid_1 alpha">
<a href="/rowers/workout/{{ workout.id }}/c2uploadw"><img src="/static/img/c2square.jpg" alt="Concept2 icon" width="60" height="60"></a>
</div>
{% endif %}
{% else %}
<div class="grid_1 alpha">
<img src="/static/img/c2square_checked.png" alt="Concept2 icon" width="60" height="60"></a>
</div>
{% endif %}
{% if workout.uploadedtostrava == 0 %}
{% if user.rower.stravatoken == None or user.rower.stravatoken == '' %}
<div class="grid_1">
<a href="/rowers/me/stravaauthorize">
<img src="/static/img/stravasquare_gray.png" alt="Strava icon" width="60" height="60"></a>
</div>
{% else %}
<div class="grid_1">
<a href="/rowers/workout/{{ workout.id }}/stravauploadw"><img src="/static/img/stravasquare.png" alt="Strava icon" width="60" height="60"></a>
</div>
{% endif %}
{% else %}
<div class="grid_1">
<img src="/static/img/stravasquare_checked.png" alt="Concept2 icon" width="60" height="60"></a>
</div>
{% endif %}
{% if workout.uploadedtosporttracks == 0 %}
{% if user.rower.sporttrackstoken == None or user.rower.sporttrackstoken == '' %}
<div class="grid_1">
<a href="/rowers/me/sporttracksauthorize">
<img src="/static/img/sporttrackssquare_gray.png" alt="SportTracks icon" width="60" height="60"></a>
</div>
{% else %}
<div class="grid_1">
<a href="/rowers/workout/{{ workout.id }}/sporttracksuploadw">
<img src="/static/img/sporttrackssquare.png" alt="SportTracks icon" width="60" height="60"></a>
</div>
{% endif %}
{% else %}
<div class="grid_1">
<img src="/static/img/sporttrackssquare_checked.png" alt="Concept2 icon" width="60" height="60"></a>
</div>
{% endif %}
<div class="grid_1">
<a href="/rowers/workout/{{ workout.id }}/emailtcx">
<img src="/static/img/export.png" alt="TCX Export" width="60" height="60"></a>
</div>
</div>
<div class="grid_6 omega">
<h3>Connect</h3>
<div class="grid_6">
<p>Click one of the below logos to connect to the service of your choice.
You only need to do this once. After that, the site will have access until you
revoke the authorization for the "rowingdata" app.</p>
<div class="grid_2 alpha">
<p><a href="/rowers/me/stravaauthorize/"><img src="/static/img/ConnectWithStrava.png" alt="connect with strava" width="120"></a></p>
</div>
<div class="grid_2">
<p><a href="/rowers/me/c2authorize/"><img src="/static/img/blueC2logo.png" alt="connect with Concept2" width="120"></a></p>
</div>
<div class="grid_2 omega">
<p><a href="/rowers/me/sporttracksauthorize/"><img src="/static/img/sporttracks-button.png" alt="connect with SportTracks" width="120"></a></p>
</div>
</div>
</div>
{% endblock %}

View File

@@ -1,95 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %} Flexible Plot {% endblock %}
{% block content %}
<script type="text/javascript" src="/static/js/bokeh-0.11.1.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, true, false);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="navigation" class="grid_12 alpha">
{% if user.is_authenticated and mayedit %}
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ id }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2 suffix_8 omega">
<p>
<a class="button gray small" href="/rowers/workout/{{ id }}/advanced">Advanced Edit</a>
</p>
</div>
{% endif %}
</div>
<p>&nbsp;</p>
<div id="plotbuttons" class="grid_12 alpha">
<div id="x-axis" class="grid_6 alpha">
<div class="grid_2 alpha">
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/time/{{ yparam1 }}/{{ yparam2 }}">Time</a>
</div>
<div class="grid_2">
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/distance/{{ yparam1 }}/{{ yparam2 }}">Distance</a>
</div>
<div class="grid_2 omega">
<a class="button blue small"
href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/{{ yparam2 }}/{{ yparam1 }}">Swap Y axes</a>
</div>
</div>
<div id="y-axis" class="grid_6 omega">
<div class="grid_1 prefix_2 alpha">
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/{{ yparam1 }}/pace">Pace</a>
</div>
<div class="grid_1">
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/{{ yparam1 }}/hr">HR</a>
</div>
<div class="grid_1">
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/{{ yparam1 }}/spm">SPM</a>
</div>
<div class="grid_1 omega">
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/{{ yparam1 }}/power">Power</a>
</div>
</div>
</div>
<div id="theplot" class="grid_12 alpha">
{{ the_div|safe }}
</div>
{% endblock %}

View File

@@ -1,182 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% load tz %}
{% block title %} Flexible Plot {% endblock %}
{% localtime on %}
{% block content %}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
{{ widgetscript | safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, true, false);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="navigation" class="grid_12 alpha">
{% if user.is_authenticated and mayedit %}
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ id }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2 suffix_8 omega">
<p>
<a class="button gray small" href="/rowers/workout/{{ id }}/advanced">Advanced Edit</a>
</p>
</div>
{% endif %}
</div>
<p>&nbsp;</p>
<div id="plotbuttons" class="grid_12 alpha">
<div id="x-axis" class="grid_6 alpha">
<div class="grid_2 alpha dropdown">
<button class="grid_2 alpha button blue small dropbtn">X-axis</button>
<div class="dropdown-content">
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart/time/{{ yparam1 }}/{{ yparam2 }}/{{ plottype }}">Time</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart/distance/{{ yparam1 }}/{{ yparam2 }}/{{ plottype }}">Distance</a>
{% if promember %}
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart/power/{{ yparam1 }}/{{ yparam2 }}/scatter">Power</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart/hr/{{ yparam1 }}/{{ yparam2 }}/scatter">HR</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart/spm/{{ yparam1 }}/{{ yparam2 }}/scatter">SPM</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart/peakforce/{{ yparam1 }}/{{ yparam2 }}/scatter">Peak Force</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart/averageforce/{{ yparam1 }}/{{ yparam2 }}/scatter">Average Force</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart/drivelength/{{ yparam1 }}/{{ yparam2 }}/scatter">Drive Length</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart/driveenergy/{{ yparam1 }}/{{ yparam2 }}/scatter">Work per Stroke</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart/drivespeed/{{ yparam1 }}/{{ yparam2 }}/scatter">Drive Speed</a>
{% else %}
<a class="button rosy small" href="/rowers/promembership">Power (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">HR (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">SPM (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Length (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Work per Stroke (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Speed (Pro)</a>
{% endif %}
</div>
</div>
<div class="grid_2 dropdown">
<button class="grid_2 alpha button blue small dropbtn">Left</button>
<div class="dropdown-content">
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/pace/{{ yparam2 }}/{{ plottype }}">Pace</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/hr/{{ yparam2 }}/{{ plottype }}">HR</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/spm/{{ yparam2 }}/{{ plottype }}">SPM</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/power/{{ yparam2 }}/{{ plottype }}">Power</a>
{% if promember %}
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/peakforce/{{ yparam2 }}/{{ plottype }}">Peak Force</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/averageforce/{{ yparam2 }}/{{ plottype }}">Average Force</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/drivelength/{{ yparam2 }}/{{ plottype }}">Drive Length</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/driveenergy/{{ yparam2 }}/{{ plottype }}">Work per Stroke</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/drivespeed/{{ yparam2 }}/{{ plottype }}">Drive Speed</a>
{% else %}
<a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Length (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Work per Stroke (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Speed (Pro)</a>
{% endif %}
</div>
</div>
<div class="grid_2 dropdown omega">
<button class="grid_2 alpha button blue small dropbtn">Right</button>
<div class="dropdown-content">
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/hr/{{ plottype }}">HR</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/spm/{{ plottype }}">SPM</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/power/{{ plottype }}">Power</a>
{% if promember %}
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/peakforce/{{ plottype }}">Peak Force</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/averageforce/{{ plottype }}">Average Force</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/drivelength/{{ plottype }}">Drive Length</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/driveenergy/{{ plottype }}">Work per Stroke</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/drivespeed/{{ plottype }}">Drive Speed</a>
{% else %}
<a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Length (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Work per Stroke (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Speed (Pro)</a>
{% endif %}
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/None/{{ plottype }}">None</a>
</div>
</div>
</div>
<div id="y-axis" class="grid_6 omega">
<div class="grid_2 alpha tooltip">
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
{% csrf_token %}
{% if workstrokesonly %}
<input type="hidden" name="workstrokesonly" value="True">
{% else %}
<input class="grid_2 alpha button blue small" type="hidden" name="workstrokesonly" value="False">
{% endif %}
<input class="grid_2 alpha button blue small" value="Toggle Work Strokes" type="Submit">
</form>
<span class="tooltiptext">If your data source allows, this will show or hide strokes taken during rest intervals.</span>
</div>
<div class="grid_2">
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/{{ yparam2 }}/line">Line Plot</a>
</div>
<div class="grid_2 omega">
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/{{ yparam2 }}/scatter">Scatter Plot</a>
</div>
</div>
</div>
<div id="theplot" class="grid_12 alpha flexplot">
{{ the_div|safe }}
</div>
<div id="thewidgets" class="grid_12 alpha">
{{ widgetdiv1|safe }}
{{ widgetdiv2|safe }}
</div>
{% endblock %}
{% endlocaltime %}

View File

@@ -1,162 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% load tz %}
{% block title %} Flexible Plot {% endblock %}
{% localtime on %}
{% block content %}
{{ js_res | safe }}
{{ css_res| safe }}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ the_script |safe }}
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="navigation" class="grid_12 alpha">
{% if user.is_authenticated and mayedit %}
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ id }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2 suffix_8 omega">
<p>
<a class="button gray small" href="/rowers/workout/{{ id }}/advanced">Advanced Edit</a>
</p>
</div>
{% endif %}
</div>
<p>&nbsp;</p>
<div id="plotbuttons" class="grid_12 alpha">
<div id="x-axis" class="grid_6 alpha">
<div class="grid_2 alpha dropdown">
<button class="grid_2 alpha button blue small dropbtn">X-axis</button>
<div class="dropdown-content">
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart2/time/{{ yparam1 }}/{{ yparam2 }}/{{ plottype }}">Time</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart2/distance/{{ yparam1 }}/{{ yparam2 }}/{{ plottype }}">Distance</a>
{% if promember %}
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart2/power/{{ yparam1 }}/{{ yparam2 }}/scatter">Power</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart2/hr/{{ yparam1 }}/{{ yparam2 }}/scatter">HR</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart2/spm/{{ yparam1 }}/{{ yparam2 }}/scatter">SPM</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart2/peakforce/{{ yparam1 }}/{{ yparam2 }}/scatter">Peak Force</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart2/averageforce/{{ yparam1 }}/{{ yparam2 }}/scatter">Average Force</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart2/drivelength/{{ yparam1 }}/{{ yparam2 }}/scatter">Drive Length</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart2/driveenergy/{{ yparam1 }}/{{ yparam2 }}/scatter">Work per Stroke</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart2/drivespeed/{{ yparam1 }}/{{ yparam2 }}/scatter">Drive Speed</a>
{% else %}
<a class="button rosy small" href="/rowers/promembership">Power (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">HR (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">SPM (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Length (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Work per Stroke (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Speed (Pro)</a>
{% endif %}
</div>
</div>
<div class="grid_2 dropdown">
<button class="grid_2 alpha button blue small dropbtn">Left</button>
<div class="dropdown-content">
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/pace/{{ yparam2 }}/{{ plottype }}">Pace</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/hr/{{ yparam2 }}/{{ plottype }}">HR</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/spm/{{ yparam2 }}/{{ plottype }}">SPM</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/power/{{ yparam2 }}/{{ plottype }}">Power</a>
{% if promember %}
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/peakforce/{{ yparam2 }}/{{ plottype }}">Peak Force</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/averageforce/{{ yparam2 }}/{{ plottype }}">Average Force</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/drivelength/{{ yparam2 }}/{{ plottype }}">Drive Length</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/driveenergy/{{ yparam2 }}/{{ plottype }}">Work per Stroke</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/drivespeed/{{ yparam2 }}/{{ plottype }}">Drive Speed</a>
{% else %}
<a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Length (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Work per Stroke (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Speed (Pro)</a>
{% endif %}
</div>
</div>
<div class="grid_2 dropdown omega">
<button class="grid_2 alpha button blue small dropbtn">Right</button>
<div class="dropdown-content">
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/{{ yparam1 }}/hr/{{ plottype }}">HR</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/{{ yparam1 }}/spm/{{ plottype }}">SPM</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/{{ yparam1 }}/power/{{ plottype }}">Power</a>
{% if promember %}
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/{{ yparam1 }}/peakforce/{{ plottype }}">Peak Force</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/{{ yparam1 }}/averageforce/{{ plottype }}">Average Force</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/{{ yparam1 }}/drivelength/{{ plottype }}">Drive Length</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/{{ yparam1 }}/driveenergy/{{ plottype }}">Work per Stroke</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/{{ yparam1 }}/drivespeed/{{ plottype }}">Drive Speed</a>
{% else %}
<a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Length (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Work per Stroke (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Drive Speed (Pro)</a>
{% endif %}
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/{{ yparam1 }}/None/{{ plottype }}">None</a>
</div>
</div>
</div>
<div id="y-axis" class="grid_6 omega">
<div class="grid_2 alpha tooltip">
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
{% csrf_token %}
{% if workstrokesonly %}
<input type="hidden" name="workstrokesonly" value="True">
{% else %}
<input class="grid_2 alpha button blue small" type="hidden" name="workstrokesonly" value="False">
{% endif %}
<input class="grid_2 alpha button blue small" value="Toggle Work Strokes" type="Submit">
</form>
<span class="tooltiptext">If your data source allows, this will show or hide strokes taken during rest intervals.</span>
</div>
<div class="grid_2">
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/{{ yparam1 }}/{{ yparam2 }}/line">Line Plot</a>
</div>
<div class="grid_2 omega">
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart2/{{ xparam }}/{{ yparam1 }}/{{ yparam2 }}/scatter">Scatter Plot</a>
</div>
</div>
</div>
<div id="theplot" class="grid_12 alpha">
{{ the_div|safe }}
</div>
{% endblock %}
{% endlocaltime %}

View File

@@ -1,14 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Change Workout {% endblock %}
{% block content %}
<div class="grid_12">
<p class="midden">
<a title="By Photoglob Zurich, reprinted by Detroit Publishing Co. [Public domain], via Wikimedia Commons" href="https://commons.wikimedia.org/wiki/File%3AHenley_Regatta%2C_Henley-on-Thames%2C_England%2C_1890s.jpg"><img width="512" alt="Henley Regatta, Henley-on-Thames, England, 1890s" src="https://upload.wikimedia.org/wikipedia/commons/thumb/d/d9/Henley_Regatta%2C_Henley-on-Thames%2C_England%2C_1890s.jpg/512px-Henley_Regatta%2C_Henley-on-Thames%2C_England%2C_1890s.jpg"/></a></p>
</div>
{% endblock %}

View File

@@ -1,51 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Delete Graph Image {% endblock %}
{% block content %}
<div id="workouts" class="grid_6 alpha">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<h1>Confirm Workout Delete</h1>
This will delete the following workout and all linked graph images:
<table width=100%>
<tr>
<th>Date:</th><td>{{ workout.date }}</td>
</tr><tr>
<th>Time:</th><td>{{ workout.starttime }}</td>
</tr><tr>
<th>Distance:</th><td>{{ workout.distance }}m</td>
</tr><tr>
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
</tr>
</table>
<div class="grid_2 alpha">
<p>
<a class="button green small" href="/rowers/dashboard/">Cancel</a>
</div>
<div class="grid_2">
<p>
<a class="button red small" href="/rowers/workout/{{ workout.id }}/delete">Delete</a>
</p>
</div>
</div>
<div id="images" class="grid_6 omega">
<p>
&nbsp;
</b>
</div>
{% endblock %}

View File

@@ -1,85 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}View Workout {% endblock %}
{% block content %}
<script type="text/javascript" src="/static/js/bokeh-0.11.1.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, false, false);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="title" class="grid_12 alpha">
<h1>Indoor Rower Power Histogram</h1>
</div>
<div id="summary" class="grid_6 alpha">
<p>Summary for {{ theuser.first_name }} {{ theuser.last_name }}
between {{ startdate|date }} and {{ enddate|date }}</p>
<p>Direct link for other Pro users:
<a href="/rowers/{{ id }}/histo/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}">http://rowsandall.com/rowers/{{ id }}/histo/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}</a>
</p>
</div>
<div id="form" class="grid_6 omega">
<p>Use this form to select a different date range:</p>
<p>
Select start and end date for a date range:
<div class="grid_4 alpha">
<form enctype="multipart/form-data" action="" method="post">
<table>
{{ form.as_table }}
</table>
{% csrf_token %}
</div>
<div class="grid_2 omega">
<input name='daterange' class="button green" type="submit" value="Submit"> </form>
</div>
<div class="grid_4 alpha">
<form enctype="multipart/form-data" action="" method="post">
Or use the last {{ deltaform }} days.
</div>
<div class="grid_2 omega">
{% csrf_token %}
<input name='datedelta' class="button green" type="submit" value="Submit">
</form>
</div>
</div>
<div id="graph" class="grid_12 alpha">
{{ the_div|safe }}
</div>
{% endblock %}

View File

@@ -1,53 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}View Workout {% endblock %}
{% block content %}
<script type="text/javascript" src="/static/js/bokeh-0.11.1.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, false, false);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="workouts" class="grid_12 alpha">
<h1>Indoor Rower Power Histogram</h1>
<p>Summary of the past 12 months for {{ theuser.first_name }} {{ theuser.last_name }}</p>
<p>Direct link for other Pro users:
<a href="/rowers/{{ id }}/histo-all">http://rowsandall.com/rowers/{{ id }}/histo-all</a>
</p>
{{ the_div|safe }}
</div>
{% endblock %}

View File

@@ -1,64 +0,0 @@
{% extends "base.html" %}
{% block title %}Contact Us{% endblock title %}
{% block content %}
<div class="grid_6 alpha">
<h3>Import Workouts</h2>
<div class="grid_6">
<div class="grid_3 alpha">
<p>
<a href="/rowers/workout/stravaimport"><img src="/static/img/stravalogo.png" alt="strava logo" width="140"></a>
</p>
</div>
<div class="grid_3 omega">
<p>Import workouts from Strava</p>
</div>
</div>
<div class="grid_6">
<div class="grid_3 alpha">
<p>
<a href="/rowers/workout/c2import"><img src="/static/img/blueC2logo.png" alt="Concept2 logo" width="140"></a>
</p>
</div>
<div class="grid_3 omega">
<p>Import workouts from the Concept2 logbook</p>
</div>
<div class="grid_3 alpha">
<p>
<a href="/rowers/workout/sporttracksimport"><img src="/static/img/sporttracks-button.png" alt="SportTracks logo" width="140"></a>
</p>
</div>
<div class="grid_3 omega">
<p>Import workouts from SportTracks</p>
</div>
</div>
</div>
<div class="grid_6 omega">
<h3>Connect</h3>
<div class="grid_6">
<p>Click one of the below logos to connect to the service of your choice.
You only need to do this once. After that, the site will have access until you
revoke the authorization for the "rowingdata" app.</p>
<div class="grid_2 alpha">
<p><a href="/rowers/me/stravaauthorize/"><img src="/static/img/ConnectWithStrava.png" alt="connect with strava" width="120"></a></p>
</div>
<div class="grid_2">
<p><a href="/rowers/me/c2authorize/"><img src="/static/img/blueC2logo.png" alt="connect with Concept2" width="120"></a></p>
</div>
<div class="grid_2 omega">
<p><a href="/rowers/me/sporttracksauthorize/"><img src="/static/img/sporttracks-button.png" alt="connect with SportTracks" width="120"></a></p>
</div>
</div>
</div>
{% endblock content %}

View File

@@ -1,3 +0,0 @@
graph = {{ my_data|safe }};
mpld3.draw_figure("fig01", graph);

View File

@@ -1,68 +0,0 @@
{% extends "base.html" %}
{% block title %}About us{% endblock title %}
{% block content %}
<div class="grid_6 alpha">
<h2>Introduction</h2>
<p>This is a solution for the self-tracking rowers.</p>
<p>Some of us use Concept2 rowing machines. Some of us are On-The-Water
rowers. All of us will use smartphone apps, smart watches, fitness (GPS)
watches, etc. to track our activities.</p>
<p>Most of them will cross-train. Bike. Run. Skate.</p>
<p>That means, the Concept2 logbook is not a sufficient training logbook for us.</p>
<p>At the same time, the Concept2 logbook is used in rankings, for challenges,
and more. Many of us will want to log all our rowing on the Concept2 logbook.</p>
<p>So there are a couple of challenges here:</p>
<ul>
<li><p>How do I get my erg rows on Strava/SportTracks/Garmin Connect?</p>
<blockquote>
<ul>
<li>Use an ANT+ device, like explained here: <a href="https://dr3do.wordpress.com/2015/07/09/hurray/" rel="nofollow">https://dr3do.wordpress.com/2015/07/09/hurray/</a></li>
<li>Import from RowPro to SportTracks</li>
<li>There are many smartphone apps to capture data from the PM3/4/5 erg monitor. Not many of them export in a format that is suitable for upload to the above-mentioned sites.</li>
</ul>
</blockquote>
</li>
<li><p>How do I get all my rows (including OTW) into the Concept2 logbook</p>
<blockquote>
<ul>
<li>For On-Water and Erg: Add them manually</li>
<li>For erg: Upload from ErgData, RowPro, Concept2 utility</li>
</ul>
</blockquote>
</li>
</ul>
<p>This project aims at giving you ways to:</p>
<ul>
<li><p>Upload fitness data captured in TCX format to the Concept2 logbook (implemented)</p>
<blockquote>
<ul>
<li>This should cover all your On-Water activities, whether they are captured with a SpeedCoach, a GPS fitness watch, your phone, or any other device. As long as you are able to export a valid TCX file.</li>
</ul>
</blockquote>
</li>
<li><p>Get erg data captured with apps that have no <q>upload to Concept2</q> functionality and upload them to the Concept2 logbook (implemented)</p>
<blockquote>
<ul>
<li>For example: painsled</li>
</ul>
</blockquote>
<li><p>Create useful plots. Who wants to be limited to what the on-line logbooks plot. Get your data and create:</p>
<blockquote>
<ul>
<li>Color HR band charts or Pie Charts (implemented)</li>
<li>Plot drive length, drive time, and other erg related parameters as a function of time or distance (to be implemented)</li>
</ul>
</blockquote>
</li>
</ul>
</div>
<div class="grid_6 omega">
<h2>Credits</h2>
<p>The project is based on python plotting code by
Greg Smith (<a href="https://quantifiedrowing.wordpress.com/" rel="nofollow">https://quantifiedrowing.wordpress.com/</a>)
and inspired by the RowPro Dan Burpee spreadsheet
(<a href="http://www.sub7irc.com/RP_Split_Template.zip" rel="nofollow">http://www.sub7irc.com/RP_Split_Template.zip</a>).</p>
</div>
{% endblock content %}

View File

@@ -1,54 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Graphs{% endblock %}
{% block content %}
<h1>Recent Graphs</h1>
{% if graphs1 %}
<div class="grid_1 alpha">
<p>&nbsp;</p>
</div>
{% for graph in graphs1 %}
<div id="thumb-container" class="grid_2">
<a href="/rowers/graph/{{ graph.id }}/">
<img src="/{{ graph.filename }}"
onerror="this.src='/static/img/waiting.png'"
alt="{{ graph.filename }}" width="120" height="100"></a>
</div>
{% endfor %}
<div class="grid_1 omega">
<p>&nbsp;</p>
</div>
<div class="grid_12">
<p>&nbsp;</p>
</div>
<div class="grid_1 alpha">
<p>&nbsp;</p>
</div>
{% for graph in graphs2 %}
<div id="thumb-container" class="grid_2">
<a href="/rowers/graph/{{ graph.id }}/">
<img src="/{{ graph.filename }}"
onerror="this.src='/static/img/waiting.png'"
alt="{{ graph.filename }}" width="120" height="100"></a>
</div>
{% endfor %}
<div class="grid_1 omega">
<p>&nbsp;</p>
</div>
{% else %}
<p> No graphs found </p>
{% endif %}
{% endblock %}

View File

@@ -1,52 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Workouts{% endblock %}
{% block content %}
<h1>My Workouts</h1>
{% if workouts %}
<table width="70%" class="listtable">
<thead>
<tr>
<th> Date</th>
<th> Time</th>
<th> Name</th>
<th> Type</th>
<th> Distance </th>
<th> Duration </th>
<th> Avg HR </th>
<th> Max HR </th>
<th> Delete</th>
<th> Export</th>
</tr>
</thead>
</tbody>
{% for workout in workouts %}
<tr>
<td> {{ workout.date }} </td>
<td> {{ workout.starttime }} </td>
<td>
{% if user.rower.rowerplan == 'pro' %}
<a href="/rowers/workout/{{ workout.id }}/edit">{{ workout.name }}</a> </td>
{% else %}
<a href="/rowers/workout/{{ workout.id }}/edit">{{ workout.name }}</a> </td>
{% endif %}
<td> {{ workout.workouttype }} </td>
<td> {{ workout.distance }}m</td>
<td> {{ workout.duration |durationprint:"%H:%M:%S.%f" }} </td>
<td> {{ workout.averagehr }} </td>
<td> {{ workout.maxhr }} </td>
<td> <a class="button red small" href="/rowers/workout/{{ workout.id }}/deleteconfirm">Delete</td>
<td> <a class="button blue small" href="/rowers/workout/{{ workout.id }}/export">Export</a> </td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p> No workouts found </p>
{% endif %}
{% endblock %}

View File

@@ -1,26 +0,0 @@
<html>
<head>
<title>Login Form</title>
</head>
<body>
<h1>Login</h1>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
<table class="formtable">
{{ form.as_table }}
</table>
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}">
<input type="submit" value="Submit">
</form>
<p>
<a href="/rowers/register">register</a>
</p>
</body>
</html>

View File

@@ -1,162 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Advanced Features {% endblock %}
{% block content %}
<div id="workouts" class="grid_6 alpha">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<h1>Advanced OTW features</h1>
{% if user.rower.rowerplan == 'basic' %}
<p>This is a preview of the page with advanced functionality for Pro users. See <a href="/rowers/about">the About page</a> for more information and to sign up for Pro Membership</a>
{% endif %}
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/advanced">Advanced Edit</a>
</p>
</div>
<div class="grid_2 omega">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/export">Export</a>
</p>
</div>
<div class="grid_6 alpha">
<table width=100%>
<tr>
<th>Date:</th><td>{{ workout.date }}</td>
</tr><tr>
<th>Time:</th><td>{{ workout.starttime }}</td>
</tr><tr>
<th>Distance:</th><td>{{ workout.distance }}m</td>
</tr><tr>
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
</tr>
<th>Public link to this workout</th>
<td>
<a href="/rowers/workout/{{ workout.id }}">http://rowsandall.com/rowers/workout/{{ workout.id }}</a>
<td>
</table>
</div>
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
{% if user.rower.rowerplan == 'pro' %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/wind">Edit Wind Data</a>
{% else %}
<a class="button blue small" href="/rowers/about">Edit Wind Data</a>
{% endif %}
</p>
<p>
Add wind data for OTW workouts
</p>
</div>
<div class="grid_2">
<p>
{% if user.rower.rowerplan == 'pro' %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/stream">Edit Stream Data</a>
{% else %}
<a class="button blue small" href="/rowers/about">Edit Stream Data</a>
{% endif %}
</p>
<p>
For river dwellers. Add stream information.
</p>
</div>
<div class="grid_2 omega">
<p>
{% if user.rower.rowerplan == 'pro' %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/otwsetpower">OTW Power</a>
{% else %}
<a class="button blue small" href="/rowers/about">OTW Power</a>
{% endif %}
</p>
<p>
Run OTW Power calculations (wind & stream correction, equivalent erg pace)
</p>
</div>
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
{% if user.rower.rowerplan == 'pro' %}
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/interactiveotwplot">Corrected Pace Plot</a>
{% else %}
<a class="button blue small" href="/rowers/about">Corrected Pace Plot</a>
{% endif %}
</p>
<p>
Wind and Stream corrected pace plots will be here.
</p>
</div>
<div class="grid_2 suffix_2 omega">
<p>
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/interactiveplot">Big Interactive Plot</a>
</p>
<p>
See (and save) the big interactive plot
</p>
</div>
</div>
</div>
</div>
<div id="advancedplots" class="grid_6 omega">
<div class="grid_6 alpha">
<script type="text/javascript" src="/static/js/bokeh-0.11.1.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, true, true);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="interactiveplot" class="grid_6 omega">
{{ the_div |safe }}
</div>
</div>
{% endblock %}

View File

@@ -1,80 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}View Workout {% endblock %}
{% block content %}
<script type="text/javascript" src="/static/js/bokeh-0.11.1.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, false, false);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="workouts" class="grid_12 alpha">
<h1>Interactive Plot</h1>
{% if user.is_authenticated and mayedit %}
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/advanced">Advanced Edit</a>
</p>
</div>
<div class="grid_2">
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/wind">Edit Wind Data</a>
</div>
<div class="grid_2">
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/stream">Edit Stream Data</a>
</div>
<div class="grid_2">
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/otwsetpower">OTW Power</a>
</div>
{% endif %}
{{ the_div|safe }}
<p>
<h3>Notes</h3>
<ul>
<li>Is your erg pace slower than you expected? This may be a sign of room for improvement regarding your technique. An alternative explanation is that your team mates are fatter than they told you! For example, put 80.0 kg if your four consists of 2 70kg guys and 2 90kg guys.</li>
<li>In order to speed up the calculation, we are running the calculation only for every 10th datapoint, using interpolation in between. Some very fine pace shifts may disappear.</li>
<li>While the wind and stream correction is fairly reliable, the OTW to OTE conversion sometimes throws errors. Those data points are omitted and replaced by interpolated values. We are sorry if this messed up some of your plots.</li>
<li>Read more details about the way we calculate things <a href="/rowers/physics"</a>here</a>.</li>
</ul>
</p>
</div>
{% endblock %}

View File

@@ -1,58 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Advanced Features {% endblock %}
{% block content %}
<div id="workouts" class="grid_6 alpha">
<h1>Run OTW Power Calculations</h1>
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2 suffix_2 omega">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/advanced">Advanced Edit</a>
</p>
</div>
<div class="grid_6 alpha">
<p>
For the advanced OTW power and wind correction calculation,
we need to know the boat type and the average weight per crew member.
Currently only 1x (single) is implemented. Setting the value to
2x (double) will still run the calculations for a single.
We use FISA minimum boat weight and standard rigging for our calculations.
</p>
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<table>
{{ form.as_table }}
</table>
{% csrf_token %}
</div>
<div id="formbutton" class="grid_2 prefix_2 suffix_2">
<input class="button green" type="submit" value="Update & Run">
</div>
</form>
</div>
<div id="advancedplots" class="grid_6 omega">
<img src="/static/img/rivercurrent.jpg" width="400">
The Rowsandall Physics Department at work.
</div>
{% endblock %}

View File

@@ -1,155 +0,0 @@
{% extends "base.html" %}
{% block title %}About us{% endblock title %}
{% block content %}
<div class="grid_6 alpha">
<h3>How we calculate things</h3>
<p>You are reading this because you want to understand how the wind/stream conversion and the conversion from OTW pace to OTE pace works.</p>
<p>The conversions are done using a one-dimensional mechanical model that is
introduced <a href="https://sanderroosendaal.wordpress.com/index/">here</a>.
The model takes into account, among others, the following parameters:
<ul>
<li>Stroke rate</li>
<li>Stroke length</li>
<li>Rigging parameters</li>
<li>Rower and boat weight</li>
</ul>
For this site, we use "standard" rigging parameters, blade shapes, and FISA minimum boat weights. For the eight, I add the weight of a cox (at the FISA minimum weight). The stroke length is also set at a fixed value, but in the future I
will allow you to adjust to your own stroke length.
</p>
<p>
Knowing boat type (rigging), pace and stroke rate, and taking into account
the influence of wind and stream (if provided), I am able to find the
mechanical power that you provide to the rowing system by a reverse
calculation. That is, I vary the input force until I find the one that
corresponds to your actual pace at that stroke rate.
</p>
<p>
Knowing the power, I can calculate how fast you would have gone without
external wind and stream influences by running the calculation in a forward
way, using the power and force profile found. This is the wind/stream
corrected pace, which I think is useful to know and be able to compare
from training to training and between different rowing venues.
</p>
<p>
Using another algorithm to calculate total mechanical power on an erg, I can
calculate what the erg display would show you if you rowed on the erg with
the same average power, at the same stroke rate. The calculations are done
for a statical Concept2 erg with a fairly standard drag factor. I cannot
take into account the fact that you may use different technique or would
row at a different stroke rate on the erg.
</p>
<p>
It is important to understand that the Power display on the erg is not showing
you the complete picture. In my calculations, I use my proprietary algorithms
to calculate the additional power that goes into moving your body weight up
and down the slide on a static erg. To get the most accurate results, it is
important to be honest about your weight and set it independently for each
workout.
</p>
<p>Not taken into account are the following factors:
<ul>
<li>Water Temperature</li>
<li>Heavier/shorter/wider boats than the ones used by the elite</li>
<li>Bungees, weed, or other artefacts slowing down the boat</li>
<li>Boat stopping technique flaws</li>
<li>Effect of wave height or cross-wind</li>
</ul>
The water temperature has a small but measurable effect on the water density
(and thus on the drag). I am using the value at 20 degrees C, which is a
good average over the OTW season for a lake in a temperate climate. All
the other elements result in an equivalent erg pace that is probably slower
than what you can achieve on the erg. So look at it as an incentive to
improve your technique (big effect) and/or buy a faster boat (minor effect).
If your OTW to OTE pace conversion results in numbers close to what you
normally achieve on the erg, you are rowing like an elite rower (but possibly
at a lower power)!
</p>
<p>
I have checked the model both from a Physics perspective (I have a degree in
Physics, if you are interested) and compared with the data available.
An important data set has been published <a href="http://www.biorow.com/RBN_en_2007_files/App2007RowBiomNews08.pdf">here</a> by Dr Kleshnev. For sculling,
my algorithms are extremely close in reproducing that data set. For sweep
rowing, I am still fine tuning some parameters, but I am close for a pair and
a four. I had to make assumptions about Kleshnev's data, especially about the
stroke rate, but as I got realistic stroke rates (35 and higher) for world
record performance, I am quite confident.
</p>
<p>
On top of that I am constantly comparing the model's results to my own sculling
and rowing, and I will be the first to admit flaws and correct them. So please
contact me if there are any inconsistencies, suspicions, questions or simply
if you want to chat about Rowing Physics.
</p>
</div>
<div class="grid_6 omega">
<h3>Manual</h3>
<p>Here's the best way - in my mind - to use the Rowing Physics
functionality. I am assuming you have successfully uploaded or imported
a rowing workout. You must have position data (lat/long) with your row. A
TCX from CrewNerd or RiM or a workout imported from SportTracks or Strava
(where you see a map of your workout on those sites) should have those
data. I am working on adding the FIT file format that is used by SpeedCoach
GPS. For now, export the data to Strava and then import them here.
</p>
<p>Recipe for success:
<ol>
<li>Click on the workout. This will bring you to the workout Edit view</li>
<li>Click on the "Advanced" button</li>
<li>Click on Edit Wind Data (optional) to edit wind data. Go back to Advanced when you're done.</li>
<li>Click on Edit Stream Data (optional) to edit stream data. Go back to Advanced when you're done.</li>
<li>Click on OTW Power</li>
<li>Select the boat type and enter the average weight per crew member.
Do not use the crew total weight.</li>
<li>Click "Update & Run"</li>
<li>Go do something else. You will receive an email when the calculations are finished. The calculation itself will take about 10 minutes for an
hour long row, but there may be other people's calculations in the queue, so
it may take longer.</li>
<li>From the "Advanced" view, click on "Corrected Pace Plot" to see the result. From here, you can re-run the calculation with different parameters.</li>
</ol>
</p>
<p>
Once you have run the calculation, the boat type, average crew weight,
Power and corrected pace data are stored permanently on the site. If you would
export the data to Strava or SportTracks now, those sites will have the
Power data.
</p>
<h3>Why does the calculation take so much time?</h3>
<p>I am running the calculations from a first principles base, so for
each data point that I am calculating, I am finding the stroke average
force, then calculating corrected pace (wind/stream) and finding the
corresponding erg power. I am not taking any shortcuts. The advantage
of this approach is that I can give you numbers irrespective of your
weight, speed, stroke rate, sex, etc. The model can deal with circumstances
it has not encountered before. The downside is that it takes time.</p>
<p>
A much faster approach would be to simply take pre-calculated data from
a table and interpolate. The advantage of this approach is is speed. The
disadvantage is that extrapolation outside the limits of the available
data is dangerous and will lead to erroneous results.</p>
<p>Future versions of this site will use a hybrid approach
but only for pace/wind/stream/stroke rate/weight combinations that I consider
well validated. For that, I need to collect data, so keep the workouts coming!
</p>
<img src="/static/img/validation.png" width="450">
</div>
{% endblock content %}

View File

@@ -1,122 +0,0 @@
{% extends "base.html" %}
{% block title %}About us{% endblock title %}
{% block content %}
<div class="grid_6 alpha">
<h2>Introduction</h2>
<p>This is a solution for the self-tracking rowers.</p>
<p>Some of us use Concept2 rowing machines. Some of us are On-The-Water
rowers. All of us will use smartphone apps, smart watches, fitness (GPS)
watches, etc. to track our activities.</p>
<p>Most of them will cross-train. Bike. Run. Skate.</p>
<p>That means, the Concept2 logbook is not a sufficient training logbook for us.</p>
<p>At the same time, the Concept2 logbook is used in rankings, for challenges,
and more. Many of us will want to log all our rowing on the Concept2 logbook.</p>
<p>So there are a couple of challenges here:</p>
<ul>
<li><p>How do I get my erg rows on Strava/SportTracks/Garmin Connect?</p>
<blockquote>
<ul>
<li>Use an ANT+ device, like explained here: <a href="https://dr3do.wordpress.com/2015/07/09/hurray/" rel="nofollow">https://dr3do.wordpress.com/2015/07/09/hurray/</a></li>
<li>Import from RowPro to SportTracks</li>
<li>There are many smartphone apps to capture data from the PM3/4/5 erg monitor. Not many of them export in a format that is suitable for upload to the above-mentioned sites.</li>
</ul>
</blockquote>
</li>
<li><p>How do I get all my rows (including OTW) into the Concept2 logbook</p>
<blockquote>
<ul>
<li>For On-Water and Erg: Add them manually</li>
<li>For erg: Upload from ErgData, RowPro, Concept2 utility</li>
</ul>
</blockquote>
</li>
</ul>
<p>This project aims at giving you ways to:</p>
<ul>
<li><p>Upload fitness data captured in TCX format to the Concept2 logbook (implemented)</p>
<blockquote>
<ul>
<li>This should cover all your On-Water activities, whether they are captured with a SpeedCoach, a GPS fitness watch, your phone, or any other device. As long as you are able to export a valid TCX file.</li>
</ul>
</blockquote>
</li>
<li><p>Get erg data captured with apps that have no <q>upload to Concept2</q> functionality and upload them to the Concept2 logbook (implemented)</p>
<blockquote>
<ul>
<li>For example: painsled</li>
</ul>
</blockquote>
<li><p>Create useful plots. Who wants to be limited to what the on-line logbooks plot. Get your data and create:</p>
<blockquote>
<ul>
<li>Color HR band charts or Pie Charts (implemented)</li>
<li>Plot drive length, drive time, and other erg related parameters as a function of time or distance (to be implemented)</li>
</ul>
</blockquote>
</li>
</ul>
</div>
<div class="grid_6 omega">
<div class="grid_6">
<h2>Credits</h2>
<p>The project is based on python plotting code by
Greg Smith (<a href="https://quantifiedrowing.wordpress.com/" rel="nofollow">https://quantifiedrowing.wordpress.com/</a>)
and inspired by the RowPro Dan Burpee spreadsheet
(<a href="http://www.sub7irc.com/RP_Split_Template.zip" rel="nofollow">http://www.sub7irc.com/RP_Split_Template.zip</a>).</p>
</div>
<div class="grid_6">
<h2>Pro Membership</h2>
<p>Donations are welcome to keep this web site going. To help cover the hosting
costs, I have created a <q>Pro</q> membership option (for only 5 EURO per year). Once I process your
donation, I will give you access to some <q>special</q> features on this
website. </p>
<p>These features are currently under development. The current Pro membership
gives you access to a big interactive chart and a stroke metrics plot. In the near future, I am planning to add:</p>
<ul>
<li>More stroke metrics plots</li>
<li>Power curves for OTW rowing</li>
<li>Compare OTW with OTE rows</li>
</ul>
<p>Click on the PayPal button to pay for your Pro membership. It will be valid for one year with automatic renewal which you can stop at any time.
You will be taken to the secure PayPal payment site.
<ul>
<li>Please mention the username you are registered under in "instructions to seller".</li>
</ul>
</p>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="964GLEXX3THAW">
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_subscribeCC_LG_global.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online.">
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
</form>
<h2>What's new?</h2>
<p>
<ul>
<li>2016-09-20 Added the Power histogram</li>
<li>2016-08-31 Added the Ranking Piece summary and pace predictor</li>
<li>2016-08-02 Added support for the SpeedCoach GPS 2 CSV/FIT file export</li>
<li>2016-07-19 Added the possibility to download wind data from <a href="http://forecast.io">The Dark Sky / Forecast.io</a></li>
<li>2016-07-19 New Flexible interactive charts for OTE and OTW (pick your own axes parameters)</li>
<li>2016-07-07 Wind and Stream corrections for OTW (Pro functionality)</li>
<li>2016-06-23 Pro users can now compare workouts</li>
<li>2016-06-20 Fixed Strava upload and added SportTracks import and export. The export is not working reliably. We are debugging this,</li>
<li>2016-06-08 Added possibility to upload CrewNerd summary CSV file for Pro Members</li>
<li>2016-06-08 Added workout summaries</li>
<li>2016-06-05 Export to Strava is working</li>
<li>2016-06-01 We're approved on the Concept2 logbook!!!!
</ul>
</p>
</div>
</div>
{% endblock content %}

View File

@@ -1,227 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Workouts{% endblock %}
{% block content %}
<script type="text/javascript" src="/static/js/bokeh-0.11.1.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, true, false);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="title" class="grid_12 alpha">
<h1>Ranking Pieces (Indoor Rower)</h1>
</div>
<div id="summary" class="grid_6 alpha">
<p>Summary for {{ theuser.first_name }} {{ theuser.last_name }}
between {{ startdate|date }} and {{ enddate|date }}</p>
<p>Direct link for other users:
<a href="/rowers/{{ id }}/ote-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}">http://rowsandall.com/rowers/{{ id }}/ote-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}</a>
</p>
<p>The table gives the best efforts achieved on the official Concept2 ranking pieces in the selected date range.</p>
<p>This page will evolve and try to give you guidance on where to improve.</p>
</div>
<div id="form" class="grid_6 omega">
<p>Use this form to select a different date range:</p>
<p>
Select start and end date for a date range:
<div class="grid_4 alpha">
<form enctype="multipart/form-data" action="" method="post">
<table>
{{ dateform.as_table }}
</table>
{% csrf_token %}
</div>
<div class="grid_2 omega">
<input name='daterange' class="button green" type="submit" value="Submit"> </form>
</div>
<div class="grid_4 alpha">
<form enctype="multipart/form-data" action="" method="post">
Or use the last {{ deltaform }} days.
</div>
<div class="grid_2 omega">
{% csrf_token %}
<input name='datedelta' class="button green" type="submit" value="Submit">
</form>
</div>
</div>
<div class="grid_12 alpha">
<h2>Ranking Piece Results</h2>
{% if rankingworkouts %}
<table width="70%" class="listtable">
<thead>
<tr>
<th> Distance</th>
<th> Duration</th>
<th> Date</th>
<th> Avg HR </th>
<th> Max HR </th>
<th> Edit</th>
<tr>
</thead>
<tbody>
{% for workout in rankingworkouts %}
<tr>
<td> {{ workout.distance }} </td>
<td> {{ workout.duration |durationprint:"%H:%M:%S.%f" }} </td>
<td> {{ workout.date }} </td>
<td> {{ workout.averagehr }} </td>
<td> {{ workout.maxhr }} </td>
<td>
<a href="/rowers/workout/{{ workout.id }}/edit">{{ workout.name }}</a> </td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p> No ranking workouts found </p>
{% endif %}
</div>
<div id="theplot" class="grid_12 alpha">
<h2>Critical Power Plot</h2>
{{ the_div|safe }}
</div>
<div id="predictions" class="grid_12 alpha">
<h2>Pace predictions for Ranking Pieces</h2>
<p>Add non-ranking piece using the form. The piece will be added in the prediction tables below. </p>
<div class="grid_4 alpha">
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
{{ form.value }} {{ form.pieceunit }}
{% csrf_token %}
</div>
<div class="grid_2 suffix_6 omega">
<input name="piece" class="button green"
formaction="/rowers/{{ id }}/ote-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}"
type="submit" value="Add">
</form>
</div>
<div id="paul" class="grid_6 alpha">
<h3>Paul's Law</h3>
{% if nrdata >= 1 %}
<table width="70%" class="listtable">
<thead>
<tr>
<th> Duration</th>
<th> Distance</th>
<th> Power </th>
<th> Pace </th>
<tr>
</thead>
<tbody>
{% for pred in predictions %}
<tr>
{% for key, value in pred.items %}
{% if key == "distance" %}
<td> {{ value }} m </td>
{% endif %}
{% if key == "pace" %}
<td> {{ value |durationprint:"%M:%S.%f" }} </td>
{% endif %}
{% if key == "power" %}
<td> {{ value }} W </td>
{% endif %}
{% if key == "duration" %}
<td> {{ value |durationprint:"%H:%M:%S.%f" }} </td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>Insufficient data to make predictions</p>
{% endif %}
</div>
<div id="cpmodel" class="grid_6 omega">
<h3>CP Model</h3>
{% if nrdata >= 4 %}
<table width="70%" class="listtable">
<thead>
<tr>
<th> Duration</th>
<th> Distance</th>
<th> Power </th>
<th> Pace </th>
<tr>
</thead>
<tbody>
{% for pred in cpredictions %}
<tr>
{% for key, value in pred.items %}
{% if key == "distance" %}
<td> {{ value }} m </td>
{% endif %}
{% if key == "pace" %}
<td> {{ value |durationprint:"%M:%S.%f" }} </td>
{% endif %}
{% if key == "power" %}
<td> {{ value }} W </td>
{% endif %}
{% if key == "duration" %}
<td> {{ value |durationprint:"%H:%M:%S.%f" }} </td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>Insufficient data to make predictions</p>
{% endif %}
</div>
</div>
{% endblock %}

View File

@@ -1,25 +0,0 @@
{% extends "base.html" %}
{% block title %}Contact Us{% endblock title %}
{% block content %}
<div id="registrationform" class="grid_6 alpha">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form enctype="multipart/form-data" action="" method="post">
{% csrf_token %}
<table width=100%>
{{ form.as_table }}
</table>
<a href="/rowers/legal">Terms of Service</a>
<div id="formbutton" class="grid_1 prefix_4 suffix_1">
<input class="button green" type="submit" value="Submit">
</div>
</form>
</div>
{% endblock content %}

View File

@@ -1,34 +0,0 @@
{% extends "base.html" %}
{% block title %}Change Rower {% endblock %}
{% block content %}
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<div class="grid_6 alpha">
<h1>Edit your Parameters</h1>
<form enctype="multipart/form-data" action="" method="post">
<table>
{{ form.as_table }}
</table>
{% csrf_token %}
<div class="grid_2 prefix_2 suffix_2">
<input type="submit" value="Save">
</div>
</div>
<div class="grid_6 omega">
<h1>Tokens etcetera</h1>
<p>
<table>
<tr>
<th>Concept2 sync issues? Click:</th><td><a href="/rowers/me/c2refresh/"><img src="/static/img/blueC2logo.png" alt="Concept2 logo" width="140"></a></td>
</tr>
</table>
</p>
</div>
{% endblock %}

View File

@@ -1,14 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% block title %}{{ workout.name }}{% endblock %}
{% block content %}
<h1>{{ workout.name }}</h1>
<p>
<a href="/{{ graph.filename }}" download="myimage">
<image src="/{{ graph.filename }}" alt="/{{ graph.filename }}" width="960"/>
</a>
</p>
{% endblock %}

View File

@@ -1,15 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Experiment with Bokeh</title>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-0.8.1.min.js"></script>
<link rel="stylesheet" href="http://cdn.pydata.org/bokeh/release/bokeh-0.8.1.min.css">
</head>
<body>
{{ the_div|safe }}
{{ the_script|safe }}
</body>
</html>

View File

@@ -1,52 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Workouts{% endblock %}
{% block content %}
<h1>Available on Strava</h1>
{% if data %}
<table width="70%" class="listtable">
<thead>
<tr>
<th> Import </th>
<th> Duration </th>
<th> Type</th>
<th> Date</th>
<th> Distance </th>
<th> Name</th>
</tr>
</thead>
<tbody>
{% for workout in data %}
<tr>
{% for key,value in workout.items %}
{% if key == "start_date" %}
<td>{{ value }}</td>
{% endif %}
{% if key == "name" %}
<td>{{ value }}</td>
{% endif %}
{% if key == "type" %}
<td>{{ value }}</td>
{% endif %}
{% if key == "distance" %}
<td>{{ value }}m</td>
{% endif %}
{% if key == "elapsed_time" %}
<td>{{ value }}</td>
{% endif %}
{% if key == "id" %}
<td><a href="/rowers/workout/stravaimport/{{ value }}/">Import</a></td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p> No workouts found </p>
{% endif %}
{% endblock %}

View File

@@ -1,48 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Workouts{% endblock %}
{% block content %}
<h1>Available on Strava</h1>
{% if data %}
<table width="70%" class="listtable">
<thead>
<tr>
<th> Import </th>
<th> Duration </th>
<th> Type</th>
<th> Date</th>
<th> Distance </th>
</tr>
</thead>
<tbody>
{% for workout in data %}
<tr>
{% for key,value in workout.items %}
{% if key == "start_date" %}
<td>{{ value }}</td>
{% endif %}
{% if key == "type" %}
<td>{{ value }}</td>
{% endif %}
{% if key == "distance" %}
<td>{{ value }}m</td>
{% endif %}
{% if key == "elapsed_time" %}
<td>{{ value }}</td>
{% endif %}
{% if key == "id" %}
<td><a href="/rowers/workout/stravaimport/{{ value }}/">Import</a></td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p> No workouts found </p>
{% endif %}
{% endblock %}

View File

@@ -1,89 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Advanced Features {% endblock %}
{% block content %}
<div id="workouts" class="grid_6 alpha">
<h1>Stream Editor</h1>
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/advanced">Advanced Edit</a>
</p>
</div>
<div class="grid_2 omega tooltip">
<p><a class="button blue small" href="/rowers/workout/{{ workout.id }}/otwsetpower">OTW Power</a></p>
<span class="tooltiptext">Run calculations to get power values for your row.</span>
</div>
<div class="grid_6 alpha">
<p>
Edit river Stream between turning points in your row.
Use positive (+) values to denote rowing with the stream,
negative (-) values to denote rowing against the stream.
</p>
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<table>
{{ form.as_table }}
</table>
{% csrf_token %}
</div>
<div id="formbutton" class="grid_1 prefix_3 suffix_2">
<input class="button green" type="submit" value="Update">
</div>
</form>
<img src="/static/img/rivercurrent.jpg" width="400">
</div>
<div id="advancedplots" class="grid_6 omega">
<script type="text/javascript" src="/static/js/bokeh-0.11.1.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, true, true);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="interactiveplot" class="grid_6 omega">
{{ the_div |safe }}
</div>
{% endblock %}

View File

@@ -1,203 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% load tz %}
{% block title %}Change Workout {% endblock %}
{% block content %}
<div id="workouts" class="grid_6 alpha">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<h1>Edit Workout Interval Data</h1>
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/edit">Edit</a>
</p>
</div>
<div class="grid_2">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/export">Export</a>
</p>
</div>
<div class="grid_2 omega tooltip">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/advanced">Advanced</a>
</p>
<span class="tooltiptext">Advanced Functionality (More interactive Charts)</span>
</div>
</div>
{% localtime on %}
<table width=100%>
<tr>
<th>Date/Time:</th><td>{{ workout.startdatetime }}</td>
</tr><tr>
<th>Distance:</th><td>{{ workout.distance }}m</td>
</tr><tr>
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
</tr><tr>
<th>Public link to this workout</th>
<td>
<a href="/rowers/workout/{{ workout.id }}">http://rowsandall.com/rowers/workout/{{ workout.id }}</a>
<td>
</tr><tr>
<th>Public link to interactive chart</th>
<td>
<a href="/rowers/workout/{{ workout.id }}/interactiveplot">http://rowsandall.com/rowers/workout/{{ workout.id }}/interactiveplot</a>
<td>
</tr>
</table>
{% endlocaltime %}
<h1>Interval Translator</h1>
<p>This is a quick way to enter the intervals using a special mini-language.</p>
<p>You enter something like <em>8x500m/3min</em>, press "Update" and the site will interpret this for you and update the summary on the right. If you're happy with the result, press the green Save button to update the values. Nothing will be changed permanently until you hit Save.</p>
<p>Special characters are <em>x</em> (times), <em>+</em> and <em>/</em> (denotes a rest interval), as well as <em>(</em> and <em>)</em>. Units are <em>min</em> (minutes), <em>sec</em> (seconds), <em>m</em> (meters) and <em>km</em> (km). </p>
<p>A typical interval is described as "<b>10min/5min</b>", with the work part before the "<b>/</b>" and the rest part after it. A zero rest can be omitted, so a single 1000m piece could be described either as "<b>1km</b>" or "<b>1000m</b>". The basic units can be combined with "<b>+</b>" and "<b>Nx</b>". You can use parentheses as in the example below.</p>
<p>Here are a few examples.</p>
<table class="listtable" width=100%>
<tr>
<td>8x500m/2min</td><td>8 times 500m with 2 minutes rest</td>
</tr>
<tr>
<td>10km</td><td>Single distance of 10km</td>
</tr>
<tr>
<td>6min/3min + 5min/3min + 3min/3min + 3min </td>
<td>Four intervals of 6, 5, 3 and 3 minutes length, 3 minutes rest</td>
</tr>
<tr>
<td>4x(500m+500m)/5min</td><td>4 times 1km, but each km is reported as two 500m intervals without rest</td>
</tr>
<tr>
<td>2x500m/500m</td><td>A 2k rowed as 500m "on", 500m "off"</td>
</tr>
</table>
<form enctype="multipart/form-data" action="/rowers/workout/{{ workout.id }}/editintervals" method="post">
<table width=100%>
{{ form.as_table }}
</table>
{% csrf_token %}
<div id="formbutton" class="grid_1 prefix_4 suffix_1">
<input class="button green" type="submit" value="Update">
</div>
</form>
</div>
<div id="advancedplots" class="grid_6 omega">
<div class="grid_6 alpha">
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, true, true);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="interactiveplot" class="grid_6 omega">
{{ the_div |safe }}
</div>
</div>
<div id="summary" class="grid_6 omega">
<h1>Updated Summary</h1>
<form enctype="multipart/form-data" action="/rowers/workout/{{ workout.id }}/editintervals/Interval%20Data%20Saved" method="post">
{% csrf_token %}
<input type="hidden" name="{{ savebutton }}" value={{ intervalstring }}>
<input type="hidden" name="nrintervals" value={{ nrintervals }}>
{% for field in detailform %}
{{ field.as_hidden }}
{% endfor %}
<div class="grid_1 alpha">
<input class="button green" type="submit" value="Save">
</div>
<div class="grid_2">
<a class="button green" href="">Reset to last saved</a>
</div>
<div class="grid_2 omega">
<a class="button green" href="/rowers/workout/{{ workout.id }}/restore">Restore Original data</a>
</div>
</form>
<div class="grid_6 alpha">
<p>
<pre>
{{ intervalstats }}
</pre>
</p>
</div>
</div>
<div id="summary" class="grid_6 omega">
<h1>Detailed Summary Edit</h1>
<p>This is still experimental and there are known bugs. Use at your own risk. Nothing is stored permanently until you hit Save on the summary above. You can use the restore original button to restore the original values.</p>
<div class="grid_6 alpha">
<div class="grid_1 alpha"><strong>#</strong></div>
<div class="grid_1">
<strong>Time</strong>
</div>
<div class="grid_1">
<strong>Distance</strong>
</div>
<div class="grid_1 suffix_2 omega">
<strong>Type</strong>
</div>
</div>
<form enctype="multipart/form-data" action="/rowers/workout/{{ workout.id }}/editintervals" method="post">
{% for i in nrintervals|times %}
<div class="grid_6 alpha">
<div class="grid_1 alpha">{{ i }}</div>
<div class="grid_1">
{% get_field_id i "intervalt_" detailform %}
</div>
<div class="grid_1">
{% get_field_id i "intervald_" detailform %}
</div>
<div class="grid_2 suffix_1 omega">
{% get_field_id i "type_" detailform %}
</div>
</div>
{% endfor %}
{% csrf_token %}
<div id="formbutton" class="grid_1 prefix_4 suffix_1">
<input type="hidden" name="nrintervals" value={{ nrintervals }}>
<input class="button green" type="submit" value="Update">
</div>
</form>
</div>
{% endblock %}

View File

@@ -1,54 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %} Flexible Plot {% endblock %}
{% block content %}
{{ js_res | safe }}
{{ css_res| safe }}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ the_script |safe }}
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="navigation" class="grid_12 alpha">
{% if user.is_authenticated and mayedit %}
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ id }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2 suffix_8 omega">
<p>
<a class="button gray small" href="/rowers/workout/{{ id }}/advanced">Advanced Edit</a>
</p>
</div>
{% endif %}
</div>
<p>&nbsp;</p>
<div id="theplot" class="grid_12 alpha">
{{ the_div|safe }}
</div>
{% endblock %}

View File

@@ -1,123 +0,0 @@
{% extends "base.html" %}
{% block title %}About us{% endblock title %}
{% block content %}
<div class="grid_6 alpha">
<h2>Introduction</h2>
<p>This is a solution for the self-tracking rowers.</p>
<p>Some of us use Concept2 rowing machines. Some of us are On-The-Water
rowers. All of us will use smartphone apps, smart watches, fitness (GPS)
watches, etc. to track our activities.</p>
<p>Most of them will cross-train. Bike. Run. Skate.</p>
<p>That means, the Concept2 logbook is not a sufficient training logbook for us.</p>
<p>At the same time, the Concept2 logbook is used in rankings, for challenges,
and more. Many of us will want to log all our rowing on the Concept2 logbook.</p>
<p>So there are a couple of challenges here:</p>
<ul>
<li><p>How do I get my erg rows on Strava/SportTracks/Garmin Connect?</p>
<blockquote>
<ul>
<li>Use an ANT+ device, like explained here: <a href="https://dr3do.wordpress.com/2015/07/09/hurray/" rel="nofollow">https://dr3do.wordpress.com/2015/07/09/hurray/</a></li>
<li>Import from RowPro to SportTracks</li>
<li>There are many smartphone apps to capture data from the PM3/4/5 erg monitor. Not many of them export in a format that is suitable for upload to the above-mentioned sites.</li>
</ul>
</blockquote>
</li>
<li><p>How do I get all my rows (including OTW) into the Concept2 logbook</p>
<blockquote>
<ul>
<li>For On-Water and Erg: Add them manually</li>
<li>For erg: Upload from ErgData, RowPro, Concept2 utility</li>
</ul>
</blockquote>
</li>
</ul>
<p>This project aims at giving you ways to:</p>
<ul>
<li><p>Upload fitness data captured in TCX format to the Concept2 logbook (implemented)</p>
<blockquote>
<ul>
<li>This should cover all your On-Water activities, whether they are captured with a SpeedCoach, a GPS fitness watch, your phone, or any other device. As long as you are able to export a valid TCX file.</li>
</ul>
</blockquote>
</li>
<li><p>Get erg data captured with apps that have no <q>upload to Concept2</q> functionality and upload them to the Concept2 logbook (implemented)</p>
<blockquote>
<ul>
<li>For example: painsled</li>
</ul>
</blockquote>
<li><p>Create useful plots. Who wants to be limited to what the on-line logbooks plot. Get your data and create:</p>
<blockquote>
<ul>
<li>Color HR band charts or Pie Charts (implemented)</li>
<li>Plot drive length, drive time, and other erg related parameters as a function of time or distance (to be implemented)</li>
</ul>
</blockquote>
</li>
</ul>
</div>
<div class="grid_6 omega">
<div class="grid_6">
<h2>Credits</h2>
<p>The project is based on python plotting code by
Greg Smith (<a href="https://quantifiedrowing.wordpress.com/" rel="nofollow">https://quantifiedrowing.wordpress.com/</a>)
and inspired by the RowPro Dan Burpee spreadsheet
(<a href="http://www.sub7irc.com/RP_Split_Template.zip" rel="nofollow">http://www.sub7irc.com/RP_Split_Template.zip</a>).</p>
</div>
<div class="grid_6">
<h2>Pro Membership</h2>
<p>Donations are welcome to keep this web site going. To help cover the hosting
costs, I have created a <q>Pro</q> membership option (for only 5 EURO per year). Once I process your
donation, I will give you access to some <q>special</q> features on this
website. </p>
<p>Currently, the Pro membership will give you the following extra functionality (and more will follow):
<ul>
<li>More stroke metrics plots</li>
<li>Power curves for OTW rowing</li>
<li>Power histogram</li>
</ul>
</p>
<p>Click on the PayPal button to pay for your Pro membership. It will be valid for one year with automatic renewal which you can stop at any time.
You will be taken to the secure PayPal payment site.
<ul>
<li>Please mention the username you are registered under in "instructions to seller".</li>
</ul>
</p>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="964GLEXX3THAW">
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_subscribeCC_LG_global.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online.">
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
</form>
<h2>What's new?</h2>
<p>
<ul>
<li>2016-09-30 Stroke Analysis Plot - with date range filtering</li>
<li>2016-09-29 Improved Flex plot, Power Histogram and Ranking Pieces - with date range filtering</li>
<li>2016-09-20 Added the Power histogram</li>
<li>2016-08-31 Added the Ranking Piece summary and pace predictor</li>
<li>2016-08-02 Added support for the SpeedCoach GPS 2 CSV/FIT file export</li>
<li>2016-07-19 Added the possibility to download wind data from <a href="http://forecast.io">The Dark Sky / Forecast.io</a></li>
<li>2016-07-19 New Flexible interactive charts for OTE and OTW (pick your own axes parameters)</li>
<li>2016-07-07 Wind and Stream corrections for OTW (Pro functionality)</li>
<li>2016-06-23 Pro users can now compare workouts</li>
<li>2016-06-20 Fixed Strava upload and added SportTracks import and export. The export is not working reliably. We are debugging this,</li>
<li>2016-06-08 Added possibility to upload CrewNerd summary CSV file for Pro Members</li>
<li>2016-06-08 Added workout summaries</li>
<li>2016-06-05 Export to Strava is working</li>
<li>2016-06-01 We're approved on the Concept2 logbook!!!!
</ul>
</p>
</div>
</div>
{% endblock content %}

View File

@@ -1,114 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Advanced Features {% endblock %}
{% block content %}
<div id="workouts" class="grid_6 alpha">
<h1>Wind Editor</h1>
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/advanced">Advanced Edit</a>
</p>
</div>
<div class="grid_2 omega tooltip">
<p><a class="button blue small" href="/rowers/workout/{{ workout.id }}/otwsetpower">OTW Power</a></p>
<span class="tooltiptext">Run calculations to get power values for your row.</span>
</div>
<div class="grid_6 alpha">
<p>
Update wind between distance 1 and distance 2. Submit wind strength
and direction at start and end of segment. Blank the form for values
you want to keep intact.
</p>
<p>
Check <a href="https://www.wunderground.com">www.wunderground.com</a>
to find historical weather data from an on-line weather station near
the location of your row.
</p>
<div class="grid_4 alpha">
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<table>
{{ form.as_table }}
</table>
{% csrf_token %}
</div>
<div class="grid_2 omega">
<a class="button green small" href="/rowers/workout/{{ workout.id }}/darkskywind">Dark Sky Data</a>
<p>
Download wind speed and bearing from <a href="http://forecast.io/">The Dark Sky</a>
</p>
</div>
<div class="grid_2 omega">
<input class="button green small" type="submit" value="Submit Form">
<p>
Manual update of the wind data from the form.
</p>
</div>
</form>
<img src="http://cliparts.co/cliparts/rTn/KaR/rTnKaRrxc.gif" width="400">
</div>
</div>
<div id="advancedplots" class="grid_6 omega">
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
{{ gmap |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, true, true);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="interactiveplot" class="grid_6 omega">
<div class="grid_6 alpha">
{{ the_div |safe }}
</div>
</div>
<div id="interactiveplot" class="grid_6 omega">
<div class="grid_6 alpha">
{{ gmapdiv |safe }}
</div>
</div>
{% endblock %}

View File

@@ -1,51 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Change Workout {% endblock %}
{% block content %}
<div id="workouts" class="grid_6 alpha">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<h1>Confirm Workout Delete</h1>
This will delete the following workout and all linked graph images:
<table width=100%>
<tr>
<th>Date:</th><td>{{ workout.date }}</td>
</tr><tr>
<th>Time:</th><td>{{ workout.starttime }}</td>
</tr><tr>
<th>Distance:</th><td>{{ workout.distance }}m</td>
</tr><tr>
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
</tr>
</table>
<div class="grid_2 alpha">
<p>
<a class="button green small" href="/rowers/dashboard/">Cancel</a>
</div>
<div class="grid_2">
<p>
<a class="button red small" href="/rowers/workout/{{ workout.id }}/delete">Delete</a>
</p>
</div>
</div>
<div id="images" class="grid_6 omega">
<p>
&nbsp;
</b>
</div>
{% endblock %}

View File

@@ -1,192 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% load tz %}
{% block title %}Change Workout {% endblock %}
{% block content %}
<div id="workouts" class="grid_6 alpha">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<h1>Edit Workout Data</h1>
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
<a class="button red small" href="/rowers/workout/{{ workout.id }}/deleteconfirm">Delete</a>
</p>
</div>
<div class="grid_2">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/export">Export</a>
</p>
</div>
<div class="grid_2 omega tooltip">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/advanced">Advanced</a>
</p>
<span class="tooltiptext">Advanced Functionality (More interactive Charts)</span>
</div>
</div>
{% localtime on %}
<table width=100%>
<tr>
<th>Date/Time:</th><td>{{ workout.startdatetime }}</td>
</tr><tr>
<th>Distance:</th><td>{{ workout.distance }}m</td>
</tr><tr>
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
</tr><tr>
<th>Public link to this workout</th>
<td>
<a href="/rowers/workout/{{ workout.id }}">http://rowsandall.com/rowers/workout/{{ workout.id }}</a>
<td>
</tr><tr>
<th>Public link to interactive chart</th>
<td>
<a href="/rowers/workout/{{ workout.id }}/interactiveplot">http://rowsandall.com/rowers/workout/{{ workout.id }}/interactiveplot</a>
<td>
</tr>
</table>
{% endlocaltime %}
<form enctype="multipart/form-data" action="" method="post">
<table width=100%>
{{ form.as_table }}
</table>
{% csrf_token %}
<div id="formbutton" class="grid_1 prefix_4 suffix_1">
<input class="button green" type="submit" value="Save">
</div>
</form>
</div>
<div id="images" class="grid_6 omega">
<h1>Images linked to this workout</h1>
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/addtimeplot">Add Time Plot</a>
</p>
</div>
<div class="grid_2">
<p>
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/adddistanceplot">Add Distance Plot</a>
</p>
</div>
<div class="grid_2 omega">
<p>
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/addpiechart">Add Pie Chart</a>
</p>
</div>
<div class="grid_6">
<p>Generating images takes roughly 1 second per minute
of your workout's duration. Please reload after a minute or so.</p>
</div>
</div>
{% if graphs1 %}
{% for graph in graphs1 %}
{% if forloop.counter == 1 %}
<div id="thumb-container" class="grid_2 alpha">
<a href="/rowers/graph/{{ graph.id }}/">
<img src="/{{ graph.filename }}"
onerror="this.src='/static/img/waiting.png'"
alt="{{ graph.filename }}" width="120" height="100"></a>
</div>
{% elif forloop.counter == 3 %}
<div id="thumb-container" class="grid_2 omega">
<a href="/rowers/graph/{{ graph.id }}/">
<img src="/{{ graph.filename }}"
onerror="this.src='/static/img/waiting.png'"
alt="{{ graph.filename }}" width="120" height="100"></a>
</div>
{% else %}
<div id="thumb-container" class="grid_2">
<a href="/rowers/graph/{{ graph.id }}/">
<img src="/{{ graph.filename }}"
onerror="this.src='/static/img/waiting.png'"
alt="{{ graph.filename }}" width="120" height="100"></a>
</div>
{% endif %}
{% endfor %}
{% for graph in graphs2 %}
{% if forloop.counter == 1 %}
<div id="thumb-container" class="grid_2 alpha">
<a href="/rowers/graph/{{ graph.id }}/">
<img src="/{{ graph.filename }}"
onerror="this.src='/static/img/waiting.png'"
alt="{{ graph.filename }}" width="120" height="100"></a>
</div>
{% elif forloop.counter == 3 %}
<div id="thumb-container" class="grid_2 omega">
<a href="/rowers/graph/{{ graph.id }}/">
<img src="/{{ graph.filename }}"
onerror="this.src='/static/img/waiting.png'"
alt="{{ graph.filename }}" width="120" height="100"></a>
</div>
{% else %}
<div id="thumb-container" class="grid_2">
<a href="/rowers/graph/{{ graph.id }}/">
<img src="/{{ graph.filename }}"
onerror="this.src='/static/img/waiting.png'"
alt="{{ graph.filename }}" width="120" height="100"></a>
</div>
{% endif %}
{% endfor %}
{% else %}
<p> No graphs found </p>
{% endif %}
</div>
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, true, true);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="summary" class="grid_6 omega">
<h1>Workout Summary</h1>
<p>
<pre>
{{ workout.summary }}
</pre>
</p>
</div>
<div id="interactiveplot" class="grid_6 omega">
{{ the_div|safe }}
</div>
{% endblock %}

View File

@@ -1,142 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}View Workout {% endblock %}
{% block content %}
<div id="workouts" class="grid_6 alpha">
<h1>Workout Data</h1>
<table width=100%>
<tr>
<th>Rower:</th><td>{{ first_name }} {{ last_name }}</td>
</tr><tr>
<tr>
<th>Name:</th><td>{{ workout.name }}</td>
</tr><tr>
<tr>
<th>Date:</th><td>{{ workout.date }}</td>
</tr><tr>
<th>Time:</th><td>{{ workout.starttime }}</td>
</tr><tr>
<th>Distance:</th><td>{{ workout.distance }}m</td>
</tr><tr>
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
</tr><tr>
<th>Type:</th><td>{{ workout.workouttype }}</td>
</tr><tr>
<th>Weight Category:</th><td>{{ workout.weightcategory }}</td>
</tr>
</table>
<h1>Workout Summary</h1>
<p>
<pre>
{{ workout.summary }}
</pre>
</p>
</div>
<div id="images" class="grid_6 omega">
<h1>Images linked to this workout</h1>
{% if graphs1 %}
{% for graph in graphs1 %}
{% if forloop.counter == 1 %}
<div id="thumb-container" class="grid_2 alpha">
<a href="/rowers/graph/{{ graph.id }}/">
<img src="/{{ graph.filename }}"
onerror="this.src='/static/img/waiting.png'"
alt="{{ graph.filename }}" width="120" height="100"></a>
</div>
{% elif forloop.counter == 3 %}
<div id="thumb-container" class="grid_2 omega">
<a href="/rowers/graph/{{ graph.id }}/">
<img src="/{{ graph.filename }}"
onerror="this.src='/static/img/waiting.png'"
alt="{{ graph.filename }}" width="120" height="100"></a>
</div>
{% else %}
<div id="thumb-container" class="grid_2">
<a href="/rowers/graph/{{ graph.id }}/">
<img src="/{{ graph.filename }}"
onerror="this.src='/static/img/waiting.png'"
alt="{{ graph.filename }}" width="120" height="100"></a>
</div>
{% endif %}
{% endfor %}
{% for graph in graphs2 %}
{% if forloop.counter == 1 %}
<div id="thumb-container" class="grid_2 alpha">
<a href="/rowers/graph/{{ graph.id }}/">
<img src="/{{ graph.filename }}"
onerror="this.src='/static/img/waiting.png'"
alt="{{ graph.filename }}" width="120" height="100"></a>
</div>
{% elif forloop.counter == 3 %}
<div id="thumb-container" class="grid_2 omega">
<a href="/rowers/graph/{{ graph.id }}/">
<img src="/{{ graph.filename }}"
onerror="this.src='/static/img/waiting.png'"
alt="{{ graph.filename }}" width="120" height="100"></a>
</div>
{% else %}
<div id="thumb-container" class="grid_2">
<a href="/rowers/graph/{{ graph.id }}/">
<img src="/{{ graph.filename }}"
onerror="this.src='/static/img/waiting.png'"
alt="{{ graph.filename }}" width="120" height="100"></a>
</div>
{% endif %}
{% endfor %}
{% else %}
<p> No graphs found </p>
{% endif %}
</div>
<script type="text/javascript" src="/static/js/bokeh-0.11.1.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, true, true);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="interactiveplot" class="grid_6 omega">
{{ the_div|safe }}
</div>
{% endblock %}