mobility-toolbox-js
Version:
Toolbox for JavaScript applications in the domains of mobility and logistics.
119 lines (118 loc) • 5.63 kB
JavaScript
import { apply, compose, create } from 'ol/transform';
import getVehiclePosition from './getVehiclePosition';
/**
* Draw all the trajectories available in a canvas.
* @param {HTMLCanvas|HTMLOffscreenCanvas} canvas The canvas where to draw the trajectories.
* @param {ViewState} trajectories An array of trajectories.
* @param {Function} style A function that returns a canvas representing a vehicle of a specific trajectory.
* @param {ViewState} viewState The view state of the map.
* @param {Object} options The options.
* @param {boolean} options.hoverVehicleId The id of the vehicle to highlight.
* @param {boolean} options.selectedVehicleId The id of the vehicle to select.
* @param {boolean} options.noInterpolate If true trajectories are not interpolated but
* drawn at the last known coordinate. Use this for performance optimization
* during map navigation.
* @private
*/
const renderTrajectories = (canvas, trajectories, style, viewState, options) => {
if (!canvas) {
return { renderedTrajectories: [] };
}
const { center, pixelRatio = 1, resolution, rotation = 0, size = [], time = Date.now(), } = viewState;
if (!resolution || !center) {
return { renderedTrajectories: [] };
}
const { filter, getScreenPixel = (pixel, viewStat) => {
return (viewStat.zoom || 0) < 12
? pixel.map((coord) => {
return Math.floor(coord);
})
: pixel;
}, hoverVehicleId, noInterpolate = false, selectedVehicleId, } = options;
const context = canvas.getContext('2d');
context === null || context === void 0 ? void 0 : context.clearRect(0, 0, canvas.width, canvas.height);
const [width, height] = size;
if (width &&
height &&
(canvas.width !== width * pixelRatio ||
canvas.height !== height * pixelRatio)) {
[canvas.width, canvas.height] = [width * pixelRatio, height * pixelRatio];
}
const coordinateToPixelTransform = compose(create(), size[0] / 2, size[1] / 2, 1 / resolution, -1 / resolution, -rotation, -center[0], -center[1]);
// Offscreen canvas has not style attribute
if (canvas.style) {
canvas.style.width = `${canvas.width / pixelRatio}px`;
canvas.style.height = `${canvas.height / pixelRatio}px`;
}
let hoverVehicleImg;
let hoverVehiclePx;
let selectedVehicleImg;
let selectedVehiclePx;
const renderedTrajectories = [];
for (let i = trajectories.length - 1; i >= 0; i -= 1) {
const trajectory = trajectories[i];
// Filter out trajectories
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
if (filter && !filter(trajectory)) {
continue;
}
// We simplify the trajectory object
// @ts-expect-error improve types
const { timeOffset, train_id: id } = trajectory.properties;
// We set the rotation and the timeFraction of the trajectory (used by tralis).
// if rotation === null that seems there is no rotation available.
const { coord, rotation: rotationIcon } = getVehiclePosition(time - (timeOffset || 0), trajectory, noInterpolate);
// We store the current vehicle position to the trajectory.
trajectories[i].properties.coordinate = coord;
trajectories[i].properties.rotation = rotationIcon;
if (!coord) {
continue;
}
let px = apply(coordinateToPixelTransform, [...coord]);
if (!px) {
continue;
}
px = px.map((p) => {
return p * pixelRatio;
});
if (px[0] < 0 ||
px[0] > canvas.width ||
px[1] < 0 ||
px[1] > canvas.height) {
continue;
}
const vehicleImg = style(trajectory, viewState, options);
if (!vehicleImg) {
continue;
}
if (hoverVehicleId !== id && selectedVehicleId !== id) {
// To optimize the performance we use integer as pixel coordinate
// to avoid an additional work by the browser on zoom level < 12.
// See https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas?retiredLocale=de#avoid_floating-point_coordinates_and_use_integers_instead
const [x, y] = getScreenPixel([px[0] - vehicleImg.width / 2, px[1] - vehicleImg.height / 2], viewState);
context === null || context === void 0 ? void 0 : context.drawImage(vehicleImg, x, y);
}
if (hoverVehicleId && hoverVehicleId === id) {
// Store the canvas to draw it at the end
hoverVehicleImg = vehicleImg;
hoverVehiclePx = px;
}
if (selectedVehicleId && selectedVehicleId === id) {
// Store the canvas to draw it at the end
selectedVehicleImg = vehicleImg;
selectedVehiclePx = px;
}
renderedTrajectories.push(trajectory);
}
if (selectedVehicleImg && selectedVehiclePx) {
context === null || context === void 0 ? void 0 : context.drawImage(selectedVehicleImg, Math.floor(selectedVehiclePx[0] - selectedVehicleImg.width / 2), Math.floor(selectedVehiclePx[1] - selectedVehicleImg.height / 2));
}
if (hoverVehicleImg && hoverVehiclePx) {
context === null || context === void 0 ? void 0 : context.drawImage(hoverVehicleImg, Math.floor(hoverVehiclePx[0] - hoverVehicleImg.width / 2), Math.floor(hoverVehiclePx[1] - hoverVehicleImg.height / 2));
}
return {
// isReady: true,
renderedTrajectories,
};
};
export default renderTrajectories;