up details theme graph page
This commit is contained in:
parent
af1233c246
commit
b959c695ae
3 changed files with 90 additions and 181 deletions
|
@ -81,7 +81,7 @@ THEMES = {
|
||||||
},
|
},
|
||||||
"advertising_board": {
|
"advertising_board": {
|
||||||
"tag_filter": "advertising=board and message=political",
|
"tag_filter": "advertising=board and message=political",
|
||||||
"important_tags": ["operator", "content"],
|
"important_tags": ["operator", ],
|
||||||
},
|
},
|
||||||
"building": {
|
"building": {
|
||||||
"tag_filter": "building",
|
"tag_filter": "building",
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
namespace App\Service;
|
namespace App\Service;
|
||||||
|
|
||||||
use App\Entity\Stats;
|
|
||||||
use App\Entity\CityFollowUp;
|
use App\Entity\CityFollowUp;
|
||||||
|
use App\Entity\Stats;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
class FollowUpService
|
class FollowUpService
|
||||||
|
@ -38,7 +38,7 @@ class FollowUpService
|
||||||
} elseif ($type === 'police') {
|
} elseif ($type === 'police') {
|
||||||
$objects = array_filter($elements, fn($el) => ($el['tags']['amenity'] ?? null) === 'police') ?? [];
|
$objects = array_filter($elements, fn($el) => ($el['tags']['amenity'] ?? null) === 'police') ?? [];
|
||||||
} elseif ($type === 'healthcare') {
|
} elseif ($type === 'healthcare') {
|
||||||
$objects = array_filter($elements, function($el) {
|
$objects = array_filter($elements, function ($el) {
|
||||||
return isset($el['tags']['healthcare'])
|
return isset($el['tags']['healthcare'])
|
||||||
|| ($el['tags']['amenity'] ?? null) === 'doctors'
|
|| ($el['tags']['amenity'] ?? null) === 'doctors'
|
||||||
|| ($el['tags']['amenity'] ?? null) === 'pharmacy'
|
|| ($el['tags']['amenity'] ?? null) === 'pharmacy'
|
||||||
|
@ -74,7 +74,7 @@ class FollowUpService
|
||||||
$objects = array_filter($elements, fn($el) => ($el['tags']['amenity'] ?? null) === 'public_bookcase') ?? [];
|
$objects = array_filter($elements, fn($el) => ($el['tags']['amenity'] ?? null) === 'public_bookcase') ?? [];
|
||||||
} elseif ($type === 'playground') {
|
} elseif ($type === 'playground') {
|
||||||
$objects = array_filter($elements, fn($el) => ($el['tags']['leisure'] ?? null) === 'playground') ?? [];
|
$objects = array_filter($elements, fn($el) => ($el['tags']['leisure'] ?? null) === 'playground') ?? [];
|
||||||
}elseif ($type === 'restaurant') {
|
} elseif ($type === 'restaurant') {
|
||||||
$objects = array_filter($elements, fn($el) => ($el['tags']['amenity'] ?? null) === 'restaurant') ?? [];
|
$objects = array_filter($elements, fn($el) => ($el['tags']['amenity'] ?? null) === 'restaurant') ?? [];
|
||||||
} else {
|
} else {
|
||||||
$objects = [];
|
$objects = [];
|
||||||
|
@ -133,8 +133,7 @@ class FollowUpService
|
||||||
$completed[] = $el;
|
$completed[] = $el;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // ... fallback pour les types sans tags attendus
|
||||||
// ... fallback pour les types sans tags attendus
|
|
||||||
else {
|
else {
|
||||||
$completed = [];
|
$completed = [];
|
||||||
$partialCompletions = array_fill(0, count($data['objects']), 0);
|
$partialCompletions = array_fill(0, count($data['objects']), 0);
|
||||||
|
@ -501,7 +500,7 @@ class FollowUpService
|
||||||
'police' => ['phone', 'website'],
|
'police' => ['phone', 'website'],
|
||||||
'healthcare' => ['name', 'contact:phone', 'phone', 'email', 'contact:email'],
|
'healthcare' => ['name', 'contact:phone', 'phone', 'email', 'contact:email'],
|
||||||
'bicycle_parking' => ['capacity', 'covered'],
|
'bicycle_parking' => ['capacity', 'covered'],
|
||||||
'advertising_board' => ['operator', 'contact:phone'],
|
'advertising_board' => ['operator'],
|
||||||
'building' => ['building'],
|
'building' => ['building'],
|
||||||
'rnb' => ['building', 'ref:FR:RNB'],
|
'rnb' => ['building', 'ref:FR:RNB'],
|
||||||
'email' => ['name', 'phone'],
|
'email' => ['name', 'phone'],
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
<link href='{{ asset('js/maplibre/maplibre-gl.css') }}' rel='stylesheet'/>
|
<link href='{{ asset('js/maplibre/maplibre-gl.css') }}' rel='stylesheet'/>
|
||||||
<link href='{{ asset('css/city-sidebar.css') }}' rel='stylesheet'/>
|
<link href='{{ asset('css/city-sidebar.css') }}' rel='stylesheet'/>
|
||||||
<style>
|
<style>
|
||||||
|
#themeMap {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.chart-container {
|
.chart-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 400px;
|
height: 400px;
|
||||||
|
@ -101,9 +105,6 @@
|
||||||
font-size: 0.95em;
|
font-size: 0.95em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-josm {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Bouton flottant suggestion desktop */
|
/* Bouton flottant suggestion desktop */
|
||||||
.suggestion-float-btn {
|
.suggestion-float-btn {
|
||||||
|
@ -230,11 +231,19 @@
|
||||||
|
|
||||||
<div class="stats-grid">
|
<div class="stats-grid">
|
||||||
<div class="stat-card">
|
<div class="stat-card">
|
||||||
<div class="stat-value" id="currentCount">{{ current_count }}</div>
|
<div class="stat-value" id="currentCount">
|
||||||
|
{{ current_count }}
|
||||||
|
<i class="bi bi-load bi-spin"></i>
|
||||||
|
...
|
||||||
|
</div>
|
||||||
<div class="stat-label">Nombre actuel</div>
|
<div class="stat-label">Nombre actuel</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-card">
|
<div class="stat-card">
|
||||||
<div class="stat-value" id="currentCompletion">{{ current_completion }}</div>
|
<div class="stat-value" id="currentCompletion">
|
||||||
|
{{ current_completion }}
|
||||||
|
<i class="bi bi-load bi-spin"></i>
|
||||||
|
...
|
||||||
|
</div>
|
||||||
<div class="stat-label">Complétion actuelle</div>
|
<div class="stat-label">Complétion actuelle</div>
|
||||||
</div>
|
</div>
|
||||||
{# <div class="stat-card"> #}
|
{# <div class="stat-card"> #}
|
||||||
|
@ -251,11 +260,6 @@
|
||||||
<div class="chart-container">
|
<div class="chart-container">
|
||||||
<canvas id="themeChart"></canvas>
|
<canvas id="themeChart"></canvas>
|
||||||
</div>
|
</div>
|
||||||
{% if completion_tags is defined %}
|
|
||||||
completion_tags
|
|
||||||
{{ dump(completion_tags[theme]) }}
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
{% if completion_tags is defined and completion_tags[theme] is defined %}
|
{% if completion_tags is defined and completion_tags[theme] is defined %}
|
||||||
<div class="card mt-4">
|
<div class="card mt-4">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
|
@ -264,7 +268,11 @@
|
||||||
<div class="card-body p-2">
|
<div class="card-body p-2">
|
||||||
<ul class="mb-0">
|
<ul class="mb-0">
|
||||||
{% for tag in completion_tags[theme] %}
|
{% for tag in completion_tags[theme] %}
|
||||||
<li><code>{{ tag }}</code></li>
|
<li>
|
||||||
|
<a href="https://wiki.openstreetmap.org/FR:Key:{{ tag }}">
|
||||||
|
<code>{{ tag }}</code>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li><span class="text-muted">Aucun critère défini</span></li>
|
<li><span class="text-muted">Aucun critère défini</span></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -273,11 +281,11 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="card mt-5">
|
<div class="card mt-5 ">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<i class="bi bi-tags"></i> Statistiques des tags utilisés dans les objets trouvés
|
<i class="bi bi-tags"></i> Statistiques des tags utilisés dans les objets trouvés
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body p-2">
|
<div class="card-body p-4">
|
||||||
<div id="tags-stats-block">
|
<div id="tags-stats-block">
|
||||||
<table class="table table-sm table-bordered mb-0" id="tags-stats-table"
|
<table class="table table-sm table-bordered mb-0" id="tags-stats-table"
|
||||||
style="max-width:600px;">
|
style="max-width:600px;">
|
||||||
|
@ -298,12 +306,12 @@
|
||||||
{# Bloc navigation autres thématiques #}
|
{# Bloc navigation autres thématiques #}
|
||||||
{% if followup_labels is defined and icons is defined %}
|
{% if followup_labels is defined and icons is defined %}
|
||||||
<hr>
|
<hr>
|
||||||
<div class="mt-4">
|
<div class="mt-4 p-6 m-4">
|
||||||
<h4>Autres thématiques de suivi :</h4>
|
<h4>Autres thématiques de suivi :</h4>
|
||||||
<ul class="list-inline">
|
<ul class="list-inline p-6 m-4">
|
||||||
{% for t, label in followup_labels %}
|
{% for t, label in followup_labels %}
|
||||||
{% if t != theme %}
|
{% if t != theme %}
|
||||||
<li class="list-inline-item mb-2">
|
<li class="list-inline-item mb-2 ml-4">
|
||||||
<a href="{{ path('admin_followup_theme_graph', {'insee_code': stats.zone, 'theme': t}) }}"
|
<a href="{{ path('admin_followup_theme_graph', {'insee_code': stats.zone, 'theme': t}) }}"
|
||||||
class="btn btn-outline-secondary">
|
class="btn btn-outline-secondary">
|
||||||
<i class="bi {{ icons[t]|default('bi-question-circle') }}"></i> {{ label }}
|
<i class="bi {{ icons[t]|default('bi-question-circle') }}"></i> {{ label }}
|
||||||
|
@ -543,6 +551,7 @@
|
||||||
const countData = {{ count_data|json_encode|raw }};
|
const countData = {{ count_data|json_encode|raw }};
|
||||||
console.log('Count data:', countData);
|
console.log('Count data:', countData);
|
||||||
|
|
||||||
|
window.countData = countData
|
||||||
const completionData = {{ completion_data|json_encode|raw }};
|
const completionData = {{ completion_data|json_encode|raw }};
|
||||||
console.log('Completion data:', completionData);
|
console.log('Completion data:', completionData);
|
||||||
|
|
||||||
|
@ -622,7 +631,7 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Graphique fusionné
|
console.log('completionData', completionData)
|
||||||
const ctx = document.getElementById('themeChart').getContext('2d');
|
const ctx = document.getElementById('themeChart').getContext('2d');
|
||||||
new Chart(ctx, {
|
new Chart(ctx, {
|
||||||
type: 'line',
|
type: 'line',
|
||||||
|
@ -637,152 +646,53 @@
|
||||||
fill: true,
|
fill: true,
|
||||||
tension: 0.1,
|
tension: 0.1,
|
||||||
yAxisID: 'y1',
|
yAxisID: 'y1',
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Pourcentage de complétion',
|
|
||||||
data
|
|
||||||
:
|
|
||||||
Array.isArray(completionData) ? completionData.map(d => ({x: new Date(d.date), y: d.value})) : [],
|
|
||||||
borderColor
|
|
||||||
:
|
|
||||||
'#198754',
|
|
||||||
backgroundColor
|
|
||||||
:
|
|
||||||
'rgba(25, 135, 84, 0.1)',
|
|
||||||
borderWidth
|
|
||||||
:
|
|
||||||
2,
|
|
||||||
fill
|
|
||||||
:
|
|
||||||
true,
|
|
||||||
tension
|
|
||||||
:
|
|
||||||
0.1,
|
|
||||||
yAxisID
|
|
||||||
:
|
|
||||||
'y2',
|
|
||||||
}
|
|
||||||
,
|
|
||||||
// Add current data point if no historical data exists
|
|
||||||
...
|
|
||||||
((!Array.isArray(countData) || countData.length === 0) && typeof currentCount !== 'undefined' ? [{
|
|
||||||
label: "Nombre actuel",
|
|
||||||
data: [{x: new Date(), y: currentCount}],
|
|
||||||
borderColor: '#dc3545',
|
|
||||||
backgroundColor: 'rgba(220, 53, 69, 0.1)',
|
|
||||||
borderWidth: 2,
|
|
||||||
pointRadius: 5,
|
|
||||||
fill: false,
|
|
||||||
yAxisID: 'y1',
|
|
||||||
}] : []),
|
|
||||||
...
|
|
||||||
((!Array.isArray(completionData) || completionData.length === 0) && typeof currentCompletion !== 'undefined' ? [{
|
|
||||||
label: "Complétion actuelle",
|
|
||||||
data: [{x: new Date(), y: currentCompletion}],
|
|
||||||
borderColor: '#fd7e14',
|
|
||||||
backgroundColor: 'rgba(253, 126, 20, 0.1)',
|
|
||||||
borderWidth: 2,
|
|
||||||
pointRadius: 5,
|
|
||||||
fill: false,
|
|
||||||
yAxisID: 'y2',
|
|
||||||
}] : [])
|
|
||||||
]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
maintainAspectRatio
|
|
||||||
:
|
|
||||||
false,
|
|
||||||
plugins
|
|
||||||
:
|
|
||||||
{
|
|
||||||
legend: {
|
|
||||||
display: true
|
|
||||||
}
|
|
||||||
,
|
|
||||||
tooltip: {
|
|
||||||
mode: 'index', intersect
|
|
||||||
:
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
,
|
|
||||||
interaction: {
|
|
||||||
mode: 'nearest', axis
|
|
||||||
:
|
|
||||||
'x', intersect
|
|
||||||
:
|
|
||||||
false
|
|
||||||
}
|
|
||||||
,
|
|
||||||
scales: {
|
|
||||||
x: {
|
|
||||||
type: 'time',
|
|
||||||
time
|
|
||||||
:
|
|
||||||
{
|
{
|
||||||
unit: 'day', displayFormats
|
label: 'Pourcentage de complétion',
|
||||||
:
|
data: Array.isArray(completionData) ? completionData.map(d => ({
|
||||||
{
|
x: new Date(d.date),
|
||||||
day: 'dd/MM/yyyy'
|
y: d.value
|
||||||
}
|
})) : [],
|
||||||
|
borderColor: '#198754',
|
||||||
|
backgroundColor: 'rgba(25, 135, 84, 0.1)',
|
||||||
|
borderWidth: 2,
|
||||||
|
fill: true,
|
||||||
|
tension: 0.1,
|
||||||
|
yAxisID: 'y2',
|
||||||
}
|
}
|
||||||
,
|
]
|
||||||
title: {
|
},
|
||||||
display: true, text
|
options: {
|
||||||
:
|
responsive: true,
|
||||||
'Date'
|
maintainAspectRatio: false,
|
||||||
}
|
plugins: {
|
||||||
}
|
legend: {display: true},
|
||||||
,
|
tooltip: {mode: 'index', intersect: false}
|
||||||
y1: {
|
},
|
||||||
type: 'linear',
|
interaction: {mode: 'nearest', axis: 'x', intersect: false},
|
||||||
position
|
scales: {
|
||||||
:
|
x: {
|
||||||
'left',
|
type: 'time',
|
||||||
title
|
time: {unit: 'day', displayFormats: {day: 'dd/MM/yyyy'}},
|
||||||
:
|
title: {display: true, text: 'Date'}
|
||||||
{
|
},
|
||||||
display: true, text
|
y1: {
|
||||||
:
|
type: 'linear',
|
||||||
"Nombre d'objets"
|
position: 'left',
|
||||||
}
|
title: {display: true, text: "Nombre d'objets"},
|
||||||
,
|
beginAtZero: true
|
||||||
beginAtZero: true
|
},
|
||||||
}
|
y2: {
|
||||||
,
|
type: 'linear',
|
||||||
y2: {
|
position: 'right',
|
||||||
type: 'linear',
|
title: {display: true, text: 'Complétion (%)'},
|
||||||
position
|
min: 0,
|
||||||
:
|
max: 100,
|
||||||
'right',
|
grid: {drawOnChartArea: false}
|
||||||
title
|
|
||||||
:
|
|
||||||
{
|
|
||||||
display: true, text
|
|
||||||
:
|
|
||||||
'Complétion (%)'
|
|
||||||
}
|
|
||||||
,
|
|
||||||
min: 0,
|
|
||||||
max
|
|
||||||
:
|
|
||||||
100,
|
|
||||||
grid
|
|
||||||
:
|
|
||||||
{
|
|
||||||
drawOnChartArea: false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
||||||
// Initialiser les statistiques
|
// Initialiser les statistiques
|
||||||
updateStats();
|
updateStats();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue