mirror of
				https://forge.chapril.org/tykayn/osm-commerces
				synced 2025-10-09 17:02:46 +02:00 
			
		
		
		
	courbes d'historique
This commit is contained in:
		
							parent
							
								
									06ced163e6
								
							
						
					
					
						commit
						d9219db84f
					
				
					 4 changed files with 233 additions and 30 deletions
				
			
		|  | @ -106,6 +106,17 @@ class Place | ||||||
|     #[ORM\Column(nullable: true)]
 |     #[ORM\Column(nullable: true)]
 | ||||||
|     private ?\DateTime $osm_data_date = null; |     private ?\DateTime $osm_data_date = null; | ||||||
| 
 | 
 | ||||||
|  |     #[ORM\Column(nullable: true)]
 | ||||||
|  |     private ?int $osm_version = null; | ||||||
|  | 
 | ||||||
|  |     #[ORM\Column(length: 255, nullable: true)]
 | ||||||
|  |     private ?string $osm_user = null; | ||||||
|  | 
 | ||||||
|  |     #[ORM\Column(nullable: true)]
 | ||||||
|  |     private ?int $osm_uid = null; | ||||||
|  | 
 | ||||||
|  |     #[ORM\Column(nullable: true)]
 | ||||||
|  |     private ?int $osm_changeset = null; | ||||||
| 
 | 
 | ||||||
|     public function getPlaceTypeName(): ?string |     public function getPlaceTypeName(): ?string | ||||||
|     { |     { | ||||||
|  | @ -216,7 +227,8 @@ class Place | ||||||
|             'addr:street' => '', |             'addr:street' => '', | ||||||
|             'website' => '', |             'website' => '', | ||||||
|             'wheelchair' => '', |             'wheelchair' => '', | ||||||
|             'note' => '' |             'note' => '', | ||||||
|  |             'fixme' => '', | ||||||
|         ], $overpass_data['tags'] ); |         ], $overpass_data['tags'] ); | ||||||
|           |           | ||||||
| 
 | 
 | ||||||
|  | @ -231,15 +243,37 @@ class Place | ||||||
|             ->setLon($orignal_overpass_data['lon']) |             ->setLon($orignal_overpass_data['lon']) | ||||||
|             ->setName(isset($overpass_data['name']) && $overpass_data['name'] != '' ? $overpass_data['name'] : null); |             ->setName(isset($overpass_data['name']) && $overpass_data['name'] != '' ? $overpass_data['name'] : null); | ||||||
| 
 | 
 | ||||||
|  |         // Traiter le timestamp OSM si disponible
 | ||||||
