Load simulation in front
This commit is contained in:
		
							parent
							
								
									f054b11743
								
							
						
					
					
						commit
						d688bff813
					
				|  | @ -1,7 +1,4 @@ | |||
| require('regenerator-runtime/runtime'); | ||||
| 
 | ||||
| const {createMap} = require('./map'); | ||||
| 
 | ||||
| require('../tam/simulation'); | ||||
| 
 | ||||
| createMap(/* map = */ 'map'); | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ const color = require('color'); | |||
| const mapboxToken = `pk.eyJ1IjoibWF0dGVvZGVsYWJyZSIsImEiOiJja2NxaTUyMmUwcmFhMn\
 | ||||
| h0NmFsdzQ3emxqIn0.cyxF0h36emIMTk3cc4VqUw`;
 | ||||
| 
 | ||||
| const simulation = require('../tam/simulation'); | ||||
| const network = require('../tam/network.json'); | ||||
| 
 | ||||
| const getRouteColors = routes => | ||||
|  | @ -39,7 +40,7 @@ const getRouteColors = routes => | |||
|     return ['#FFFFFF']; | ||||
| }; | ||||
| 
 | ||||
| const makeDataSources = async () => | ||||
| const makeDataSources = () => | ||||
| { | ||||
|     const segmentsSource = new VectorSource(); | ||||
|     const stopsSource = new VectorSource(); | ||||
|  | @ -101,7 +102,7 @@ const stopsStyle = feature => new Style({ | |||
|     }), | ||||
| }); | ||||
| 
 | ||||
