Merge branch 'feature/gauges' into develop
This commit is contained in:
7
Dockerfile
Normal file
7
Dockerfile
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
FROM python:3-alpine
|
||||||
|
COPY ./requirements.txt ./
|
||||||
|
WORKDIR /usr/src/app/
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
COPY . .
|
||||||
|
EXPOSE 8000
|
||||||
|
CMD ["python", "./manage.py", "runserver"]
|
||||||
@@ -258,7 +258,7 @@ rowingmetrics = (
|
|||||||
'ax_min': 0,
|
'ax_min': 0,
|
||||||
'ax_max': 30,
|
'ax_max': 30,
|
||||||
'default': 0,
|
'default': 0,
|
||||||
'sigfigs': 0,
|
'sigfigs': 1,
|
||||||
'mode':'water',
|
'mode':'water',
|
||||||
'type': 'pro',
|
'type': 'pro',
|
||||||
'group': 'stroke'}),
|
'group': 'stroke'}),
|
||||||
|
|||||||
@@ -29,6 +29,8 @@
|
|||||||
{% block meta %}
|
{% block meta %}
|
||||||
{% leaflet_js %}
|
{% leaflet_js %}
|
||||||
{% leaflet_css %}
|
{% leaflet_css %}
|
||||||
|
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
|
||||||
|
<script type="text/javascript" src="{% static 'js/videogauges.js' %}"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.js"></script>
|
||||||
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
|
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
@@ -252,7 +254,7 @@ function copyText() {
|
|||||||
// catchangle = ctch[Math.round(datatime)];
|
// catchangle = ctch[Math.round(datatime)];
|
||||||
{% for id, metric in metrics.items %}
|
{% for id, metric in metrics.items %}
|
||||||
{{ id }}_now = {{ id }}_values[Math.round(datatime)];
|
{{ id }}_now = {{ id }}_values[Math.round(datatime)];
|
||||||
// console.log(datatime,{{ id }}_now, "{{ metric.name }}")
|
// console.log(datatime,{{ id }},{{ id }}_now, "{{ metric.name }}")
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
@@ -270,7 +272,9 @@ function copyText() {
|
|||||||
{% for group in metricsgroups %}
|
{% for group in metricsgroups %}
|
||||||
try {
|
try {
|
||||||
set_{{ group }}();
|
set_{{ group }}();
|
||||||
} catch (e) {}
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
try {
|
try {
|
||||||
var newLatLng = new L.LatLng(lat, lon);
|
var newLatLng = new L.LatLng(lat, lon);
|
||||||
@@ -370,13 +374,36 @@ function copyText() {
|
|||||||
</span> {{ metric.unit }}
|
</span> {{ metric.unit }}
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% for group in metricsgroups %}
|
</ul>
|
||||||
<li class="grid_2">
|
<ul class="main-content">
|
||||||
<canvas id="{{ group }}"></canvas>
|
{% if 'basic' in metricsgroups %}
|
||||||
|
<li class="grid_1">
|
||||||
|
<div id="basic_spm"></div>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
<li class="grid_1">
|
||||||
|
<div id="basic_boatspeed"></div>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if 'forcepower' in metricsgroups %}
|
||||||
|
<li class="grid_1">
|
||||||
|
<div id="forcepower_power"></div>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if 'athlete' in metricsgroups %}
|
||||||
|
<li class="grid_1">
|
||||||
|
<div id="athlete_hr"></div>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if 'stroke' in metricsgroups %}
|
||||||
|
{% if workout.workouttype == 'water' %}
|
||||||
|
<li class="grid_2" style="height:500px">
|
||||||
|
<div style="width:100%;height:70%;" id="stroke_angles"></div>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="grid_2">
|
<li class="grid_2">
|
||||||
{% if analysis and user.is_authenticated and user == analysis.workout.user.user %}
|
{% if analysis and user.is_authenticated and user == analysis.workout.user.user %}
|
||||||
<p>
|
<p>
|
||||||
@@ -384,12 +411,88 @@ function copyText() {
|
|||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
|
<li class="grid_2">
|
||||||
|
<p>We're building Gauges to show the video data based on the
|
||||||
|
<a href="https://developers.google.com/chart">Google charts API</a>.
|
||||||
|
You can contribute by developing your own gauge in
|
||||||
|
<a href="https://jsfiddle.net/">JSFiddle</a> like
|
||||||
|
<a href="https://jsfiddle.net/roosendaalsander/5xrez3bu/">this example</a>.
|
||||||
|
Please send us the link to the JSFiddle example by email using the
|
||||||
|
<a href="/rowers/email/">Contact Form</a> and we'll discuss the possibilities
|
||||||
|
with you.
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</form>
|
</form>
|
||||||
<p> </p>
|
<p> </p>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(document).ready( function() {
|
$(document).ready( function() {
|
||||||
|
$(window).load(function() {
|
||||||
|
// initialize data fields
|
||||||
|
console.log('initializing first value of data');
|
||||||
|
{% for id, metric in metrics.items %}
|
||||||
|
{{ id }}_now = {{ id }}_values[0];
|
||||||
|
document.getElementById("{{ id }}").innerHTML = {{ id }}_now;
|
||||||
|
document.getElementById("{{ id }}").className = 'bold';
|
||||||
|
{% endfor %}
|
||||||
|
document.getElementById("time").innerHTML = Math.round(videotime);
|
||||||
|
var slider = document.getElementById("myRange");
|
||||||
|
document.getElementById("datatime").innerHTML = slider.value;
|
||||||
|
|
||||||
|
// gauge settings
|
||||||
|
{% if workout.workouttype != 'water' %}
|
||||||
|
speedoptions.max = 7;
|
||||||
|
speedoptions.redTo = 7;
|
||||||
|
speedoptions.majorTicks = ['0','1','2','3','4','5','6','7'];
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if 'basic' in metricsgroups %}
|
||||||
|
spm_now = spm_values[0];
|
||||||
|
boatspeed_now = boatspeed_values[0];
|
||||||
|
set_basic();
|
||||||
|
{% endif %}
|
||||||
|
{% if 'forcepower' in metricsgroups %}
|
||||||
|
poweroptions.max = {{ rower.pw_an|add:100|round100 }};
|
||||||
|
poweroptions.greenFrom = {{ rower.pw_ut2 }};
|
||||||
|
poweroptions.greenTo = {{ rower.pw_at }};
|
||||||
|
poweroptions.yellowFrom = {{ rower.pw_at }};
|
||||||
|
poweroptions.yellowTo = {{ rower.pw_an }};
|
||||||
|
poweroptions.redFrom = {{ rower.pw_an }};
|
||||||
|
poweroptions.redTo = {{ rower.pw_an|add:100|round100 }};
|
||||||
|
poweroptions.majorTicks = {{ rower.pw_an|add:100|round100|majorticks }};
|
||||||
|
{% if workout.workouttype == 'water' %}
|
||||||
|
poweroptions.max = {{ rower.pw_an|waterpower:rower|add:100|round100 }}
|
||||||
|
poweroptions.greenFrom = {{ rower.pw_ut2|waterpower:rower }};
|
||||||
|
poweroptions.greenTo = {{ rower.pw_at|waterpower:rower }};
|
||||||
|
poweroptions.yellowFrom = {{ rower.pw_at|waterpower:rower }};
|
||||||
|
poweroptions.yellowTo = {{ rower.pw_an|waterpower:rower }};
|
||||||
|
poweroptions.redFrom = {{ rower.pw_an|waterpower:rower }};
|
||||||
|
poweroptions.redTo = {{ rower.pw_an|waterpower:rower|add:100|round100 }};
|
||||||
|
poweroptions.majorTicks = {{ rower.pw_an|waterpower:rower|add:100|round100|majorticks }};
|
||||||
|
{% endif %}
|
||||||
|
power_now = power_values[0];
|
||||||
|
set_forcepower();
|
||||||
|
{% endif %}
|
||||||
|
{% if 'athlete' in metricsgroups %}
|
||||||
|
hroptions.max = {{ rower.max|round20 }}
|
||||||
|
hroptions.greenFrom = {{ rower.ut2 }}
|
||||||
|
hroptions.greenTo = {{ rower.at }}
|
||||||
|
hroptions.yellowFrom = {{ rower.at }}
|
||||||
|
hroptions.yellowTo = {{ rower.an }}
|
||||||
|
hroptions.redFrom = {{ rower.an }}
|
||||||
|
hroptions.redTo = {{ rower.max }}
|
||||||
|
hroptions.majorTicks = {{ rower.max|round20|hrmajorticks:rower.rest }}
|
||||||
|
hr_now = hr_values[0];
|
||||||
|
set_athlete();
|
||||||
|
{% endif %}
|
||||||
|
{% if 'stroke' in metricsgroups %}
|
||||||
|
{% if workout.workouttype == 'water' %}
|
||||||
|
anglesoptions.PieStartAngle = 90+catch_now;
|
||||||
|
set_stroke();
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
// cookie reader
|
// cookie reader
|
||||||
function createCookie(name,value,days) {
|
function createCookie(name,value,days) {
|
||||||
if (days) {
|
if (days) {
|
||||||
@@ -496,7 +599,8 @@ function copyText() {
|
|||||||
{% for group in metricsgroups %}
|
{% for group in metricsgroups %}
|
||||||
try {
|
try {
|
||||||
set_{{ group }}();
|
set_{{ group }}();
|
||||||
} catch (e) {}
|
} catch (e) {
|
||||||
|
}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
try {
|
try {
|
||||||
var newLatLng = new L.LatLng(lat, lon);
|
var newLatLng = new L.LatLng(lat, lon);
|
||||||
@@ -563,7 +667,9 @@ function copyText() {
|
|||||||
{% for group in metricsgroups %}
|
{% for group in metricsgroups %}
|
||||||
try {
|
try {
|
||||||
set_{{ group }}();
|
set_{{ group }}();
|
||||||
} catch (e) {}
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
try {
|
try {
|
||||||
var newLatLng = new L.LatLng(lat, lon);
|
var newLatLng = new L.LatLng(lat, lon);
|
||||||
@@ -691,6 +797,7 @@ dataplay.onclick = function() {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endlanguage %}
|
{% endlanguage %}
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ def sigdig(value, digits = 3):
|
|||||||
# return integers as is
|
# return integers as is
|
||||||
if value % 1 == 0:
|
if value % 1 == 0:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
places = digits - order - 1
|
places = digits - order - 1
|
||||||
if places > 0:
|
if places > 0:
|
||||||
fmtstr = "%%.%df" % (places)
|
fmtstr = "%%.%df" % (places)
|
||||||
@@ -83,7 +83,7 @@ def strfdelta(tdelta):
|
|||||||
seconds=seconds,
|
seconds=seconds,
|
||||||
tenths=tenths,
|
tenths=tenths,
|
||||||
)
|
)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
from rowers.teams import rower_get_managers
|
from rowers.teams import rower_get_managers
|
||||||
@@ -91,13 +91,13 @@ from rowers.teams import rower_get_managers
|
|||||||
@register.filter
|
@register.filter
|
||||||
def alertstatspercentage(list,i):
|
def alertstatspercentage(list,i):
|
||||||
alertstats = list[i-1]
|
alertstats = list[i-1]
|
||||||
|
|
||||||
return alertstats["percentage"]
|
return alertstats["percentage"]
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def alertstartdate(list,i):
|
def alertstartdate(list,i):
|
||||||
alertstats = list[i-1]
|
alertstats = list[i-1]
|
||||||
|
|
||||||
return alertstats["startdate"]
|
return alertstats["startdate"]
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
@@ -109,7 +109,7 @@ def alertnperiod(list,i):
|
|||||||
@register.filter
|
@register.filter
|
||||||
def alertenddate(list,i):
|
def alertenddate(list,i):
|
||||||
alertstats = list[i-1]
|
alertstats = list[i-1]
|
||||||
|
|
||||||
return alertstats["enddate"]
|
return alertstats["enddate"]
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
@@ -121,6 +121,37 @@ def is_coach(rower,rowers):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def waterpower(x,rower):
|
||||||
|
return int(x*(100-rower.otwslack)/100.)
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def round20(x):
|
||||||
|
return int(20.*(1+int(int(x)/20)))
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def round100(x):
|
||||||
|
return int(100.*(1+int(int(x)/100)))
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def majorticks(maxval):
|
||||||
|
ticks = range(1+int(maxval/100.))
|
||||||
|
newticks =[]
|
||||||
|
for t in ticks:
|
||||||
|
newticks.append(t*100)
|
||||||
|
|
||||||
|
return newticks
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def hrmajorticks(maxval,minval):
|
||||||
|
ticks = range(int((maxval-minval)/20.)-1)
|
||||||
|
newticks =[]
|
||||||
|
for t in ticks:
|
||||||
|
newticks.append(100+t*20)
|
||||||
|
|
||||||
|
print(newticks)
|
||||||
|
return newticks
|
||||||
|
|
||||||
def strfdeltah(tdelta):
|
def strfdeltah(tdelta):
|
||||||
hours, rest = divmod(tdelta.seconds,3600)
|
hours, rest = divmod(tdelta.seconds,3600)
|
||||||
minutes,seconds = divmod(rest,60)
|
minutes,seconds = divmod(rest,60)
|
||||||
@@ -131,7 +162,7 @@ def strfdeltah(tdelta):
|
|||||||
seconds=seconds,
|
seconds=seconds,
|
||||||
tenths=tenths,
|
tenths=tenths,
|
||||||
)
|
)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def secondstotimestring(tdelta):
|
def secondstotimestring(tdelta):
|
||||||
@@ -142,7 +173,7 @@ def secondstotimestring(tdelta):
|
|||||||
minutes=minutes,
|
minutes=minutes,
|
||||||
seconds=seconds,
|
seconds=seconds,
|
||||||
)
|
)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
@@ -218,7 +249,7 @@ def nextperiodstart(timeperiod):
|
|||||||
newenddate = newstartdate+timedelta
|
newenddate = newstartdate+timedelta
|
||||||
|
|
||||||
return newstartdate.strftime("%Y-%m-%d")
|
return newstartdate.strftime("%Y-%m-%d")
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def previousperiodend(timeperiod):
|
def previousperiodend(timeperiod):
|
||||||
startdate,enddate = getstartenddate(timeperiod)
|
startdate,enddate = getstartenddate(timeperiod)
|
||||||
@@ -243,7 +274,7 @@ def previousperiodstart(timeperiod):
|
|||||||
newstartdate = startdate-timedelta-datetime.timedelta(days=1)
|
newstartdate = startdate-timedelta-datetime.timedelta(days=1)
|
||||||
|
|
||||||
return newstartdate.strftime("%Y-%m-%d")
|
return newstartdate.strftime("%Y-%m-%d")
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def paceprint(d):
|
def paceprint(d):
|
||||||
if (d == None):
|
if (d == None):
|
||||||
@@ -288,11 +319,11 @@ def rkuserid(user):
|
|||||||
rkuserid = runkeeperstuff.get_userid(thetoken)
|
rkuserid = runkeeperstuff.get_userid(thetoken)
|
||||||
|
|
||||||
return rkuserid
|
return rkuserid
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def courselength(course):
|
def courselength(course):
|
||||||
return course_length(course)
|
return course_length(course)
|
||||||
|
|
||||||
@register.filter(is_safe=True)
|
@register.filter(is_safe=True)
|
||||||
def jsdict(dict,key):
|
def jsdict(dict,key):
|
||||||
s = dict.get(key)
|
s = dict.get(key)
|
||||||
@@ -306,7 +337,7 @@ def lookup(dict, key):
|
|||||||
s = dict.get(key)
|
s = dict.get(key)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if isinstance(s,string_types) and len(s) > 22:
|
if isinstance(s,string_types) and len(s) > 22:
|
||||||
s = s[:22]
|
s = s[:22]
|
||||||
return s
|
return s
|
||||||
@@ -317,7 +348,7 @@ def lookuplong(dict, key):
|
|||||||
s = dict.get(key)
|
s = dict.get(key)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
@@ -329,11 +360,11 @@ def ualookup(dict, key):
|
|||||||
|
|
||||||
if key=='duration':
|
if key=='duration':
|
||||||
s = secondstotimestring(int(s))
|
s = secondstotimestring(int(s))
|
||||||
|
|
||||||
|
|
||||||
if key=='starttime':
|
if key=='starttime':
|
||||||
s = dateutil.parser.parse(s)
|
s = dateutil.parser.parse(s)
|
||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
||||||
from rowers.models import PlannedSession
|
from rowers.models import PlannedSession
|
||||||
@@ -343,7 +374,7 @@ def is_session_manager(id,user):
|
|||||||
ps = PlannedSession.objects.get(id=id)
|
ps = PlannedSession.objects.get(id=id)
|
||||||
except PlannedSession.DoesNotExist:
|
except PlannedSession.DoesNotExist:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return ps.manager == user
|
return ps.manager == user
|
||||||
|
|
||||||
from rowers.models import checkworkoutuser
|
from rowers.models import checkworkoutuser
|
||||||
@@ -358,7 +389,7 @@ def may_edit(workout,request):
|
|||||||
|
|
||||||
return mayedit
|
return mayedit
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def mayeditplan(obj,request):
|
def mayeditplan(obj,request):
|
||||||
@@ -376,11 +407,11 @@ def mayeditplan(obj,request):
|
|||||||
rr = Rower.objects.get(user=request.user)
|
rr = Rower.objects.get(user=request.user)
|
||||||
if checkaccessuser(request.user,obj.rower) and rr.rowerplan not in ['basic','pro']:
|
if checkaccessuser(request.user,obj.rower) and rr.rowerplan not in ['basic','pro']:
|
||||||
mayedit = True
|
mayedit = True
|
||||||
|
|
||||||
|
|
||||||
return mayedit
|
return mayedit
|
||||||
|
|
||||||
|
|
||||||
@register.filter(name='times')
|
@register.filter(name='times')
|
||||||
def times(number):
|
def times(number):
|
||||||
return range(number)
|
return range(number)
|
||||||
@@ -480,7 +511,7 @@ def team_members(user):
|
|||||||
@register.filter
|
@register.filter
|
||||||
def openactions(user):
|
def openactions(user):
|
||||||
myteams = Team.objects.filter(manager=user)
|
myteams = Team.objects.filter(manager=user)
|
||||||
|
|
||||||
invites = TeamInvite.objects.filter(user=user).count()
|
invites = TeamInvite.objects.filter(user=user).count()
|
||||||
requests = TeamRequest.objects.filter(user=user).count()
|
requests = TeamRequest.objects.filter(user=user).count()
|
||||||
myrequests = TeamRequest.objects.filter(team__in=myteams).count()
|
myrequests = TeamRequest.objects.filter(team__in=myteams).count()
|
||||||
@@ -491,7 +522,7 @@ def openactions(user):
|
|||||||
coachrequests = CoachRequest.objects.filter(coach=user.rower).count()
|
coachrequests = CoachRequest.objects.filter(coach=user.rower).count()
|
||||||
|
|
||||||
return invites+requests+myrequests+myinvites+mycoachoffers+coachoffers+mycoachrequests+coachrequests
|
return invites+requests+myrequests+myinvites+mycoachoffers+coachoffers+mycoachrequests+coachrequests
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def team_rowers(user):
|
def team_rowers(user):
|
||||||
@@ -518,7 +549,7 @@ def coach_rowers(user):
|
|||||||
else:
|
else:
|
||||||
thelist = [c for c in coach_getcoachees(user.rower)]
|
thelist = [c for c in coach_getcoachees(user.rower)]
|
||||||
return thelist
|
return thelist
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def verbosetimeperiod(timeperiod):
|
def verbosetimeperiod(timeperiod):
|
||||||
@@ -538,7 +569,7 @@ def verbosetimeperiod(timeperiod):
|
|||||||
verbose = timeperiod
|
verbose = timeperiod
|
||||||
|
|
||||||
return verbose
|
return verbose
|
||||||
|
|
||||||
from datetime import date
|
from datetime import date
|
||||||
|
|
||||||
@ register.filter
|
@ register.filter
|
||||||
@@ -557,8 +588,8 @@ def is_future_date(the_date):
|
|||||||
def amount(value):
|
def amount(value):
|
||||||
vs = '{v}.00'.format(v=int(value))
|
vs = '{v}.00'.format(v=int(value))
|
||||||
return vs
|
return vs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def date_dif(the_date):
|
def date_dif(the_date):
|
||||||
@@ -569,7 +600,7 @@ def date_dif(the_date):
|
|||||||
else:
|
else:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def can_register(race,r):
|
def can_register(race,r):
|
||||||
return race_can_register(r,race)
|
return race_can_register(r,race)
|
||||||
@@ -618,7 +649,7 @@ def userurl(path,member):
|
|||||||
tpattern = re.compile('team\/\d+/')
|
tpattern = re.compile('team\/\d+/')
|
||||||
if tpattern.search(path) is not None:
|
if tpattern.search(path) is not None:
|
||||||
path = tpattern.sub('',path)
|
path = tpattern.sub('',path)
|
||||||
|
|
||||||
if pattern.search(path) is not None:
|
if pattern.search(path) is not None:
|
||||||
replaced = pattern.sub(userstring,path)
|
replaced = pattern.sub(userstring,path)
|
||||||
else:
|
else:
|
||||||
@@ -635,7 +666,7 @@ def teamurl(path,team):
|
|||||||
upattern = re.compile('\/user\/\d+/')
|
upattern = re.compile('\/user\/\d+/')
|
||||||
if upattern.search(path) is not None:
|
if upattern.search(path) is not None:
|
||||||
path = upattern.sub('/',path)
|
path = upattern.sub('/',path)
|
||||||
|
|
||||||
|
|
||||||
if pattern.search(path) is not None:
|
if pattern.search(path) is not None:
|
||||||
replaced = pattern.sub(teamstring,path)
|
replaced = pattern.sub(teamstring,path)
|
||||||
@@ -726,13 +757,13 @@ def nextworkout(workout,user):
|
|||||||
).exclude(id=workout.id)
|
).exclude(id=workout.id)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
if ws:
|
if ws:
|
||||||
return encoder.encode_hex(ws[0].id)
|
return encoder.encode_hex(ws[0].id)
|
||||||
else:
|
else:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def previousworkout(workout,user):
|
def previousworkout(workout,user):
|
||||||
@@ -762,6 +793,3 @@ def previousworkout(workout,user):
|
|||||||
return encoder.encode_hex(ws[0].id)
|
return encoder.encode_hex(ws[0].id)
|
||||||
else:
|
else:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,60 +1,209 @@
|
|||||||
// var opts = {
|
google.charts.load('current', {'packages':['gauge','corechart']});
|
||||||
// lines: 12,
|
google.charts.setOnLoadCallback(drawSPMChart);
|
||||||
// angle: 0.15,
|
google.charts.setOnLoadCallback(drawSpeedChart);
|
||||||
// lineWidth: 0.44,
|
google.charts.setOnLoadCallback(drawPowerChart);
|
||||||
// pointer: {
|
google.charts.setOnLoadCallback(drawHRChart);
|
||||||
// length: 0.9,
|
google.charts.setOnLoadCallback(drawStrokeAngleChart);
|
||||||
// strokeWidth: 0.035,
|
|
||||||
// color: '#000000'
|
|
||||||
// },
|
|
||||||
// limitMax: 'false',
|
|
||||||
// // percentColors: [[0.0, "#a9d70b" ], [0.50, "#a9d70b"], [1.0, "#a9d70b"]], // !!!!
|
|
||||||
// strokeColor: '#E0E0E0',
|
|
||||||
// generateGradient: true
|
|
||||||
// };
|
|
||||||
// var target = document.getElementById('angles');
|
|
||||||
// var gauge = new Gauge(target).setOptions(opts);
|
|
||||||
// gauge.maxValue = 90;
|
|
||||||
// gauge.minValue = -90;
|
|
||||||
// gauge.animationSpeed = 5;
|
|
||||||
// gauge.set(-75);
|
|
||||||
|
|
||||||
// https://github.com/bernii/gauge.js/issues/193
|
var spmdata = [
|
||||||
|
['Label', 'Value'],
|
||||||
|
['SPM', 21],
|
||||||
|
];
|
||||||
|
|
||||||
|
var speeddata = [
|
||||||
|
['Label', 'Value'],
|
||||||
|
['V m/s', 0],
|
||||||
|
];
|
||||||
|
|
||||||
var opts = {
|
var powerdata = [
|
||||||
angle: 0, // The span of the gauge arc
|
['Label','Value'],
|
||||||
lineWidth: 0.2, // The line thickness
|
['PWR',150],
|
||||||
radiusScale: 0.89, // Relative radius
|
]
|
||||||
pointer: {
|
|
||||||
length: 0.54, // // Relative to gauge radius
|
|
||||||
strokeWidth: 0.053, // The thickness
|
|
||||||
color: '#000000' // Fill color
|
|
||||||
},
|
|
||||||
limitMax: false, // If false, max value increases automatically if value > maxValue
|
|
||||||
limitMin: false, // If true, the min value of the gauge will be fixed
|
|
||||||
colorStart: '#6FADCF', // Colors
|
|
||||||
colorStop: '#8FC0DA', // just experiment with them
|
|
||||||
strokeColor: '#E0E0E0', // to see which ones work best for you
|
|
||||||
generateGradient: true,
|
|
||||||
highDpiSupport: true, // High resolution support
|
|
||||||
staticZones: [
|
|
||||||
{strokeStyle: "#00FF00", min: 0, max: 2}, // Greem
|
|
||||||
{strokeStyle: "#0000FF", min: 2, max: 3}, // Blue`
|
|
||||||
{strokeStyle: "#00FFFF", min: 3, max: 4}, // Cyan
|
|
||||||
{strokeStyle: "#FFDD00", min: 4, max: 5}, // Orange
|
|
||||||
{strokeStyle: "#FF0000", min: 5, max: 6} // Red
|
|
||||||
],
|
|
||||||
|
|
||||||
};
|
var hrdata = [
|
||||||
var target = document.getElementById('basic'); // your canvas element
|
['Label','Value'],
|
||||||
var gaugeboatspeed = new Gauge(target).setOptions(opts); // create sexy gauge!
|
['HR',110],
|
||||||
gaugeboatspeed.maxValue = 6; // set max gauge value
|
]
|
||||||
gaugeboatspeed.setMinValue(0); // Prefer setter over gauge.minValue = 0
|
|
||||||
gaugeboatspeed.animationSpeed = 10; // set animation speed (32 is default value)
|
|
||||||
gaugeboatspeed.set(0); // set actual value
|
|
||||||
|
|
||||||
// Define set_basic(values) so that gauges can be set by metricsgroups
|
var angledata = [
|
||||||
function set_basic() {
|
['Angle', 'deg'],
|
||||||
gaugeboatspeed.set(boatspeed_now);
|
['slip', 10 ],
|
||||||
|
['load', 50],
|
||||||
|
['unload', 50],
|
||||||
|
['wash', 10],
|
||||||
|
['recovery',240 ]
|
||||||
|
]
|
||||||
|
|
||||||
|
var anglesoptions = {
|
||||||
|
title: 'Stroke Angles',
|
||||||
|
legend: 'none',
|
||||||
|
pieHole: 0.5,
|
||||||
|
chartArea: { width: "100%" },
|
||||||
|
pieStartAngle: 35,
|
||||||
|
pieSliceText: 'value',
|
||||||
|
pieSliceTextStyle: {color:'black',fontSize:12},
|
||||||
|
slices: {
|
||||||
|
0: { color: 'lightblue' },
|
||||||
|
1: { color: 'lightgreen' },
|
||||||
|
2: { color: 'yellow'},
|
||||||
|
3: { color: 'orange'},
|
||||||
|
4: { color: 'transparent', textStyle: {color:'transparent'}}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var hroptions = {
|
||||||
|
min: 100, max: 200,
|
||||||
|
width: 400, height: 120,
|
||||||
|
greenFrom: 100, greenTo: 135,
|
||||||
|
yellowFrom: 135,yellowTo: 157,
|
||||||
|
redFrom: 157, redTo: 200,
|
||||||
|
minorTicks: 5
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var spmoptions = {
|
||||||
|
min:0, max: 50,
|
||||||
|
width: 400, height: 120,
|
||||||
|
greenFrom: 20, greenTo: 30,
|
||||||
|
yellowFrom: 30,yellowTo: 40,
|
||||||
|
redFrom: 40, redTo: 50,
|
||||||
|
majorTicks: ['0','10','20','30','40','50'],
|
||||||
|
minorTicks: 10
|
||||||
|
};
|
||||||
|
|
||||||
|
var speedoptions = {
|
||||||
|
min:0, max: 6,
|
||||||
|
width: 400, height: 120,
|
||||||
|
greenFrom: 2, greenTo: 4,
|
||||||
|
yellowFrom: 4,yellowTo: 5,
|
||||||
|
redFrom: 5, redTo: 6,
|
||||||
|
majorTicks: ['0','1','2','3','4','5','6'],
|
||||||
|
minorTicks: 10
|
||||||
|
};
|
||||||
|
|
||||||
|
var poweroptions = {
|
||||||
|
min: 0, max: 1000,
|
||||||
|
width: 400, height: 120,
|
||||||
|
greenFrom: 100, greenTo: 200,
|
||||||
|
yellowFrom: 200,yellowTo: 400,
|
||||||
|
redFrom: 400, redTo: 1000,
|
||||||
|
majorTicks: ['0','200','400','600','800','1000'],
|
||||||
|
minorTicks: 5
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var dataspm = null;
|
||||||
|
var dataspeed = null;
|
||||||
|
var spmchart = null;
|
||||||
|
var speedchart = null;
|
||||||
|
var powerchart = null;
|
||||||
|
var datapower = null;
|
||||||
|
var dataangles = null;
|
||||||
|
|
||||||
|
// SPM chart
|
||||||
|
function drawSPMChart() {
|
||||||
|
console.log('first draw SPM chart');
|
||||||
|
dataspm = new google.visualization.arrayToDataTable(spmdata);
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
spmchart = new google.visualization.Gauge(document.getElementById('basic_spm'));
|
||||||
|
spmchart.draw(dataspm,spmoptions);
|
||||||
|
} catch(err) {
|
||||||
|
|
||||||
|
}
|
||||||
|
// spmchart.draw(data, spmoptions);
|
||||||
|
|
||||||
|
// Define set_basic(values) so that gauges can be set by metricsgroups
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Speed Chart
|
||||||
|
function drawSpeedChart() {
|
||||||
|
dataspeed = new google.visualization.arrayToDataTable(speeddata);
|
||||||
|
|
||||||
|
try {
|
||||||
|
speedchart = new google.visualization.Gauge(document.getElementById('basic_boatspeed'));
|
||||||
|
speedchart.draw(dataspeed,speedoptions);
|
||||||
|
} catch(err) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Power chart
|
||||||
|
function drawPowerChart() {
|
||||||
|
datapower = new google.visualization.arrayToDataTable(powerdata);
|
||||||
|
try {
|
||||||
|
powerchart = new google.visualization.Gauge(document.getElementById('forcepower_power'));
|
||||||
|
powerchart.draw(datapower,poweroptions)
|
||||||
|
} catch(err) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// HR chart
|
||||||
|
function drawHRChart() {
|
||||||
|
datahr = new google.visualization.arrayToDataTable(hrdata);
|
||||||
|
try {
|
||||||
|
hrchart = new google.visualization.Gauge(document.getElementById('athlete_hr'));
|
||||||
|
hrchart.draw(datahr,hroptions);
|
||||||
|
} catch(err) {
|
||||||
|
console.log('no hr div');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stroke angle chart
|
||||||
|
function drawStrokeAngleChart() {
|
||||||
|
dataangles = new google.visualization.arrayToDataTable(angledata);
|
||||||
|
try {
|
||||||
|
angleschart = new google.visualization.PieChart(document.getElementById('stroke_angles'));
|
||||||
|
angleschart.draw(dataangles,anglesoptions);
|
||||||
|
} catch(err) {
|
||||||
|
console.log('no angles div');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_basic() {
|
||||||
|
dataspm.setCell(0,1,spm_now);
|
||||||
|
spmchart.draw(dataspm, spmoptions);
|
||||||
|
|
||||||
|
dataspeed.setCell(0,1,boatspeed_now);
|
||||||
|
speedchart.draw(dataspeed,speedoptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_athlete() {
|
||||||
|
datahr.setCell(0,1,hr_now);
|
||||||
|
try {
|
||||||
|
hrchart.draw(datahr,hroptions);
|
||||||
|
} catch(err) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_stroke() {
|
||||||
|
var piestartangle = 90+catch_now;
|
||||||
|
var load = Math.max(-catch_now-slip_now+peakforceangle_now);
|
||||||
|
var unload = Math.max(finish_now-wash_now-peakforceangle_now) ;
|
||||||
|
var recovery = Math.max(360+catch_now-finish_now);
|
||||||
|
// console.log('load ',load,'; unload ',unload,'; recovery ',recovery,'; pie start angle ',piestartangle);
|
||||||
|
dataangles.setCell(0,1,slip_now);
|
||||||
|
dataangles.setCell(1,1,load);
|
||||||
|
dataangles.setCell(2,1,unload);
|
||||||
|
dataangles.setCell(3,1,wash_now);
|
||||||
|
dataangles.setCell(4,1,recovery);
|
||||||
|
anglesoptions.pieStartAngle = piestartangle;
|
||||||
|
try {
|
||||||
|
angleschart.draw(dataangles,anglesoptions);
|
||||||
|
} catch(err) {
|
||||||
|
console.log('failed: ',err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_forcepower() {
|
||||||
|
datapower.setCell(0,1,power_now);
|
||||||
|
try {
|
||||||
|
powerchart.draw(datapower,poweroptions);
|
||||||
|
} catch(err) {}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user