Move courses rendering to separate file

This commit is contained in:
Mattéo Delabre 2021-05-24 22:59:56 +02:00
parent 20f04408fc
commit aeef4b5ae9
Signed by: matteo
GPG Key ID: AE3FBD02DC583ABB
2 changed files with 148 additions and 141 deletions

139
src/front/map/courses.js Normal file
View File

@ -0,0 +1,139 @@
import { getVectorContext } from "ol/render";
import Point from "ol/geom/Point";
import { fromExtent } from 'ol/geom/Polygon';
import { Style, Icon } from "ol/style";
import { sizes, cacheStyle, makeBorderColor, makeCourseColor } from "./common";
import network from "../../tam/network.json";
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);
});
};

View File

@ -1,59 +1,10 @@
import "ol/ol.css";
import { Map, View } from "ol";
import { getVectorContext } from "ol/render";
import Point from "ol/geom/Point";
import { fromExtent } from 'ol/geom/Polygon';
import * as proj from "ol/proj";
import { Style, Icon } from "ol/style";
import * as tilesLayers from "./tiles";
import * as networkLayers from "./network";
import { sizes, cacheStyle, makeBorderColor, makeCourseColor } from "./common";
import network from "../../tam/network.json";
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]
})
});
},
);
import { getLayers as getTilesLayers } from "./tiles";
import { getLayers as getNetworkLayers } from "./network";
import { setupCoursesAnimation } from "./courses";
export const create = (target, coursesSimulation, onClick) => {
const view = new View({
@ -63,101 +14,18 @@ export const create = (target, coursesSimulation, onClick) => {
constrainResolution: true
});
const tilesLayers = getTilesLayers();
const networkLayers = getNetworkLayers();
const stopsLayer = networkLayers[2];
const map = new Map({
target,
layers: [
...tilesLayers.getLayers(),
...networkLayers.getLayers()
],
layers: [...tilesLayers, ...networkLayers],
view
});
const stopsLayer = map.getLayers().item(3);
// 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();
});
setupCoursesAnimation(map, coursesSimulation, stopsLayer, onClick);
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);
});
return map;
};