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:
Peter Stockings
2023-12-09 14:42:33 +11:00
parent 9d5d3b4507
commit e3435df8b5
3 changed files with 21 additions and 109 deletions

6
app.py
View File

@@ -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
View File

@@ -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

View File

@@ -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']) }}