|  |         if (isset($orignal_overpass_data['timestamp']) && $orignal_overpass_data['timestamp']) { | ||||||
|  |             try { | ||||||
|  |                 $osmDate = new \DateTime($orignal_overpass_data['timestamp']); | ||||||
|  |                 $this->setOsmDataDate($osmDate); | ||||||
|  |             } catch (\Exception $e) { | ||||||
|  |                 // En cas d'erreur de parsing de la date, on ignore
 | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Traiter les autres métadonnées OSM
 | ||||||
|  |         if (isset($orignal_overpass_data['version'])) { | ||||||
|  |             $this->setOsmVersion($orignal_overpass_data['version']); | ||||||
|  |         } | ||||||
|  |         if (isset($orignal_overpass_data['user'])) { | ||||||
|  |             $this->setOsmUser($orignal_overpass_data['user']); | ||||||
|  |         } | ||||||
|  |         if (isset($orignal_overpass_data['uid'])) { | ||||||
|  |             $this->setOsmUid($orignal_overpass_data['uid']); | ||||||
|  |         } | ||||||
|  |         if (isset($orignal_overpass_data['changeset'])) { | ||||||
|  |             $this->setOsmChangeset($orignal_overpass_data['changeset']); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         $mapping = [ |         $mapping = [ | ||||||
|             ['key' => 'postcode', 'setter' => 'setZipCode', 'source' => $overpass_data], |             ['key' => 'postcode', 'setter' => 'setZipCode', 'source' => $overpass_data], | ||||||
|             ['key' => 'email', 'setter' => 'setEmail', 'source' => $overpass_data], |             ['key' => 'email', 'setter' => 'setEmail', 'source' => $overpass_data], | ||||||
|             ['key' => 'opening_hours', 'setter' => 'setHasOpeningHours', 'source' => $overpass_data['tags'] ?? []], |             ['key' => 'opening_hours', 'setter' => 'setHasOpeningHours', 'source' => $overpass_data['tags'] ?? []], | ||||||
|             ['key' => 'note', 'setter' => 'setNote', 'source' => $overpass_data['tags'] ?? []], |  | ||||||
|             ['key' => 'addr:housenumber', 'setter' => 'setHasAddress', 'source' => $overpass_data['tags'] ?? []], |             ['key' => 'addr:housenumber', 'setter' => 'setHasAddress', 'source' => $overpass_data['tags'] ?? []], | ||||||
|             ['key' => 'website', 'setter' => 'setHasWebsite', 'source' => $overpass_data['tags'] ?? []], |             ['key' => 'website', 'setter' => 'setHasWebsite', 'source' => $overpass_data['tags'] ?? []], | ||||||
|             ['key' => 'wheelchair', 'setter' => 'setHasWheelchair', 'source' => $overpass_data['tags'] ?? []], |             ['key' => 'wheelchair', 'setter' => 'setHasWheelchair', 'source' => $overpass_data['tags'] ?? []], | ||||||
|             ['key' => 'note', 'setter' => 'setHasNote', 'source' => $overpass_data['tags'] ?? []], |  | ||||||
|             ['key' => 'siret', 'setter' => 'setSiret', 'source' => $overpass_data['tags'] ?? []], |             ['key' => 'siret', 'setter' => 'setSiret', 'source' => $overpass_data['tags'] ?? []], | ||||||
|             ['key' => 'addr:street', 'setter' => 'setStreet', 'source' => $overpass_data['tags'] ?? []], |             ['key' => 'addr:street', 'setter' => 'setStreet', 'source' => $overpass_data['tags'] ?? []], | ||||||
|             ['key' => 'addr:housenumber', 'setter' => 'setHousenumber', 'source' => $overpass_data['tags'] ?? []], |             ['key' => 'addr:housenumber', 'setter' => 'setHousenumber', 'source' => $overpass_data['tags'] ?? []], | ||||||
|  | @ -251,6 +285,26 @@ class Place | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         // Traiter les notes et fixme
 | ||||||
|  |         $noteContent = ''; | ||||||
|  |         $hasNote = false; | ||||||
|  |          | ||||||
|  |         if (isset($orignal_overpass_data['tags']['note']) && $orignal_overpass_data['tags']['note'] !== '') { | ||||||
|  |             $noteContent .= $orignal_overpass_data['tags']['note']; | ||||||
|  |             $hasNote = true; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         if (isset($orignal_overpass_data['tags']['fixme']) && $orignal_overpass_data['tags']['fixme'] !== '') { | ||||||
|  |             if ($noteContent !== '') { | ||||||
|  |                 $noteContent .= "\n\n"; | ||||||
|  |             } | ||||||
|  |             $noteContent .= "FIXME: " . $orignal_overpass_data['tags']['fixme']; | ||||||
|  |             $hasNote = true; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         $this->setNoteContent($noteContent); | ||||||
|  |         $this->setHasNote($hasNote); | ||||||
|  | 
 | ||||||
|         $this |         $this | ||||||
|         // ->setOsmId($overpass_data['id'])
 |         // ->setOsmId($overpass_data['id'])
 | ||||||
|         // ->setOsmKind($overpass_data['type'])
 |         // ->setOsmKind($overpass_data['type'])
 | ||||||
|  | @ -263,8 +317,7 @@ class Place | ||||||
|         ->setHasOpeningHours($overpass_data['opening_hours'] ? true : false) |         ->setHasOpeningHours($overpass_data['opening_hours'] ? true : false) | ||||||
|         ->setHasAddress($overpass_data['addr:housenumber'] && $overpass_data['addr:street'] ? true : false) |         ->setHasAddress($overpass_data['addr:housenumber'] && $overpass_data['addr:street'] ? true : false) | ||||||
|         ->setHasWebsite($overpass_data['website'] ? true : false) |         ->setHasWebsite($overpass_data['website'] ? true : false) | ||||||
|         ->setHasWheelchair($overpass_data['wheelchair'] and $overpass_data['wheelchair'] != '' ? true : false) |         ->setHasWheelchair($overpass_data['wheelchair'] and $overpass_data['wheelchair'] != '' ? true : false); | ||||||
|         ->setHasNote($overpass_data['note'] and $overpass_data['note'] != '' ? true : false); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function __construct() |     public function __construct() | ||||||
|  | @ -643,4 +696,52 @@ class Place | ||||||
| 
 | 
 | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     public function getOsmVersion(): ?int | ||||||
|  |     { | ||||||
|  |         return $this->osm_version; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function setOsmVersion(?int $osm_version): static | ||||||
|  |     { | ||||||
|  |         $this->osm_version = $osm_version; | ||||||
|  | 
 | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function getOsmUser(): ?string | ||||||
|  |     { | ||||||
|  |         return $this->osm_user; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function setOsmUser(?string $osm_user): static | ||||||
|  |     { | ||||||
|  |         $this->osm_user = $osm_user; | ||||||
|  | 
 | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function getOsmUid(): ?int | ||||||
|  |     { | ||||||
|  |         return $this->osm_uid; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function setOsmUid(?int $osm_uid): static | ||||||
|  |     { | ||||||
|  |         $this->osm_uid = $osm_uid; | ||||||
|  | 
 | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function getOsmChangeset(): ?int | ||||||
|  |     { | ||||||
|  |         return $this->osm_changeset; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function setOsmChangeset(?int $osm_changeset): static | ||||||
|  |     { | ||||||
|  |         $this->osm_changeset = $osm_changeset; | ||||||
|  | 
 | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -101,10 +101,10 @@ public function find_siret($tags) { | ||||||
| 
 | 
 | ||||||
|     public function get_export_query($zone) { |     public function get_export_query($zone) { | ||||||
|         return <<<QUERY |         return <<<QUERY | ||||||
| [out:csv(::id,::type,::lat,::lon,name,amenity,shop,office,healthcare,"contact:email",email,"contact:phone",phone,"contact:website",website,image,url,wikidata, opening_hours,"contact:housenumber","addr:housenumber","contact:street","addr:street",note,fixme,harassment_prevention,cuisine,brand,tourism,source,zip_code,"ref:FR:SIRET")]; | [out:csv(::id,::type,::lat,::lon,::timestamp,::version,::user,::uid,::changeset,name,amenity,shop,office,healthcare,"contact:email",email,"contact:phone",phone,"contact:website",website,image,url,wikidata, opening_hours,"contact:housenumber","addr:housenumber","contact:street","addr:street",note,fixme,harassment_prevention,cuisine,brand,tourism,source,zip_code,"ref:FR:SIRET")]; | ||||||
| {{geocodeArea:"{$zone}, France"}}->.searchArea; | {{geocodeArea:"{$zone}, France"}}->.searchArea; | ||||||
| {$this->overpass_base_places} | {$this->overpass_base_places} | ||||||
| out skel qt; | out meta; | ||||||
| QUERY; | QUERY; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -112,7 +112,7 @@ QUERY; | ||||||
|         return '[out:json][timeout:25]; |         return '[out:json][timeout:25]; | ||||||
| area["ref:INSEE"="'.$zone.'"]->.searchArea; | area["ref:INSEE"="'.$zone.'"]->.searchArea; | ||||||
| '.$this->overpass_base_places.' | '.$this->overpass_base_places.' | ||||||
| out center tags;'; | out meta;'; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private $more_tags = ['image', 'ref:FR:SIRET']; |     private $more_tags = ['image', 'ref:FR:SIRET']; | ||||||
|  | @ -180,7 +180,14 @@ out center tags;'; | ||||||
|                             'name' => $element['tags']['name'] ?? '', |                             'name' => $element['tags']['name'] ?? '', | ||||||
|                             'lat' => $element['lat'] ?? null, |                             'lat' => $element['lat'] ?? null, | ||||||
|                             'lon' => $element['lon'] ?? null, |                             'lon' => $element['lon'] ?? null, | ||||||
|                             'tags' => $element['tags'] |                             'tags' => $element['tags'], | ||||||
|  |                             // Métadonnées OSM
 | ||||||
|  |                             'timestamp' => $element['timestamp'] ?? null, | ||||||
|  |                             'version' => $element['version'] ?? null, | ||||||
|  |                             'user' => $element['user'] ?? null, | ||||||
|  |                             'uid' => $element['uid'] ?? null, | ||||||
|  |                             'changeset' => $element['changeset'] ?? null, | ||||||
|  |                             'modified' => $element['timestamp'] ?? null | ||||||
|                         ]; |                         ]; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  | @ -11,33 +11,124 @@ | ||||||
| document.addEventListener('DOMContentLoaded', function() { | document.addEventListener('DOMContentLoaded', function() { | ||||||
|     const ctx = document.getElementById('completionHistoryChart').getContext('2d'); |     const ctx = document.getElementById('completionHistoryChart').getContext('2d'); | ||||||
|      |      | ||||||
|     new Chart(ctx, { |     // Préparer les données pour chaque aspect | ||||||
|         type: 'line', |     const labels = [ | ||||||
|         data: { |  | ||||||
|             labels: [ |  | ||||||
|         {% for stat in statsHistory %} |         {% for stat in statsHistory %} | ||||||
|             '{{ stat.date|date('d/m/Y') }}'{% if not loop.last %},{% endif %} |             '{{ stat.date|date('d/m/Y') }}'{% if not loop.last %},{% endif %} | ||||||
|         {% endfor %} |         {% endfor %} | ||||||
|             ], |     ]; | ||||||
|             datasets: [{ |      | ||||||
|                 label: 'Taux de complétion (%)', |     const completionData = [ | ||||||
|                 data: [ |  | ||||||
|         {% for stat in statsHistory %} |         {% for stat in statsHistory %} | ||||||
|             {{ stat.completionPercent }}{% if not loop.last %},{% endif %} |             {{ stat.completionPercent }}{% if not loop.last %},{% endif %} | ||||||
|         {% endfor %} |         {% endfor %} | ||||||
|                 ], |     ]; | ||||||
|  |      | ||||||
|  |     const openingHoursData = [ | ||||||
|  |         {% for stat in statsHistory %} | ||||||
|  |             {% if stat.placesCount > 0 %} | ||||||
|  |                 {{ ((stat.openingHoursCount / stat.placesCount) * 100)|round(1) }}{% if not loop.last %},{% endif %} | ||||||
|  |             {% else %} | ||||||
|  |                 0{% if not loop.last %},{% endif %} | ||||||
|  |             {% endif %} | ||||||
|  |         {% endfor %} | ||||||
|  |     ]; | ||||||
|  |      | ||||||
|  |     const addressData = [ | ||||||
|  |         {% for stat in statsHistory %} | ||||||
|  |             {% if stat.placesCount > 0 %} | ||||||
|  |                 {{ ((stat.addressCount / stat.placesCount) * 100)|round(1) }}{% if not loop.last %},{% endif %} | ||||||
|  |             {% else %} | ||||||
|  |                 0{% if not loop.last %},{% endif %} | ||||||
|  |             {% endif %} | ||||||
|  |         {% endfor %} | ||||||
|  |     ]; | ||||||
|  |      | ||||||
|  |     const websiteData = [ | ||||||
|  |         {% for stat in statsHistory %} | ||||||
|  |             {% if stat.placesCount > 0 %} | ||||||
|  |                 {{ ((stat.websiteCount / stat.placesCount) * 100)|round(1) }}{% if not loop.last %},{% endif %} | ||||||
|  |             {% else %} | ||||||
|  |                 0{% if not loop.last %},{% endif %} | ||||||
|  |             {% endif %} | ||||||
|  |         {% endfor %} | ||||||
|  |     ]; | ||||||
|  |      | ||||||
|  |     const siretData = [ | ||||||
|  |         {% for stat in statsHistory %} | ||||||
|  |             {% if stat.placesCount > 0 %} | ||||||
|  |                 {{ ((stat.siretCount / stat.placesCount) * 100)|round(1) }}{% if not loop.last %},{% endif %} | ||||||
|  |             {% else %} | ||||||
|  |                 0{% if not loop.last %},{% endif %} | ||||||
|  |             {% endif %} | ||||||
|  |         {% endfor %} | ||||||
|  |     ]; | ||||||
|  |      | ||||||
|  |     new Chart(ctx, { | ||||||
|  |         type: 'line', | ||||||
|  |         data: { | ||||||
|  |             labels: labels, | ||||||
|  |             datasets: [ | ||||||
|  |                 { | ||||||
|  |                     label: 'Taux de complétion global (%)', | ||||||
|  |                     data: completionData, | ||||||
|                     borderColor: 'rgb(75, 192, 192)', |                     borderColor: 'rgb(75, 192, 192)', | ||||||
|                 backgroundColor: 'rgba(75, 192, 192, 0.2)', |                     backgroundColor: 'rgba(75, 192, 192, 0.1)', | ||||||
|                     tension: 0.3, |                     tension: 0.3, | ||||||
|                 fill: true |                     fill: false, | ||||||
|             }] |                     borderWidth: 3 | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     label: 'Horaires d\'ouverture (%)', | ||||||
|  |                     data: openingHoursData, | ||||||
|  |                     borderColor: 'rgb(255, 99, 132)', | ||||||
|  |                     backgroundColor: 'rgba(255, 99, 132, 0.1)', | ||||||
|  |                     tension: 0.3, | ||||||
|  |                     fill: false, | ||||||
|  |                     borderWidth: 2 | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     label: 'Adresses (%)', | ||||||
|  |                     data: addressData, | ||||||
|  |                     borderColor: 'rgb(54, 162, 235)', | ||||||
|  |                     backgroundColor: 'rgba(54, 162, 235, 0.1)', | ||||||
|  |                     tension: 0.3, | ||||||
|  |                     fill: false, | ||||||
|  |                     borderWidth: 2 | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     label: 'Sites web (%)', | ||||||
|  |                     data: websiteData, | ||||||
|  |                     borderColor: 'rgb(255, 205, 86)', | ||||||
|  |                     backgroundColor: 'rgba(255, 205, 86, 0.1)', | ||||||
|  |                     tension: 0.3, | ||||||
|  |                     fill: false, | ||||||
|  |                     borderWidth: 2 | ||||||
|  |                 }, | ||||||
|  |                 { | ||||||
|  |                     label: 'SIRET (%)', | ||||||
|  |                     data: siretData, | ||||||
|  |                     borderColor: 'rgb(153, 102, 255)', | ||||||
|  |                     backgroundColor: 'rgba(153, 102, 255, 0.1)', | ||||||
|  |                     tension: 0.3, | ||||||
|  |                     fill: false, | ||||||
|  |                     borderWidth: 2 | ||||||
|  |                 } | ||||||
|  |             ] | ||||||
|         }, |         }, | ||||||
|         options: { |         options: { | ||||||
|             responsive: true, |             responsive: true, | ||||||
|             plugins: { |             plugins: { | ||||||
|                 title: { |                 title: { | ||||||
|                     display: true, |                     display: true, | ||||||
|                     text: 'Évolution du taux de complétion au fil du temps' |                     text: 'Évolution des taux de complétion par aspect au fil du temps' | ||||||
|  |                 }, | ||||||
|  |                 legend: { | ||||||
|  |                     position: 'top', | ||||||
|  |                     labels: { | ||||||
|  |                         usePointStyle: true, | ||||||
|  |                         padding: 20 | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             }, |             }, | ||||||
|             scales: { |             scales: { | ||||||
|  | @ -46,7 +137,7 @@ document.addEventListener('DOMContentLoaded', function() { | ||||||
|                     max: 100, |                     max: 100, | ||||||
|                     title: { |                     title: { | ||||||
|                         display: true, |                         display: true, | ||||||
|                         text: 'Complétion (%)' |                         text: 'Pourcentage (%)' | ||||||
|                     } |                     } | ||||||
|                 }, |                 }, | ||||||
|                 x: { |                 x: { | ||||||
|  | @ -55,6 +146,10 @@ document.addEventListener('DOMContentLoaded', function() { | ||||||
|                         text: 'Date' |                         text: 'Date' | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |             }, | ||||||
|  |             interaction: { | ||||||
|  |                 intersect: false, | ||||||
|  |                 mode: 'index' | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|  | @ -128,7 +128,7 @@ | ||||||
| 
 | 
 | ||||||
| {% block javascripts %} | {% block javascripts %} | ||||||
|     {{ parent() }} |     {{ parent() }} | ||||||
| <script src='{{ asset('js/utils.js') }}'></script> | {# <script src='{{ asset('js/utils.js') }}'></script> #} | ||||||
|     <script type="module"> |     <script type="module"> | ||||||
|         import { adjustListGroupFontSize } from '{{ asset('js/utils.js') }}'; |         import { adjustListGroupFontSize } from '{{ asset('js/utils.js') }}'; | ||||||
|         document.addEventListener('DOMContentLoaded', function() { |         document.addEventListener('DOMContentLoaded', function() { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Tykayn
						Tykayn