Added slider and improved behavior of video analysis
This commit is contained in:
@@ -1899,6 +1899,9 @@ def leaflet_chart_video(lat,lon,name=""):
|
|||||||
"Nautical": nautical,
|
"Nautical": nautical,
|
||||||
}},{{
|
}},{{
|
||||||
"Navionics":navionics,
|
"Navionics":navionics,
|
||||||
|
}},
|
||||||
|
{{
|
||||||
|
position:'topleft'
|
||||||
}}).addTo(mymap);
|
}}).addTo(mymap);
|
||||||
|
|
||||||
var marker = L.marker([{latbegin}, {longbegin}]).addTo(mymap);
|
var marker = L.marker([{latbegin}, {longbegin}]).addTo(mymap);
|
||||||
|
|||||||
@@ -15,15 +15,54 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.slidecontainer {
|
||||||
|
width: 100%; /* Width of the outside container */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The slider itself */
|
||||||
|
.slider {
|
||||||
|
-webkit-appearance: none; /* Override default CSS styles */
|
||||||
|
appearance: none;
|
||||||
|
width: 100%; /* Full-width */
|
||||||
|
height: 25px; /* Specified height */
|
||||||
|
background: #d3d3d3; /* Grey background */
|
||||||
|
outline: none; /* Remove outline */
|
||||||
|
opacity: 0.7; /* Set transparency (for mouse-over effects on hover) */
|
||||||
|
-webkit-transition: .2s; /* 0.2 seconds transition on hover */
|
||||||
|
transition: opacity .2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mouse-over effects */
|
||||||
|
.slider:hover {
|
||||||
|
opacity: 1; /* Fully shown on mouse-over */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The slider handle (use -webkit- (Chrome, Opera, Safari, Edge) and -moz- (Firefox) to override default look) */
|
||||||
|
.slider::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none; /* Override default look */
|
||||||
|
appearance: none;
|
||||||
|
width: 25px; /* Set a specific slider handle width */
|
||||||
|
height: 25px; /* Slider handle height */
|
||||||
|
background: #4CAF50; /* Green background */
|
||||||
|
cursor: pointer; /* Cursor on hover */
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider::-moz-range-thumb {
|
||||||
|
width: 25px; /* Set a specific slider handle width */
|
||||||
|
height: 25px; /* Slider handle height */
|
||||||
|
background: #4CAF50; /* Green background */
|
||||||
|
cursor: pointer; /* Cursor on hover */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
{% language 'en' %}
|
{% language 'en' %}
|
||||||
<h1>Video Analysis for {{ workout.name }}</h1>
|
<h1>Video Analysis for {{ workout.name }}</h1>
|
||||||
<ul class="main-content">
|
<ul class="main-content">
|
||||||
<li class="grid_4">
|
<li>
|
||||||
<div style="height:100%" id="theplot" class="flexplot mapdiv">
|
Data Time
|
||||||
{{ mapdiv | safe}}
|
<span id="datatime">
|
||||||
|
</span> seconds
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Video Time
|
Video Time
|
||||||
@@ -40,11 +79,21 @@
|
|||||||
<span id="speed">
|
<span id="speed">
|
||||||
</span> m/s
|
</span> m/s
|
||||||
</li>
|
</li>
|
||||||
<li class="grid_4">
|
<li class="grid_2">
|
||||||
|
<div style="height:100%" id="theplot" class="flexplot mapdiv">
|
||||||
|
{{ mapdiv | safe}}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="slidecontainer">
|
||||||
|
<input type="range" min="0" max="{{ maxtime }}" value="{{ analysis.delay }}" class="slider" id="myRange">
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="grid_2">
|
||||||
<div id="player"></div>
|
<div id="player"></div>
|
||||||
<script>
|
<script>
|
||||||
// 1. Code for the map
|
// 1. Code for the map
|
||||||
{{ mapscript | safe }}
|
{{ mapscript | safe }}
|
||||||
|
|
||||||
// 2. This code loads the IFrame Player API code asynchronously.
|
// 2. This code loads the IFrame Player API code asynchronously.
|
||||||
var tag = document.createElement('script');
|
var tag = document.createElement('script');
|
||||||
|
|
||||||
@@ -75,16 +124,20 @@
|
|||||||
|
|
||||||
// 4. The API will call this function when the video player is ready.
|
// 4. The API will call this function when the video player is ready.
|
||||||
function onPlayerReady(event) {
|
function onPlayerReady(event) {
|
||||||
event.target.playVideo();
|
// event.target.playVideo();
|
||||||
function updateTime() {
|
function updateTime() {
|
||||||
var oldTime = videotime;
|
var oldTime = videotime;
|
||||||
if(player && player.getCurrentTime) {
|
if(player && player.getCurrentTime) {
|
||||||
videotime = player.getCurrentTime();
|
videotime = player.getCurrentTime();
|
||||||
velo = boatspeed[Math.round(videotime)];
|
var delay = document.getElementById("myRange").value;
|
||||||
lat = latitude[Math.round(videotime)];
|
var datatime = parseFloat(videotime)+parseFloat(delay);
|
||||||
lon = longitude[Math.round(videotime)];
|
velo = boatspeed[Math.round(datatime)];
|
||||||
strokerate = spm[Math.round(videotime)];
|
lat = latitude[Math.round(datatime)];
|
||||||
|
lon = longitude[Math.round(datatime)];
|
||||||
|
strokerate = spm[Math.round(datatime)];
|
||||||
|
|
||||||
document.getElementById("time").innerHTML = Math.round(videotime);
|
document.getElementById("time").innerHTML = Math.round(videotime);
|
||||||
|
document.getElementById("datatime").innerHTML = Math.round(datatime);
|
||||||
document.getElementById("speed").innerHTML = velo;
|
document.getElementById("speed").innerHTML = velo;
|
||||||
document.getElementById("spm").innerHTML = strokerate;
|
document.getElementById("spm").innerHTML = strokerate;
|
||||||
var newLatLng = new L.LatLng(lat, lon);
|
var newLatLng = new L.LatLng(lat, lon);
|
||||||
@@ -99,9 +152,6 @@
|
|||||||
|
|
||||||
// when the time changes, this will be called.
|
// when the time changes, this will be called.
|
||||||
function onProgress(currentTime) {
|
function onProgress(currentTime) {
|
||||||
if(currentTime > 20) {
|
|
||||||
console.log("the video reached 20 seconds!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopVideo() {
|
function stopVideo() {
|
||||||
@@ -143,6 +193,26 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<script>
|
||||||
|
// slider
|
||||||
|
var slider = document.getElementById("myRange");
|
||||||
|
{% if analysis and user.is_authenticated and user == rower.user %}
|
||||||
|
document.getElementById("myRange").style.display = "block";
|
||||||
|
{% else %}
|
||||||
|
document.getElementById("myRange").style.display = "none";
|
||||||
|
{% endif %}
|
||||||
|
var output = document.getElementById("id_delay");
|
||||||
|
output.value = slider.value; // Display the default slider value
|
||||||
|
|
||||||
|
// Update the current slider value (each time you drag the slider handle)
|
||||||
|
slider.oninput = function() {
|
||||||
|
output.value = this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
output.oninput = function() {
|
||||||
|
slider.value = this.value;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
{% endlanguage %}
|
{% endlanguage %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -45,6 +45,11 @@
|
|||||||
<i class="fas fa-balance-scale fa-fw"></i> Compare
|
<i class="fas fa-balance-scale fa-fw"></i> Compare
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li id="video-analysis">
|
||||||
|
<a href="/rowers/workout/{{ workout.id|encode }}/video/">
|
||||||
|
<i class="fas fa-video-plus fa-fw"></i> Video Analysis
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
{% if user.is_authenticated and workout|may_edit:request %}
|
{% if user.is_authenticated and workout|may_edit:request %}
|
||||||
<li id="chart-image">
|
<li id="chart-image">
|
||||||
<a href="/rowers/workout/{{ workout.id|encode }}/image/">
|
<a href="/rowers/workout/{{ workout.id|encode }}/image/">
|
||||||
@@ -74,11 +79,6 @@
|
|||||||
<i class="fas fa-map-marked-alt fa-fw"></i> Map
|
<i class="fas fa-map-marked-alt fa-fw"></i> Map
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li id="video-analysis">
|
|
||||||
<a href="/rowers/workout/{{ workout.id|encode }}/video/">
|
|
||||||
<i class="fas fa-video-plus fa-fw"></i> Video Analysis
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li id="chart-empower">
|
<li id="chart-empower">
|
||||||
<a href="/rowers/workout/{{ workout.id|encode }}/forcecurve/">
|
<a href="/rowers/workout/{{ workout.id|encode }}/forcecurve/">
|
||||||
<i class="fas fa-dumbbell fa-fw"></i> Force Curve
|
<i class="fas fa-dumbbell fa-fw"></i> Force Curve
|
||||||
|
|||||||
@@ -173,6 +173,7 @@ $('#id_workouttype').change();
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% for video in videos %}
|
{% for video in videos %}
|
||||||
<li>
|
<li>
|
||||||
|
<div>{{ video.name }}</div>
|
||||||
<a href="/rowers/video/{{ video.id|encode }}/">
|
<a href="/rowers/video/{{ video.id|encode }}/">
|
||||||
<img src="https://img.youtube.com/vi/{{ video.video_id }}/hqdefault.jpg"/>
|
<img src="https://img.youtube.com/vi/{{ video.video_id }}/hqdefault.jpg"/>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -69,6 +69,10 @@ def workout_video_view(request,id=''):
|
|||||||
form = VideoAnalysisCreateForm(request.POST)
|
form = VideoAnalysisCreateForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
video_id = form.cleaned_data['url']
|
video_id = form.cleaned_data['url']
|
||||||
|
try:
|
||||||
|
video_id = get_video_id(form.cleaned_data['url'])
|
||||||
|
except (TypeError,ValueError):
|
||||||
|
pass
|
||||||
delay = form.cleaned_data['delay']
|
delay = form.cleaned_data['delay']
|
||||||
if 'save_button' in request.POST:
|
if 'save_button' in request.POST:
|
||||||
analysis.name = form.cleaned_data['name']
|
analysis.name = form.cleaned_data['name']
|
||||||
@@ -101,8 +105,8 @@ def workout_video_view(request,id=''):
|
|||||||
df2 = df.resample('1s').mean().interpolate()
|
df2 = df.resample('1s').mean().interpolate()
|
||||||
|
|
||||||
|
|
||||||
mask = df2['time'] < delay
|
#mask = df2['time'] < delay
|
||||||
df2 = df2.mask(mask).dropna()
|
#df2 = df2.mask(mask).dropna()
|
||||||
df2['time'] = (df2['time']-df2['time'].min())
|
df2['time'] = (df2['time']-df2['time'].min())
|
||||||
|
|
||||||
boatspeed = (100*df2['velo']).astype(int)/100.
|
boatspeed = (100*df2['velo']).astype(int)/100.
|
||||||
@@ -112,8 +116,8 @@ def workout_video_view(request,id=''):
|
|||||||
|
|
||||||
coordinates.set_index(pd.to_timedelta(coordinates['time'],unit='s'),inplace=True)
|
coordinates.set_index(pd.to_timedelta(coordinates['time'],unit='s'),inplace=True)
|
||||||
coordinates = coordinates.resample('1s').mean().interpolate()
|
coordinates = coordinates.resample('1s').mean().interpolate()
|
||||||
mask = coordinates['time'] < delay
|
#mask = coordinates['time'] < delay
|
||||||
coordinates = coordinates.mask(mask).dropna()
|
#coordinates = coordinates.mask(mask).dropna()
|
||||||
coordinates['time'] = coordinates['time']-coordinates['time'].min()
|
coordinates['time'] = coordinates['time']-coordinates['time'].min()
|
||||||
latitude = coordinates['latitude']
|
latitude = coordinates['latitude']
|
||||||
longitude = coordinates['longitude']
|
longitude = coordinates['longitude']
|
||||||
@@ -158,6 +162,7 @@ def workout_video_view(request,id=''):
|
|||||||
'form':form,
|
'form':form,
|
||||||
'breadcrumbs':breadcrumbs,
|
'breadcrumbs':breadcrumbs,
|
||||||
'analysis':analysis,
|
'analysis':analysis,
|
||||||
|
'maxtime':coordinates['time'].max(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@@ -206,8 +211,8 @@ def workout_video_create_view(request,id=0):
|
|||||||
df2 = df.resample('1s').mean().interpolate()
|
df2 = df.resample('1s').mean().interpolate()
|
||||||
|
|
||||||
|
|
||||||
mask = df2['time'] < delay
|
#mask = df2['time'] < delay
|
||||||
df2 = df2.mask(mask).dropna()
|
#df2 = df2.mask(mask).dropna()
|
||||||
df2['time'] = (df2['time']-df2['time'].min())
|
df2['time'] = (df2['time']-df2['time'].min())
|
||||||
|
|
||||||
boatspeed = (100*df2['velo']).astype(int)/100.
|
boatspeed = (100*df2['velo']).astype(int)/100.
|
||||||
@@ -217,8 +222,8 @@ def workout_video_create_view(request,id=0):
|
|||||||
|
|
||||||
coordinates.set_index(pd.to_timedelta(coordinates['time'],unit='s'),inplace=True)
|
coordinates.set_index(pd.to_timedelta(coordinates['time'],unit='s'),inplace=True)
|
||||||
coordinates = coordinates.resample('1s').mean().interpolate()
|
coordinates = coordinates.resample('1s').mean().interpolate()
|
||||||
mask = coordinates['time'] < delay
|
#mask = coordinates['time'] < delay
|
||||||
coordinates = coordinates.mask(mask).dropna()
|
#coordinates = coordinates.mask(mask).dropna()
|
||||||
coordinates['time'] = coordinates['time']-coordinates['time'].min()
|
coordinates['time'] = coordinates['time']-coordinates['time'].min()
|
||||||
latitude = coordinates['latitude']
|
latitude = coordinates['latitude']
|
||||||
longitude = coordinates['longitude']
|
longitude = coordinates['longitude']
|
||||||
@@ -251,6 +256,8 @@ def workout_video_create_view(request,id=0):
|
|||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
analysis = {'delay':delay}
|
||||||
|
|
||||||
return render(request,
|
return render(request,
|
||||||
'embedded_video.html',
|
'embedded_video.html',
|
||||||
{
|
{
|
||||||
@@ -261,7 +268,9 @@ def workout_video_create_view(request,id=0):
|
|||||||
'mapdiv': mapdiv,
|
'mapdiv': mapdiv,
|
||||||
'video_id': video_id,
|
'video_id': video_id,
|
||||||
'form':form,
|
'form':form,
|
||||||
|
'analysis':analysis,
|
||||||
'breadcrumbs':breadcrumbs,
|
'breadcrumbs':breadcrumbs,
|
||||||
|
'maxtime':coordinates['time'].max()
|
||||||
})
|
})
|
||||||
|
|
||||||
# Show the EMpower Oarlock generated Stroke Profile
|
# Show the EMpower Oarlock generated Stroke Profile
|
||||||
|
|||||||
Reference in New Issue
Block a user