Merge branch 'release/v12.76'
This commit is contained in:
@@ -2049,21 +2049,70 @@ def leaflet_chart(lat,lon,name=""):
|
|||||||
|
|
||||||
return script,div
|
return script,div
|
||||||
|
|
||||||
def leaflet_chart_compare(workoutids,labeldict={},startenddict={}):
|
def leaflet_chart_compare(course,workoutids,labeldict={},startenddict={}):
|
||||||
data = []
|
data = []
|
||||||
for id in workoutids:
|
for id in workoutids:
|
||||||
w = Workout.objects.get(id=id)
|
w = Workout.objects.get(id=id)
|
||||||
rowdata = rdata(w.csvfilename)
|
rowdata = rdata(w.csvfilename)
|
||||||
|
time = rowdata.df['TimeStamp (sec)']
|
||||||
df = pd.DataFrame({
|
df = pd.DataFrame({
|
||||||
'id':id,
|
'workoutid':id,
|
||||||
'lat':rowdata.df[' latitude'],
|
'lat':rowdata.df[' latitude'],
|
||||||
'lon':rowdata.df[' longitude']
|
'lon':rowdata.df[' longitude'],
|
||||||
|
'time':time-time[0],
|
||||||
})
|
})
|
||||||
data.append(f)
|
data.append(df)
|
||||||
|
|
||||||
df = pd.concat(data,axis=0)
|
df = pd.concat(data,axis=0)
|
||||||
|
|
||||||
|
|
||||||
|
latmean,lonmean,coordinates = course_coord_center(course)
|
||||||
|
lat_min, lat_max, long_min, long_max = course_coord_maxmin(course)
|
||||||
|
|
||||||
|
coordinates = course_spline(coordinates)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course")
|
||||||
|
|
||||||
|
plabels = ''
|
||||||
|
|
||||||
|
for p in polygons:
|
||||||
|
coords = polygon_coord_center(p)
|
||||||
|
|
||||||
|
plabels += """
|
||||||
|
var marker = L.marker([{latbegin}, {longbegin}]).addTo(mymap);
|
||||||
|
marker.bindPopup("<b>{name}</b>");
|
||||||
|
|
||||||
|
""".format(
|
||||||
|
latbegin = coords[0],
|
||||||
|
longbegin = coords[1],
|
||||||
|
name = p.name
|
||||||
|
)
|
||||||
|
|
||||||
|
pcoordinates = """[
|
||||||
|
"""
|
||||||
|
|
||||||
|
for p in polygons:
|
||||||
|
pcoordinates += """[
|
||||||
|
["""
|
||||||
|
|
||||||
|
points = GeoPoint.objects.filter(polygon=p).order_by("order_in_poly")
|
||||||
|
|
||||||
|
for pt in points:
|
||||||
|
pcoordinates += "[{x},{y}],".format(
|
||||||
|
x = pt.latitude,
|
||||||
|
y = pt.longitude
|
||||||
|
)
|
||||||
|
|
||||||
|
# remove last comma
|
||||||
|
pcoordinates = pcoordinates[:-1]
|
||||||
|
pcoordinates += """]
|
||||||
|
],
|
||||||
|
"""
|
||||||
|
|
||||||
|
pcoordinates += """
|
||||||
|
]"""
|
||||||
|
|
||||||
|
|
||||||
# Throw out 0,0
|
# Throw out 0,0
|
||||||
@@ -2071,25 +2120,26 @@ def leaflet_chart_compare(workoutids,labeldict={},startenddict={}):
|
|||||||
df = df.loc[(df!=0).any(axis=1)]
|
df = df.loc[(df!=0).any(axis=1)]
|
||||||
df.fillna(method='bfill',axis=0,inplace=True)
|
df.fillna(method='bfill',axis=0,inplace=True)
|
||||||
df.fillna(method='ffill',axis=0,inplace=True)
|
df.fillna(method='ffill',axis=0,inplace=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
lat = df['lat']
|
lat = df['lat']
|
||||||
lon = df['lon']
|
lon = df['lon']
|
||||||
if lat.empty or lon.empty:
|
if lat.empty or lon.empty:
|
||||||
return [0,"invalid coordinate data"]
|
return [0,"invalid coordinate data"]
|
||||||
|
|
||||||
|
latbegin = lat.values[0]
|
||||||
|
longbegin = lon.values[0]
|
||||||
|
latend = lat.values[-1]
|
||||||
|
longend = lon.values[-1]
|
||||||
|
|
||||||
|
colors = itertools.cycle(palette)
|
||||||
|
try:
|
||||||
|
items = itertools.izip(workoutids,colors)
|
||||||
|
except AttributeError:
|
||||||
|
items = zip(workoutids,colors)
|
||||||
|
|
||||||
|
|
||||||
coordinates = zip(lat,lon)
|
|
||||||
|
|
||||||
scoordinates = "["
|
|
||||||
|
|
||||||
for x,y in coordinates:
|
|
||||||
scoordinates += """[{x},{y}],
|
|
||||||
""".format(
|
|
||||||
x=x,
|
|
||||||
y=y
|
|
||||||
)
|
|
||||||
|
|
||||||
scoordinates += "]"
|
|
||||||
|
|
||||||
script = """
|
script = """
|
||||||
<script>
|
<script>
|
||||||
@@ -2162,16 +2212,12 @@ def leaflet_chart_compare(workoutids,labeldict={},startenddict={}):
|
|||||||
"Navionics":navionics,
|
"Navionics":navionics,
|
||||||
}}).addTo(mymap);
|
}}).addTo(mymap);
|
||||||
|
|
||||||
var marker = L.marker([{latbegin}, {longbegin}]).addTo(mymap);
|
|
||||||
marker.bindPopup("<b>Start</b>");
|
|
||||||
var emarker = new L.marker([{latend}, {longend}]).addTo(mymap);
|
|
||||||
emarker.bindPopup("<b>End</b>");
|
|
||||||
|
|
||||||
var latlongs = {scoordinates}
|
var platlongs = {pcoordinates}
|
||||||
var polyline = L.polyline(latlongs, {{color:'red'}}).addTo(mymap)
|
var polygons = L.polygon(platlongs, {{color:'blue'}}).addTo(mymap)
|
||||||
mymap.fitBounds(polyline.getBounds())
|
|
||||||
|
{plabels}
|
||||||
|
|
||||||
</script>
|
|
||||||
""".format(
|
""".format(
|
||||||
latmean=latmean,
|
latmean=latmean,
|
||||||
lonmean=lonmean,
|
lonmean=lonmean,
|
||||||
@@ -2179,9 +2225,69 @@ def leaflet_chart_compare(workoutids,labeldict={},startenddict={}):
|
|||||||
latend=latend,
|
latend=latend,
|
||||||
longbegin=longbegin,
|
longbegin=longbegin,
|
||||||
longend=longend,
|
longend=longend,
|
||||||
scoordinates=scoordinates,
|
pcoordinates=pcoordinates,
|
||||||
|
plabels=plabels,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
for id,color in items:
|
||||||
|
group = df[df['workoutid']==int(id)].copy()
|
||||||
|
try:
|
||||||
|
startsecond,endsecond = startenddict[id]
|
||||||
|
except KeyError:
|
||||||
|
startsecond = 0
|
||||||
|
endsecond = 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
label = labeldict[id]
|
||||||
|
except KeyError:
|
||||||
|
label = str(id)
|
||||||
|
|
||||||
|
group.sort_values(by='time',ascending=True,inplace=True)
|
||||||
|
group.dropna(axis=0,how='any',inplace=True)
|
||||||
|
if endsecond > 0:
|
||||||
|
group['time'] = group['time'] - startsecond
|
||||||
|
mask = group['time'] < 0
|
||||||
|
group.mask(mask,inplace=True)
|
||||||
|
mask = group['time'] > (endsecond-startsecond)
|
||||||
|
group.mask(mask,inplace=True)
|
||||||
|
|
||||||
|
lat = group['lat'].dropna()
|
||||||
|
lon = group['lon'].dropna()
|
||||||
|
|
||||||
|
coordinates = zip(lat,lon)
|
||||||
|
|
||||||
|
scoordinates = "["
|
||||||
|
for x,y in coordinates:
|
||||||
|
scoordinates += """[{x},{y}],
|
||||||
|
""".format(x=x,y=y)
|
||||||
|
scoordinates += "]"
|
||||||
|
|
||||||
|
script += """
|
||||||
|
var latlongs = {scoordinates}
|
||||||
|
var polyline = L.polyline(latlongs, {{color:'{color}'}}).addTo(mymap)
|
||||||
|
polyline.bindPopup("<b>{label}</b>",{{ autoPan: false, autoClose: false }}).openPopup()
|
||||||
|
polyline.on('mouseover',function(ev) {{
|
||||||
|
ev.target.openPopup();
|
||||||
|
}});
|
||||||
|
polyline.on('dblclick', function (e) {{
|
||||||
|
mymap.removeLayer(this);
|
||||||
|
}});
|
||||||
|
mymap.fitBounds(polyline.getBounds())
|
||||||
|
""".format(
|
||||||
|
scoordinates=scoordinates,
|
||||||
|
color=color,
|
||||||
|
label=label,
|
||||||
|
id=id,
|
||||||
|
)
|
||||||
|
|
||||||
|
script += """
|
||||||
|
|
||||||
|
</script>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
div = """
|
div = """
|
||||||
<div id="map_canvas" style="width: 100%; height: 100%; min-height: 100vh"><p> </p></div>
|
<div id="map_canvas" style="width: 100%; height: 100%; min-height: 100vh"><p> </p></div>
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
{% extends "newbase.html" %}
|
{% extends "newbase.html" %}
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
{% load rowerfilters %}
|
{% load rowerfilters %}
|
||||||
|
{% load leaflet_tags %}
|
||||||
|
|
||||||
|
{% block meta %}
|
||||||
|
{% leaflet_js %}
|
||||||
|
{% leaflet_css %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block title %}View Comparison {% endblock %}
|
{% block title %}View Comparison {% endblock %}
|
||||||
|
|
||||||
@@ -11,32 +17,17 @@
|
|||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{{ interactiveplot |safe }}
|
<h1>Course Map Comparison</h1>
|
||||||
|
|
||||||
<h1>Interactive Comparison</h1>
|
<p>Click on a line to see the label. Double click on a line to remove it. Reload to get back all lines.</p>
|
||||||
|
<p>We show your original GPS coordinates on the course. For course time, we use a finer interpolation, to get
|
||||||
|
the exact time when you crossed the line.</p>
|
||||||
|
|
||||||
|
<div class="mapdiv">
|
||||||
<ul class="main-content">
|
{{ mapdiv|safe }}
|
||||||
<li class="grid_4">
|
{{ mapscript|safe }}
|
||||||
<div>
|
|
||||||
{{ the_div|safe }}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</li>
|
|
||||||
<li class="grid_4">
|
|
||||||
<form enctype="multipart/form-data" action="" method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<table>
|
|
||||||
{{ chartform.as_table }}
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<input name='workoutselectform' class="button green" type="submit" value="Submit">
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@@ -377,6 +377,10 @@
|
|||||||
<p>
|
<p>
|
||||||
<a href="/rowers/virtualevent/{{ race.id }}/compare"
|
<a href="/rowers/virtualevent/{{ race.id }}/compare"
|
||||||
title="Compare the workouts of all competitors">Compare Results</a>
|
title="Compare the workouts of all competitors">Compare Results</a>
|
||||||
|
{% if race.sessiontype == 'race' %}
|
||||||
|
<a href="/rowers/virtualevent/{{ race.id }}/mapcompare"
|
||||||
|
title="Compare the courses taken by the competitors">Compare Course</a>
|
||||||
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
{% if race.manager == request.user %}
|
{% if race.manager == request.user %}
|
||||||
<a href="/rowers/virtualevent/{{ race.id }}/download"
|
<a href="/rowers/virtualevent/{{ race.id }}/download"
|
||||||
|
|||||||
@@ -342,6 +342,8 @@ urlpatterns = [
|
|||||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/wind/$',views.workout_wind_view,name='workout_wind_view'),
|
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/wind/$',views.workout_wind_view,name='workout_wind_view'),
|
||||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/image/$',views.workout_uploadimage_view,name='workout_uploadimage_view'),
|
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/image/$',views.workout_uploadimage_view,name='workout_uploadimage_view'),
|
||||||
re_path(r'^virtualevent/(?P<id>\d+)/compare/$',views.virtualevent_compare_view,name='virtualevent_compare_view'),
|
re_path(r'^virtualevent/(?P<id>\d+)/compare/$',views.virtualevent_compare_view,name='virtualevent_compare_view'),
|
||||||
|
re_path(r'^virtualevent/(?P<id>\d+)/mapcompare/$',views.virtualevent_mapcompare_view,
|
||||||
|
name='virtualevent_mapcompare_view'),
|
||||||
re_path(r'^virtualevent/(?P<id>\d+)/image/$',
|
re_path(r'^virtualevent/(?P<id>\d+)/image/$',
|
||||||
views.virtualevent_uploadimage_view,name='virtualevent_uploadimage_view'),
|
views.virtualevent_uploadimage_view,name='virtualevent_uploadimage_view'),
|
||||||
re_path(r'^virtualevent/(?P<id>\d+)/setimage/(?P<logoid>\d+)/$',
|
re_path(r'^virtualevent/(?P<id>\d+)/setimage/(?P<logoid>\d+)/$',
|
||||||
|
|||||||
@@ -1491,6 +1491,97 @@ def team_comparison_select(request,
|
|||||||
'teams':get_my_teams(request.user),
|
'teams':get_my_teams(request.user),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def virtualevent_mapcompare_view(request,id=0):
|
||||||
|
results = []
|
||||||
|
|
||||||
|
r = None
|
||||||
|
if not request.user.is_anonymous:
|
||||||
|
r = getrower(request.user)
|
||||||
|
|
||||||
|
try:
|
||||||
|
race = VirtualRace.objects.get(id=id)
|
||||||
|
except VirtualRace.DoesNotExist:
|
||||||
|
raise Http404("Virtual Challenge does not exist")
|
||||||
|
|
||||||
|
if race.sessiontype != 'race':
|
||||||
|
url = reverse(virtualevent_view,kwargs={'id':id})
|
||||||
|
messages.error(request,"This challenge doesn't have map data")
|
||||||
|
return HttpResponseRedirect(request)
|
||||||
|
|
||||||
|
results = VirtualRaceResult.objects.filter(
|
||||||
|
race=race,
|
||||||
|
workoutid__isnull=False,
|
||||||
|
coursecompleted=True,
|
||||||
|
).order_by("distance","duration")
|
||||||
|
|
||||||
|
workoutids = [result.workoutid for result in results]
|
||||||
|
|
||||||
|
startenddict = {}
|
||||||
|
if race.sessiontype == 'race':
|
||||||
|
for result in results:
|
||||||
|
startenddict[result.workoutid] = (result.startsecond,result.endsecond)
|
||||||
|
|
||||||
|
if len(workoutids) == 0:
|
||||||
|
url = reverse('virtualevent_view',
|
||||||
|
kwargs={
|
||||||
|
'id':race.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
messages.info(request,'There are no results to display')
|
||||||
|
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
workouts = []
|
||||||
|
for id in workoutids:
|
||||||
|
try:
|
||||||
|
workouts.append(Workout.objects.get(id=id))
|
||||||
|
except Workout.DoesNotExist:
|
||||||
|
pass
|
||||||
|
|
||||||
|
labeldict = {
|
||||||
|
int(w.id): w.__str__() for w in workouts
|
||||||
|
}
|
||||||
|
|
||||||
|
script,div = leaflet_chart_compare(race.course,workoutids,
|
||||||
|
labeldict=labeldict,
|
||||||
|
startenddict=startenddict)
|
||||||
|
|
||||||
|
breadcrumbs = [
|
||||||
|
{
|
||||||
|
'url': reverse('virtualevents_view'),
|
||||||
|
'name': 'Racing'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url':reverse('virtualevent_view',
|
||||||
|
kwargs={
|
||||||
|
'id':race.id,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
'name': race.name
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url':reverse('virtualevent_mapcompare_view',
|
||||||
|
kwargs={
|
||||||
|
'id':race.id,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
'name': 'Course Compare'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
return render(request,'mapcompare.html',
|
||||||
|
{'mapscript':script,
|
||||||
|
'mapdiv':div,
|
||||||
|
'breadcrumbs':breadcrumbs,
|
||||||
|
'rower':r,
|
||||||
|
'race':race,
|
||||||
|
'results':results,
|
||||||
|
'active':'nav-racing',
|
||||||
|
'teamid':0,
|
||||||
|
'teams':[]
|
||||||
|
})
|
||||||
|
|
||||||
def virtualevent_compare_view(request,id=0):
|
def virtualevent_compare_view(request,id=0):
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
@@ -1506,7 +1597,7 @@ def virtualevent_compare_view(request,id=0):
|
|||||||
try:
|
try:
|
||||||
race = VirtualRace.objects.get(id=id)
|
race = VirtualRace.objects.get(id=id)
|
||||||
except VirtualRace.DoesNotExist:
|
except VirtualRace.DoesNotExist:
|
||||||
raise Http404("Virtual Race does not exist")
|
raise Http404("Virtual Challenge does not exist")
|
||||||
|
|
||||||
if race.sessiontype == 'race':
|
if race.sessiontype == 'race':
|
||||||
script,div = course_map(race.course)
|
script,div = course_map(race.course)
|
||||||
@@ -1531,6 +1622,8 @@ def virtualevent_compare_view(request,id=0):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if len(workoutids) == 0:
|
if len(workoutids) == 0:
|
||||||
url = reverse('virtualevent_view',
|
url = reverse('virtualevent_view',
|
||||||
kwargs={
|
kwargs={
|
||||||
|
|||||||
Reference in New Issue
Block a user