Mattéo Delabre
4 years ago
5 changed files with 213 additions and 170 deletions
@ -1,6 +1,6 @@ |
|||
// eslint-disable-next-line node/no-extraneous-require
|
|||
require("regenerator-runtime/runtime"); |
|||
|
|||
const { createMap } = require("./map"); |
|||
const map = require("./map/index.js"); |
|||
|
|||
createMap(/* map = */ "map"); |
|||
map.create(/* map = */ "map"); |
|||
|
@ -0,0 +1,42 @@ |
|||
const colorModule = require("color"); |
|||
|
|||
/** |
|||
* Turn the main color of a line into a color suitable for using as a border. |
|||
* @param {string} mainColor Original color. |
|||
* @returns {string} Hexadecimal representation of the border color. |
|||
*/ |
|||
const makeBorderColor = mainColor => { |
|||
const hsl = colorModule(mainColor).hsl(); |
|||
|
|||
hsl.color = Math.max(0, hsl.color[2] -= 20); |
|||
return hsl.hex(); |
|||
}; |
|||
|
|||
exports.makeBorderColor = makeBorderColor; |
|||
|
|||
/** |
|||
* Turn the main color of a line into a color suitable for using as a border. |
|||
* @param {string} mainColor Original color. |
|||
* @returns {string} Hexadecimal representation of the border color. |
|||
*/ |
|||
const makeCourseColor = mainColor => { |
|||
const hsl = colorModule(mainColor).hsl(); |
|||
|
|||
hsl.color = Math.max(0, hsl.color[2] += 10); |
|||
return hsl.hex(); |
|||
}; |
|||
|
|||
exports.makeCourseColor = makeCourseColor; |
|||
|
|||
const sizes = { |
|||
segmentOuter: 8, |
|||
segmentInner: 6, |
|||
stopRadius: 6, |
|||
stopBorder: 1.5, |
|||
courseSize: 15, |
|||
courseOuterBorder: 13, |
|||
courseBorder: 10, |
|||
courseInnerBorder: 7 |
|||
}; |
|||
|
|||
exports.sizes = sizes; |
@ -0,0 +1,132 @@ |
|||
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.<Layer>} 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; |
@ -0,0 +1,25 @@ |
|||
const TileLayer = require("ol/layer/Tile").default; |
|||
const XYZSource = require("ol/source/XYZ").default; |
|||
|
|||
const mapboxToken = "pk.eyJ1IjoibWF0dGVvZGVsYWJyZSIsImEiOiJja2NxaTUyMmUwcmFhMn\ |
|||
h0NmFsdzQ3emxqIn0.cyxF0h36emIMTk3cc4VqUw"; |
|||
|
|||
/** |
|||
* Create the list of layers for displaying the background map. |
|||
* @returns {Array.<Layer>} List of map layers. |
|||
*/ |
|||
const getLayers = () => { |
|||
const backgroundSource = new XYZSource({ |
|||
url: `https://api.mapbox.com/${[ |
|||
"styles", "v1", "mapbox", "streets-v11", |
|||
"tiles", "512", "{z}", "{x}", "{y}" |
|||
].join("/")}?access_token=${mapboxToken}`,
|
|||
tileSize: [512, 512] |
|||
}); |
|||
|
|||
return [new TileLayer({ |
|||
source: backgroundSource |
|||
})]; |
|||
}; |
|||
|
|||
exports.getLayers = getLayers; |
Loading…
Reference in new issue