[tasks] Add weigh in graph

This commit is contained in:
2026-06-04 22:13:14 -04:00
parent 50b10689fc
commit 6471413681
3 changed files with 142 additions and 2 deletions

View File

@ -1,5 +1,6 @@
import logging
import pendulum
from django.contrib import messages
from django.http import HttpResponseRedirect
from django.urls import reverse_lazy
@ -8,6 +9,7 @@ from rest_framework import status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from scrobbles.models import Scrobble
from scrobbles.views import ScrobbleableDetailView, ScrobbleableListView
from tasks.models import Task
@ -23,6 +25,72 @@ class TaskListView(ScrobbleableListView):
class TaskDetailView(ScrobbleableDetailView):
model = Task
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
if self.object.title != "Weigh-in":
return ctx
scrobbles = list(
Scrobble.objects.filter(
user=self.request.user,
task=self.object,
log__weight__isnull=False,
).order_by("timestamp")
)
if not scrobbles:
return ctx
labels = []
weight_data = []
body_fat_data = []
bmi_data = []
for s in scrobbles:
ts = s.timestamp
if isinstance(ts, str):
ts = pendulum.parse(ts)
labels.append(ts.strftime("%Y-%m-%d"))
log = s.log if isinstance(s.log, dict) else {}
raw_weight = log.get("weight")
weight_data.append(
float(raw_weight) if raw_weight is not None else None
)
raw_bf = log.get("body_fat")
body_fat_data.append(
float(raw_bf) if raw_bf is not None else None
)
raw_bmi = log.get("bmi")
bmi_data.append(
float(raw_bmi) if raw_bmi is not None else None
)
ctx["weighin_chart"] = {
"labels": labels,
"datasets": [
{
"label": "Weight",
"data": weight_data,
"borderColor": "#4bc0c0",
"fill": False,
"yAxisID": "y",
},
{
"label": "Body Fat %",
"data": body_fat_data,
"borderColor": "#ff6384",
"fill": False,
"yAxisID": "y1",
},
{
"label": "BMI",
"data": bmi_data,
"borderColor": "#36a2eb",
"fill": False,
"yAxisID": "y2",
},
],
}
return ctx
@api_view(["GET"])
@permission_classes([IsAuthenticated])

View File

@ -2,6 +2,7 @@
{% load mathfilters %}
{% load static %}
{% load naturalduration %}
{% load l10n %}
{% block title %}{{object.title}}{% endblock %}
@ -39,6 +40,15 @@
</p>
</div>
</div>
{% if weighin_chart %}
<div class="row mb-4">
<div class="col-md-8">
<canvas id="weighinChart" width="800" height="300"></canvas>
</div>
</div>
{% endif %}
<div class="row">
<p>{{scrobbles.count}} scrobbles</p>
<p>
@ -94,3 +104,61 @@
{% endif %}
</div>
{% endblock %}
{% block extra_js %}
{% if weighin_chart %}
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.4/dist/Chart.min.js"></script>
<script>
var ctx = document.getElementById('weighinChart').getContext('2d');
new Chart(ctx, {
type: 'line',
data: {
labels: {{ weighin_chart.labels|safe }},
datasets: [
{
label: 'Weight',
data: {{ weighin_chart.datasets.0.data|safe }},
borderColor: '{{ weighin_chart.datasets.0.borderColor }}',
backgroundColor: 'transparent',
pointRadius: 2,
fill: false,
yAxisID: 'y',
},
{
label: 'Body Fat %',
data: {{ weighin_chart.datasets.1.data|safe }},
borderColor: '{{ weighin_chart.datasets.1.borderColor }}',
backgroundColor: 'transparent',
pointRadius: 2,
fill: false,
yAxisID: 'y1',
},
{
label: 'BMI',
data: {{ weighin_chart.datasets.2.data|safe }},
borderColor: '{{ weighin_chart.datasets.2.borderColor }}',
backgroundColor: 'transparent',
pointRadius: 2,
fill: false,
yAxisID: 'y2',
},
]
},
options: {
responsive: true,
scales: {
xAxes: [{
ticks: { maxTicksLimit: 25, maxRotation: 45 },
}],
yAxes: [
{ id: 'y', type: 'linear', position: 'left', scaleLabel: { display: true, labelString: 'Weight' } },
{ id: 'y1', type: 'linear', position: 'right', scaleLabel: { display: true, labelString: 'Body Fat %' }, gridLines: { display: false } },
{ id: 'y2', type: 'linear', position: 'right', scaleLabel: { display: true, labelString: 'BMI' }, gridLines: { display: false } },
]
},
legend: { position: 'bottom' },
}
});
</script>
{% endif %}
{% endblock %}