katja's git: oeffisearch

fast and simple tripplanner

commit 82b6a3d784c7de061dc353b207a9e48d27aee964
parent e6097aa9e6af51ce42a7393a710b303e3ea0b815
Author: Katja (ctucx) <git@ctu.cx>
Date: Sat, 19 Apr 2025 00:20:54 +0200

journeysCanvas: use lit's `ref` directive to bind to canvas
2 files changed, 83 insertions(+), 87 deletions(-)
M
src/journeysCanvas.js
|
168
+++++++++++++++++++++++++++++++++++++++----------------------------------------
M
src/journeysView.js
|
2
+-
diff --git a/src/journeysCanvas.js b/src/journeysCanvas.js
@@ -1,4 +1,5 @@
 import { html } from 'lit';
+import { ref, createRef } from 'lit/directives/ref.js';
 import { BaseView } from './baseView.js';
 
 import { CustomDate } from './helpers.js';

@@ -50,8 +51,7 @@ export class JourneysCanvas extends BaseView {
 	constructor () {
 		super();
 
-		this.canvasElement = null;
-		this.canvasContext = null;
+		this.canvasRef   = createRef();
 		this.canvasState = {
 			handlersConnected: false,
 			textCache: {},

@@ -79,7 +79,7 @@ export class JourneysCanvas extends BaseView {
 		this.canvasState.offsetX = (window.innerWidth / this.canvasState.dpr) > 600 ? 140 : 80;
 	};
 
-	getCanvas = () => html`<canvas @mousedown=${this.mouseDownHandler} @touchstart=${this.mouseDownHandler}></canvas>`;
+	getCanvas = () => html`<canvas @mousedown=${this.mouseDownHandler} @touchstart=${this.mouseDownHandler} ${ref(this.canvasRef)}></canvas>`;
 
 	connectCanvas = () => {
 		if (!this.canvasState.handlersConnected) {

@@ -91,16 +91,7 @@ export class JourneysCanvas extends BaseView {
 			window.addEventListener('zoom',      this.resizeHandler);
 			this.canvasState.handlersConnected = true;
 		}
-
-		if (this.canvasElement === null) {
-			const canvasElement = this.renderRoot.querySelector('canvas');
-
-			if (canvasElement !== null) {
-				this.canvasElement = canvasElement;
-				this.canvasContext = this.canvasElement.getContext('2d');
-				this.resizeHandler();
-			}
-		}
+		this.resizeHandler();
 	};
 
 	disconnectCanvas = () => {

@@ -111,12 +102,14 @@ export class JourneysCanvas extends BaseView {
 		window.removeEventListener('resize',    this.resizeHandler);
 		window.removeEventListener('zoom',      this.resizeHandler);
 		this.canvasState.handlersConnected = false;
-		this.canvasElement = null;
-		this.canvasContext = null;
 	};
 
 	resizeHandler = () => {
-		if (this.canvasContext === null) return true;
+		const canvasElement = this.canvasRef.value;
+
+		if (canvasElement === undefined) return true;
+
+		const canvasContext = canvasElement.getContext('2d');
 
 		this.canvasState.dpr = window.devicePixelRatio || 1;
 

@@ -125,14 +118,14 @@ export class JourneysCanvas extends BaseView {
 		this.canvasState.rectWidthWithPadding = this.canvasState.rectWidth + 2 * this.canvasState.padding;
 
 		const rect = this.renderRoot.querySelector('header').getBoundingClientRect();
-		this.canvasElement.width        = window.innerWidth * this.canvasState.dpr;
-		this.canvasElement.height       = (window.innerHeight - rect.height) * this.canvasState.dpr;
-		this.canvasElement.style.width  = `${window.innerWidth}px`;
-		this.canvasElement.style.height = `${window.innerHeight - rect.height - 4}px`;
+		canvasElement.width        = window.innerWidth * this.canvasState.dpr;
+		canvasElement.height       = (window.innerHeight - rect.height) * this.canvasState.dpr;
+		canvasElement.style.width  = `${window.innerWidth}px`;
+		canvasElement.style.height = `${window.innerHeight - rect.height - 4}px`;
 
-		this.canvasContext.restore();
-		this.canvasContext.save();
-		this.canvasContext.scale(this.canvasState.dpr, this.canvasState.dpr);
+		canvasContext.restore();
+		canvasContext.save();
+		canvasContext.scale(this.canvasState.dpr, this.canvasState.dpr);
 
 		this.canvasState.lastAnimationUpdate = 0;
 		this.renderCanvas();

@@ -253,35 +246,38 @@ export class JourneysCanvas extends BaseView {
 	};
 
 	renderCanvas = () => {
-		if (this.canvasContext === null) return;
+		const canvasElement = this.canvasRef.value;
+		if (canvasElement === undefined) return true;
+
+		const canvasContext = canvasElement.getContext('2d');
 
 		const drawButton = mode => {
 			const buttonPath = new Path2D('M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z');
 
-			this.canvasContext.fillStyle = '#fff';
-			this.canvasContext.shadowColor = '#00000080';
-			this.canvasContext.save();
-			this.canvasContext.scale(3, 3);
-			if (mode === 'earlier') this.canvasContext.translate(x / 3 - 15, this.canvasElement.height / this.canvasState.dpr / 6 - 24);
-			if (mode === 'later')   this.canvasContext.translate(x / 3 + 5, this.canvasElement.height / this.canvasState.dpr / 6);
-			if (mode === 'earlier') this.canvasContext.rotate(-Math.PI*1.5);
-			if (mode === 'later')   this.canvasContext.rotate(Math.PI*1.5);
-			this.canvasContext.fill(buttonPath);
-			this.canvasContext.restore();
-			this.canvasContext.beginPath();
-			if (mode === 'earlier') this.canvasContext.arc(x - 80, this.canvasElement.height / this.canvasState.dpr / 2 - 35,50,0,2*Math.PI);
-			if (mode === 'later') this.canvasContext.arc(x + 50, this.canvasElement.height / this.canvasState.dpr / 2 - 35,50,0,2*Math.PI);
-			this.canvasContext.fillStyle = '#ffffff40';
-			this.canvasContext.fill();
-			this.canvasContext.strokeStyle = '#00000020';
-			this.canvasContext.stroke();
+			canvasContext.fillStyle = '#fff';
+			canvasContext.shadowColor = '#00000080';
+			canvasContext.save();
+			canvasContext.scale(3, 3);
+			if (mode === 'earlier') canvasContext.translate(x / 3 - 15, canvasElement.height / this.canvasState.dpr / 6 - 24);
+			if (mode === 'later')   canvasContext.translate(x / 3 + 5, canvasElement.height / this.canvasState.dpr / 6);
+			if (mode === 'earlier') canvasContext.rotate(-Math.PI*1.5);
+			if (mode === 'later')   canvasContext.rotate(Math.PI*1.5);
+			canvasContext.fill(buttonPath);
+			canvasContext.restore();
+			canvasContext.beginPath();
+			if (mode === 'earlier') canvasContext.arc(x - 80, canvasElement.height / this.canvasState.dpr / 2 - 35,50,0,2*Math.PI);
+			if (mode === 'later') canvasContext.arc(x + 50, canvasElement.height / this.canvasState.dpr / 2 - 35,50,0,2*Math.PI);
+			canvasContext.fillStyle = '#ffffff40';
+			canvasContext.fill();
+			canvasContext.strokeStyle = '#00000020';
+			canvasContext.stroke();
 		}
 
-		this.canvasContext.clearRect(0, 0, this.canvasElement.width / this.canvasState.dpr, this.canvasElement.height / this.canvasState.dpr);
+		canvasContext.clearRect(0, 0, canvasElement.width / this.canvasState.dpr, canvasElement.height / this.canvasState.dpr);
 		let x = this.canvasState.offsetX - this.viewState.indexOffset * this.canvasState.rectWidthWithPadding, y;
 
 		const firstVisibleJourney = Math.max(0, Math.floor((-x + this.canvasState.padding) / this.canvasState.rectWidthWithPadding));
-		const numVisibleJourneys = Math.ceil(this.canvasElement.width / this.canvasState.dpr / this.canvasState.rectWidthWithPadding);
+		const numVisibleJourneys = Math.ceil(canvasElement.width / this.canvasState.dpr / this.canvasState.rectWidthWithPadding);
 		const visibleJourneys = this.viewState.journeys.slice(firstVisibleJourney, firstVisibleJourney + numVisibleJourneys);
 
 		if (!visibleJourneys.length) return;

@@ -291,7 +287,7 @@ export class JourneysCanvas extends BaseView {
 			visibleJourneys.map(journey => journey.legs[journey.legs.length-1].plannedArrival)
 				.concat(visibleJourneys.map(journey => journey.legs[journey.legs.length-1].arrival)
 				));
-		const targetScaleFactor = 1 / (targetLastArrival - targetFirstDeparture) * (this.canvasElement.height - 64 * this.canvasState.dpr) / this.canvasState.dpr;
+		const targetScaleFactor = 1 / (targetLastArrival - targetFirstDeparture) * (canvasElement.height - 64 * this.canvasState.dpr) / this.canvasState.dpr;
 
 		const now    = new Date();
 		const factor = Math.min(.3, (now - this.canvasState.lastAnimationUpdate) / 20);

@@ -322,18 +318,18 @@ export class JourneysCanvas extends BaseView {
 
 		let time = this.viewState.journeys[0].legs[0].plannedDeparture;
 
-		this.canvasContext.font = `${(window.innerWidth / this.canvasState.dpr) > 600 ? 20 : 15}px sans-serif`;
-		this.canvasContext.fillStyle = '#aaa';
+		canvasContext.font = `${(window.innerWidth / this.canvasState.dpr) > 600 ? 20 : 15}px sans-serif`;
+		canvasContext.fillStyle = '#aaa';
 		while (time < this.canvasState.lastArrival) {
 			const y = (time - this.canvasState.firstDeparture) * this.canvasState.scaleFactor + 32;
-			this.canvasContext.fillText(time.formatTime(), (window.innerWidth / this.canvasState.dpr) > 600 ? 30 : 10, y);
-			this.canvasContext.fillRect(0, y, this.canvasElement.width / this.canvasState.dpr, 1);
+			canvasContext.fillText(time.formatTime(), (window.innerWidth / this.canvasState.dpr) > 600 ? 30 : 10, y);
+			canvasContext.fillRect(0, y, canvasElement.width / this.canvasState.dpr, 1);
 			time = new CustomDate(Number(time) + 3600000);//Math.floor(120/scaleFactor));
 		}
 
-		this.canvasContext.fillStyle = '#fa5';
+		canvasContext.fillStyle = '#fa5';
 		y = (new Date() - this.canvasState.firstDeparture) * this.canvasState.scaleFactor + 32;
-		this.canvasContext.fillRect(0, y-2, this.canvasElement.width / this.canvasState.dpr, 5);
+		canvasContext.fillRect(0, y-2, canvasElement.width / this.canvasState.dpr, 5);
 
 		if (this.viewState.earlierRef) drawButton('earlier');
 

@@ -346,10 +342,10 @@ export class JourneysCanvas extends BaseView {
 
 					y = (leg.plannedDeparture - this.canvasState.firstDeparture) * this.canvasState.scaleFactor + 32;
 
-					this.canvasContext.fillStyle   = '#44444480';
-					this.canvasContext.strokeStyle = '#ffffff80';
-					this.canvasContext.fillRect(x - this.canvasState.padding, y, this.canvasState.rectWidth, duration);
-					this.canvasContext.strokeRect(x - this.canvasState.padding, y, this.canvasState.rectWidth, duration);
+					canvasContext.fillStyle   = '#44444480';
+					canvasContext.strokeStyle = '#ffffff80';
+					canvasContext.fillRect(x - this.canvasState.padding, y, this.canvasState.rectWidth, duration);
+					canvasContext.strokeRect(x - this.canvasState.padding, y, this.canvasState.rectWidth, duration);
 				}
 			});
 

@@ -370,47 +366,47 @@ export class JourneysCanvas extends BaseView {
 
 				y = ((leg.departure || leg.plannedDeparture) - this.canvasState.firstDeparture) * this.canvasState.scaleFactor + 32;
 
-				this.canvasContext.shadowColor = '#00000060';
-				if (!this.settingsState.disableCanvasBlur) this.canvasContext.shadowBlur = 5;
+				canvasContext.shadowColor = '#00000060';
+				if (!this.settingsState.disableCanvasBlur) canvasContext.shadowBlur = 5;
 
 				if (leg.walking || leg.transfer) {
-					this.canvasContext.fillStyle = '#777';
-					this.canvasContext.fillRect(x + this.canvasState.rectWidth / 2 - this.canvasState.rectWidth / 10, y, this.canvasState.rectWidth / 5, duration);
+					canvasContext.fillStyle = '#777';
+					canvasContext.fillRect(x + this.canvasState.rectWidth / 2 - this.canvasState.rectWidth / 10, y, this.canvasState.rectWidth / 5, duration);
 				} else {
-					this.canvasContext.fillStyle = this.getColor('fill', leg);
-					this.canvasContext.fillRect(x, y, this.canvasState.rectWidth, duration);
-					this.canvasContext.strokeStyle = this.getColor('text', leg);
-					this.canvasContext.strokeRect(x, y, this.canvasState.rectWidth, duration);
+					canvasContext.fillStyle = this.getColor('fill', leg);
+					canvasContext.fillRect(x, y, this.canvasState.rectWidth, duration);
+					canvasContext.strokeStyle = this.getColor('text', leg);
+					canvasContext.strokeRect(x, y, this.canvasState.rectWidth, duration);
 				}
-				if (!this.settingsState.disableCanvasBlur) this.canvasContext.shadowBlur = 0;
+				if (!this.settingsState.disableCanvasBlur) canvasContext.shadowBlur = 0;
 
 				let preRenderedText = this.getTextCache(formatLineDisplayName(leg.line), this.getColor('text', leg));
 				let offset = duration / 2;
 				if ((offset + preRenderedText.height / this.canvasState.dpr) < duration - 5) {
-					this.canvasContext.scale(1 / this.canvasState.dpr, 1 / this.canvasState.dpr);
-					this.canvasContext.drawImage(preRenderedText, this.canvasState.dpr * (x + 5), Math.floor(this.canvasState.dpr * (y + offset) - preRenderedText.height / 2.3));
-					this.canvasContext.scale(this.canvasState.dpr, this.canvasState.dpr);
+					canvasContext.scale(1 / this.canvasState.dpr, 1 / this.canvasState.dpr);
+					canvasContext.drawImage(preRenderedText, this.canvasState.dpr * (x + 5), Math.floor(this.canvasState.dpr * (y + offset) - preRenderedText.height / 2.3));
+					canvasContext.scale(this.canvasState.dpr, this.canvasState.dpr);
 					offset += preRenderedText.height / this.canvasState.dpr / 1.3 + 5;
 				}
 
 				this.getTrainTypeTexts(leg).forEach(typeText => {
 					const preRenderedTypeText = this.getTextCache(typeText, '#555');
 					if ((offset + preRenderedText.height / this.canvasState.dpr) < duration - 5) {
-						this.canvasContext.scale(1 / this.canvasState.dpr, 1 / this.canvasState.dpr);
-						this.canvasContext.drawImage(preRenderedTypeText, this.canvasState.dpr * (x + 5), Math.floor(this.canvasState.dpr * (y + offset) - preRenderedTypeText.height / 2.3));
-						this.canvasContext.scale(this.canvasState.dpr, this.canvasState.dpr);
+						canvasContext.scale(1 / this.canvasState.dpr, 1 / this.canvasState.dpr);
+						canvasContext.drawImage(preRenderedTypeText, this.canvasState.dpr * (x + 5), Math.floor(this.canvasState.dpr * (y + offset) - preRenderedTypeText.height / 2.3));
+						canvasContext.scale(this.canvasState.dpr, this.canvasState.dpr);
 						offset += preRenderedText.height / this.canvasState.dpr / 2;
 					}
 				});
 
 				if (leg.cancelled) {
-					this.canvasContext.beginPath();
-					this.canvasContext.moveTo(x, y);
-					this.canvasContext.lineTo(x + this.canvasState.rectWidth, y + duration);
-					this.canvasContext.strokeStyle = this.getColor('cancelFill', leg);
-					this.canvasContext.lineWidth = 5;
-					this.canvasContext.stroke();
-					this.canvasContext.lineWidth = 1;
+					canvasContext.beginPath();
+					canvasContext.moveTo(x, y);
+					canvasContext.lineTo(x + this.canvasState.rectWidth, y + duration);
+					canvasContext.strokeStyle = this.getColor('cancelFill', leg);
+					canvasContext.lineWidth = 5;
+					canvasContext.stroke();
+					canvasContext.lineWidth = 1;
 				}
 
 				/* draw journey start and end time */

@@ -420,22 +416,22 @@ export class JourneysCanvas extends BaseView {
 				if (journey.legs.indexOf(leg) == 0) times.push([leg.arrival || leg.plannedArrival, y + duration + 7.5]);
 				times.forEach(([time, y]) => {
 					preRenderedText = this.getTextCache(time.formatTime(), '#fff', 15);
-					this.canvasContext.scale(1 / this.canvasState.dpr, 1 / this.canvasState.dpr);
-					this.canvasContext.drawImage(preRenderedText, Math.ceil(this.canvasState.dpr * (x + ((this.canvasState.rectWidth - preRenderedText.width/this.canvasState.dpr)) / 2)), this.canvasState.dpr * (y - 7.5));
-					this.canvasContext.scale(this.canvasState.dpr, this.canvasState.dpr);
+					canvasContext.scale(1 / this.canvasState.dpr, 1 / this.canvasState.dpr);
+					canvasContext.drawImage(preRenderedText, Math.ceil(this.canvasState.dpr * (x + ((this.canvasState.rectWidth - preRenderedText.width/this.canvasState.dpr)) / 2)), this.canvasState.dpr * (y - 7.5));
+					canvasContext.scale(this.canvasState.dpr, this.canvasState.dpr);
 				});
 
 				if (leg.loadFactor && duration > 20) {
-					this.canvasContext.shadowColor = '#00000090';
-					if (!this.settingsState.disableCanvasBlur) this.canvasContext.shadowBlur = 2;
+					canvasContext.shadowColor = '#00000090';
+					if (!this.settingsState.disableCanvasBlur) canvasContext.shadowBlur = 2;
 					[ "#777", "#aaa", "#aaa" ];
 					for (let i = 0; i < 3; i++) {
-						this.canvasContext.beginPath();
-						this.canvasContext.fillStyle = this.getColor('loadFactor', leg.loadFactor, i);
-						this.canvasContext.arc(x + (i + 3) * this.canvasState.rectWidth / 8, y + duration - 9.5, 5, 0, 2 * Math.PI, false);
-						this.canvasContext.fill();
+						canvasContext.beginPath();
+						canvasContext.fillStyle = this.getColor('loadFactor', leg.loadFactor, i);
+						canvasContext.arc(x + (i + 3) * this.canvasState.rectWidth / 8, y + duration - 9.5, 5, 0, 2 * Math.PI, false);
+						canvasContext.fill();
 					}
-					if (!this.settingsState.disableCanvasBlur) this.canvasContext.shadowBlur = 0;
+					if (!this.settingsState.disableCanvasBlur) canvasContext.shadowBlur = 0;
 				}
 
 				x -= xOffset;
diff --git a/src/journeysView.js b/src/journeysView.js
@@ -77,7 +77,7 @@ export class JourneysView extends JourneysCanvas {
 		}
 
 		if (this.mode === 'canvas') {	
-			if (this.canvas === null) this.connectCanvas();
+			this.connectCanvas();
 			if (previous.has('viewState') && this.viewState !== null) {
 				this.renderCanvas();
 				await this.getCoachSequences();