Load simulation in front
This commit is contained in:
parent
f054b11743
commit
d688bff813
|
@ -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');
|
||||||
|
|
|
@ -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]),
|
||||||
|
|
|
@ -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,20 +163,66 @@ 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 run = callback =>
|
||||||
|
{
|
||||||
const courses = {};
|
const courses = {};
|
||||||
let lastFrame = null;
|
let lastFrame = null;
|
||||||
let lastUpdate = null;
|
let lastUpdate = null;
|
||||||
|
|
||||||
const loop = now =>
|
const loop = () =>
|
||||||
{
|
{
|
||||||
const time = lastFrame === null ? 0 : now - lastFrame;
|
const now = Date.now();
|
||||||
|
|
||||||
lastFrame = now;
|
|
||||||
updatePositions(courses, time);
|
|
||||||
|
|
||||||
if (lastUpdate === null || lastUpdate + 5000 <= now)
|
if (lastUpdate === null || lastUpdate + 5000 <= now)
|
||||||
{
|
{
|
||||||
|
@ -183,7 +230,15 @@ const loop = now =>
|
||||||
updateFromTam(courses);
|
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