147 lines
4.5 KiB
JavaScript
147 lines
4.5 KiB
JavaScript
import network from "../../data/network.json";
|
|
import * as routing from "../../data/routing.js";
|
|
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.<Layer>} List of map layers.
|
|
*/
|
|
export const getLayers = () => {
|
|
const segmentsSource = new VectorSource();
|
|
const stopsSource = new VectorSource();
|
|
|
|
// Turn GeoJSON stops list into a vector source
|
|
const readStops = hash => Object.values(hash).map(json => {
|
|
json.properties.lines = json.properties.routes.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);
|
|
});
|
|
|
|
stopsSource.addFeatures(readStops(network.stops));
|
|
|
|
// Link stops with segments
|
|
const makeSegments = function* (lines) {
|
|
for (const [lineRef, line] of Object.entries(network.lines)) {
|
|
for (const route of line.routes) {
|
|
for (let i = 0; i + 1 < route.stops.length; ++i) {
|
|
const stop1 = network.stops[route.stops[i]].id;
|
|
const stop2 = network.stops[route.stops[i + 1]].id;
|
|
|
|
const segment = routing.findSegment(stop1, stop2);
|
|
segment.properties.lines = [lineRef];
|
|
segment.properties.colors = [line.color];
|
|
|
|
yield geojsonReader.readFeature(segment);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
segmentsSource.addFeatures([...makeSegments(network.lines)]);
|
|
|
|
// 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];
|
|
};
|