Show course informations in side pane
This commit is contained in:
		
							parent
							
								
									fe08c42920
								
							
						
					
					
						commit
						d9869ce2f7
					
				|  | @ -7,21 +7,31 @@ | |||
|         <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> | ||||
| 
 | ||||
|         <style> | ||||
|             body, html | ||||
|             { | ||||
|             body, html { | ||||
|                 padding: 0; | ||||
|                 margin: 0; | ||||
|                 height: 100%; | ||||
|             } | ||||
| 
 | ||||
|             #map | ||||
|             { | ||||
|             body { | ||||
|                 display: flex; | ||||
|                 flex-direction: row; | ||||
|             } | ||||
| 
 | ||||
|             #informations { | ||||
|                 flex: 0 0 600px; | ||||
|                 padding: 20px; | ||||
|                 overflow-y: auto; | ||||
|             } | ||||
| 
 | ||||
|             #map { | ||||
|                 width: 100%; | ||||
|                 height: 100%; | ||||
|             } | ||||
|         </style> | ||||
|     </head> | ||||
|     <body> | ||||
|         <div id="informations"></div> | ||||
|         <div id="map"></div> | ||||
|         <script src="index.js"></script> | ||||
|     </body> | ||||
|  |  | |||
|  | @ -1,6 +1,89 @@ | |||
| // eslint-disable-next-line node/no-extraneous-require
 | ||||
| require("regenerator-runtime/runtime"); | ||||
| 
 | ||||
| const network = require("../tam/network.json"); | ||||
| const simulation = require("../tam/simulation"); | ||||
| const map = require("./map/index.js"); | ||||
| 
 | ||||
| map.create(/* map = */ "map"); | ||||
| // Run courses simulation
 | ||||
| const coursesSimulation = simulation.start(); | ||||
| global.courses = coursesSimulation.courses; | ||||
| 
 | ||||
| const informations = document.querySelector("#informations"); | ||||
| let courseId = null; | ||||
| 
 | ||||
| const displayTime = date => [ | ||||
|     date.getHours(), | ||||
|     date.getMinutes(), | ||||
|     date.getSeconds() | ||||
| ].map(number => number.toString().padStart(2, '0')).join(':'); | ||||
| 
 | ||||
| setInterval(() => { | ||||
|     let html = ` | ||||
|         <dl> | ||||
|             <dt>Heure actuelle</dt> | ||||
|             <dd>${displayTime(new Date())}</dd> | ||||
|         </dl> | ||||
|     `;
 | ||||
| 
 | ||||
|     if (courseId !== null && courseId in coursesSimulation.courses) { | ||||
|         const course = coursesSimulation.courses[courseId]; | ||||
| 
 | ||||
|         const timeToHTML = time => Math.ceil((time - Date.now()) / 1000); | ||||
| 
 | ||||
|         const stopToHTML = stopId => network.stops[stopId].properties.name; | ||||
| 
 | ||||
|         const passingsToHTML = passings => passings.map(([stopId, time]) => ` | ||||
|             <tr> | ||||
|                 <td>${stopToHTML(stopId)}</td> | ||||
|                 <td>${displayTime(new Date(time))}</td> | ||||
|             </tr> | ||||
|         `).join('\n');
 | ||||
| 
 | ||||
|         html += ` | ||||
|             <dl> | ||||
|                 <dt>ID</dt> | ||||
|                 <dd>${courseId}</dd> | ||||
| 
 | ||||
|                 <dt>Ligne</dt> | ||||
|                 <dd>${course.line}</dd> | ||||
| 
 | ||||
|                 <dt>Destination</dt> | ||||
|                 <dd>${stopToHTML(course.finalStop)}</dd> | ||||
| 
 | ||||
|                 <dt>État</dt> | ||||
|                 <dd>${course.state === 'moving' | ||||
|                         ? `Entre ${stopToHTML(course.departureStop)} | ||||
|                            et ${stopToHTML(course.arrivalStop)}` | ||||
|                         : `À l’arrêt ${stopToHTML(course.currentStop)}`}</dd> | ||||
| 
 | ||||
|                 ${course.state === 'moving' ? ` | ||||
|                     <dt>Arrivée dans</dt> | ||||
|                     <dd>${timeToHTML(course.arrivalTime)} s</dd> | ||||
| 
 | ||||
|                     <dt>Distance parcourue</dt> | ||||
|                     <dd>${Math.ceil(course.traveledDistance)} m</dd> | ||||
| 
 | ||||
|                     <dt>Vitesse</dt> | ||||
|                     <dd>${Math.ceil(course.speed * 3600)} km/h</dd> | ||||
|                 ` : ` | ||||
|                     <dt>Départ dans</dt> | ||||
|                     <dd>${timeToHTML(course.departureTime)} s</dd> | ||||
|                 `}
 | ||||
|             </dl> | ||||
| 
 | ||||
|             <h2>Arrêts précédents</h2> | ||||
|             <table>${passingsToHTML(course.prevPassings)}</table> | ||||
| 
 | ||||
|             <h2>Arrêts suivants</h2> | ||||
|             <table>${passingsToHTML(course.nextPassings)}</table> | ||||
|         `;
 | ||||
|     } | ||||
| 
 | ||||
|     informations.innerHTML = html; | ||||
| }, 1000); | ||||
| 
 | ||||
| // Create the network and courses map
 | ||||
| map.create(/* map = */ "map", coursesSimulation, course => { | ||||
|     courseId = course; | ||||
| }); | ||||
|  |  | |||
|  | @ -9,7 +9,6 @@ const tilesLayers = require("./tiles"); | |||
| const networkLayers = require("./network"); | ||||
| const { sizes, makeBorderColor, makeCourseColor } = require("./common"); | ||||
| const network = require("../../tam/network.json"); | ||||
| const simulation = require("../../tam/simulation"); | ||||
| 
 | ||||
| const courseStyles = {}; | ||||
| 
 | ||||
|  | @ -59,7 +58,7 @@ const getCourseStyle = lineColor => { | |||
|     return courseStyles[lineColor]; | ||||
| }; | ||||
| 
 | ||||
| const create = target => { | ||||
| const create = (target, coursesSimulation, onClick) => { | ||||
|     const view = new View({ | ||||
|         center: proj.fromLonLat([3.88, 43.605]), | ||||
|         zoom: 14, | ||||
|  | @ -78,32 +77,9 @@ const create = target => { | |||
| 
 | ||||
|     const stopsLayer = map.getLayers().item(3); | ||||
| 
 | ||||
|     // Run courses simulation
 | ||||
|     const simulInstance = simulation.start(); | ||||
| 
 | ||||
|     // Course on which the view is currently focused
 | ||||
|     let focusedCourse = null; | ||||
| 
 | ||||
|     const startFocus = courseId => { | ||||
|         if (courseId in simulInstance.courses) { | ||||
|             const course = simulInstance.courses[courseId]; | ||||
| 
 | ||||
|             view.animate({ | ||||
|                 center: course.position, | ||||
|                 duration: 500 | ||||
|             }, () => { | ||||
|                 focusedCourse = courseId; | ||||
|             }); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     const stopFocus = () => { | ||||
|         focusedCourse = null; | ||||
|     }; | ||||
| 
 | ||||
|     // Draw courses directly on the map
 | ||||
|     map.on("postcompose", ev => { | ||||
|         simulInstance.update(); | ||||
|         coursesSimulation.update(); | ||||
| 
 | ||||
|         // The normal way to access a layer’s vector context is through the
 | ||||
|         // `postrender` event of that layer. However, `postrender` is not
 | ||||
|  | @ -121,7 +97,8 @@ const create = target => { | |||
| 
 | ||||
|             const ctx = getVectorContext(ev); | ||||
| 
 | ||||
|             for (const course of Object.values(simulInstance.courses)) { | ||||
|             for (const course of Object.values(coursesSimulation.courses)) { | ||||
|                 const point = new Point(course.position); | ||||
|                 const color = network.lines[course.line].color; | ||||
|                 const style = getCourseStyle(color); | ||||
| 
 | ||||
|  | @ -131,14 +108,7 @@ const create = target => { | |||
|                 ); | ||||
| 
 | ||||
|                 ctx.setStyle(style); | ||||
| 
 | ||||
|                 const point = new Point(course.position); | ||||
| 
 | ||||
|                 ctx.drawGeometry(point); | ||||
| 
 | ||||
|                 if (course.id === focusedCourse) { | ||||
|                     view.setCenter(course.position); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  | @ -149,22 +119,18 @@ const create = target => { | |||
| 
 | ||||
|     map.on("singleclick", ev => { | ||||
|         const mousePixel = map.getPixelFromCoordinate(ev.coordinate); | ||||
|         const maxDistance = sizes.courseSize + sizes.courseOuterBorder; | ||||
|         const maxDistance = sizes.courseSize + sizes.courseInnerBorder; | ||||
| 
 | ||||
|         for (const course of Object.values(simulInstance.courses)) { | ||||
|         for (const course of Object.values(coursesSimulation.courses)) { | ||||
|             const coursePixel = map.getPixelFromCoordinate(course.position); | ||||
|             const dx = mousePixel[0] - coursePixel[0]; | ||||
|             const dy = mousePixel[1] - coursePixel[1]; | ||||
|             const distance = dx * dx + dy * dy; | ||||
| 
 | ||||
|             if (distance <= maxDistance * maxDistance) { | ||||
|                 startFocus(course.id); | ||||
|                 return; | ||||
|                 onClick(course.id); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Clicking anywhere else resets focus
 | ||||
|         stopFocus(); | ||||
|     }); | ||||
| 
 | ||||
|     return map; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue