Improve front rendering performance

This commit is contained in:
Mattéo Delabre 2021-05-23 16:35:40 +02:00
parent 05d7faa725
commit 7465314a12
Signed by: matteo
GPG Key ID: AE3FBD02DC583ABB
3 changed files with 73 additions and 50 deletions

View File

@ -18,6 +18,26 @@ export const makeCourseColor = mainColor => {
return color(mainColor).lighten(0.2).hex();
};
/**
* Make an OpenLayers style function cache its results.
* @param {Function} createStyle Create a style based on the cache key value.
* @param {Function} [cacheKey] Return the cache key for each feature
* (default: identity function).
* @return {Function} Style function that caches the generated styles.
*/
export const cacheStyle = (createStyle, cacheKey = x => x) => {
const cache = {};
return (feature) => {
const key = cacheKey(feature);
if (!(key in cache)) {
cache[key] = createStyle(key);
}
return cache[key];
};
};
export const sizes = {
segmentOuter: 8,
segmentInner: 6,

View File

@ -3,17 +3,16 @@ 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, makeBorderColor, makeCourseColor } from "./common";
import { sizes, cacheStyle, makeBorderColor, makeCourseColor } from "./common";
import network from "../../tam/network.json";
const courseStyles = {};
const getCourseStyle = lineColor => {
if (!(lineColor in courseStyles)) {
const courseStyle = cacheStyle(
lineColor => {
const icon = window.document.createElement("canvas");
const shapeSize = sizes.courseSize;
@ -47,16 +46,14 @@ const getCourseStyle = lineColor => {
iconCtx.fill();
}
courseStyles[lineColor] = new Style({
return new Style({
image: new Icon({
img: icon,
imgSize: [icon.width, icon.height]
})
});
}
return courseStyles[lineColor];
};
},
);
export const create = (target, coursesSimulation, onClick) => {
const view = new View({
@ -96,11 +93,17 @@ export const create = (target, coursesSimulation, onClick) => {
/* 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 = getCourseStyle(color);
const style = courseStyle(color);
style.getImage().setRotation(
view.getRotation() +

View File

@ -1,8 +1,8 @@
import network from "../../tam/network.json";
import { makeBorderColor, sizes } from "./common";
import { cacheStyle, makeBorderColor, sizes } from "./common";
import GeoJSON from "ol/format/GeoJSON";
import VectorLayer from "ol/layer/Vector";
import VectorImageLayer from "ol/layer/VectorImage";
import VectorSource from "ol/source/Vector";
import { Style, Fill, Stroke, Circle } from "ol/style";
@ -10,34 +10,41 @@ import { Style, Fill, Stroke, Circle } from "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
})
});
const segmentBorderStyle = cacheStyle(
color => new Style({
stroke: new Stroke({
color: makeBorderColor(color),
width: sizes.segmentOuter
})
}),
feature => feature.get("colors")[0],
);
// 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
})
});
const segmentInnerStyle = cacheStyle(
color => new Style({
stroke: new Stroke({
color,
width: sizes.segmentInner
})
}),
feature => feature.get("colors")[0],
);
// 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
})
});
const stopStyle = cacheStyle(
color => new Style({
image: new Circle({
fill: new Fill({ color }),
stroke: new Stroke({
color: makeBorderColor(color),
width: sizes.stopBorder
}),
radius: sizes.stopRadius
})
}),
feature => feature.get("colors")[0],
);
/**
* Order for features related to a network line inside the same layer.
@ -75,7 +82,6 @@ export const getLayers = () => {
// 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"
@ -96,34 +102,28 @@ export const getLayers = () => {
stopsSource.addFeatures(readFeatures(network.stops));
// Background layer on which the darker borders of line segments are drawn
const segmentsBorderLayer = new VectorLayer({
const segmentsBorderLayer = new VectorImageLayer({
source: segmentsSource,
renderOrder: lineFeaturesOrder,
style: segmentBorderStyle,
updateWhileInteracting: true,
updateWhileAnimating: true
imageRatio: 2,
});
// 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({
const segmentsInnerLayer = new VectorImageLayer({
source: segmentsSource,
renderOrder: lineFeaturesOrder,
style: segmentInnerStyle,
updateWhileInteracting: true,
updateWhileAnimating: true
imageRatio: 2,
});
const stopsLayer = new VectorLayer({
const stopsLayer = new VectorImageLayer({
source: stopsSource,
renderOrder: lineFeaturesOrder,
style: stopStyle,
imageRatio: 2,
minZoom: 13,
updateWhileInteracting: true,
updateWhileAnimating: true
});
return [segmentsBorderLayer, segmentsInnerLayer, stopsLayer];