| const createMap = async (target) => | ||||
| const createMap = target => | ||||
| { | ||||
|     // Map background
 | ||||
|     const backgroundSource = new XYZSource({ | ||||
|  | @ -116,8 +117,8 @@ const createMap = async (target) => | |||
|         source: backgroundSource, | ||||
|     }); | ||||
| 
 | ||||
|     // Data overlay
 | ||||
|     const {segmentsSource, stopsSource} = await makeDataSources(); | ||||
|     // Static data overlay
 | ||||
|     const {segmentsSource, stopsSource} = makeDataSources(); | ||||
| 
 | ||||
|     const segmentsBorderLayer = new VectorLayer({ | ||||
|         source: segmentsSource, | ||||
|  | @ -144,6 +145,63 @@ const createMap = async (target) => | |||
|         updateWhileAnimating: true, | ||||
|     }); | ||||
| 
 | ||||
|     // Dynamic data overlay
 | ||||
|     const coursesSource = new VectorSource(); | ||||
| 
 | ||||
|     const onFrame = courses => | ||||
|     { | ||||
|         // Remove stale courses
 | ||||
|         for (let feature of coursesSource.getFeatures()) | ||||
|         { | ||||
|             if (!(feature.getId() in courses)) | ||||
|             { | ||||
|                 coursesSource.removeFeature(feature); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Add new courses or update existing courses
 | ||||
|         const newFeatures = []; | ||||
| 
 | ||||
|         for (let [courseId, course] of Object.entries(courses)) | ||||
|         { | ||||
|             if ('position' in course) | ||||
|             { | ||||
|                 const feature = coursesSource.getFeatureById(courseId); | ||||
|                 const coords = proj.fromLonLat([ | ||||
|                     course.position.lon, | ||||
|                     course.position.lat | ||||
|                 ]); | ||||
| 
 | ||||
|                 if (feature === null) | ||||
|                 { | ||||
|                     const feature = new Feature({ | ||||
|                         colors: ['#FF0000'], | ||||
|                         geometry: new Point(coords) | ||||
|                     }); | ||||
| 
 | ||||
|                     feature.setId(courseId); | ||||
|                     newFeatures.push(feature); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     feature.getGeometry().setCoordinates(coords); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         coursesSource.addFeatures(newFeatures); | ||||
|     }; | ||||
| 
 | ||||
|     simulation.run(onFrame); | ||||
| 
 | ||||
|     const coursesLayer = new VectorLayer({ | ||||
|         source: coursesSource, | ||||
|         style: stopsStyle, | ||||
| 
 | ||||
|         updateWhileInteracting: true, | ||||
|         updateWhileAnimating: true, | ||||
|     }); | ||||
| 
 | ||||
|     // Setup map
 | ||||
|     const map = new Map({ | ||||
|         target, | ||||
|  | @ -152,6 +210,7 @@ const createMap = async (target) => | |||
|             segmentsBorderLayer, | ||||
|             segmentsInnerLayer, | ||||
|             stopsLayer, | ||||
|             coursesLayer, | ||||
|         ], | ||||
|         view: new View({ | ||||
|             center: proj.fromLonLat([3.88, 43.605]), | ||||
|  |  | |||
|  | @ -149,6 +149,7 @@ const updatePositions = (courses, time) => | |||
|     { | ||||
|         if (course.state === 'moving') | ||||
|         { | ||||
|             // Increase the travelled distance respective to the current speed
 | ||||
|             const delta = course.speed * time; | ||||
| 
 | ||||
|             const segment = getCurrentSegment(course); | ||||
|  | @ -162,20 +163,66 @@ const updatePositions = (courses, time) => | |||
|             { | ||||
|                 course.traveledDistance += delta; | ||||
|             } | ||||
| 
 | ||||
|             // Recompute updated position
 | ||||
|             const departureStop = network.stops[course.departureStop]; | ||||
|             const arrivalStop = network.stops[course.arrivalStop]; | ||||
|             const nextNodeIndex = segment.points.findIndex( | ||||
|                 ({distance}) => distance >= course.traveledDistance); | ||||
| 
 | ||||
|             if (nextNodeIndex === 0) | ||||
|             { | ||||
|                 course.position = { | ||||
|                     lat: departureStop.lat, | ||||
|                     lon: departureStop.lon | ||||
|                 }; | ||||
|             } | ||||
|             else if (nextNodeIndex === -1) | ||||
|             { | ||||
|                 course.position = { | ||||
|                     lat: arrivalStop.lat, | ||||
|                     lon: arrivalStop.lon | ||||
|                 }; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 const previousNode = segment.points[nextNodeIndex - 1]; | ||||
|                 const nextNode = segment.points[nextNodeIndex]; | ||||
| 
 | ||||
|                 const curLength = course.traveledDistance | ||||
|                     - previousNode.distance; | ||||
|                 const totalLength = nextNode.distance | ||||
|                     - previousNode.distance; | ||||
|                 const progression = curLength / totalLength; | ||||
| 
 | ||||
|                 course.position = { | ||||
|                     lat: progression * nextNode.lat | ||||
|                         + (1 - progression) * previousNode.lat, | ||||
|                     lon: progression * nextNode.lon | ||||
|                         + (1 - progression) * previousNode.lon, | ||||
|                 }; | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             const currentStop = network.stops[course.currentStop]; | ||||
|             course.position = { | ||||
|                 lat: currentStop.lat, | ||||
|                 lon: currentStop.lon, | ||||
|             }; | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| const run = callback => | ||||
| { | ||||
|     const courses = {}; | ||||
|     let lastFrame = null; | ||||
|     let lastUpdate = null; | ||||
| 
 | ||||
| const loop = now => | ||||
|     const loop = () => | ||||
|     { | ||||
|     const time = lastFrame === null ? 0 : now - lastFrame; | ||||
| 
 | ||||
|     lastFrame = now; | ||||
|     updatePositions(courses, time); | ||||
|         const now = Date.now(); | ||||
| 
 | ||||
|         if (lastUpdate === null || lastUpdate + 5000 <= now) | ||||
|         { | ||||
|  | @ -183,7 +230,15 @@ const loop = now => | |||
|             updateFromTam(courses); | ||||
|         } | ||||
| 
 | ||||
|     requestAnimationFrame(loop); | ||||
|         const time = lastFrame === null ? 0 : now - lastFrame; | ||||
|         lastFrame = now; | ||||
|         updatePositions(courses, time); | ||||
| 
 | ||||
|         callback(courses); | ||||
|     }; | ||||
| 
 | ||||
| requestAnimationFrame(loop); | ||||
|     const interval = setInterval(loop, 24); | ||||
|     return () => clearInterval(interval); | ||||
| }; | ||||
| 
 | ||||
| exports.run = run; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue