mirror of
https://forge.chapril.org/tykayn/osm-commerces
synced 2025-10-04 17:04:53 +02:00
up command and labourage
This commit is contained in:
parent
8cfea30fdf
commit
a81112a018
5 changed files with 279 additions and 86 deletions
|
@ -89,6 +89,12 @@ Récupère et stocke les coordonnées lat/lon pour toutes les villes dans la bas
|
|||
php bin/console app:update-city-coordinates
|
||||
```
|
||||
|
||||
### Mise à jour des Stats avec kind vide
|
||||
Change les Stats qui ont un kind vide (NULL) pour leur mettre "user" en kind et les enregistre :
|
||||
```shell
|
||||
php bin/console app:update-empty-stats-kind
|
||||
```
|
||||
|
||||
### Test du budget
|
||||
Teste le calcul du budget pour une ville donnée :
|
||||
```shell
|
||||
|
|
67
src/Command/UpdateEmptyStatsKindCommand.php
Normal file
67
src/Command/UpdateEmptyStatsKindCommand.php
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Entity\Stats;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'app:update-empty-stats-kind',
|
||||
description: 'Change les Stats créés avant aujourd\'hui avec une kind vide pour leur mettre "user" en kind'
|
||||
)]
|
||||
class UpdateEmptyStatsKindCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $entityManager
|
||||
)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$io->title('Mise à jour des Stats avec kind vide créés avant aujourd\'hui');
|
||||
|
||||
// Date d'aujourd'hui à minuit
|
||||
$today = new \DateTime();
|
||||
$today->setTime(0, 0, 0);
|
||||
|
||||
// Trouver toutes les Stats avec kind NULL créés avant aujourd'hui
|
||||
$stats = $this->entityManager->getRepository(Stats::class)
|
||||
->createQueryBuilder('s')
|
||||
// ->where('s.kind IS NULL')
|
||||
->where('s.date_created < :today')
|
||||
->setParameter('today', $today)
|
||||
->getQuery()
|
||||
->getResult();
|
||||
|
||||
if (empty($stats)) {
|
||||
$io->success('Aucune Stats avec kind vide créée avant aujourd\'hui trouvée.');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$count = count($stats);
|
||||
$io->info(sprintf('Trouvé %d Stats avec kind vide créées avant aujourd\'hui.', $count));
|
||||
|
||||
// Mettre à jour chaque Stats avec kind = "user"
|
||||
$io->progressStart($count);
|
||||
foreach ($stats as $stat) {
|
||||
$stat->setKind('user');
|
||||
$this->entityManager->persist($stat);
|
||||
$io->progressAdvance();
|
||||
}
|
||||
$io->progressFinish();
|
||||
|
||||
// Enregistrer les changements
|
||||
$this->entityManager->flush();
|
||||
|
||||
$io->success(sprintf('%d Stats créées avant aujourd\'hui ont été mises à jour avec kind = "user".', $count));
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
|
@ -3,24 +3,22 @@
|
|||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use App\Entity\Place;
|
||||
use App\Entity\Stats;
|
||||
use App\Entity\StatsHistory;
|
||||
use App\Service\Motocultrice;
|
||||
use App\Service\ActionLogger;
|
||||
use App\Service\BudgetService;
|
||||
use App\Service\FollowUpService;
|
||||
use App\Service\Motocultrice;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use function uuid_create;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Twig\Environment;
|
||||
use App\Service\ActionLogger;
|
||||
use DateTime;
|
||||
use App\Service\FollowUpService;
|
||||
use phpDocumentor\Reflection\DocBlock\Tags\Var_;
|
||||
use function uuid_create;
|
||||
|
||||
final class AdminController extends AbstractController
|
||||
{
|
||||
|
@ -31,12 +29,13 @@ final class AdminController extends AbstractController
|
|||
|
||||
public function __construct(
|
||||
private EntityManagerInterface $entityManager,
|
||||
private Motocultrice $motocultrice,
|
||||
private BudgetService $budgetService,
|
||||
private Environment $twig,
|
||||
private ActionLogger $actionLogger,
|
||||
FollowUpService $followUpService
|
||||
) {
|
||||
private Motocultrice $motocultrice,
|
||||
private BudgetService $budgetService,
|
||||
private Environment $twig,
|
||||
private ActionLogger $actionLogger,
|
||||
FollowUpService $followUpService
|
||||
)
|
||||
{
|
||||
$this->followUpService = $followUpService;
|
||||
}
|
||||
|
||||
|
@ -46,7 +45,6 @@ final class AdminController extends AbstractController
|
|||
{
|
||||
|
||||
|
||||
|
||||
$this->actionLogger->log('labourer_toutes_les_zones', []);
|
||||
$updateExisting = true;
|
||||
|
||||
|
@ -103,8 +101,7 @@ final class AdminController extends AbstractController
|
|||
->setSiret($this->motocultrice->find_siret($placeData['tags']) ?? '')
|
||||
->setAskedHumainsSupport(false)
|
||||
->setLastContactAttemptDate(null)
|
||||
->setPlaceCount(0)
|
||||
// ->setOsmData($placeData['modified'] ?? null)
|
||||
->setPlaceCount(0)// ->setOsmData($placeData['modified'] ?? null)
|
||||
;
|
||||
|
||||
// Mettre à jour les données depuis Overpass
|
||||
|
@ -324,7 +321,44 @@ final class AdminController extends AbstractController
|
|||
$this->followUpService->generateCityFollowUps($stats, $this->motocultrice, $this->entityManager);
|
||||
$followups = $stats->getCityFollowUps();
|
||||
}
|
||||
$commerces = $stats->getPlaces();
|
||||
$commerces = $stats->getPlacesCount();
|
||||
if (!$commerces) {
|
||||
// labourer
|
||||
$places_found = $this->motocultrice->labourer($insee_code);
|
||||
if (count($places_found)) {
|
||||
var_dump(count($places_found));
|
||||
|
||||
foreach ($places_found as $placeData) {
|
||||
$newPlace = new Place();
|
||||
$newPlace->setOsmId($placeData['id'])
|
||||
->setOsmKind($placeData['type'])
|
||||
->setZipCode($insee_code)
|
||||
->setUuidForUrl($this->motocultrice->uuid_create())
|
||||
->setModifiedDate(new \DateTime())
|
||||
->setStats($stats)
|
||||
->setDead(false)
|
||||
->setOptedOut(false)
|
||||
->setMainTag($this->motocultrice->find_main_tag($placeData['tags']) ?? '')
|
||||
->setStreet($this->motocultrice->find_street($placeData['tags']) ?? '')
|
||||
->setHousenumber($this->motocultrice->find_housenumber($placeData['tags']) ?? '')
|
||||
->setSiret($this->motocultrice->find_siret($placeData['tags']) ?? '')
|
||||
->setAskedHumainsSupport(false)
|
||||
->setLastContactAttemptDate(null)
|
||||
->setPlaceCount(0)// ->setOsmData($placeData['modified'] ?? null)
|
||||
;
|
||||
|
||||
// Mettre à jour les données depuis Overpass
|
||||
$newPlace->update_place_from_overpass_data($placeData);
|
||||
|
||||
$stats->addPlace($newPlace);
|
||||
$newPlace->setStats($stats);
|
||||
$this->entityManager->persist($newPlace);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->entityManager->persist($newPlace);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->actionLogger->log('stats_de_ville', ['insee_code' => $insee_code, 'nom' => $stats->getZone()]);
|
||||
// Récupérer tous les commerces de la zone
|
||||
// $commerces = $this->entityManager->getRepository(Place::class)->findBy(['zip_code' => $insee_code, 'dead' => false]);
|
||||
|
@ -347,9 +381,12 @@ final class AdminController extends AbstractController
|
|||
|
||||
// Données pour le graphique des modifications par trimestre
|
||||
$modificationsByQuarter = [];
|
||||
foreach ($commerces as $commerce) {
|
||||
if ($commerce->getOsmDataDate()) {
|
||||
$date = $commerce->getOsmDataDate();
|
||||
if (isset($commerces) && count($commerces) > 0) {
|
||||
|
||||
foreach ($commerces as $commerce) {
|
||||
if ($commerce->getOsmDataDate()) {
|
||||
$date = $commerce->getOsmDataDate();
|
||||
}
|
||||
$year = $date->format('Y');
|
||||
$quarter = ceil($date->format('n') / 3);
|
||||
$key = $year . '-Q' . $quarter;
|
||||
|
@ -393,10 +430,10 @@ final class AdminController extends AbstractController
|
|||
'p.osm_user',
|
||||
'COUNT(p.id) as nb',
|
||||
'AVG((CASE WHEN p.has_opening_hours = true THEN 1 ELSE 0 END) +'
|
||||
. ' (CASE WHEN p.has_address = true THEN 1 ELSE 0 END) +'
|
||||
. ' (CASE WHEN p.has_website = true THEN 1 ELSE 0 END) +'
|
||||
. ' (CASE WHEN p.has_wheelchair = true THEN 1 ELSE 0 END) +'
|
||||
. ' (CASE WHEN p.has_note = true THEN 1 ELSE 0 END)) / 5 * 100 as completion_moyen'
|
||||
. ' (CASE WHEN p.has_address = true THEN 1 ELSE 0 END) +'
|
||||
. ' (CASE WHEN p.has_website = true THEN 1 ELSE 0 END) +'
|
||||
. ' (CASE WHEN p.has_wheelchair = true THEN 1 ELSE 0 END) +'
|
||||
. ' (CASE WHEN p.has_note = true THEN 1 ELSE 0 END)) / 5 * 100 as completion_moyen'
|
||||
)
|
||||
->where('p.osm_user IS NOT NULL')
|
||||
->andWhere("p.osm_user != ''")
|
||||
|
@ -503,7 +540,7 @@ final class AdminController extends AbstractController
|
|||
}
|
||||
// Tri par date dans chaque série
|
||||
foreach ($ctc_completion_series as &$points) {
|
||||
usort($points, function($a, $b) {
|
||||
usort($points, function ($a, $b) {
|
||||
return strcmp($a['date'], $b['date']);
|
||||
});
|
||||
}
|
||||
|
@ -607,15 +644,15 @@ final class AdminController extends AbstractController
|
|||
// Cas particuliers multi-valeurs (ex: healthcare)
|
||||
if ($theme === 'healthcare') {
|
||||
if ($main_tag && (
|
||||
str_starts_with($main_tag, 'healthcare=') ||
|
||||
in_array($main_tag, [
|
||||
'amenity=doctors',
|
||||
'amenity=pharmacy',
|
||||
'amenity=hospital',
|
||||
'amenity=clinic',
|
||||
'amenity=social_facility'
|
||||
])
|
||||
)) {
|
||||
str_starts_with($main_tag, 'healthcare=') ||
|
||||
in_array($main_tag, [
|
||||
'amenity=doctors',
|
||||
'amenity=pharmacy',
|
||||
'amenity=hospital',
|
||||
'amenity=clinic',
|
||||
'amenity=social_facility'
|
||||
])
|
||||
)) {
|
||||
$match = true;
|
||||
}
|
||||
} else {
|
||||
|
@ -714,7 +751,6 @@ final class AdminController extends AbstractController
|
|||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* rediriger vers l'url unique quand on est admin
|
||||
*/
|
||||
|
@ -793,7 +829,8 @@ final class AdminController extends AbstractController
|
|||
$stats->setPopulation((int)$data['population']);
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
// Compléter le budget si manquant
|
||||
if (!$stats->getBudgetAnnuel()) {
|
||||
|
@ -815,7 +852,8 @@ final class AdminController extends AbstractController
|
|||
$stats->setLat((string)$data['centre']['coordinates'][1]);
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
// Mettre à jour la date de requête de labourage
|
||||
$stats->setDateLabourageRequested(new \DateTime());
|
||||
|
@ -846,7 +884,7 @@ final class AdminController extends AbstractController
|
|||
// Toujours générer les CityFollowUp (mais ne jamais les supprimer)
|
||||
// $themes = \App\Service\FollowUpService::getFollowUpThemes();
|
||||
// foreach (array_keys($themes) as $theme) {
|
||||
$this->followUpService->generateCityFollowUps($stats, $this->motocultrice, $this->entityManager, true);
|
||||
$this->followUpService->generateCityFollowUps($stats, $this->motocultrice, $this->entityManager, true);
|
||||
// }
|
||||
$this->entityManager->flush();
|
||||
return $this->redirectToRoute('app_admin_stats', ['insee_code' => $insee_code]);
|
||||
|
@ -966,9 +1004,9 @@ final class AdminController extends AbstractController
|
|||
fclose($handle);
|
||||
|
||||
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
#[Route('/admin/export_csv/{insee_code}', name: 'app_admin_export_csv')]
|
||||
public function export_csv(string $insee_code): Response
|
||||
{
|
||||
|
@ -1730,15 +1768,15 @@ final class AdminController extends AbstractController
|
|||
// Cas particuliers multi-valeurs (ex: healthcare)
|
||||
if ($theme === 'healthcare') {
|
||||
if ($main_tag && (
|
||||
str_starts_with($main_tag, 'healthcare=') ||
|
||||
in_array($main_tag, [
|
||||
'amenity=doctors',
|
||||
'amenity=pharmacy',
|
||||
'amenity=hospital',
|
||||
'amenity=clinic',
|
||||
'amenity=social_facility'
|
||||
])
|
||||
)) {
|
||||
str_starts_with($main_tag, 'healthcare=') ||
|
||||
in_array($main_tag, [
|
||||
'amenity=doctors',
|
||||
'amenity=pharmacy',
|
||||
'amenity=hospital',
|
||||
'amenity=clinic',
|
||||
'amenity=social_facility'
|
||||
])
|
||||
)) {
|
||||
$match = true;
|
||||
}
|
||||
} else {
|
||||
|
@ -1830,7 +1868,7 @@ final class AdminController extends AbstractController
|
|||
}
|
||||
}
|
||||
foreach ($ctc_completion_series as &$points) {
|
||||
usort($points, function($a, $b) {
|
||||
usort($points, function ($a, $b) {
|
||||
return strcmp($a['date'], $b['date']);
|
||||
});
|
||||
}
|
||||
|
@ -1870,7 +1908,7 @@ final class AdminController extends AbstractController
|
|||
foreach ($places as $place) {
|
||||
$rue = $place->getStreet() ?: '(sans nom)';
|
||||
if (!isset($rues[$rue])) {
|
||||
$rues[$rue] = [ 'places' => [], 'completion_sum' => 0 ];
|
||||
$rues[$rue] = ['places' => [], 'completion_sum' => 0];
|
||||
}
|
||||
$rues[$rue]['places'][] = $place;
|
||||
$rues[$rue]['completion_sum'] += $place->getCompletionPercentage();
|
||||
|
|
|
@ -96,10 +96,10 @@ class PublicController extends AbstractController
|
|||
$debug = '';
|
||||
if ($this->getParameter('kernel.environment') !== 'prod') {
|
||||
$debug = 'Bonjour, nous sommes des bénévoles d\'OpenStreetMap France et nous vous proposons de modifier les informations de votre commerce. Voici votre lien unique de modification: ' . $this->generateUrl('app_public_edit', [
|
||||
'zipcode' => $zipCode,
|
||||
'name' => $place_name,
|
||||
'uuid' => $place->getUuidForUrl()
|
||||
], true);
|
||||
'zipcode' => $zipCode,
|
||||
'name' => $place_name,
|
||||
'uuid' => $place->getUuidForUrl()
|
||||
], true);
|
||||
}
|
||||
$this->addFlash('success', 'Un email vous sera envoyé avec le lien de modification. ' . $debug);
|
||||
}
|
||||
|
@ -112,10 +112,10 @@ class PublicController extends AbstractController
|
|||
->to($destinataire)
|
||||
->subject('Votre lien de modification OpenStreetMap')
|
||||
->text('Bonjour, nous sommes des bénévoles d\'OpenStreetMap France et nous vous proposons de modifier les informations de votre commerce. Voici votre lien unique de modification: ' . $this->generateUrl('app_public_edit', [
|
||||
'zipcode' => $zipCode,
|
||||
'name' => $place_name,
|
||||
'uuid' => $existingPlace ? $existingPlace->getUuidForUrl() : $place->getUuidForUrl()
|
||||
], true));
|
||||
'zipcode' => $zipCode,
|
||||
'name' => $place_name,
|
||||
'uuid' => $existingPlace ? $existingPlace->getUuidForUrl() : $place->getUuidForUrl()
|
||||
], true));
|
||||
|
||||
$this->mailer->send($message);
|
||||
|
||||
|
@ -272,8 +272,8 @@ class PublicController extends AbstractController
|
|||
'name' => $cityName,
|
||||
'zone' => $stat->getZone(),
|
||||
'coordinates' => [
|
||||
'lat' => (float) $stat->getLat(),
|
||||
'lon' => (float) $stat->getLon()
|
||||
'lat' => (float)$stat->getLat(),
|
||||
'lon' => (float)$stat->getLon()
|
||||
],
|
||||
'placesCount' => $stat->getPlacesCount(),
|
||||
'completionPercent' => $stat->getCompletionPercent(),
|
||||
|
@ -329,8 +329,8 @@ class PublicController extends AbstractController
|
|||
if (!empty($data) && isset($data[0]['lat']) && isset($data[0]['lon'])) {
|
||||
error_log("DEBUG: Coordonnées trouvées pour $cityName ($inseeCode): " . $data[0]['lat'] . ", " . $data[0]['lon']);
|
||||
return [
|
||||
'lat' => (float) $data[0]['lat'],
|
||||
'lon' => (float) $data[0]['lon']
|
||||
'lat' => (float)$data[0]['lat'],
|
||||
'lon' => (float)$data[0]['lon']
|
||||
];
|
||||
} else {
|
||||
error_log("DEBUG: Aucune coordonnée trouvée pour $cityName ($inseeCode)");
|
||||
|
@ -1060,22 +1060,61 @@ class PublicController extends AbstractController
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate marker color based on completion percentage
|
||||
* Returns a gradient from intense green (high completion) to gray (low completion) with 10 intermediate shades
|
||||
*/
|
||||
private function calculateMarkerColor(float $completionPercent): string
|
||||
{
|
||||
// Define the colors for the gradient
|
||||
$greenColor = [0, 170, 0]; // Intense green RGB
|
||||
$grayColor = [128, 128, 128]; // Gray RGB
|
||||
|
||||
// Ensure completion percent is between 0 and 100
|
||||
$completionPercent = max(0, min(100, $completionPercent));
|
||||
|
||||
// Calculate the position in the gradient (0 to 1)
|
||||
$position = $completionPercent / 100;
|
||||
|
||||
// Calculate the RGB values for the gradient
|
||||
$r = intval($grayColor[0] + ($greenColor[0] - $grayColor[0]) * $position);
|
||||
$g = intval($grayColor[1] + ($greenColor[1] - $grayColor[1]) * $position);
|
||||
$b = intval($grayColor[2] + ($greenColor[2] - $grayColor[2]) * $position);
|
||||
|
||||
// Convert RGB to hexadecimal
|
||||
return sprintf('#%02x%02x%02x', $r, $g, $b);
|
||||
}
|
||||
|
||||
#[Route('/cities', name: 'app_public_cities')]
|
||||
public function cities(): Response
|
||||
{
|
||||
$stats = $this->entityManager->getRepository(Stats::class)->findAll();
|
||||
// Only select Stats that have an empty kind or 'user' kind
|
||||
$stats = $this->entityManager->getRepository(Stats::class)
|
||||
->createQueryBuilder('s')
|
||||
->where('s.kind IS NULL OR s.kind = :user_kind')
|
||||
->setParameter('user_kind', 'user')
|
||||
->orderBy('s.name', 'ASC')
|
||||
->getQuery()
|
||||
->getResult();
|
||||
|
||||
// Prepare data for the map
|
||||
$citiesForMap = [];
|
||||
foreach ($stats as $stat) {
|
||||
if ($stat->getZone() !== 'undefined' && preg_match('/^\d+$/', $stat->getZone())) {
|
||||
// Calculate marker color based on completion percentage
|
||||
// Gradient from intense green (high completion) to gray (low completion) with 10 intermediate shades
|
||||
$completionPercent = $stat->getCompletionPercent();
|
||||
// Ensure we have a float value even if getCompletionPercent returns null
|
||||
$markerColor = $this->calculateMarkerColor($completionPercent ?? 0);
|
||||
|
||||
$citiesForMap[] = [
|
||||
'name' => $stat->getName(),
|
||||
'zone' => $stat->getZone(),
|
||||
'lat' => $stat->getLat(),
|
||||
'lon' => $stat->getLon(),
|
||||
'placesCount' => $stat->getPlacesCount(),
|
||||
'completionPercent' => $stat->getCompletionPercent(),
|
||||
'completionPercent' => $completionPercent,
|
||||
'markerColor' => $markerColor,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,43 @@
|
|||
width: 100%;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.map-legend {
|
||||
background: white;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,0.1);
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.legend-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.legend-gradient {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.legend-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.legend-color {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -37,17 +74,28 @@
|
|||
<div class="map-container">
|
||||
<div id="citiesMap"></div>
|
||||
<div class="map-legend">
|
||||
<div class="legend-item">
|
||||
<div class="legend-color" style="background-color: #28a745;"></div>
|
||||
<span>Complétion > 80%</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color" style="background-color: #17a2b8;"></div>
|
||||
<span>Complétion 50-80%</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color" style="background-color: #ffc107;"></div>
|
||||
<span>Complétion < 50%</span>
|
||||
<div class="legend-title">Pourcentage de complétion</div>
|
||||
<div class="legend-gradient">
|
||||
<div class="legend-item">
|
||||
<div class="legend-color" style="background-color: #808080;"></div>
|
||||
<span>0%</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color" style="background-color: #6a9a40;"></div>
|
||||
<span>25%</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color" style="background-color: #55b400;"></div>
|
||||
<span>50%</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color" style="background-color: #40ce00;"></div>
|
||||
<span>75%</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color" style="background-color: #00aa00;"></div>
|
||||
<span>100%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -109,13 +157,8 @@
|
|||
{% if citiesForMap is not empty %}
|
||||
{% for city in citiesForMap %}
|
||||
{% if city.lat and city.lon %}
|
||||
// Determine marker color based on completion percentage
|
||||
|
||||
{% if city.completionPercent > 80 %}
|
||||
color = '#28a745'; // Green for high completion
|
||||
{% elseif city.completionPercent > 50 %}
|
||||
color = '#17a2b8'; // Blue for medium completion
|
||||
{% endif %}
|
||||
// Use the marker color calculated in the controller
|
||||
color = '{{ city.markerColor }}';
|
||||
|
||||
// Create marker and popup
|
||||
new maplibregl.Marker({color: color})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue