获取字符串的在html页面上的宽度并且若文字过长则缩小字体填充

某个页面有这样一个需求:一个固定宽度的div,若文字过长,则缩小字体填充。

看到同事采用的是用php的GD库的imagettfbbox函数来计算文字的宽度。

imagettfbbox(float $size,float $angle,string $font_filename,string $string,array $options = []): array|false

 取得使用 TrueType 字体的文本的边界框,返回四个顶点的x和y坐标值数据或者false

size字体的尺寸,单位:点(磅)。

angle测量字符串的角度(以度为单位)。

fontfile想要使用的 TrueType 字体的路径。

string要测量的字符串。

<?php

function getFontSize($text)
{
    $base_fs = 14;
    $base_width = 150;
    $fontfile = './fonts/Arial.ttf';
    // 取得使用 TrueType 字体的文本的边界框
    //第一个参数单位pt,绝对尺寸单位,而px是相对尺寸单位和DPI有关,当DPI为72时,1pt等于1px,本例中假定DPI=72
    $font_box = imagettfbbox($base_fs, 0, $fontfile, $text);
    $width = $font_box[2] - $font_box[0];
    if ($width > $base_width) {
        $font_size = round($base_fs * ($base_width / ($font_box[2] - $font_box[0])), 2);
    } else {
        $font_size = $base_fs;
    }
    return compact('text', 'width', 'font_size');
}

$text_arr = [
    'A1-I have a good time every day.',
    'A2-I come from China.',
    'M3-I enjoy going fishing.',
    "我乐于和平地生活。",
    "我来自中国。",
    "我喜欢去钓鱼。"
];

$res = [];
foreach ($text_arr as $text) {
    $val = getFontSize($text);
    $res[] = $val;
}
?>

<style>
    * {
        margin: 0;
        padding: 0
    }

    div.text {
        border: 1px solid red;
        width: 150px;
        height: 20px;
        line-height: 20px;
        font: normal 14px Arial;
    }
</style>
<script>
    console.log(<?= json_encode($res) ?>)
</script>
<div>
    <?php foreach ($res as $row): ?>
        <div class="text" style="font-size: <?= $row['font_size'] ?>px;"><?= $row['text'] ?></div>
    <?php endforeach ?>
</div>

     

计算文字大小和客户端的DPI有关,在server上计算感觉不是很适合,看看有没有客户端的解决方案。

<style>
  * {
    margin: 0;
    padding: 0;
  }
  div.text {
    border: 1px solid red;
    width: 150px;
    height: 20px;
    line-height: 20px;
    font: normal 14px Arial;
  }
</style>
<div id="content"></div>
<div id="content_canvas"></div>
<script>
  function getTextWidth(text) {
    const font = "normal 14px Arial";
    const element = document.createElement("span");
    element.style.font = font;
    element.style.visibility = "hidden";
    element.textContent = text;
    document.body.appendChild(element);
    const width = element.offsetWidth;
    document.body.removeChild(element);
    return width;
  }

  function getTextWidthByCanvas(text) {
    const font = "normal 14px Arial";
    const canvas = document.createElement("canvas");
    const context = canvas.getContext("2d");
    context.font = font;
    const metrics = context.measureText(text);
    return metrics.width;
  }

  function getFontSize(width) {
    const base_fs = 14;
    const base_width = 150;
    let font_size = 14;
    if (width > base_width) {
      font_size = (base_fs * (base_width / width)).toFixed(2);
    }
    return font_size;
  }

  const text_arr = ["I come from China.I have a good time every day.", "A2-I come from China.", "M3-I enjoy going fishing.", "我乐于和平地生活。", "我来自中国。", "我喜欢去钓鱼。"];

  function renderHtml(domId, type = "canvas") {
    console.log(type, "--------------");
    let html = "";
    for (let text of text_arr) {
      const width = type == "canvas" ? getTextWidthByCanvas(text) : getTextWidth(text);
      const font_size = getFontSize(width);
      console.log(text, width, font_size);

      html += `<div class="text" style="font-size:${font_size}px;">${text}</div>`;
    }
    document.querySelector("#" + domId).innerHTML = html;
  }

  renderHtml("content", "elem");
  renderHtml("content_canvas");
</script>

           

这种就好很多,文字较长时能够缩小字体填充,且填充的宽度几乎可以占满div

 

posted @   carol2014  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示