Split front/map.js
This commit is contained in:
parent
079fbcf310
commit
dd950a95e8
|
@ -1,6 +1,6 @@
|
||||||
// eslint-disable-next-line node/no-extraneous-require
|
// eslint-disable-next-line node/no-extraneous-require
|
||||||
require("regenerator-runtime/runtime");
|
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;
|
|
@ -1,125 +1,15 @@
|
||||||
require("ol/ol.css");
|
require("ol/ol.css");
|
||||||
|
|
||||||
const { Map, View } = require("ol");
|
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 { getVectorContext } = require("ol/render");
|
||||||
|
|
||||||
const Point = require("ol/geom/Point").default;
|
const Point = require("ol/geom/Point").default;
|
||||||
|
|
||||||
const proj = require("ol/proj");
|
const proj = require("ol/proj");
|
||||||
|
const { Style, Icon } = require("ol/style");
|
||||||
const { Style, Fill, Stroke, Circle, Icon } = require("ol/style");
|
const tilesLayers = require("./tiles");
|
||||||
const colorModule = require("color");
|
const networkLayers = require("./network");
|
||||||
|
const { sizes, makeBorderColor, makeCourseColor } = require("./common");
|
||||||
const mapboxToken = "pk.eyJ1IjoibWF0dGVvZGVsYWJyZSIsImEiOiJja2NxaTUyMmUwcmFhMn\
|
const network = require("../../tam/network.json");
|
||||||
h0NmFsdzQ3emxqIn0.cyxF0h36emIMTk3cc4VqUw";
|
const simulation = require("../../tam/simulation");
|
||||||
|
|
||||||
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 courseStyles = {};
|
const courseStyles = {};
|
||||||
|
|
||||||
|
@ -169,53 +59,7 @@ const getCourseStyle = lineColor => {
|
||||||
return courseStyles[lineColor];
|
return courseStyles[lineColor];
|
||||||
};
|
};
|
||||||
|
|
||||||
const createMap = target => {
|
const create = 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 view = new View({
|
const view = new View({
|
||||||
center: proj.fromLonLat([3.88, 43.605]),
|
center: proj.fromLonLat([3.88, 43.605]),
|
||||||
zoom: 14,
|
zoom: 14,
|
||||||
|
@ -226,14 +70,14 @@ const createMap = target => {
|
||||||
const map = new Map({
|
const map = new Map({
|
||||||
target,
|
target,
|
||||||
layers: [
|
layers: [
|
||||||
backgroundLayer,
|
...tilesLayers.getLayers(),
|
||||||
segmentsBorderLayer,
|
...networkLayers.getLayers()
|
||||||
segmentsInnerLayer,
|
|
||||||
stopsLayer
|
|
||||||
],
|
],
|
||||||
view
|
view
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const stopsLayer = map.getLayers().item(3);
|
||||||
|
|
||||||
// Run courses simulation
|
// Run courses simulation
|
||||||
const simulInstance = simulation.start();
|
const simulInstance = simulation.start();
|
||||||
|
|
||||||
|
@ -322,4 +166,4 @@ const createMap = target => {
|
||||||
return map;
|
return map;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.createMap = createMap;
|
exports.create = create;
|
|
@ -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