Switch to using custom svg sparkline for exercise graphs on person view, this isnt a proper implementation as it separate requests for each exercise selected (Want to get rid of dependency on plotly)
This commit is contained in:
6
app.py
6
app.py
@@ -432,7 +432,11 @@ def calculate_relative_positions(start_dates):
|
||||
|
||||
@ app.route("/person/<int:person_id>/exercise/<int:exercise_id>/sparkline", methods=['GET'])
|
||||
def get_exercise_progress_for_user(person_id, exercise_id):
|
||||
exercise_progress = db.get_exercise_progress_for_user(person_id, exercise_id)
|
||||
min_date = convert_str_to_date(request.args.get(
|
||||
'min_date'), '%Y-%m-%d')
|
||||
max_date = convert_str_to_date(request.args.get(
|
||||
'max_date'), '%Y-%m-%d')
|
||||
exercise_progress = db.get_exercise_progress_for_user(person_id, exercise_id, min_date, max_date)
|
||||
|
||||
if not exercise_progress:
|
||||
abort(404)
|
||||
|
||||
15
db.py
15
db.py
@@ -464,7 +464,7 @@ class DataBase():
|
||||
'SELECT exercise_id, name FROM exercise')
|
||||
return exercises
|
||||
|
||||
def get_exercise_progress_for_user(self, person_id, exercise_id):
|
||||
def get_exercise_progress_for_user(self, person_id, exercise_id, min_date=None, max_date=None):
|
||||
# Execute SQL query to fetch topset data for a specific person and exercise
|
||||
topsets = self.execute("""
|
||||
SELECT
|
||||
@@ -479,10 +479,13 @@ class DataBase():
|
||||
JOIN
|
||||
workout W ON T.workout_id = W.workout_id
|
||||
WHERE
|
||||
W.person_id = %s AND E.exercise_id = %s
|
||||
W.person_id = %s
|
||||
AND E.exercise_id = %s AND
|
||||
(%s IS NULL OR W.start_date >= %s) AND
|
||||
(%s IS NULL OR W.start_date <= %s)
|
||||
ORDER BY
|
||||
W.start_date;
|
||||
""", [person_id, exercise_id])
|
||||
""", [person_id, exercise_id, min_date, min_date, max_date, max_date])
|
||||
|
||||
# Return None if no topsets found
|
||||
if not topsets:
|
||||
@@ -500,9 +503,9 @@ class DataBase():
|
||||
|
||||
# Calculate viewBox dimensions
|
||||
date_range = max_date - min_date
|
||||
e1rm_range = max_e1rm - min_e1rm
|
||||
reps_range = max_reps - min_reps
|
||||
weight_range = max_weight - min_weight
|
||||
e1rm_range = (max_e1rm - min_e1rm) or 1
|
||||
reps_range = (max_reps - min_reps) or 1
|
||||
weight_range = (max_weight - min_weight) or 1
|
||||
vb_width, vb_height = date_range.days, e1rm_range
|
||||
vb_width *= 200 / vb_width # Scale to 200px width
|
||||
vb_height *= 75 / vb_height # Scale to 75px height
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap mb-1">
|
||||
<div class="w-full md:w-1/4 px-2 md:px-3 mb-6 md:mb-0">
|
||||
<div class="w-full md:w-1/3 px-2 md:px-3 mb-6 md:mb-0">
|
||||
<div class="mb-1 w-full">
|
||||
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="grid-city">
|
||||
Exercises
|
||||
@@ -60,7 +60,7 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full md:w-1/4 px-2 md:px-3 mb-6 md:mb-0">
|
||||
<div class="w-full md:w-1/3 px-2 md:px-3 mb-6 md:mb-0">
|
||||
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="grid-city">
|
||||
Min date
|
||||
</label>
|
||||
@@ -81,7 +81,7 @@
|
||||
hx-target="#container" hx-push-url="true" hx-trigger="change">
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full md:w-1/4 px-2 md:px-3 mb-6 md:mb-0">
|
||||
<div class="w-full md:w-1/3 px-2 md:px-3 mb-6 md:mb-0">
|
||||
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="grid-zip">
|
||||
Max date
|
||||
</label>
|
||||
@@ -102,22 +102,6 @@
|
||||
hx-target="#container" hx-push-url="true" hx-trigger="change">
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full md:w-1/4 px-2 md:px-3 mb-6 md:mb-0">
|
||||
<div class="mb-1 w-full">
|
||||
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="grid-city">
|
||||
Graph Axis
|
||||
</label>
|
||||
<select name="graph_axis" class="bg-gray-50 border border-gray-300 " multiple
|
||||
hx-get="{{ url_for('get_person', person_id=person['PersonId']) }}"
|
||||
hx-include="[name='exercise_id'],[name='min_date'],[name='max_date'],[name='graph_axis']"
|
||||
hx-target="#container" hx-push-url="true"
|
||||
_="init js(me) tail.select(me, { multiple: true, placeholder: 'Select graphs' }) end">
|
||||
<option value="repetitions" {% if "repetitions" in graph_axis %}selected{% endif %}>Repetitions</option>
|
||||
<option value="weight" {% if "weight" in graph_axis %}selected{% endif %}>Weigh</option>
|
||||
<option value="estimated1rm" {% if "estimated1rm" in graph_axis %}selected{% endif %}>Estimated 1RM</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% with person_id=person['PersonId'], tags=tags %}
|
||||
@@ -186,95 +170,16 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if graph_axis %}
|
||||
<div class="mt-4 mb-4 w-full grid grid-cols-1 2xl:grid-cols-2 gap-4">
|
||||
{% for exercise_graph in person['ExerciseGraphs'] %}
|
||||
{% for exercise_id in selected_exercise_ids %}
|
||||
<div class="bg-white shadow rounded-lg p-4 sm:p-6 xl:p-8 ">
|
||||
<div class="flex flex-col items-center">
|
||||
<div class="flex-shrink-0">
|
||||
<span class="text-2xl sm:text-3xl leading-none font-bold text-gray-900">{{
|
||||
exercise_graph['ExerciseName'] }}</span>
|
||||
</div>
|
||||
<div id="e-{{ exercise_graph['ExerciseId'] }}" class="w-full mt-2 aspect-video"></div>
|
||||
<script>
|
||||
Plotly.newPlot("e-{{ exercise_graph['ExerciseId'] }}", [
|
||||
{% if 'repetitions' in graph_axis %}
|
||||
{
|
||||
x: {{ exercise_graph['StartDates'] | replace('"', "'") | safe }},
|
||||
y: {{ exercise_graph['Repetitions'] | replace('"', "'") | safe }},
|
||||
name: 'Reps',
|
||||
type: 'scatter'
|
||||
},
|
||||
{% endif %}
|
||||
{% if 'weight' in graph_axis %}
|
||||
{
|
||||
x: {{ exercise_graph['StartDates'] | replace('"', "'") | safe }},
|
||||
y: {{ exercise_graph['Weights'] | replace('"', "'") | safe }},
|
||||
name: 'Weight',
|
||||
yaxis: 'y2',
|
||||
type: 'scatter'
|
||||
},
|
||||
{% endif %}
|
||||
{% if 'estimated1rm' in graph_axis %}
|
||||
{
|
||||
x: {{ exercise_graph['StartDates'] | replace('"', "'") | safe }},
|
||||
y: {{ exercise_graph['Estimated1RM'] | replace('"', "'") | safe }},
|
||||
name: 'Estimated 1RM',
|
||||
yaxis: 'y3',
|
||||
type: 'scatter'
|
||||
},
|
||||
{% endif %}
|
||||
],
|
||||
{
|
||||
margin: {
|
||||
t: 20, // Increase top margin to move the graph downwards
|
||||
l: 50, // Increase left margin if the graph is too far to the right
|
||||
r: 50, // Increase right margin for the same reason
|
||||
b: 40 // Bottom margin for better layout
|
||||
},
|
||||
xaxis: { type: 'date', showgrid: false },
|
||||
yaxis: { title: 'Reps', showgrid: false },
|
||||
yaxis2: {
|
||||
title: 'Weight',
|
||||
overlaying: 'y',
|
||||
side: 'right',
|
||||
showgrid: false,
|
||||
position: 0.94
|
||||
},
|
||||
yaxis3: {
|
||||
title: 'Estimated 1RM',
|
||||
overlaying: 'y',
|
||||
side: 'right',
|
||||
showgrid: false,
|
||||
position: 1.00
|
||||
},
|
||||
showlegend: false,
|
||||
legend: {
|
||||
|
||||
font: {
|
||||
size: 10 // Adjust the font size of the legend to make it smaller
|
||||
},
|
||||
"orientation": "h"
|
||||
}
|
||||
}, {
|
||||
responsive: true,
|
||||
displayModeBar: false,
|
||||
//staticPlot: true,
|
||||
displaylogo: false,
|
||||
modeBarButtonsToRemove: ['toImage', 'sendDataToCloud', 'zoom2d', 'pan2d', 'select2d', 'lasso2d',
|
||||
'zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d', 'hoverClosestCartesian',
|
||||
'hoverCompareCartesian', 'zoom3d', 'pan3d', 'orbitRotation', 'tableRotation',
|
||||
'resetCameraDefault3d', 'resetCameraLastSave3d', 'hoverClosest3d', 'zoomInGeo',
|
||||
'zoomOutGeo', 'resetGeo', 'hoverClosestGeo', 'hoverClosestGl2d', 'hoverClosestPie',
|
||||
'toggleHover', 'resetViews', 'toggleSpikelines', 'resetViewMapbox'
|
||||
]
|
||||
});
|
||||
</script>
|
||||
<div class="hidden"
|
||||
hx-get="{{ url_for('get_exercise_progress_for_user', person_id=person['PersonId'], exercise_id=exercise_id, min_date=min_date, max_date=max_date) }}"
|
||||
hx-trigger="load" hx-target="this" hx-swap="outerHTML">
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{{ render_partial('partials/stats.html', stats=person['Stats']) }}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user