commit ecfa26d8a354088513c43e5c424a423a51977090
parent a4f52eb0f3af347612a2dda414bfd3dcc065fc38
Author: Yureka <yuka@yuka.dev>
Date: Mon, 26 Dec 2022 17:30:20 +0100
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(-)
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" ];