diff --git a/src/front/map.js b/src/front/map.js index de3f54c..0216792 100644 --- a/src/front/map.js +++ b/src/front/map.js @@ -8,6 +8,7 @@ const XYZSource = require('ol/source/XYZ').default; const VectorLayer = require('ol/layer/Vector').default; const VectorSource = require('ol/source/Vector').default; +const {getVectorContext} = require('ol/render'); const Feature = require('ol/Feature').default; const Point = require('ol/geom/Point').default; @@ -75,21 +76,21 @@ const makeBorderColor = mainColor => return hsl.hex(); }; -const segmentsBorderStyle = feature => new Style({ +const segmentBorderStyle = feature => new Style({ stroke: new Stroke({ color: makeBorderColor(feature.get('colors')[0]), width: 8, }), }); -const segmentsInnerStyle = feature => new Style({ +const segmentInnerStyle = feature => new Style({ stroke: new Stroke({ color: feature.get('colors')[0], width: 6, }), }); -const stopsStyle = feature => new Style({ +const stopStyle = feature => new Style({ image: new Circle({ fill: new Fill({ color: feature.get('colors')[0], @@ -102,6 +103,19 @@ const stopsStyle = feature => new Style({ }), }); +const courseStyle = new Style({ + image: new Circle({ + fill: new Fill({ + color: '#FF0000', + }), + stroke: new Stroke({ + color: makeBorderColor('#FF0000'), + width: 1.5, + }), + radius: 6, + }), +}); + const createMap = target => { // Map background @@ -122,7 +136,7 @@ const createMap = target => const segmentsBorderLayer = new VectorLayer({ source: segmentsSource, - style: segmentsBorderStyle, + style: segmentBorderStyle, updateWhileInteracting: true, updateWhileAnimating: true, @@ -130,7 +144,7 @@ const createMap = target => const segmentsInnerLayer = new VectorLayer({ source: segmentsSource, - style: segmentsInnerStyle, + style: segmentInnerStyle, updateWhileInteracting: true, updateWhileAnimating: true, @@ -138,71 +152,21 @@ const createMap = target => const stopsLayer = new VectorLayer({ source: stopsSource, - style: stopsStyle, + style: stopStyle, minZoom: 13, updateWhileInteracting: 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 + const view = new View({ + center: proj.fromLonLat([3.88, 43.605]), + zoom: 13, + maxZoom: 22, + constrainResolution: true, }); - // Setup map const map = new Map({ target, layers: [ @@ -210,16 +174,44 @@ const createMap = target => segmentsBorderLayer, segmentsInnerLayer, stopsLayer, - coursesLayer, ], - view: new View({ - center: proj.fromLonLat([3.88, 43.605]), - zoom: 13, - maxZoom: 22, - constrainResolution: true, - }), + view, }); + // Run courses simulation and draw directly on the map + const simulInstance = simulation.start(); + + map.on('postcompose', ev => + { + simulInstance.update(); + + // The normal way to access a layer’s vector context is through the + // `postrender` event of that layer. However, `postrender` is not + // triggered when no feature of the layer is inside the current + // bounding box, but we want to draw vehicles in between stops even + // if no stop is visible. This hack listens to the global `postcompose` + // event, which is always triggered at every frame, and reconstructs + // the stops layer’s vector context from internal variables + if (stopsLayer.renderer_) + { + ev.context = stopsLayer.renderer_.context; + ev.inversePixelTransform + = stopsLayer.renderer_.inversePixelTransform; + + const ctx = getVectorContext(ev); + ctx.setStyle(courseStyle); + + for (let course of Object.values(simulInstance.courses)) + { + const point = new Point(course.position); + ctx.drawGeometry(point); + } + } + + map.render(); + }); + + map.render(); return map; };