tracktracker/src/front/map/vehicles.js

234 lines
7.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// import { getVectorContext } from "ol/render";
// import Point from "ol/geom/Point";
// import { fromExtent } from 'ol/geom/Polygon';
// import { Style, Icon } from "ol/style";
import * as turfHelpers from "@turf/helpers";
import { scaleZoom, makeBorderColor, makeCourseColor } from "./common";
import network from "../../data/network.json";
const VEHICLE_SIZE = 15;
const VEHICLE_BORDER = 10;
const makeVehicleIcon = size => {
const canvas = window.document.createElement("canvas");
const context = canvas.getContext("2d");
canvas.width = size;
canvas.height = size;
const cx = size / 2;
const cy = size / 2;
const iconSize = 0.4 * size;
const borderSize = 0.2 * size;
context.fillStyle = "black";
context.strokeStyle = "black";
context.lineWidth = borderSize;
context.lineJoin = "round";
context.miterLimit = 200000;
context.beginPath();
context.moveTo(cx - 0.3 * iconSize, cy + 0.5 * iconSize);
context.lineTo(cx, cy - 0.5 * iconSize);
context.lineTo(cx + 0.3 * iconSize, cy + 0.5 * iconSize);
context.closePath();
context.stroke();
context.fill();
return {
width: size,
height: size,
data: context.getImageData(0, 0, size, size).data,
};
};
/**
* Add layers that display the live vehicle positions on the map.
* @param {Map} map The map to add the layers to.
*/
export const addLayers = map => {
map.addImage("vehicle", makeVehicleIcon(128), {sdf: true});
map.addSource("vehicles", {
type: "geojson",
data: turfHelpers.featureCollection([]),
});
for (let [kind, factor] of [
["outer", 0.3],
["border", 0.25],
["inner", 0.2],
]) {
map.addLayer({
id: `vehicles-${kind}`,
type: "symbol",
source: "vehicles",
layout: {
"icon-image": "vehicle",
"icon-size": scaleZoom(factor),
"icon-allow-overlap": true,
"icon-rotation-alignment": "map",
"icon-rotate": ["get", "bearing"],
},
paint: {
"icon-color": ["get", `${kind}Color`],
},
});
}
};
/**
* Update the vehicle positions on the map.
* @param {Map} map The map to update.
* @param {Array<Object>} courses The active courses.
*/
export const update = (map, courses) => {
const features = Object.values(courses);
for (let course of features) {
const props = course.properties;
props.borderColor = network.lines[props.line].color;
props.innerColor = makeCourseColor(props.borderColor);
props.outerColor = makeBorderColor(props.borderColor);
}
map.getSource("vehicles").setData(
turfHelpers.featureCollection(Object.values(courses))
);
};
// const courseStyle = cacheStyle(
// lineColor => {
// const icon = window.document.createElement("canvas");
// const shapeSize = sizes.courseSize;
// const iconSize = sizes.courseSize + sizes.courseOuterBorder;
// icon.width = iconSize;
// icon.height = iconSize;
// const cx = icon.width / 2;
// const cy = icon.height / 2;
// const iconCtx = icon.getContext("2d");
// for (const [color, size] of [
// [makeBorderColor(lineColor), sizes.courseOuterBorder],
// [lineColor, sizes.courseBorder],
// [makeCourseColor(lineColor), sizes.courseInnerBorder]
// ]) {
// iconCtx.fillStyle = color;
// iconCtx.strokeStyle = color;
// iconCtx.lineWidth = size;
// iconCtx.lineJoin = "round";
// iconCtx.miterLimit = 200000;
// iconCtx.beginPath();
// iconCtx.moveTo(cx - 0.5 * shapeSize, cy - 0.3 * shapeSize);
// iconCtx.lineTo(cx + 0.5 * shapeSize, cy);
// iconCtx.lineTo(cx - 0.5 * shapeSize, cy + 0.3 * shapeSize);
// iconCtx.closePath();
// iconCtx.stroke();
// iconCtx.fill();
// }
// return new Style({
// image: new Icon({
// img: icon,
// imgSize: [icon.width, icon.height]
// })
// });
// },
// );
// export const setupCoursesAnimation = (
// map, coursesSimulation, stopsLayer, onClick
// ) => {
// const view = map.getView();
// // Draw courses directly on the map
// map.on("postcompose", ev => {
// coursesSimulation.update();
// // The normal way to access a layers vector context is through the
// // `postrender` event of that layer. However, `postrender` is not
// // triggered when no feature of the layer is inside the current
// // bounding box, but we want to draw vehicles in between stops even
// // if no stop is visible. This hack listens to the global `postcompose`
// // event, which is always triggered at every frame, and reconstructs
// // the stops layers vector context from internal variables
// /* eslint-disable no-underscore-dangle */
// if (stopsLayer.renderer_) {
// ev.context = stopsLayer.renderer_.context;
// ev.inversePixelTransform =
// stopsLayer.renderer_.inversePixelTransform;
// /* eslint-enable no-underscore-dangle */
// const ctx = getVectorContext(ev);
// const bbox = fromExtent(map.getView().calculateExtent());
// bbox.scale(1.05);
// for (const course of Object.values(coursesSimulation.courses)) {
// if (!bbox.intersectsCoordinate(course.position)) {
// continue;
// }
// const point = new Point(course.position);
// const color = network.lines[course.line].color;
// const style = courseStyle(color);
// style.getImage().setRotation(
// view.getRotation() +
// course.angle
// );
// ctx.setStyle(style);
// ctx.drawGeometry(point);
// }
// }
// map.render();
// });
// map.on("singleclick", ev => {
// const mousePixel = map.getPixelFromCoordinate(ev.coordinate);
// const maxDistance = sizes.courseSize + sizes.courseInnerBorder;
// const clicked = [];
// for (const course of Object.values(coursesSimulation.courses)) {
// const coursePixel = map.getPixelFromCoordinate(course.position);
// const dx = mousePixel[0] - coursePixel[0];
// const dy = mousePixel[1] - coursePixel[1];
// const distance = dx * dx + dy * dy;
// if (distance <= maxDistance * maxDistance) {
// clicked.push(course.id);
// }
// }
// // Sort selected courses in increasing departing/arrival time
// clicked.sort((id1, id2) => {
// const course1 = coursesSimulation.courses[id1];
// const course2 = coursesSimulation.courses[id2];
// const time1 = (
// course1.state === "moving"
// ? course1.arrivalTime
// : course1.departureTime
// );
// const time2 = (
// course2.state === "moving"
// ? course2.arrivalTime
// : course2.departureTime
// );
// return time1 - time2;
// });
// onClick(clicked);
// });
// };