Load simulation in front

This commit is contained in:
Mattéo Delabre 2020-07-23 17:29:35 +02:00
parent f054b11743
commit d688bff813
Signed by: matteo
GPG Key ID: AE3FBD02DC583ABB
3 changed files with 133 additions and 22 deletions

View File

@ -1,7 +1,4 @@
require('regenerator-runtime/runtime'); require('regenerator-runtime/runtime');
const {createMap} = require('./map'); const {createMap} = require('./map');
require('../tam/simulation');
createMap(/* map = */ 'map'); createMap(/* map = */ 'map');

View File

@ -21,6 +21,7 @@ const color = require('color');
const mapboxToken = `pk.eyJ1IjoibWF0dGVvZGVsYWJyZSIsImEiOiJja2NxaTUyMmUwcmFhMn\ const mapboxToken = `pk.eyJ1IjoibWF0dGVvZGVsYWJyZSIsImEiOiJja2NxaTUyMmUwcmFhMn\
h0NmFsdzQ3emxqIn0.cyxF0h36emIMTk3cc4VqUw`; h0NmFsdzQ3emxqIn0.cyxF0h36emIMTk3cc4VqUw`;
const simulation = require('../tam/simulation');
const network = require('../tam/network.json'); const network = require('../tam/network.json');
const getRouteColors = routes => const getRouteColors = routes =>
@ -39,7 +40,7 @@ const getRouteColors = routes =>
return ['#FFFFFF']; return ['#FFFFFF'];
}; };
const makeDataSources = async () => const makeDataSources = () =>
{ {
const segmentsSource = new VectorSource(); const segmentsSource = new VectorSource();
const stopsSource = new VectorSource(); const stopsSource = new VectorSource();
@ -101,7 +102,7 @@ const stopsStyle = feature => new Style({
}), }),
}); });
const createMap = async (target) => const createMap = target =>
{ {
// Map background // Map background
const backgroundSource = new XYZSource({ const backgroundSource = new XYZSource({
@ -116,8 +117,8 @@ const createMap = async (target) =>
source: backgroundSource, source: backgroundSource,
}); });
// Data overlay // Static data overlay
const {segmentsSource, stopsSource} = await makeDataSources(); const {segmentsSource, stopsSource} = makeDataSources();
const segmentsBorderLayer = new VectorLayer({ const segmentsBorderLayer = new VectorLayer({
source: segmentsSource, source: segmentsSource,
@ -144,6 +145,63 @@ const createMap = async (target) =>
updateWhileAnimating: true, 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 // Setup map
const map = new Map({ const map = new Map({
target, target,
@ -152,6 +210,7 @@ const createMap = async (target) =>
segmentsBorderLayer, segmentsBorderLayer,
segmentsInnerLayer, segmentsInnerLayer,
stopsLayer, stopsLayer,
coursesLayer,
], ],
view: new View({ view: new View({
center: proj.fromLonLat([3.88, 43.605]), center: proj.fromLonLat([3.88, 43.605]),

View File

@ -149,6 +149,7 @@ const updatePositions = (courses, time) =>
{ {
if (course.state === 'moving') if (course.state === 'moving')
{ {
// Increase the travelled distance respective to the current speed
const delta = course.speed * time; const delta = course.speed * time;
const segment = getCurrentSegment(course); const segment = getCurrentSegment(course);
@ -162,28 +163,82 @@ const updatePositions = (courses, time) =>
{ {
course.traveledDistance += delta; 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 courses = {}; const run = callback =>
let lastFrame = null;
let lastUpdate = null;
const loop = now =>
{ {
const time = lastFrame === null ? 0 : now - lastFrame; const courses = {};
let lastFrame = null;
let lastUpdate = null;
lastFrame = now; const loop = () =>
updatePositions(courses, time);
if (lastUpdate === null || lastUpdate + 5000 <= now)
{ {
lastUpdate = now; const now = Date.now();
updateFromTam(courses);
}
requestAnimationFrame(loop); if (lastUpdate === null || lastUpdate + 5000 <= now)
{
lastUpdate = now;
updateFromTam(courses);
}
const time = lastFrame === null ? 0 : now - lastFrame;
lastFrame = now;
updatePositions(courses, time);
callback(courses);
};
const interval = setInterval(loop, 24);
return () => clearInterval(interval);
}; };
requestAnimationFrame(loop); exports.run = run;