Недавний проект включает веб-рисование с использованием операций d3.svg
выполнить. На рисунках часто используется текст, аsvg
внутреннийtext
Элементы не обрабатывают перенос текста так же, как обычные элементы DOM, поэтому требуются некоторые приемы.
Обычно есть два подхода.
- использовать
tspan
Пучокtext
разделить на несколько строк, пересчитать каждуюtspan
изy
координировать.
<svg xmlns="http://www.w3.org/2000/svg">
<text font-size="14">
<tspan x="0" y="10">较长文文本一行</tspan>
<tspan x="0" y="28">放不下就换行</tspan>
</text>
</svg>
- использовать
foreignObject
Оборачивает элементы DOM и использует возможности макета текста DOM для автоматической обработки разрывов строк.
<svg xmlns="http://www.w3.org/2000/svg">
<foreignObject width="120" height="50">
<body xmlns="http://www.w3.org/1999/xhtml">
<p style="font-size:14px;margin:0;">较长文文本一行放不下就换行</p>
</body>
</foreignObject>
</svg>
Оба метода имеют свои преимущества: метод 1 может точно контролировать положение разрыва строки, но ему необходимо вычислять конкретные координаты. Способ 2 не требует вычисления внутренних координат, но разбивается по словам, и ничего не может сделать для длинных английских слов.
Я столкнулся с тем, что одно длинное английское слово должно отображаться в новой строке, поэтому можно использовать только метод 1. Требованием к продукту является то, что текст автоматически адаптируется под размер экрана, и если ширины не хватает, он будет отображаться на новой строке. Результаты, как показано ниже:
Радарная диаграмма
Слово Outperformance усечено. Принцип заключается в том, чтобы сначалаtext
вставить элементtspan
, и заполните буквы в слове одну за другой, чтобы определить, достигает ли ширина элемента предела. Если предел превышен, вставьте другойtspan
, при расчете новогоtspan
изy
координировать. благодаря предварительным знаниямtext
конкретное место,x
Просто будьте последовательны. код показывает, как показано ниже:
function wrapWord(text, width) {
text.each(function() {
var text = d3.select(this),
words = text.text().split('').reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = text.node().getBoundingClientRect().height,
x = +text.attr('x'),
y = +text.attr('y'),
tspan = text.text(null).append('tspan').attr('x', x).attr('y', y);
while (word = words.pop()) {
line.push(word);
const dash = lineNumber > 0 ? '-' : '';
tspan.text(dash + line.join(''));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(''));
line = [word];
tspan = text.append('tspan').attr('x', x).attr('y', ++lineNumber * lineHeight + y).text(word);
}
}
});
}
Если у вас есть лучший способ, пожалуйста, прокомментируйте и дайте нам свой совет!