calcul progression

This commit is contained in:
Tykayn 2025-07-05 10:29:53 +02:00 committed by tykayn
parent 2bbc7153c6
commit c81affd3e3
8 changed files with 275 additions and 50 deletions

View file

@ -101,28 +101,99 @@ if (canvas) {
// Affichage de la progression sur une semaine
function getDelta(data, days) {
if (!data.length) return null;
const now = new Date(data[data.length - 1].x);
const refDate = new Date(now.getTime() - days * 24 * 60 * 60 * 1000);
let ref = null;
const last = data[data.length - 1].y;
// Chercher la mesure exacte à la date de référence
let exactRef = null;
for (let i = data.length - 1; i >= 0; i--) {
const d = new Date(data[i].x);
if (d <= refDate) {
ref = data[i].y;
exactRef = data[i].y;
break;
}
}
const last = data[data.length - 1].y;
return ref !== null ? last - ref : null;
// Si on a trouvé une mesure exacte, l'utiliser
if (exactRef !== null) {
return last - exactRef;
}
// Sinon, chercher les deux mesures les plus proches pour faire une interpolation
let beforeRef = null;
let afterRef = null;
let beforeDate = null;
let afterDate = null;
// Chercher la mesure juste avant la date de référence
for (let i = data.length - 1; i >= 0; i--) {
const d = new Date(data[i].x);
if (d < refDate) {
beforeRef = data[i].y;
beforeDate = d;
break;
}
}
// Chercher la mesure juste après la date de référence
for (let i = 0; i < data.length; i++) {
const d = new Date(data[i].x);
if (d > refDate) {
afterRef = data[i].y;
afterDate = d;
break;
}
}
// Si on a les deux mesures, faire une interpolation linéaire
if (beforeRef !== null && afterRef !== null && beforeDate !== null && afterDate !== null) {
const timeDiff = afterDate.getTime() - beforeDate.getTime();
const refTimeDiff = refDate.getTime() - beforeDate.getTime();
const ratio = refTimeDiff / timeDiff;
const interpolatedRef = beforeRef + (afterRef - beforeRef) * ratio;
return last - interpolatedRef;
}
// Si on n'a qu'une mesure avant, l'utiliser
if (beforeRef !== null) {
return last - beforeRef;
}
// Si on n'a qu'une mesure après, l'utiliser
if (afterRef !== null) {
return last - afterRef;
}
// Si aucune mesure n'est disponible, retourner null
return null;
}
function formatDelta(val) {
if (val === null) return 'Pas de données';
if (val === 0) return '0';
return (val > 0 ? '+' : '') + val;
}
const delta7dCount = getDelta(countData, 7);
const delta7dCompletion = getDelta(completionData, 7);
const infoDiv = document.createElement('div');
infoDiv.className = 'mt-3 alert ' + (delta7dCount === null ? 'alert-secondary' : 'alert-info');
infoDiv.innerHTML = `<strong>Progression sur 7 jours :</strong> ${delta7dCount === null ? '<span title="Données insuffisantes pour calculer la progression">Aucune donnée</span>' : (delta7dCount > 0 ? '+' + delta7dCount : delta7dCount === 0 ? '0' : delta7dCount)}`;
let progressionText = '';
if (delta7dCount === null) {
progressionText = '<span title="Données insuffisantes pour calculer la progression">Aucune donnée</span>';
} else {
const countText = delta7dCount > 0 ? '+' + delta7dCount : delta7dCount === 0 ? '0' : delta7dCount;
const completionText = delta7dCompletion !== null ?
(delta7dCompletion > 0 ? '+' + delta7dCompletion.toFixed(1) : delta7dCompletion === 0 ? '0' : delta7dCompletion.toFixed(1)) + '%' :
'N/A';
progressionText = `${countText} objets, ${completionText} complétion`;
}
infoDiv.innerHTML = `<strong>Progression sur 7 jours :</strong> ${progressionText}`;
canvas.parentNode.appendChild(infoDiv);
</script>
{% endblock %}

View file

@ -12,6 +12,9 @@
<a href="{{ path('app_admin_labourer', {'insee_code': stats.zone, 'deleteMissing': 1}) }}" class="btn btn-primary">
<i class="bi bi-shovel"></i> Labourer la zone
</a>
<a href="{{ path('app_admin_labourer', {'insee_code': stats.zone, 'deleteMissing': 1, 'disableFollowUpCleanup': 1}) }}" class="btn btn-warning" title="Labourer sans nettoyer les suivis OSM">
<i class="bi bi-shield-check"></i> Labourer (sans nettoyage)
</a>
<a href="{{ path('app_admin_stats', {'insee_code': stats.zone}) }}" class="btn btn-info">
<i class="bi bi-bar-chart"></i> Voir les stats
</a>

View file

@ -11,6 +11,7 @@
<div class="example-wrapper">
<h1>Labourage fait sur la zone "{{ stats.zone }} {{stats.name}}" ✅</h1>
<a href="{{ path('app_admin_labourer', {'insee_code': stats.zone}) }}" class="btn btn-primary" id="labourer">Labourer les mises à jour</a>
<a href="{{ path('app_admin_labourer', {'insee_code': stats.zone, 'deleteMissing': 1, 'disableFollowUpCleanup': 1}) }}" class="btn btn-warning" id="labourer-no-cleanup" title="Labourer sans nettoyer les suivis OSM">Labourer (sans nettoyage)</a>
<a href="{{ path('app_admin_stats', {'insee_code': stats.zone}) }}" class="btn btn-primary" id="labourer">Voir les résultats</a>
<p>

View file

@ -76,6 +76,9 @@
</div>
<div class="col-md-6 col-12">
<a href="{{ path('app_admin_labourer', {'insee_code': stats.zone, 'deleteMissing': 1}) }}" class="btn btn-primary" id="labourer">Labourer les mises à jour</a>
<a href="{{ path('app_admin_labourer', {'insee_code': stats.zone, 'deleteMissing': 1, 'disableFollowUpCleanup': 1}) }}" class="btn btn-warning ms-2" id="labourer-no-cleanup" title="Labourer sans nettoyer les suivis OSM">
<i class="bi bi-shield-check"></i> Labourer (sans nettoyage)
</a>
<a href="{{ path('admin_followup_graph', {'insee_code': stats.zone}) }}" class="btn btn-info ms-2" id="followup-graph-link">
<i class="bi bi-graph-up"></i> Suivi OSM (graphes)
</a>
@ -169,6 +172,24 @@
<a href="http://127.0.0.1:8111/import?url=https://overpass-api.de/api/interpreter?data={{ overpass_query|url_encode }}" target="_blank" class="fw-bold text-decoration-underline text-dark" title="Charger dans JOSM">{{ followup_labels[type]|default(type|capitalize) }}</a><br>
<span title="Nombre"> {{ data.count is defined ? data.count.getMeasure() : '?' }}</span><br>
<span title="Complétion"> {{ completion is not null ? completion : '?' }}%</span>
{% if progression7Days[type] is defined %}
{% set countDelta = progression7Days[type].count %}
{% set completionDelta = progression7Days[type].completion %}
{% if countDelta is not null or completionDelta is not null %}
<small class="text-muted">
{% if countDelta is not null %}
<span title="Progression sur 7 jours - Nombre d'objets">
{{ countDelta > 0 ? '+' ~ countDelta : countDelta == 0 ? '0' : countDelta }}
</span>
{% endif %}
{% if completionDelta is not null %}
<span title="Progression sur 7 jours - Complétion">
{{ completionDelta > 0 ? '+' ~ completionDelta|round(1) : completionDelta == 0 ? '0' : completionDelta|round(1) }}%
</span>
{% endif %}
</small>
{% endif %}
{% endif %}
</div>
</div>
</div>

View file

@ -210,6 +210,13 @@
>
<i class="bi bi-recycle"></i>
</a>
<a href="{{ path('app_admin_labourer', {'insee_code': stat.zone, 'deleteMissing': 1, 'disableFollowUpCleanup': 1}) }}"
class="btn btn-sm btn-warning btn-labourer"
data-zip-code="{{ stat.zone }}"
title="Labourer cette ville sans nettoyer les suivis OSM"
>
<i class="bi bi-shield-check"></i>
</a>
<a href="{{ path('app_admin_delete_by_zone', {'insee_code': stat.zone}) }}"
class="btn btn-sm btn-danger"