const network = require("../../tam/network.json"); const { makeBorderColor, sizes } = require("./common"); const GeoJSON = require("ol/format/GeoJSON").default; const VectorLayer = require("ol/layer/Vector").default; const VectorSource = require("ol/source/Vector").default; const { Style, Fill, Stroke, Circle } = require("ol/style"); const geojsonReader = new GeoJSON({ featureProjection: "EPSG:3857" }); // Style used for the border of line segments const segmentBorderStyle = feature => new Style({ stroke: new Stroke({ color: makeBorderColor(feature.get("colors")[0]), width: sizes.segmentOuter }) }); // Style used for the inner part of line segments const segmentInnerStyle = feature => new Style({ stroke: new Stroke({ color: feature.get("colors")[0], width: sizes.segmentInner }) }); // Style used for line stops const stopStyle = feature => new Style({ image: new Circle({ fill: new Fill({ color: feature.get("colors")[0] }), stroke: new Stroke({ color: makeBorderColor(feature.get("colors")[0]), width: sizes.stopBorder }), radius: sizes.stopRadius }) }); /** * Order for features related to a network line inside the same layer. * @param {Feature} feature1 First feature to order. * @param {Feature} feature2 Second feature to order. * @returns {number} -1 if `feature1` comes before `feature2`, 1 if * `feature2` comes before `feature1`, 0 if the order is irrelevant. */ const lineFeaturesOrder = (feature1, feature2) => { // Place features with no lines attributed on the background const lines1 = feature1.get("lines"); if (lines1.length === 0) { return -1; } const lines2 = feature2.get("lines"); if (lines2.length === 0) { return 1; } // Draw lines with a lower numeric value first return Math.max(...lines2) - Math.max(...lines1); }; /** * Create the list of layers for displaying the transit network. * @returns {Array.} List of map layers. */ const getLayers = () => { const segmentsSource = new VectorSource(); const stopsSource = new VectorSource(); // Turn GeoJSON stops list and segments list into vector sources const readFeatures = hash => Object.values(hash).map(json => { json.properties.lines = json.properties.routes.filter( // Only consider normal routes (excluding alternate routes) ([lineRef, routeRef]) => network.lines[lineRef].routes[routeRef].state === "normal" ).map(([lineRef]) => lineRef); if (json.properties.lines.length >= 1) { json.properties.colors = json.properties.lines.map( lineRef => network.lines[lineRef].color ); } else { json.properties.colors = ["#FFFFFF"]; } return geojsonReader.readFeature(json); }); segmentsSource.addFeatures(readFeatures(network.segments)); stopsSource.addFeatures(readFeatures(network.stops)); // Background layer on which the darker borders of line segments are drawn const segmentsBorderLayer = new VectorLayer({ source: segmentsSource, renderOrder: lineFeaturesOrder, style: segmentBorderStyle, updateWhileInteracting: true, updateWhileAnimating: true }); // Foreground layer on which the lighter inner part of line segments are // drawn. The two layers are separated so that forks blend nicely together const segmentsInnerLayer = new VectorLayer({ source: segmentsSource, renderOrder: lineFeaturesOrder, style: segmentInnerStyle, updateWhileInteracting: true, updateWhileAnimating: true }); const stopsLayer = new VectorLayer({ source: stopsSource, renderOrder: lineFeaturesOrder, style: stopStyle, minZoom: 13, updateWhileInteracting: true, updateWhileAnimating: true }); return [segmentsBorderLayer, segmentsInnerLayer, stopsLayer]; }; exports.getLayers = getLayers;