feat: 优化描述区文字渲染逻辑,动态调整字体大小以适应区域并确保文本垂直居中
This commit is contained in:
parent
39044f3d65
commit
3e5aad1237
@ -1466,38 +1466,47 @@ function drawArea(ctx: CanvasRenderingContext2D, pen: MapPen): void {
|
||||
// 如果是描述区且有描述内容,渲染描述文字
|
||||
if (type === MapAreaType.描述区 && desc) {
|
||||
ctx.fillStyle = get(theme, 'color') ?? '';
|
||||
// 使用更大的字体显示描述文字
|
||||
const descFontSize = Math.min(w / 6, h / 1.5, 128); // 根据区域大小自适应字体大小,最大128px
|
||||
|
||||
// 动态计算字体大小,让文字填充区域
|
||||
let descFontSize = Math.min(w / 2, h / 2, 200);
|
||||
let lines: string[] = [];
|
||||
|
||||
while (descFontSize > 8) {
|
||||
ctx.font = `${descFontSize}px ${fontFamily}`;
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'top'; // 使用 top 基准,便于精确计算
|
||||
const maxCharsPerLine = Math.floor(w / (descFontSize * 0.8));
|
||||
|
||||
// 文字换行处理
|
||||
const words = desc.split('');
|
||||
const maxCharsPerLine = Math.floor(w / (descFontSize * 0.6)); // 估算每行能容纳的字符数
|
||||
const lines: string[] = [];
|
||||
|
||||
for (let i = 0; i < words.length; i += maxCharsPerLine) {
|
||||
lines.push(words.slice(i, i + maxCharsPerLine).join(''));
|
||||
if (maxCharsPerLine < 1) {
|
||||
descFontSize = Math.floor(descFontSize * 0.9);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 使用 measureText 精确计算字体高度
|
||||
const testText = '测试文字'; // 用于测量字体高度的测试文字
|
||||
const textMetrics = ctx.measureText(testText);
|
||||
const actualFontHeight = textMetrics.actualBoundingBoxAscent + textMetrics.actualBoundingBoxDescent;
|
||||
const lineSpacing = actualFontHeight * 0.2; // 行间距为字体高度的20%
|
||||
const descLineHeight = actualFontHeight + lineSpacing;
|
||||
// 文字换行
|
||||
lines = [];
|
||||
for (let i = 0; i < desc.length; i += maxCharsPerLine) {
|
||||
lines.push(desc.slice(i, i + maxCharsPerLine));
|
||||
}
|
||||
|
||||
// 计算整个文本块的总高度
|
||||
const totalHeight = lines.length * descLineHeight - lineSpacing; // 减去最后一行不需要的行间距
|
||||
// 计算文本高度
|
||||
const textMetrics = ctx.measureText('测试文字');
|
||||
const lineHeight = textMetrics.actualBoundingBoxAscent + textMetrics.actualBoundingBoxDescent;
|
||||
const totalHeight = lines.length * lineHeight * 1.1;
|
||||
|
||||
// 计算文本块的起始Y坐标,确保整个文本块在区域中垂直居中
|
||||
if (totalHeight <= h * 0.9) break;
|
||||
descFontSize = Math.floor(descFontSize * 0.9);
|
||||
}
|
||||
|
||||
// 渲染文字
|
||||
ctx.font = `${descFontSize}px ${fontFamily}`;
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'top';
|
||||
|
||||
const textMetrics = ctx.measureText('测试文字');
|
||||
const lineHeight = textMetrics.actualBoundingBoxAscent + textMetrics.actualBoundingBoxDescent;
|
||||
const totalHeight = lines.length * lineHeight * 1.1;
|
||||
const startY = y + h / 2 - totalHeight / 2;
|
||||
|
||||
lines.forEach((line, index) => {
|
||||
const lineY = startY + index * descLineHeight;
|
||||
// 水平居中:x + w / 2,垂直居中:lineY
|
||||
ctx.fillText(line, x + w / 2, lineY);
|
||||
ctx.fillText(line, x + w / 2, startY + index * lineHeight * 1.1);
|
||||
});
|
||||
} else if (type !== MapAreaType.描述区 && label) {
|
||||
// 非描述区才显示标签
|
||||
|
Loading…
x
Reference in New Issue
Block a user