gpt4 book ai didi

javascript - Javascript/Jquery使文本完全适合div给定尺寸并带有换行符(如果需要)

转载 作者:行者123 更新时间:2023-11-27 23:20:12 25 4
gpt4 key购买 nike

我要花一些时间来解决这个问题:我使用了这些功能,以便将单行文本适合给定的尺寸。

function getFontSize(width, height, text, font, callback) {
var n = 100;
var ctxfont = n + 'px ' + font;
var result = measureTextHeight(ctxfont, text);
while (result.width > width || result.height > height) {
n--;
var ctxfont = n + 'px ' + font;
var result = measureTextHeight(ctxfont, text);
}
callback({
'width': result.width,
'height': result.height,
'size': n
});
}

function measureTextHeight(ctxFont, text) {
var width = 1500;
var height = 500;

var canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
ctx.save();
ctx.font = ctxFont;
ctx.clearRect(0, 0, width, height);
ctx.fillText(text, parseInt(width * 0.1, 10), parseInt(height / 2, 10));
ctx.restore();
document.body.appendChild(canvas);
var data = ctx.getImageData(0, 0, width, height).data;


var topMost = false;
var bottomMost = false;
var leftMost = false;
var rightMost = false;
for (var x = 0; x < width; x++) {
for (var y = 0; (y < height) && (!leftMost); y++) {
//console.log("x: %s y: %s index: %s", x,y, getAlphaIndexForCoordinates(x,y,width,height).toString() );
if (data[getAlphaIndexForCoordinates(x, y, width, height)] != 0) {
leftMost = x;
}
}
}
for (var y = 0; y < height; y++) {
for (var x = 0; (x < width) && (!topMost); x++) {
//console.log("x: %s y: %s index: %s", x,y, getAlphaIndexForCoordinates(x,y,width,height).toString() );
if (data[getAlphaIndexForCoordinates(x, y, width, height)] != 0) {
topMost = y;
}
}
}
for (var x = width - 1; x >= 0; x--) {
for (var y = height - 1; (y >= 0) && (!rightMost); y--) {
//console.log("x: %s y: %s index: %s", x,y, getAlphaIndexForCoordinates(x,y,width,height).toString() );
if (data[getAlphaIndexForCoordinates(x, y, width, height)] != 0) {
rightMost = x;
}
}
}
for (var y = height - 1; y >= 0; y--) {
for (var x = width - 1; (x >= 0) && (!bottomMost); x--) {
//console.log("x: %s y: %s index: %s", x,y, getAlphaIndexForCoordinates(x,y,width,height).toString() );
if (data[getAlphaIndexForCoordinates(x, y, width, height)] != 0) {
bottomMost = y;
}
}
}
canvas.remove();
return ({
width: (rightMost - leftMost) + 1
, height: (bottomMost - topMost) + 1
});
}

function getAlphaIndexForCoordinates(x, y, width, height) {
return (((width * 4 * y) + 4 * x) + 3);
}


我将所需的尺寸和字体传递给getFontSize函数,它返回文本的实际宽度和高度以及完成它所需的字体大小。这样,我可以使用ctx.filltext()函数将文本绘制到画布上,并使其尽可能最佳,然后根据其宽度和高度将其居中对齐。我不确定这是否是实现所需结果的最有效方法,但它是否有效。

我现在想做的是代替单行设置,我可以为div设置给定的宽度和高度,然后给文本,使其完全适合那些尺寸,并在需要时添加换行符,并仍然返回实际宽度和文本的高度,这样我就可以像小提琴一样正确地将其绘制到画布上: http://jsfiddle.net/vkgjrd3e/尽管在小提琴中div的底部仍然有一些空间。

考虑到它的字体和容器尺寸,我试图达到的效果是最适合文本。如果需要,添加换行符。

最佳答案

最简单的方法可能是使用CSS的功能,而不是自己动手做。

您可以创建一个虚拟div,在其中添加,并增加其字体大小,直到不再适合为止。
之前的字体大小是正确的。

然后,您可以使用Range对象遍历此的textContent,以获取CSS将会生成的换行符。 Range API提供了一种方便的getBoundingClientRect方法,使我们能够找到光标所在的位置。我们只需要记住最后一个y位置,当它改变时,我们知道前面的字符是该行的最后一个。

但是,此技术也有一些缺点。


在DOM中,多个空格字符被压缩为一个。 CanvasContext API没有相同的行为,因此我们需要在解析文本之前摆脱这些。
这些措施是基于容器边界框进行的,这意味着它不会检查绘制的像素,因此您可能会有一些字符溢出(例如Zalgo͚̠͓ͣ̔͐̽),而另一些字符则不能完全适合该框(取决于上升和下降)每个字符的血统)。
...可能是其他人。




function getBestFontSize(text, width, height, userstyles) {
if(!text) return null;

const cont = document.createElement('div');
cont.classList.add('best-font-size-tester');
const style = cont.style;

if(typeof width === 'number') width += 'px';
if(typeof height === 'number') height += 'px';
Object.assign(style, {width, height}, userstyles);

const span = document.createElement('span');
span.textContent = text;
cont.appendChild(span);
document.body.appendChild(cont);

let size = 0;

const max = cont.getBoundingClientRect();
while(true) {
style.fontSize = size + 'px';
let rect = span.getBoundingClientRect();
if(rect.bottom > max.bottom || rect.right > max.right) {
// overflown
size -= 1; // the correct size was the one before
break;
}
size++;
}
if(size === 0) {
// even at 0 it doesn't fit...
return null;
}
// now we'll get the line breaks by walking through our text content
style.fontSize = size + 'px';
const lines = getLineBreaks(span.childNodes[0], max.top);
// cleanup
document.body.removeChild(cont);

return {
fontSize: size,
lines: lines
};
}

function getLineBreaks(node, contTop) {
if(!node) return [];
const range = document.createRange();
const lines = [];
range.setStart(node, 0);
let prevBottom = range.getBoundingClientRect().bottom;
let str = node.textContent;
let current = 1;
let lastFound = 0;
let bottom = 0;
while(current <= str.length) {
range.setStart(node, current);
if(current < str.length -1)
range.setEnd(node, current+1);
bottom = range.getBoundingClientRect().bottom;
if(bottom > prevBottom) {
lines.push({
y: prevBottom - (contTop || 0),
text: str.substr(lastFound , current - lastFound)
});
prevBottom = bottom;
lastFound = current;
}
current++;
}
// push the last line
lines.push({
y: bottom - (contTop || 0),
text: str.substr(lastFound)
});

return lines;
}

const ctx = canvas.getContext('2d');
ctx.textBaseline = 'bottom';
txt_area.oninput = e => {
const input = txt_area.value
.replace(/(\s)(?=\1)/g, ''); // remove all double spaces
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.translate(19.5,19.5);
ctx.strokeRect(0,0,100,100);

if(!input.length) return;
const bestFit = getBestFontSize(input, 100, 100, {
fontFamily: 'sans-serif',
fontWeight: '600',
textAlign: 'center'
});
// apply thesame options we passed
ctx.font = '600 ' + bestFit.fontSize + 'px sans-serif';
ctx.textAlign = 'center';
// translate again because text-align: center
ctx.translate(50.5,0);
bestFit.lines.forEach(({text, y}) => ctx.fillText(text, 0, y));
};
txt_area.oninput();

.best-font-size-tester {
border: 1px solid;
position: absolute;
overflow: visible;
opacity: 0;
z-index: -1;
pointer-events: none;
}

<textarea id="txt_area">This is an example text to fit the div even with line breaks</textarea>
<canvas id="canvas"></canvas>

关于javascript - Javascript/Jquery使文本完全适合div给定尺寸并带有换行符(如果需要),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58051691/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com