mirror of
https://github.com/imgfloat/server.git
synced 2026-02-05 03:39:26 +00:00
127 lines
3.6 KiB
JavaScript
127 lines
3.6 KiB
JavaScript
const MAX_LINES = 8;
|
|
const PADDING = 16;
|
|
const LINE_HEIGHT = 22;
|
|
const FONT = "16px 'Helvetica Neue', Arial, sans-serif";
|
|
|
|
function wrapLine(ctx, text, maxWidth) {
|
|
if (!text) {
|
|
return [""];
|
|
}
|
|
const words = text.split(" ");
|
|
const lines = [];
|
|
let current = "";
|
|
words.forEach((word) => {
|
|
const test = current ? `${current} ${word}` : word;
|
|
if (ctx.measureText(test).width > maxWidth && current) {
|
|
lines.push(current);
|
|
current = word;
|
|
} else {
|
|
current = test;
|
|
}
|
|
});
|
|
if (current) {
|
|
lines.push(current);
|
|
}
|
|
return lines;
|
|
}
|
|
|
|
function formatLines(messages, ctx, width) {
|
|
const maxWidth = Math.max(width - PADDING * 2, 0);
|
|
const lines = [];
|
|
messages.forEach((message) => {
|
|
const prefixText = message.displayName ? `${message.displayName}: ` : "";
|
|
const bodyText = message.message || "";
|
|
const nameColor = message.tags?.color || "#ffffff";
|
|
if (!prefixText) {
|
|
wrapLine(ctx, bodyText, maxWidth).forEach((line) =>
|
|
lines.push({
|
|
prefixText: "",
|
|
prefixWidth: 0,
|
|
nameColor,
|
|
text: line,
|
|
}),
|
|
);
|
|
return;
|
|
}
|
|
|
|
const prefixWidth = ctx.measureText(prefixText).width;
|
|
const words = bodyText.split(" ");
|
|
let current = "";
|
|
let isFirstLine = true;
|
|
let availableWidth = Math.max(maxWidth - prefixWidth, 0);
|
|
|
|
const flushLine = () => {
|
|
lines.push({
|
|
prefixText: isFirstLine ? prefixText : "",
|
|
prefixWidth: isFirstLine ? prefixWidth : 0,
|
|
nameColor,
|
|
text: current,
|
|
});
|
|
current = "";
|
|
isFirstLine = false;
|
|
availableWidth = maxWidth;
|
|
};
|
|
|
|
if (!words.length || !bodyText.trim()) {
|
|
lines.push({
|
|
prefixText,
|
|
prefixWidth,
|
|
nameColor,
|
|
text: "",
|
|
});
|
|
return;
|
|
}
|
|
|
|
words.forEach((word) => {
|
|
const test = current ? `${current} ${word}` : word;
|
|
if (ctx.measureText(test).width > availableWidth && current) {
|
|
flushLine();
|
|
current = word;
|
|
} else {
|
|
current = test;
|
|
}
|
|
});
|
|
|
|
if (current) {
|
|
flushLine();
|
|
}
|
|
});
|
|
return lines.slice(-MAX_LINES);
|
|
}
|
|
|
|
function tick(context) {
|
|
const { ctx, width, height, chatMessages } = context;
|
|
if (!ctx) {
|
|
return;
|
|
}
|
|
ctx.clearRect(0, 0, width, height);
|
|
ctx.font = FONT;
|
|
ctx.textBaseline = "top";
|
|
|
|
const messages = Array.isArray(chatMessages) ? chatMessages : [];
|
|
if (messages.length === 0) {
|
|
return;
|
|
}
|
|
|
|
const lines = formatLines(messages, ctx, width);
|
|
const boxHeight = lines.length * LINE_HEIGHT + PADDING * 2;
|
|
const boxWidth = Math.max(
|
|
...lines.map((line) => line.prefixWidth + ctx.measureText(line.text).width),
|
|
120,
|
|
);
|
|
|
|
ctx.fillStyle = "rgba(0, 0, 0, 0.55)";
|
|
ctx.fillRect(PADDING, height - boxHeight - PADDING, boxWidth + PADDING * 2, boxHeight);
|
|
|
|
lines.forEach((line, index) => {
|
|
const x = PADDING * 2;
|
|
const y = height - boxHeight - PADDING + PADDING + index * LINE_HEIGHT;
|
|
if (line.prefixText) {
|
|
ctx.fillStyle = line.nameColor || "#ffffff";
|
|
ctx.fillText(line.prefixText, x, y);
|
|
}
|
|
ctx.fillStyle = "#ffffff";
|
|
ctx.fillText(line.text, x + line.prefixWidth, y);
|
|
});
|
|
}
|