đșïž Moteur de routage + đ§ Visualisation Ă©dition traces gpx
Tracer des itinĂ©aires Ă lâaide du moteur de routage GraphHopper. Visualiser, Ă©diter et crĂ©er des traces gpx avec un fork de lâapplication web gpx.studio (Git)
GraphHopper et gpx.studio sont installés sur un serveur debian cwwk rnmkcy.eu
192.168.0.205
đșïž GraphHopper
GraphHopper est un moteur de routage rapide et efficace dans la mĂ©moire publiĂ© sous Apache License 2.0. Il peut ĂȘtre utilisĂ© comme bibliothĂšque Java ou serveur Web autonome pour calculer la distance, le temps, instructions tour par tour et de nombreux attributs routiers pour un itinĂ©raire entre deux points ou plus.
Création dossier graphhopper
1
mkdir -p /sharenfs/docker-data/graphhopper/{data,graph-cache,srtm}
Télécharger les données OpenStreetMap France (OSM)
GraphHopper calcule des routes à partir de données OSM au format PBF (.osm.pbf).
Le lien pour toute les zones (ex : Europe, France, etc.): http://download.geofabrik.de/
đ„ TĂ©lĂ©charger zone France (france-latest.osm.pbf)
Copier le fichier dans le dossier data
1
cp france-latest.osm.pbf /sharenfs/docker-data/graphhopper/data/france.osm.pbf
Fichier de configuration (yaml)
Le fichier de configuration /sharenfs/docker-data/graphhopper/config.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
graphhopper:
# Fichier d'entrĂ©e OpenStreetMap en PBF ou XML, peut ĂȘtre modifiĂ© via la ligne de commande
# -Ddw.graphhopper.datareader.file=some.pbf
datareader.file: ""
# Dossier local utilisé par GraphHopper pour stocker ses données
graph.location: graph-cache
##### Profils de routage ####
# Le routage peut ĂȘtre effectuĂ© uniquement pour les profils listĂ©s ci-dessous. Pour plus d'informations sur les profils
# et les profils personnalisés, consultez la documentation à docs/core/profiles.md ou les exemples dans
# web/src/test/java/com/graphhopper/application/resources/ ou la classe CustomWeighting pour les détails bruts.
#
# En général, un profil comprend les éléments suivants :
# - name (obligatoire) : un identifiant unique pour le profil
# - weighting (optionnel) : par défaut 'custom'
# - turn_costs (optionnel) :
# vehicle_types: [motorcar, motor_vehicle] (types de véhicules utilisés pour les restrictions de tournage spécifiques au véhicule)
# u_turn_costs: 60 (pénalité de temps pour faire un demi-tour en secondes)
# allow_turn_penalty_in_request: true (activer la pĂ©nalitĂ© de tournage personnalisĂ©e pour les requĂȘtes au moment de l'exĂ©cution)
#
# Selon les champs ci-dessus, il existe d'autres propriétés utilisables, par exemple :
# - custom_model_files : lorsque vous avez spécifié "weighting: custom", vous devez définir un ou plusieurs fichiers JSON recherchés dans
# custom_models.directory ou le dossier de travail qui définit le custom_model. Si vous voulez un modÚle vide, vous pouvez
# définir "custom_model_files: []"
# Vous pouvez aussi utiliser le champ `custom_model` et spécifier votre modÚle personnalisédans le profil directement.
#
# Pour Ă©viter les requĂȘtes de routage de longue durĂ©e, vous devriez gĂ©nĂ©ralement activer le mode speed ou hybrid pour tous les profils donnĂ©s
# (voir ci-dessous). Ou au moins limiter le nombre de `routing.max_visited_nodes`.
profiles:
- name: car
# Par défaut, car n'arrive pas avec des restrictions de tournage car cela nécessite moins de ressources. Décommentez la suite si vous en avez besoin :
# turn_costs:
# vehicle_types: [motorcar, motor_vehicle]
# u_turn_costs: 60
# pour des coûts de tournage plus avancés, voir avoid_turns.json
custom_model_files: [car.json]
# Par défaut, foot et bike n'ont pas de préparation CH car cela nécessite moins de ressources. Les ajouterce à "profiles_ch" si vous en avez besoin.
- name: foot
custom_model_files: [foot.json, foot_elevation.json]
- name: bike
custom_model_files: [bike.json, bike_elevation.json]
# Décommentez les profils intégréssi vous voulez plus de profils. AprÚs le démarrage de GraphHopper, il affichera quelles encoded values vous devrez ajouter à graph.encoded_values dans ce fichier de configuration.
#
# - name: racingbike
# custom_model_files: [racingbike.json, bike_elevation.json]
#
# - name: mtb
# custom_model_files: [mtb.json, bike_elevation.json]
#
# - name: custom_profile
# navigation_mode: bike
# turn_costs:
# vehicle_types: [bicycle]
# u_turn_costs: 10
# custom_model_files: [your_custom_model.json]
#
# # Voir bus.json pour plus de détails.
# - name: bus
# turn_costs:
# vehicle_types: [bus, motor_vehicle]
# u_turn_costs: 60
# custom_model_files: [bus.json]
#
# Vous pouvez configurer un profil avec des coûts de tournage comme "3 secondes pour gaucher" et "5 secondes pour les tournages à droite" via :
# 1. ajouter l'entrée turn_costs au profil (voir par ex. le profil car)
# 2. ajouter orientation Ă la liste graph.encoded_values
# 3. ajouter avoid_turns.json Ă custom_model_files
# Ăditer avoid_turns.json ou crĂ©er votre propre fichier JSON et le mettre dans "custom_models.directory". Voir aussi bike_tc.yml.
#
# Autres modĂšles personnalisĂ©s non listĂ©s ici : car4wd.json, motorcycle.json, truck.json ou cargo-bike.json. Vous devrez peut-ĂȘtre les modifier et les tester avant une utilisation en production.
# Voir ./core/src/main/resources/com/graphhopper/custom_models et nous dire si vous modifiez, améliorez ou créez de nouveaux modÚles !
# Il existe aussi le modĂšle personnalisĂ© curvature.json qui peut ĂȘtre utile pour un profil motorcycle ou l'opposĂ© pour un profil truck.
# Ensuite, spécifiez un dossier pour trouver vos propres fichiers de modÚle personnalisés :
# custom_models.directory: custom_models
# Mode speed :
# Il est possible d'accélérer le routage en effectuant une préparation spéciale du graphe (Contraction Hierarchies, CH). Cela nécessite
# plus de RAM/espace disque pour stocker le graphe prĂ©parĂ©, mais aussi signifie moins d'utilisation de mĂ©moire par requĂȘte. Avec la liste suivante
# vous pouvez dĂ©finir pour lesquels des profils de routage ci-dessus une telle prĂ©paration doit ĂȘtre effectuĂ©e. Notez que pour supporter
# les profils avec `turn_costs`, une préparation plus élaborée est requise (temps de préparation plus long et plus d'utilisation de mémoire
# ) et le routage sera aussi plus lent que sans `turn_costs`.
profiles_ch:
- profile: car
# Mode hybrid :
# Similaire au mode speed, le mode hybrid (Landmarks, LM) accélÚre aussi le routage en calculant des données auxiliaires
# Ă l'avance. Il n'est pas aussi rapide que le mode speed, mais plus flexible.
#
# Utilisation avancĂ©e : Il est possible d'utiliser la mĂȘme prĂ©paration pour plusieurs profils, ce qui Ă©conomise de la mĂ©moire et du temps de prĂ©paration.
# Pour cela, utiliser par exemple `preparation_profile: my_other_profile` oĂč `my_other_profile` est le nom d'un autre
# profil pour lequel un profil LM existe. Important : Cela donnera des résultats de routage corrects uniquement si les poids
# calculés pour le profil sont égaux ou supérieurs (pour chaque edge) à ceux calculés pour le profil utilisé pour la préparation (`my_other_profile`)
profiles_lm: []
#### Encodagedes valeurs ####
# Ajouter des informations supplémentaires à chaque edge. Utilisé pour les détails de chemin (#1548) et les modÚles personnalisés (docs/core/custom-models.md)
# Exemples de valeurs :
# average_slope,country,curvature,hazmat,hgv,hike_rating,lanes,max_height,max_length, ...
# Pour plus de détails et une liste complÚte, voir la documentation : https://github.com/graphhopper/graphhopper/blob/master/docs/core/custom-models.md
# Les routes privées sont bloquées par défaut. Pour désactiver cela, vous pouvez spécifier block_private=false comme option :
# car_access|block_private=false, bike_access|block_private=false
# Par défaut, nous ajoutons les encoded values nécessaires pour car.json, bike.json et foot.json (les supprimer si vous ne les avez pas besoin)
graph.encoded_values: |
car_access, car_average_speed, country, road_class, roundabout, max_speed, road_environment,
foot_access, foot_average_speed, foot_priority, foot_road_access, hike_rating, average_slope,
bike_access, bike_average_speed, bike_priority, bike_road_access, bike_network, mtb_rating, ferry_speed
#### Mode speed, hybrid et flexible ####
# Pour accélérer la préparation CH pour plusieurs profils, vous pouvez augmenter les threads par défaut si vous avez assez de RAM.
# Changez ce paramÚtre uniquement si vous savez ce que vous faites et si le défaut a fonctionné pour vous.
# prepare.ch.threads: 1
# Pour ajuster les performances vs l'utilisation de mémoire pour le mode hybrid, utiliser
# prepare.lm.landmarks: 16
# Rendre la préparation des landmarks parallÚle si vous avez assez de RAM. Changez ceci uniquement si vous savez ce que vous faites et si
# le défaut a fonctionné pour vous.
# prepare.lm.threads: 1
#### ĂlĂ©vations ####
# Cela populated votre graphe avec des données d'élévation utilisant SRTM. Décommentez pour désactiver (pas d'élévation). Lire plus à ce sujet dans docs/core/elevation.md
graph.elevation.provider: srtm
# emplacement par défaut pour le cache est /tmp/srtm
# graph.elevation.cache_dir: ./srtmprovider/
# Si vous avez un disque lent ou beaucoup de RAM, changez le MMAP par défaut vers :
# graph.elevation.dataaccess: RAM_STORE
# Pour activer l'interpolation bilinéaire lors de l'échantillonnage de l'élévation aux points (par défaut utilise nearest neighbor) :
# graph.elevation.interpolate: bilinear
# Réduire l'ascension/descente par edge sans changer la pente maximale :
# graph.elevation.edge_smoothing: ramer
# élimine les fluctuations d'élévation jusqu'à max_elevation (en mÚtres) et remplace l'élévation par une valeur basée sur la pente moyenne
# graph.elevation.edge_smoothing.ramer.max_elevation: 5
# Utiliser une approche de moyennage pour le lissage révélera des valeurs non affectées par les outliers et des pentes réalistes et des valeurs d'altitude totales (haut et bas)
# graph.elevation.edge_smoothing: moving_average
# taille de fenĂȘtre en mĂštres le long d'un chemin utilisĂ©e pour moyenner l'Ă©lĂ©vation d'un nĆud
# graph.elevation.edge_smoothing.moving_average.window_size: 150
# Pour augmenter la résolution du profil d'élévation, utilisez les deux paramÚtres suivants pour ajuster la résolution supplémentaire dont vous avez besoin
# contre l'espace de stockage supplémentaire utilisé pour les géométries d'edge. Vous devriez activer l'interpolation bilinéaire quand vous utilisez
# ces fonctionnalités (voir #1953 pour les détails).
# - premiĂšrement, dĂ©finir la distance (en mĂštres) Ă laquelle les Ă©chantillons d'Ă©lĂ©vation doivent ĂȘtre pris sur les edges longs
# graph.elevation.long_edge_sampling_distance: 60
# - secondairement, définir la tolérance d'élévation (en mÚtres) à utiliser lors de la simplification des polylignes car le défaut ignore
# l'élévation et supprimera les points supplémentaires que l'échantillonnage d'edge long a ajoutés
# graph.elevation.way_point_max_distance: 10
#### Défauts dépendants du pays pour les vitesse maxima ####
# Cette fonctionnalité définit une vitesse maximale dans la valeur encodée 'max_speed' si aucun tag maxspeed n'a été trouvé. Elle est dépendante du pays
# et basée sur plusieurs rÚgles. Voir https://github.com/westnordost/osm-legal-default-speeds
# Pour utiliser, décommentez la suite, puis activez urban density ci-dessous et ajouter 'country' à graph.encoded_values
# max_speed_calculator.enabled: true
#### Densité urbaine (zones construites) ####
# Cette fonctionnalité permet de classifier les routes en 'rural', 'residential' et 'city' (encoded value 'urban_density')
# Utiliser 1 ou plus de threads pour activer la fonctionnalité
# graph.urban_density.threads: 8
# Utiliser des sensibilités plus hautes/plus basses si trop peu/trop de routes tombent dans les catégories correspondantes.
# Utiliser des radii plus petits accélérerad la classification, mais changez uniquement ces valeurs si vous savez ce que vous faites.
# Si vous n'avez pas besoin de la classification city (plutÎt lente), définissez city_radius à zéro.
# graph.urban_density.residential_radius: 400
# graph.urban_density.residential_sensitivity: 6000
# graph.urban_density.city_radius: 1500
# graph.urban_density.city_sensitivity: 1000
#### Sous-réseaux ####
# Dans beaucoup de cas, le réseau routier consiste en composants indépendants sans aucun trajet passant entre eux. Dans
# le cas le plus simple, vous pouvez imaginer une Ăźle sans pont ou connexion ferry. Le paramĂštre suivant
# permet de dĂ©finir une taille minimale (nombre d'edges) pour tels composants dĂ©tachĂ©s. Cela peut ĂȘtre utilisĂ© pour rĂ©duire le nombre
# de cas oĂč une connexion entre deux locations n'est pas trouvĂ©e.
prepare.min_network_size: 200
prepare.subnetworks.threads: 1
#### Routage ####
# Vous pouvez dĂ©finir le nombre maximal de nĆuds visitĂ©s pendant le routage. Cela peut entraĂźner des connexions non trouvĂ©es si il n'y a pas
# de connexion entre deux points dans les nĆuds visitĂ©s donnĂ©s. Le dĂ©faut est Integer.MAX_VALUE. Utile pour le mode flexibility
# routing.max_visited_nodes: 1000000
# défaut pour snap_preventions
routing.snap_preventions_default: tunnel, bridge, ferry
# Le temps maximum en millisecondes aprĂšs lequel une requĂȘte de routage sera annulĂ©e. Cela a quelques particularitĂ©s
# spĂ©cifiques Ă l'algorithme de routage, mais gĂ©nĂ©ralement cela devrait permettre la prĂ©vention des requĂȘtes de longue durĂ©e. Le dĂ©faut est Long.MAX_VALUE
# routing.timeout_ms: 300000
# ContrĂŽler combien de landmarks actifs sont sĂ©lectionnĂ©s par dĂ©faut, cela peut amĂ©liorer les performances de requĂȘte
# routing.lm.active_landmarks: 4
# Vous pouvez limiter la distance max entre deux waypoints consĂ©cutifs des requĂȘtes de routage flexible Ă ĂȘtre infĂ©rieure ou Ă©gale
# à la distance donnée en mÚtres. Le défaut est fixé à 1000 km.
routing.non_ch.max_waypoint_distance: 1000000
#### Stockage ####
# Exclut certains types de highways pendant l'import OSM pour accélérer le processus et réduire la taille du graphe.
# Une application typique est d'exclure les highways 'footway','cycleway','path' et peut-ĂȘtre 'track' pour
# les véhicules motorisés. Cela conduit à un graphe plus petit et moins dense, car il y a moins de ways (obviously),
# mais aussi car il y a moins de croisements entre highways (=junctions).
# Un autre exemple typique est d'exclure 'motorway', 'trunk' et peut-ĂȘtre 'primary' highways pour bicycle ou pedestrian routing.
import.osm.ignored_highways: ''
# import.osm.ignored_highways: footway,construction,cycleway,path,steps # utiliser si vous avez uniquement des profils de véhicules motorisés uniquement
# import.osm.ignored_highways: motorway,trunk # utiliser si vous avez uniquement des profils de véhicules non motorisés
# écrira les noms de way dans la langue préférée (code de langue défini selon ISO 639-1 ou ISO 639-2) :
# datareader.preferred_language: en
# configurer l'accÚs mémoire, utiliser RAM_STORE pour les serveurs bien équipés (défaut et recommandé)
graph.dataaccess.default_type: RAM_STORE
# Si MMAP n'est pas adapté pour tout, vous pouvez l'utiliser pour des fichiers sélectionnés par ex. lors de l'import pour réduire l'utilisation de heap (voir #2440) :
# graph.dataaccess.type.geometry: MMAP
# graph.dataaccess.type.edges: MMAP
# graph.dataaccess.type.nodes: MMAP
# graph.dataaccess.type.nodes_ch.*: MMAP
# graph.dataaccess.type.shortcuts_.*: MMAP
# Si aussi pour le routage l'environnement est contraint en heap et que vous pouvez sacrifier la vitesse, vous pouvez aussi utiliser MMAP mais peut-ĂȘtre les prĂ©charger :
# premiĂšre rĂšgle correspond
# graph.dataaccess.mmap.preload.nodes_ch_car.*: 100
# graph.dataaccess.mmap.preload.nodes_ch.*: 30
#### Zones personnalisées ####
# GraphHopper lit des fichiers GeoJSON polygon y compris leurs propriétés de ce dossier et les rend disponibles
# à tous les tag parsers et modÚles personnalisés. Toutes les Features GeoJSON doivent avoir la propriété "id".
# Les frontiĂšres de pays sont incluses automatiquement (voir countries.geojson).
# custom_areas.directory: path/to/custom_areas
#### RĂšgles de pays ####
# GraphHopper applique des rÚgles de routage spécifiques au pays pendant l'import (pas activé par défaut).
# Vous devez rééfaire l'import pour que les changements prennent effet.
# country_rules.enabled: true
# Configuration du serveur Dropwizard
server:
application_connectors:
- type: http
port: 8989
# pour des raisons de sécurité, binder à localhost
bind_host: 0.0.0.0
# augmenter la limite de requĂȘte GET - pas nĂ©cessaire si /maps UI n'est pas utilisĂ© ou utilisĂ© sans modĂšles personnalisĂ©s
max_request_header_size: 50k
request_log:
appenders: []
admin_connectors:
- type: http
port: 8990
bind_host: localhost
# Voir https://www.dropwizard.io/en/latest/manual/core.html#logging
logging:
appenders:
- type: file
time_zone: UTC
current_log_filename: logs/graphhopper.log
log_format: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
archive: true
archived_log_filename_pattern: ./logs/graphhopper-%d.log.gz
archived_file_count: 30
never_block: true
- type: console
time_zone: UTC
log_format: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
loggers:
"com.graphhopper.osm_warnings":
level: DEBUG
additive: false
appenders:
- type: file
currentLogFilename: logs/osm_warnings.log
archive: false
logFormat: '[%level] %msg%n'
Lancer docker (bash + java et chemins)
Exécuter la commande Docker
1
2
3
4
5
6
7
8
9
docker run -d --name graphhopper --restart unless-stopped \
-p 8989:8989 \
-v /sharenfs/docker-data/graphhopper/data:/data \
-v /sharenfs/docker-data/graphhopper/graph-cache:/graph-cache \
-v /sharenfs/docker-data/graphhopper/srtm:/srtm \
--entrypoint /bin/bash \
israelhikingmap/graphhopper \
-c 'java -Ddw.graphhopper.datareader.file=/data/france.osm.pbf -Ddw.graphhopper.graph.location=/graph-cache -jar *.jar server config.yml'
GraphHopper dĂ©marre et lance lâimport (âstart creating graphâŠâ).
Le âconnexion rĂ©-initialisĂ©eâ que tu voyais vient trĂšs probablement du fait que tu testais pendant que le serveur/jetty nâĂ©tait pas encore prĂȘt Ă rĂ©pondre proprement.
Fais juste : 1) Attends la fin de build (logs)
1
docker logs -f graphhopper
2) En parallĂšle, teste toutes les 30s jusquâĂ obtenir un 200 :
1
curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8989/
Quand ça répond correctement, on validera le point crucial pour toi : POST /route avec ton payload (profile + details + custom_model).
Copie ensuite 30-50 derniĂšres lignes du docker logs une fois lâimport terminĂ© (quand tu vois âGraph createdâ / âLoading finishedâ ou similaire), et je te dis quoi mettre dans routing.ts exactement cĂŽtĂ© nouveau endpoint (et si ton custom_model est bien acceptĂ© par cette API).
Patienter environ 1hâŠ
1
curl -sS -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8989/
OK, le serveur répond (HTTP 303) donc il est en place.
Remarques sur docker run
Cette commande détruit le container
1
docker rm -f graphhopper >/dev/null 2>&1 || true
docker rmsupprime un container. docs.docker-f(alias de--force) force la suppression mĂȘme si le container est en cours dâexĂ©cution (il est arrĂȘtĂ© automatiquement avant suppression). runebook>/dev/null 2>&1cache les sorties normales et erreurs.|| trueĂ©vite que le script Ă©choue si le container nâexiste pas dĂ©jĂ .
Donc cette commande dĂ©truit bien le container nommĂ© graphhopper si il existe mais ne touche pas aux volumes (/sharenfs/docker-data/graphhopper/...) car tu nâas pas utilisĂ© -v/--volumes avec rm. docs.docker
Il nây a pas de construction (build) Ă chaque lancement de la commande docker run :
1
2
3
4
5
6
7
8
docker run -d --name graphhopper --restart unless-stopped \
-p 8989:8989 \
-v /sharenfs/docker-data/graphhopper/data:/data \
-v /sharenfs/docker-data/graphhopper/graph-cache:/graph-cache \
-v /sharenfs/docker-data/graphhopper/srtm:/srtm \
--entrypoint /bin/bash \
israelhikingmap/graphhopper \
-c 'java -Ddw.graphhopper.datareader.file=/data/france.osm.pbf -Ddw.graphhopper.graph.location=/graph-cache -jar *.jar server config.yml'
- La premiĂšre fois, Docker rĂ©cupĂšre lâimage
israelhikingmap/graphhopper(pull) si elle nâest pas locale. - Ensuite,
docker runcrée un nouveau container à partir de cette image et lance le processus Java. - à chaque exécution de
docker runavec--name graphhopper, si un container nommĂ©graphhopperexiste dĂ©jĂ , tu as normalement une erreur ; dans ton cas, la commandedocker rm -f graphhopperavantdocker runpermet de :- supprimer lâancien container,
- puis crĂ©er un nouveau avec le mĂȘme nom et les mĂȘmes volumes.
Les volumes persistent car ils sont sur le host (/sharenfs/docker-data/graphhopper/...). Donc :
- Le graphe précalculé dans
/graph-cachereste, - Les données OSM dans
/datarestent, - Seul le container (lâinstance) est dĂ©truit et recreated.
Il nây a pas de rebuild de lâimage Ă chaque fois, juste un nouveau container Ă partir de lâimage existante.
docker rm -f graphhopperdĂ©truit le container, mais pas les volumes.- Il nây a pas de build Ă chaque lancement, juste un nouveau container Ă partir de lâimage existante.
Migrer graphhopper vers docker compose
Pour migrer du âdocker runâ actuel au âdocker composâ sans perte de donnĂ©es
Voici la procédure pour migrer de ton docker run actuel vers Docker Compose sans perdre de données (graphe, données OSM, cache SRTM).
VĂ©rifier que le container actuel est bien arrĂȘtĂ© mais persistant
1
2
3
4
5
6
7
8
9
10
11
# Voir le container graphhopper
docker ps -a | grep graphhopper
# ArrĂȘter le container (si il est encore en cours)
docker stop graphhopper
# Supprimer le container
docker rm graphhopper
# vérification
docker ps -a | grep graphhopper
Les volumes sont sur le host, donc les données sont présentes:
/sharenfs/docker-data/graphhopper/dataâfrance.osm.pbf/sharenfs/docker-data/graphhopper/graph-cacheâ graphe prĂ©calculĂ©/sharenfs/docker-data/graphhopper/srtmâ cache SRTM (Ă©lĂ©vation)
Tu nâas rien Ă copier si ces chemins sont dĂ©jĂ utilisĂ©s par le container actuel.
Créer fichier /sharenfs/docker-data/graphhopper/docker-compose.yml équivalent à la commande docker run :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
services:
graphhopper:
image: israelhikingmap/graphhopper
container_name: graphhopper
restart: unless-stopped
ports:
- "8989:8989"
environment:
- JAVA_OPTS=-Ddw.server.applicationConnectors[0].bindHost=0.0.0.0
volumes:
- /sharenfs/docker-data/graphhopper/data:/data
- /sharenfs/docker-data/graphhopper/graph-cache:/graph-cache
- /sharenfs/docker-data/graphhopper/srtm:/srtm
- /sharenfs/docker-data/graphhopper/config.yml:/graphhopper/config.yml
entrypoint:
- /bin/bash
command:
- '-c'
- 'java -Ddw.graphhopper.datareader.file=/data/france.osm.pbf -Ddw.graphhopper.graph.location=/graph-cache -jar *.jar server /graphhopper/config.yml'
Se rendre dans le dossier contenant docker-compose.yml :
1
2
3
4
5
# dossier contenant docker-compose.yml
cd /sharenfs/docker-data/graphhopper/
# Démarrer le service
docker compose up -d
Utilisation :
1
2
3
4
5
6
7
8
9
10
11
# 1. Démarrer (crée le container si nécessaire)
docker compose up -d
# 2. ArrĂȘter sans dĂ©truire le container
docker compose stop
# 3. ArrĂȘter et supprimer le container (Ă©quivalent Ă docker rm -f)
docker compose down
# 4. Si tu veux recréer le container mais garder les volumes
docker compose up -d --force-recreate
docker compose downsupprime le container mais garde les volumes (car ils sont bind mounts sur le host).--force-recreaterecrĂ©e le container mĂȘme sâil nâa pas changĂ©, sans toucher aux volumes.
Ainsi, tu évites le docker rm -f manuel et tu as une gestion plus propre et reproductible.
Erreur lecture config.yml
/sharenfs/docker-data/graphhopper/docker-compose.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
services:
graphhopper:
image: israelhikingmap/graphhopper
container_name: graphhopper
restart: unless-stopped
ports:
- "8989:8989"
volumes:
- /sharenfs/docker-data/graphhopper/data:/data
- /sharenfs/docker-data/graphhopper/graph-cache:/graph-cache
- /sharenfs/docker-data/graphhopper/srtm:/srtm
entrypoint:
- /bin/bash
command:
- '-c'
- 'java -Ddw.graphhopper.datareader.file=/data/france.osm.pbf -Ddw.graphhopper.graph.location=/graph-cache -jar *.jar server config.yml'
docker compose logs -f
1
graphhopper | java.io.FileNotFoundException: File config.yml not found
ls /sharenfs/docker-data/graphhopper
1
config.yml data docker-compose.yml graph-cache srtm
Le problĂšme est que config.yml nâest pas montĂ© dans le container.
Dans ta commande docker run originale, le fichier config.yml Ă©tait accessible car tu dĂ©marrais depuis le dossier host oĂč il se trouvait (le working directory du container incluait ce fichier).
Dans Docker Compose, tu montes seulement data, graph-cache et srtm, mais pas config.yml, donc le container ne le voit pas.
Solution : monter config.yml dans le container
Modify ton docker-compose.yml pour ajouter le volume config.yml :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
services:
graphhopper:
image: israelhikingmap/graphhopper
container_name: graphhopper
restart: unless-stopped
ports:
- "8989:8989"
volumes:
- /sharenfs/docker-data/graphhopper/data:/data
- /sharenfs/docker-data/graphhopper/graph-cache:/graph-cache
- /sharenfs/docker-data/graphhopper/srtm:/srtm
- /sharenfs/docker-data/graphhopper/config.yml:/graphhopper/config.yml
entrypoint:
- /bin/bash
command:
- '-c'
- 'java -Ddw.graphhopper.datareader.file=/data/france.osm.pbf -Ddw.graphhopper.graph.location=/graph-cache -jar *.jar server /graphhopper/config.yml'
Changes :
- Ajout du volume :
```yaml
- /sharenfs/docker-data/graphhopper/config.yml:/graphhopper/config.yml ```
- Dans la commande Java, tu passes maintenant le chemin absolu dans le container :
1
server /graphhopper/config.yml
au lieu de
server config.yml.
Appliquer la modification
1
2
3
4
5
6
7
# 1. Sauvegarder le nouveau docker-compose.yml
cd /sharenfs/docker-data/graphhopper/
# 2. Recréer le container avec la nouvelle configuration
docker compose up -d --force-recreate
# 3. Vérifier les logs
docker compose logs -f
Le fichier config.yml sera maintenant accessible dans le container sous /graphhopper/config.yml, et Java le trouvera.
Vérifier fonctionnement
1
2
3
4
5
# Voir le statut
docker compose ps
# Logs
docker compose logs -f
Test le routage (curl)
Passe maintenant au test le plus important : un POST /route avec ton format routing.ts.
Exécuter :
1
2
3
4
5
6
7
8
9
10
11
12
# Tester le routage
curl -sS -X POST http://127.0.0.1:8989/route \
-H "Content-Type: application/json" \
-d '{
"points": [[0.991,47.199],[0.891,47.199]],
"profile": "foot",
"elevation": true,
"points_encoded": false,
"details": ["road_class","hike_rating","mtb_rating"],
"custom_model": {}
}'
echo
Si tu obtiens un JSON (ou au moins pas une erreur HTTP), dis-moi :
- le code HTTP (si erreur)
- et le message dâerreur (si ça Ă©choue)
Ensuite je te confirme la modif exacte de routing.ts pour pointer vers https://graphhopper.rnmkcy.eu/route (et si custom_model doit ĂȘtre vide ou non pour que ça marche).
1
{"message":"Cannot find the path details: [surface]","hints":[{"message":"Cannot find the path details: [surface]","details":"java.lang.IllegalArgumentException"}]}
Ăa confirme que ton GraphHopper (v12 + ton config/import) nâa pas activĂ©/autorisĂ© la âdetailsâ surface (et potentiellement dâautres). Dans ton routing.ts, soit on retire les dĂ©tails non supportĂ©s, soit on les active cĂŽtĂ© serveur.
Le plus simple cÎté code : remplacer graphhopperDetails par une liste sans surface (et garder ce qui marche).
Fais ce changement dans routing.ts :
1
2
- const graphhopperDetails = ['road_class', 'surface', 'hike_rating', 'mtb_rating'];
+ const graphhopperDetails = ['road_class', 'hike_rating', 'mtb_rating'];
Test sans surface
1
2
3
4
5
6
7
8
9
10
curl -sS -X POST http://127.0.0.1:8989/route \
-H "Content-Type: application/json" \
-d '{
"points": [[0.991,47.199],[0.891,47.199]],
"profile": "foot",
"elevation": true,
"points_encoded": false,
"details": ["road_class","hike_rating","mtb_rating"],
"custom_model": {}
}' |jq
| ĂlĂ©ment | Ton exemple (correct) |
|---|---|
points |
[[lon,lat],[lon,lat]] â [longueur, lat] |
profile |
"foot" (au lieu de "vehicle": "car") |
points_encoded |
false (pour utiliser [lon,lat] explicites) |
details |
["road_class","hike_rating","mtb_rating"] |
custom_model |
{} explicite |
curl flags |
-sS (silencieux + suivir SSL) |
| URL | http://127.0.0.1:8989/route |
Cet appel demande un itinéraire à pied, avec élévation, et retourne les détails de classe de voie, de rating randonnée et MTB.[docs.graphhopper]
Structure
Dossier /sharenfs/docker-data/graphhopper
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/sharenfs/docker-data/graphhopper
âââ config.yml
âââ data
â  âââ default-gh
â  âââ france.osm.pbf
âââ docker-compose.yml
âââ graph-cache
â  âââ edgekv_keys
â  âââ edgekv_vals
â  âââ edges
â  âââ geometry
â  âââ location_index
â  âââ nodes
â  âââ nodes_ch_car
â  âââ properties
â  âââ properties.txt
â  âââ shortcuts_car
âââ srtm
Nginx (proxy)
Fichier : /etc/nginx/conf.d/graphhopper.rnmkcy.eu.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
server {
listen 80;
server_name graphhopper.rnmkcy.eu;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name graphhopper.rnmkcy.eu;
# Certificats SSL
include /etc/nginx/conf.d/ssl-modern.inc;
client_max_body_size 20m;
location / {
proxy_pass http://127.0.0.1:8989;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_read_timeout 300;
}
}
Puis :
1
sudo nginx -t && sudo systemctl reload nginx
Modif routing.ts
Remplace juste la base :
1
2
- fetch('https://graphhopper.gpx.studio/route', {
+ fetch('https://graphhopper.rnmkcy.eu/route', {
Test
1
2
3
4
5
6
7
8
9
10
curl -sS -X POST https://graphhopper.rnmkcy.eu/route \
-H "Content-Type: application/json" \
-d '{
"points": [[0.991,47.199],[0.891,47.199]],
"profile": "foot",
"elevation": true,
"points_encoded": false,
"details": ["road_class","hike_rating","mtb_rating"],
"custom_model": {}
}' |jq
đ§ gpx.studio
Cloner gpx.studio dans le dossier courant
1
2
# cloner le dernier gpx.studio
git clone https://github.com/gpxstudio/gpx.studio.git
Le code est divisé en deux parties:
gpx: une bibliothĂšque de typescript pour parser et manipuler des fichiers GPX,site web: le site lui-mĂȘme, qui est une application SvelteKit.
Vous aurez besoin de Node.js pour construire et exécuter ces deux parties.
Construction bibliothĂšque gpx
Construction bibliothĂšque gpx
1
2
3
cd gpx.studio/gpx
npm install
npm run build
npm website install
Pour pouvoir charger la carte, vous devrez créer votre propre Maptiler API key et la stocker dans un fichier .env dans le répertoire website.
1
2
3
cd ../website
echo PUBLIC_MAPTILER_KEY=nUWxxxxxxxxxxxxxxgb > .env
npm install
Modifications des sources website
website/src/lib/docs/ , en fr uniquement
1
2
3
4
5
6
7
8
# Ne garder que les dossiers en et fr
mkdir -p /tmp/docs
mv website/src/lib/docs/en /tmp/docs/
mv website/src/lib/docs/fr /tmp/docs/
rm -r website/src/lib/docs/
mv /tmp/docs/en website/src/lib/docs/
mv /tmp/docs/fr website/src/lib/docs/
ls website/src/lib/docs/
website/src/locales/, en.json fr.json uniquement
1
find website/src/locales/ -name "*.json" -type f -not \( -name 'en.json' -or -name 'fr.json' \) -delete
website/src/lib/languages.ts
1
2
3
4
export const languages: Record<string, string> = {
en: 'English',
fr: 'Français',
};
website/src/lib/components/toolbar/tools/routing/routing.ts
- const graphhopperDetails = ['road_class', 'surface', 'hike_rating', 'mtb_rating']; + const graphhopperDetails = ['road_class', 'hike_rating', 'mtb_rating']; - let response = await fetch('https://graphhopper.gpx.studio/route', { + let response = await fetch('https://graphhopper.rnmkcy.eu/route', {Supprimer les boutons aide et donate
Fichier website/src/lib/components/Menu.svelte , supprimer les lignes 545 Ă 557
1
2
3
4
5
6
7
8
9
10
11
12
13
<Button
variant="ghost"
href="https://opencollective.com/gpxstudio"
target="_blank"
class="cursor-default h-fit rounded-md font-bold text-support hover:text-support px-3 py-0.5"
aria-label={i18n._('menu.donate')}
>
<HeartHandshake size="18" class="md:hidden" />
<span class="hidden md:flex flex-row items-center">
{i18n._('menu.donate')}
<Heart size="16" class="ml-1" fill="var(--support)" />
</span>
</Button>
Opérations supplémentaires
1
2
3
4
# checher 'en'
find src/ -name "*" -type f -exec grep -Hn "'en'" {} \;
# Remplacer 'en' par 'fr'
find src/ -name "*" -type f -exec sed -i "s#'en'#'fr'#g" {} \;
website/src/hooks.server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
< const language = event.params.language ?? 'en';
---
> //const language = event.params.language ?? 'fr';
> const language = 'fr';
31,32c32,33
< "name": "gpx.studio",
< "url": "https://gpx.studio"
---
> "name": "gpx.rnmkcy.eu",
> "url": "https://gpx.rnmkcy.eu"
49c50
< <link rel="alternate" hreflang="x-default" href="https://gpx.studio${getURLForLanguage('en', path)}" />
---
> <link rel="alternate" hreflang="x-default" href="https://gpx.studio${getURLForLanguage('fr', path)}" />
54c55
< headTag += ` <link rel="alternate" hreflang="${lang}" href="https://gpx.studio${getURLForLanguage(lang, path)}" />
---
> headTag += ` <link rel="alternate" hreflang="${lang}" href="https://gpx.rnmkcy.eu${getURLForLanguage(lang, path)}" />
src/routes/+layout.svelte
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
33c33
< folders.indexOf('l') >= 0 ? (folders[folders.indexOf('l') + 1] ?? 'en') : 'en';
---
> folders.indexOf('l') >= 0 ? (folders[folders.indexOf('l') + 1] ?? 'fr') : 'fr';
49,50c49,50
< } else if (i18n.lang !== 'en') {
< i18n.lang = 'en';
---
> } else if (i18n.lang !== 'fr') {
> i18n.lang = 'fr';
53c53
< i18n.lang = 'en';
---
> i18n.lang = 'fr';
67c67
< let showNavAndFooter = $derived(page.route.id === null || !appRoutes.includes(page.route.id));
---
> let showNavAndFooter = $derived(page.route.id === null || !appRoutes.includes(page.route.id));
81c81
< <Footer />
---
> <!--<Footer />-->
Construction website
On lance le build
1
npm run build
Résultat construction
1
2
3
4
5
6
7
8
9
10
â built in 41.58s
Run npm run preview to preview your production build locally.
> Using @sveltejs/adapter-static
Wrote site to "build"
â done
> website@0.0.1 postbuild
> npx tsx src/lib/scripts/sitemap.ts
AprĂšs la construction on copie le dossier build
1
2
3
4
5
6
7
# Mise Ă jour site nginx
sudo rm -rf /var/www/gpx.studio
sudo cp -r /sharenfs/gpx.studio/website/build /var/www/gpx.studio
# les droits
sudo chown www-data:www-data -R /var/www/gpx.studio
# Recharger nginx
sudo systemctl reload nginx
AccĂšs par le lien https://gpx.rnmkcy.eu


cwwk - gpx.rnmkcy.eu
Configuration nginx /etc/nginx/conf.d/gpx.rnmkcy.eu.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name gpx.rnmkcy.eu;
include /etc/nginx/conf.d/ssl-modern.inc;
root /var/www/gpx.studio;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
# forcer /app et /app/ vers le bon fichier
location = /app { return 302 /app.html; }
location = /app/ { return 302 /app.html; }
# et les variantes avec langue (ex: /fr/app/)
location ~ ^/(fr|en|es|de|cs|tr|it|pt-BR|nl|zh|eu)/app$ {
return 302 /$1/app.html;
}
location ~ ^/(fr|en|es|de|cs|tr|it|pt-BR|nl|zh|eu)/app/$ {
return 302 /$1/app.html;
}
# pareil pour embed si besoin
location = /embed { return 302 /embed.html; }
location = /embed/ { return 302 /embed.html; }
location ~ ^/(fr|en|es|de|cs|tr|it|pt-BR|nl|zh|eu)/embed$ {
return 302 /$1/embed.html;
}
location ~ ^/(fr|en|es|de|cs|tr|it|pt-BR|nl|zh|eu)/embed/$ {
return 302 /$1/embed.html;
}
}
Vérifier et recharger nginx
1
2
sudo nginx -t
sudo systemctl reload nginx
Crédits
Ce projet utilise les projets open source suivants:
- Développement :
- Svelte and SvelteKit â seamless development experience
- MDsveX â permettant une documentation basĂ©e sur Markdown
- svelte-i18n - localisation facile
- Design:
- shadcn-svelte â beaux composants
- lucide-svelte â belles icĂŽnes
- tailwindcss - un style facile
- Chart.js â graphiques magnifiques et rapides
- Logique :
- immer â gestion complexe de l ' Ătat
- Dexie.js â IndexedDB wrapper
- fast-xml-parser â Fast GPX file parsing
- SortableJS â crĂ©ant un arbre de fichiers triable
- Mapping:
- Mapbox GL JS â cartes interactives magnifiques et rapides
- brouter â Moteur de routage
- OpenStreetMap â map data used by Mapbox and brouter
- Recherche :
- DocSearch â moteur de recherche de la documentation
- FR:Calcul dâitinĂ©raires
Annexe
Test local
1
npm run preview
Lance le serveur avec une adresse locale
1
2
3
4
5
6
> website@0.0.1 preview
> vite preview
â Local: http://localhost:4173/
â Network: use --host to expose
â press h + enter to show help
LâexĂ©cution a lieu sur un serveur, utilisation de SSH tunneling, sur un poste ayant un accĂšs SSH, ouvrir un terminal et exĂ©cuter la commande suivante
1
ssh -L 9500:localhost:4173 yick@192.168.0.205 -p 55205 -i /home/yann/.ssh/yick-ed25519
Puis ouvrir le lien suivant dans un navigateur : localhost:9500
gpx.studio mode dev
1
npm run dev
Le serveur est accessible sur le lien http://localhost:5173/, q pour sortir
1
2
3
4
5
6
7
8
9
10
11
12
13
> website@0.0.1 dev
> vite dev
Forced re-optimization of dependencies
VITE v5.4.8 ready in 1305 ms
â Local: http://localhost:5173/
â Network: use --host to expose
â press h + enter to show help
Browserslist: caniuse-lite is outdated. Please run:
npx update-browserslist-db@latest
Why you should do it regularly: https://github.com/browserslist/update-db#readme
LâexĂ©cution a lieu sur un serveur, utilisation de SSH tunneling, sur un poste ayant un accĂšs SSH, ouvrir un terminal et exĂ©cuter la commande suivante
1
ssh -L 9500:localhost:4173 yick@192.168.0.205 -p 55205 -i /home/yann/.ssh/yick-ed25519
Puis ouvrir le lien suivant dans un navigateur : localhost:9500

