Split front/map.js

This commit is contained in:
Mattéo Delabre 2020-07-26 15:57:09 +02:00
parent 079fbcf310
commit dd950a95e8
Signed by: matteo
GPG Key ID: AE3FBD02DC583ABB
5 changed files with 213 additions and 170 deletions

View File

@ -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");

42
src/front/map/common.js Normal file
View File

@ -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;

View File

@ -1,125 +1,15 @@
require("ol/ol.css");
const { Map, View } = require("ol");
const GeoJSON = require("ol/format/GeoJSON").default;
const reader = new GeoJSON({ featureProjection: "EPSG:3857" });
const TileLayer = require("ol/layer/Tile").default;
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 Point = require("ol/geom/Point").default;
const proj = require("ol/proj");
const { Style, Fill, Stroke, Circle, Icon } = require("ol/style");
const colorModule = require("color");
const mapboxToken = "pk.eyJ1IjoibWF0dGVvZGVsYWJyZSIsImEiOiJja2NxaTUyMmUwcmFhMn\
h0NmFsdzQ3emxqIn0.cyxF0h36emIMTk3cc4VqUw";
const simulation = require("../tam/simulation");
const network = require("../tam/network.json");
const lineFeaturesOrder = (feature1, feature2) => {
const lines1 = feature1.get("lines");
if (lines1.length === 0) {
return -1;
}
const lines2 = feature2.get("lines");
if (lines2.length === 0) {
return 1;
}
return Math.min(...lines1) - Math.min(...lines2);
};
const makeDataSources = () => {
const segmentsSource = new VectorSource();
const stopsSource = new VectorSource();
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 reader.readFeature(json);
});
segmentsSource.addFeatures(readFeatures(network.segments));
stopsSource.addFeatures(readFeatures(network.stops));
return { segmentsSource, stopsSource };
};
const makeBorderColor = mainColor => {
const hsl = colorModule(mainColor).hsl();
hsl.color = Math.max(0, hsl.color[2] -= 20);
return hsl.hex();
};
const makeCourseColor = mainColor => {
const hsl = colorModule(mainColor).hsl();
hsl.color = Math.max(0, hsl.color[2] += 10);
return hsl.hex();
};
const sizes = {
segmentOuter: 8,
segmentInner: 6,
stopRadius: 6,
stopBorder: 1.5,
courseSize: 15,
courseOuterBorder: 13,
courseBorder: 10,
courseInnerBorder: 7
};
const segmentBorderStyle = feature => new Style({
stroke: new Stroke({
color: makeBorderColor(feature.get("colors")[0]),
width: sizes.segmentOuter
})
});
const segmentInnerStyle = feature => new Style({
stroke: new Stroke({
color: feature.get("colors")[0],
width: sizes.segmentInner
})
});
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
})
});
const { Style, Icon } = require("ol/style");
const tilesLayers = require("./tiles");
const networkLayers = require("./network");
const { sizes, makeBorderColor, makeCourseColor } = require("./common");
const network = require("../../tam/network.json");
const simulation = require("../../tam/simulation");
const courseStyles = {};
@ -169,53 +59,7 @@ const getCourseStyle = lineColor => {
return courseStyles[lineColor];
};
const createMap = target => {
// Map background
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]
});
const backgroundLayer = new TileLayer({
source: backgroundSource
});
// Static data overlay
const { segmentsSource, stopsSource } = makeDataSources();
const segmentsBorderLayer = new VectorLayer({
source: segmentsSource,
renderOrder: lineFeaturesOrder,
style: segmentBorderStyle,
updateWhileInteracting: true,
updateWhileAnimating: true
});
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
});
// Setup map
const create = target => {
const view = new View({
center: proj.fromLonLat([3.88, 43.605]),
zoom: 14,
@ -226,14 +70,14 @@ const createMap = target => {
const map = new Map({
target,
layers: [
backgroundLayer,
segmentsBorderLayer,
segmentsInnerLayer,
stopsLayer
...tilesLayers.getLayers(),
...networkLayers.getLayers()
],
view
});
const stopsLayer = map.getLayers().item(3);
// Run courses simulation
const simulInstance = simulation.start();
@ -322,4 +166,4 @@ const createMap = target => {
return map;
};
exports.createMap = createMap;
exports.create = create;

132
src/front/map/network.js Normal file
View File

@ -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;

25
src/front/map/tiles.js Normal file
View File

@ -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;