import network from "../../data/network.json"; import { cacheStyle, makeBorderColor, sizes } from "./common"; import GeoJSON from "ol/format/GeoJSON"; import VectorImageLayer from "ol/layer/VectorImage"; import VectorSource from "ol/source/Vector"; import { Style, Fill, Stroke, Circle } from "ol/style"; const geojsonReader = new GeoJSON({ featureProjection: "EPSG:3857" }); // Style used for the border of line segments const segmentBorderStyle = cacheStyle( color => new Style({ stroke: new Stroke({ color: makeBorderColor(color), width: sizes.segmentOuter }) }), feature => feature.get("colors")[0], ); // Style used for the inner part of line segments const segmentInnerStyle = cacheStyle( color => new Style({ stroke: new Stroke({ color, width: sizes.segmentInner }) }), feature => feature.get("colors")[0], ); // Style used for line stops const stopStyle = cacheStyle( color => new Style({ image: new Circle({ fill: new Fill({ color }), stroke: new Stroke({ color: makeBorderColor(color), width: sizes.stopBorder }), radius: sizes.stopRadius }) }), feature => feature.get("colors")[0], ); /** * 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. */ export 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 VectorImageLayer({ source: segmentsSource, renderOrder: lineFeaturesOrder, style: segmentBorderStyle, imageRatio: 2, }); // 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 VectorImageLayer({ source: segmentsSource, renderOrder: lineFeaturesOrder, style: segmentInnerStyle, imageRatio: 2, }); const stopsLayer = new VectorImageLayer({ source: stopsSource, renderOrder: lineFeaturesOrder, style: stopStyle, imageRatio: 2, minZoom: 13, }); return [segmentsBorderLayer, segmentsInnerLayer, stopsLayer]; };