ctucx.git: trainsearch

web based trip-planner, fork of https://cyberchaos.dev/yuka/trainsearch

commit ecfa26d8a354088513c43e5c424a423a51977090
parent a4f52eb0f3af347612a2dda414bfd3dcc065fc38
Author: Yureka <yuka@yuka.dev>
Date: Mon, 26 Dec 2022 17:30:20 +0100

improved canvas texts
1 file changed, 49 insertions(+), 46 deletions(-)
M
src/canvas.js
|
95
+++++++++++++++++++++++++++++++++++++++++--------------------------------------
diff --git a/src/canvas.js b/src/canvas.js
@@ -60,25 +60,36 @@ const canvasState = {
 	offsetX: 0,
 };
 
-const textCache = {};
+let textCache = {};
 let textCacheWidth;
 let textCacheDpr;
 
-const typeTextFor = leg => {
+const typeTextsFor = leg => {
 	const fahrtNr = leg.line?.fahrtNr;
-	if (!fahrtNr) return;
+	if (!fahrtNr) return [];
 	const key = coachSequenceCacheKey(fahrtNr, leg.plannedDeparture);
-	if (!key) return;
+	if (!key) return [];
 	const info = coachSequenceCache[key];
 	if (!info || info instanceof Promise) {
-		return;
+		return [];
 	}
-	let text = info.sequence?.groups[0]?.baureihe?.name;
-	if (!text) return;
-	while (text.length < 12) {
-		text = ' ' + text + ' ';
+	const counts = {};
+	for (let group of info.sequence?.groups) {
+		const name = group.baureihe?.name;
+		if (!name) continue;
+		counts[name] = (counts[name] ? counts[name] : 0) + 1;
 	}
-	return text;
+	return Object.entries(counts).map(([name, count]) => {
+		let text = "";
+		if (count > 1) {
+			text += `${count} x `;
+		}
+		text += name;
+		while (text.length < 12) {
+			text = ' ' + text + ' ';
+		}
+		return text;
+	});
 };
 
 export const setupCanvas = (data, isUpdate) => {

@@ -112,7 +123,6 @@ export const setupCanvas = (data, isUpdate) => {
 	window.addEventListener('touchmove', mouseMoveHandler);
 	window.addEventListener('resize', resizeHandler);
 	window.addEventListener('zoom', resizeHandler);
-	if (data) updateTextCache();
 	resizeHandler();
 
 	return {

@@ -129,10 +139,15 @@ export const setupCanvas = (data, isUpdate) => {
 	};
 };
 
-const addTextToCache = (text, color, fixedHeight) => {
-	if (textCache[text] && textCache[text].width > 0 && textCache[text].height > 0) {
-		return;
+const getTextCache = (text, color, fixedHeight) => {
+	const index = `${text}|${color}|${fixedHeight}`;
+	if (!textCache[index]) {
+		textCache[index] = makeTextCache(text, color, fixedHeight);
 	}
+	return textCache[index];
+};
+
+const makeTextCache = (text, color, fixedHeight) => {
 	const canvas = document.createElement('canvas');
 	const ctx = canvas.getContext('2d');
 	ctx.shadowColor = '#00000080';

@@ -156,28 +171,15 @@ const addTextToCache = (text, color, fixedHeight) => {
 	ctx.font = `${height}px sans-serif`;
 	ctx.fillStyle = color;
 	ctx.fillText(text, 0, height);
-	textCache[text] = canvas;
+
+	return canvas;
 };
 
 const updateTextCache = () => {
-	textCache.length = 0;
+	console.log('update text cache');
+	textCache = {};
 	textCacheWidth = rectWidth;
 	textCacheDpr = dpr;
-	for (const journey of canvasState.journeys) {
-		for (const leg of journey.legs) {
-			addTextToCache(textFor(leg), colorFor(leg, 'text'));
-			const typeText = typeTextFor(leg);
-			if (typeText) addTextToCache(typeText, '#555');
-
-			const times = [];
-
-			if (journey.legs.indexOf(leg) == journey.legs.length - 1) times.push(leg.arrival || leg.plannedArrival);
-			if (journey.legs.indexOf(leg) == 0) times.push(leg.departure || leg.plannedDeparture);
-			for (const time of times) {
-				addTextToCache(formatTime(time), '#fff', 15);
-			}
-		}
-	}
 };
 
 let lastAnimationUpdate = 0, firstDeparture = 0, scaleFactor = 0, lastArrival = 0;

@@ -300,19 +302,22 @@ const renderJourneys = () => {
 			}
 			//ctx.shadowBlur = 0;
 
-			let preRenderedText = textCache[textFor(leg)];
-			if (preRenderedText && (preRenderedText.height / dpr) < duration - 5) {
+			let preRenderedText = getTextCache(textFor(leg), colorFor(leg, 'text'));
+			let offset = duration / 2;
+			if ((offset + preRenderedText.height / dpr) < duration - 5) {
 				ctx.scale(1 / dpr, 1 / dpr);
-				ctx.drawImage(preRenderedText, dpr * (x + 5), Math.floor(dpr * (y + duration / 2) - preRenderedText.height / 2.3));
+				ctx.drawImage(preRenderedText, dpr * (x + 5), Math.floor(dpr * (y + offset) - preRenderedText.height / dpr / 1.3));
 				ctx.scale(dpr, dpr);
+				offset += preRenderedText.height / dpr / 1.3;
 			}
-			const typeText = typeTextFor(leg);
-			if (typeText) {
-				const preRenderedTypeText = textCache[typeText];
-				if (preRenderedTypeText && (preRenderedTypeText.height / dpr + preRenderedText.height / dpr) < duration - 5) {
+			const typeTexts = typeTextsFor(leg);
+			for (const typeText of typeTexts) {
+				const preRenderedTypeText = getTextCache(typeText, '#555');
+				if ((offset + preRenderedText.height / dpr) < duration - 5) {
 					ctx.scale(1 / dpr, 1 / dpr);
-					ctx.drawImage(preRenderedTypeText, dpr * (x + 5), Math.floor(dpr * (y + duration / 2 + preRenderedText.height / 2 + 10) - preRenderedTypeText.height / 2.3));
+					ctx.drawImage(preRenderedTypeText, dpr * (x + 5), Math.floor(dpr * (y + offset) - preRenderedTypeText.height / dpr / 1.3));
 					ctx.scale(dpr, dpr);
+					offset += preRenderedText.height / dpr / 1.3;
 				}
 			}
 

@@ -333,15 +338,13 @@ const renderJourneys = () => {
 			if (journey.legs.indexOf(leg) == journey.legs.length - 1) times.push([leg.departure || leg.plannedDeparture, y - 9.5]);
 			if (journey.legs.indexOf(leg) == 0) times.push([leg.arrival || leg.plannedArrival, y + duration + 7.5]);
 			for (const [time, y] of times) {
-				preRenderedText = textCache[formatTime(time)];
-				if (preRenderedText) {
-					ctx.scale(1 / dpr, 1 / dpr);
-					ctx.drawImage(preRenderedText, Math.ceil(dpr * (x + ((rectWidth - preRenderedText.width/dpr)) / 2)), dpr * (y - 7.5));
-					ctx.scale(dpr, dpr);
-				}
+				preRenderedText = getTextCache(formatTime(time), '#fff', 15);
+				ctx.scale(1 / dpr, 1 / dpr);
+				ctx.drawImage(preRenderedText, Math.ceil(dpr * (x + ((rectWidth - preRenderedText.width/dpr)) / 2)), dpr * (y - 7.5));
+				ctx.scale(dpr, dpr);
 			}
 
-			if (leg.loadFactor) {
+			if (leg.loadFactor && offset < duration - 10) {
 				ctx.shadowColor = '#00000090';
 				//ctx.shadowBlur = 2;
 				[ "#777", "#aaa", "#aaa" ];