Как подогнать размер шрифта чтобы текст располагался по всей длине пути
Вопрос инициирован комментарием @Leonid'a под ответом на вопрос Получить svg с изогнутым текстом в виде арки
чтобы размер шрифта подгонялся под длину пути так, чтобы текст располагался по всей длине этого пути.
.container {
width:50vw;
height:50vh;
}
#txt {
fill:#005E46;
font-size:52px;
font-face:sans-serif;
font-weight:bold;
}
<div class="container">
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 10 656 544" >
<path id="top" fill="none" stroke="red" d="m 86.959108,536.92194 c 0,0 -10.133315,-158.67922 2.022305,-236.60967 4.731862,-30.33627 12.118517,-61.28378 27.301117,-87.97026 15.93166,-28.00312 39.52587,-51.70293 64.71375,-71.79182 23.23934,-18.53481 49.18226,-35.65231 77.85874,-43.479558 41.30634,-11.274567 86.74257,-12.863251 128.41636,-3.033457 31.55069,7.442015 59.98355,26.093615 85.94795,45.501855 16.60888,12.41505 30.85349,28.04167 43.47955,44.49071 14.07865,18.34144 27.2555,38.01449 35.39034,59.65799 8.44276,22.46274 10.89155,46.88973 13.14498,70.78067 7.08982,75.16651 1.01115,226.49814 1.01115,226.49814" />
<text id="txt" dy="-10" >
<textPath xlink:href="#top" lengthAdjust="spacingAndGlyphs" textLength="1175" startOffset="0%" >
Весь очень длинный текст целиком вокруг арки
</textPath>
</text>
</svg>
</div>
Ответы (2 шт):
Решить эту задачу помогут атрибуты text: textLength и lengthAdjust
Если установить textLength равным длине path вдоль которого расположено слово или фраза из нескольких слов, то текст займет всю длину path, при любом размере шрифта.
В примере ниже длина path арки равна 1175px устанавливаем textLength="1175" и текст полностью займет всю арку при любом размере шрифта
font-size:52px;
.container {
width:50vw;
height:50vh;
}
#txt {
fill:#005E46;
font-size:52px;
font-face:sans-serif;
font-weight:bold;
}
<div class="container">
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 10 656 544" >
<path id="top" fill="none" stroke="red" d="M87 537s-10.2-158.8 2-236.7c4.7-30.3 12.1-61.3 27.3-88a258 258 0 0 1 64.7-71.7c23.2-18.6 49.2-35.7 77.9-43.5a264.5 264.5 0 0 1 128.4-3c31.5 7.4 60 26 86 45.4 16.5 12.5 30.8 28 43.4 44.5 14 18.4 27.3 38 35.4 59.7 8.4 22.5 10.9 46.9 13.1 70.8 7.1 75.1 1 226.5 1 226.5" />
<text id="txt" dy="-10" >
<textPath xlink:href="#top" lengthAdjust="spacingAndGlyphs" textLength="1175" startOffset="0%" >
Весь очень длинный текст целиком вокруг арки
</textPath>
</text>
</svg>
</div>
<script>
const length = document.getElementById('top').getTotalLength();
console.log(`Длина линии:` + length);
</script>
В следующем примере уменьшим вдвое длину textLength="1175 / 2 = 587.5"
Фраза займет ровно половину длины арки
.container {
width:50vw;
height:50vh;
}
#txt {
fill:#005E46;
font-size:52px;
font-face:sans-serif;
font-weight:bold;
}
<div class="container">
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 10 656 544" >
<path id="top" fill="none" stroke="red" d="M87 537s-10.2-158.8 2-236.7c4.7-30.3 12.1-61.3 27.3-88a258 258 0 0 1 64.7-71.7c23.2-18.6 49.2-35.7 77.9-43.5a264.5 264.5 0 0 1 128.4-3c31.5 7.4 60 26 86 45.4 16.5 12.5 30.8 28 43.4 44.5 14 18.4 27.3 38 35.4 59.7 8.4 22.5 10.9 46.9 13.1 70.8 7.1 75.1 1 226.5 1 226.5" />
<text id="txt" dy="-10" >
<textPath xlink:href="#top" lengthAdjust="spacingAndGlyphs" textLength="587.5" startOffset="0%" >
Весь очень длинный текст наполовину арки
</textPath>
</text>
</svg>
</div>
Удваиваем количество слов, чтобы уместиться на этой же длине textLength="1175" каждый символ сжимается.
.container {
width:50vw;
height:50vh;
}
#txt {
fill:#005E46;
font-size:52px;
font-face:sans-serif;
font-weight:bold;
}
<div class="container">
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 10 656 544" >
<path id="top" fill="none" stroke="red" d="M87 537s-10.2-158.8 2-236.7c4.7-30.3 12.1-61.3 27.3-88a258 258 0 0 1 64.7-71.7c23.2-18.6 49.2-35.7 77.9-43.5a264.5 264.5 0 0 1 128.4-3c31.5 7.4 60 26 86 45.4 16.5 12.5 30.8 28 43.4 44.5 14 18.4 27.3 38 35.4 59.7 8.4 22.5 10.9 46.9 13.1 70.8 7.1 75.1 1 226.5 1 226.5" />
<text id="txt" dy="-10" >
<textPath xlink:href="#top" lengthAdjust="spacingAndGlyphs" textLength="1175" startOffset="0%" >
Весь очень длинный текст целиком вокруг арки *** Весь очень длинный текст целиком вокруг арки
</textPath>
</text>
</svg>
</div>
Тот же пример с длинной, удвоенной фразой, но размер шрифта увеличим с 52 до 72px. Фраза будет занимать тоже место по длине, но символы ещё больше сожмутся и вырастут по высоте.
.container {
width:50vw;
height:50vh;
}
#txt {
fill:#005E46;
font-size:72px;
font-face:sans-serif;
font-weight:bold;
}
<div class="container">
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 10 656 544" >
<path id="top" fill="none" stroke="red" d="M87 537s-10.2-158.8 2-236.7c4.7-30.3 12.1-61.3 27.3-88a258 258 0 0 1 64.7-71.7c23.2-18.6 49.2-35.7 77.9-43.5a264.5 264.5 0 0 1 128.4-3c31.5 7.4 60 26 86 45.4 16.5 12.5 30.8 28 43.4 44.5 14 18.4 27.3 38 35.4 59.7 8.4 22.5 10.9 46.9 13.1 70.8 7.1 75.1 1 226.5 1 226.5" />
<text id="txt" dy="-10" >
<textPath xlink:href="#top" lengthAdjust="spacingAndGlyphs" textLength="1175" startOffset="0%" >
Весь очень длинный текст целиком вокруг арки *** Весь очень длинный текст целиком вокруг арки
</textPath>
</text>
</svg>
</div>
Вывод
Размер глифов шрифта под определенную длину с целью её полного заполнения, вычисляется самим препроцессором SVG.
Это может быть реализовано двумя способами:
- При большой длине
textLengthиlengthAdjust="spacingAndGlyphs"и малом количестве символов они будут сильно растянуты, чтобы заполнить всю длину
.container {
width:50vw;
height:50vh;
}
#txt {
fill:#005E46;
font-size:24px;
font-face:sans-serif;
font-weight:bold;
}
<div class="container">
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 10 656 544" >
<path id="top" fill="none" stroke="red" d="M87 537s-10.2-158.8 2-236.7c4.7-30.3 12.1-61.3 27.3-88a258 258 0 0 1 64.7-71.7c23.2-18.6 49.2-35.7 77.9-43.5a264.5 264.5 0 0 1 128.4-3c31.5 7.4 60 26 86 45.4 16.5 12.5 30.8 28 43.4 44.5 14 18.4 27.3 38 35.4 59.7 8.4 22.5 10.9 46.9 13.1 70.8 7.1 75.1 1 226.5 1 226.5" />
<text id="txt" dy="-10" >
<textPath xlink:href="#top" lengthAdjust="spacingAndGlyphs" textLength="1175" startOffset="0%" >
ВОКРУГ АРКИ
</textPath>
</text>
</svg>
</div>
- При большой длине
textLengthи lengthAdjust="spacing" (значение по умолчанию) и малом количестве символов расстояние между символами будет значительно увеличено
.container {
width:50vw;
height:50vh;
}
#txt {
fill:#005E46;
font-size:24px;
font-face:sans-serif;
font-weight:bold;
}
<div class="container">
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 10 656 544" >
<path id="top" fill="none" stroke="red" d="M87 537s-10.2-158.8 2-236.7c4.7-30.3 12.1-61.3 27.3-88a258 258 0 0 1 64.7-71.7c23.2-18.6 49.2-35.7 77.9-43.5a264.5 264.5 0 0 1 128.4-3c31.5 7.4 60 26 86 45.4 16.5 12.5 30.8 28 43.4 44.5 14 18.4 27.3 38 35.4 59.7 8.4 22.5 10.9 46.9 13.1 70.8 7.1 75.1 1 226.5 1 226.5" />
<text id="txt" dy="-10" >
<textPath xlink:href="#top" textLength="1175" lengthAdjust="spacing" startOffset="0%" >
ВОКРУГ АРКИ
</textPath>
</text>
</svg>
</div>
const svg = document.querySelector('svg');
const path = document.querySelector('path');
const txt = document.getElementById('txt');
txt.addEventListener('input', drawText);
drawText();
function drawText(){
let text = txt.value; // Значение инпута - наш текст
let real_width = svg.getBoundingClientRect().width; // Ширина SVG реальная
let view_width = +svg.getAttribute('viewBox').split(' ')[2]; // Ширина по viewBox
let k = real_width/view_width; // Коэффициент для корректировки размеров
let path_len = path.getTotalLength()*k; // Реальная длина пути
let svg_hidden = document.createElement('svg'); // Создаем другой SVG для вставки текста размером шрифта 1px для нахождения длины текста
let text_hidden = document.createElement('text');
text_hidden.style.fontSize = '1px';
text_hidden.style.fontFamily = 'sans-serif';
text_hidden.style.opacity = '0';
text_hidden.textContent = text;
svg_hidden.append(text_hidden);
document.body.append(svg_hidden);
// устанавливаем тексту из основного SVG размер, исходя из соотношения длины пути и размера текста при 1px, округляем в меньшую сторону
svg.querySelector('text').style.fontSize = Math.floor(path_len/text_hidden.offsetWidth)/k + 'px';
let text_path = svg.querySelector('textPath');
text_path.textContent = text;
text_path.setAttribute('textLength', path_len/k);
document.body.removeChild(svg_hidden); // Удаляем вспомогательный SVG
}
<svg viewBox="0 0 600 400" height="calc(100vh - 45px)">
<path id="textpath" d="M 50 390 L 50 290 A 250 250 180 1 1 550 290 L 550 390" fill="none" stroke="blue"></path>
<text style="font-family:sans-serif">
<textPath xlink:href="#textpath" lengthAdjust="spacing">
</textPath>
</text>
</svg>
<input type="text" id="txt" style="width:100%" value="Как подобрать размер шрифта">