如何实现canvas画布任意宽高时,所绘制的文字都一样清晰。

发布于 2022-09-13 01:01:36 字数 5540 浏览 25 评论 0

我在canvas画布上填充了文本,但是文字看起来有点模糊,

然后获取了当前设备的dpr,来计算设置了画布宽高如下:

canvas.width = (clientWidth + 2 * margin) * dpr;
canvas.height = (clientHeight + 2 * margin) * dpr;
canvas.style.width = clientWidth + 2 * margin + "px";
canvas.style.height = clientHeight + 2 * margin + "px";

container容器的宽高为width: 300px;height: 100px;时,文字内容看起来清晰正常,
但是当container容器宽高为为其他任意大小时,文字就会变得不清晰。
我想知道的是这是为什么,我需要怎么解决这个异常。

完整的代码如下,可直接复制代码查看效果,调整15、16行代码的数值,复现我所描述的问题

<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>比邻商店-bilinStore</title>
  <style>
    html, body{
      height: 100%;
      width: 100%;
    }
    .container{
      width: 300px;
      height: 100px;
      position: relative;
    }

  </style>
</head>

<body>
  <div class="container">

  </div>
</body>

<script>

  function drawCardBg({
    container,
    fillStyle = '#003477',
    titleWidth = 0.4,
    margin = 10,
    radiu = 10,
    title = 'card',
    showborder = false
  }) {
    const containerNode = document.querySelector(container);
    const { clientWidth, clientHeight } = containerNode;

    // 获取设备dpi
    const dpr = window.devicePixelRatio || window.webkitDevicePixelRatio || window.mozDevicePixelRatio || 1;

    // 创建高分辨率画布
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    // 设置canvas样式属性
    canvas.width = (clientWidth + 2 * margin) * dpr;
    canvas.height = (clientHeight + 2 * margin) * dpr;
    canvas.style.width = clientWidth + 2 * margin + "px";
    canvas.style.height = clientHeight + 2 * margin + "px";
    canvas.style.position = 'absolute';
    canvas.style.top = '50%';
    canvas.style.left = '50%';
    canvas.style.transform = 'translate(-50%, -50%)';
    canvas.style.zIndex = -1;
    ctx.scale(dpr, dpr);

    // 插入到指定位置
    document.querySelector(container).appendChild(canvas);
  
    const [width, height] = [clientWidth + margin, clientHeight + margin];
  
    /**
     * 计算标题的宽度
     * 这里标题的宽度有两种状态,一种直接指定确定的宽度,另一种指定宽度百分比,
     * 在这里计算百分比所占大小
     * canvas中只能使用int类型的宽度,最终以px为单位显示
     */
     if (titleWidth < 1) titleWidth = width * titleWidth;
    const sideWidth = (width - titleWidth) / 2 - 15;
  
    /**
     * 绘制整体的背景
     */
    ctx.beginPath();
    ctx.moveTo(margin + radiu, margin);
  
    // 绘制顶部线条
    ctx.lineTo(width - radiu, margin);
    // 绘制右上角的圆角
    ctx.arc(
      width - radiu,
      margin + radiu,
      radiu,
      (Math.PI / 180) * 270,
      0,
      false,
    );
  
    // 绘制右边线条
    ctx.lineTo(width, height - 2 * radiu);
    // 绘制右下角的圆角
    ctx.arc(
      width - radiu,
      height - radiu,
      radiu,
      0,
      (Math.PI / 180) * 90,
      0,
      false,
    );
  
    /**绘制标题的不规则凹陷区域和下边线条 */
    ctx.lineTo(width - sideWidth, height);
    ctx.lineTo(width - sideWidth - 15, height - 17);
    ctx.lineTo(width - sideWidth - 15 - titleWidth, height - 17);
    ctx.lineTo(width - sideWidth - 30 - titleWidth, height);
  
    // 绘制左下角的圆角
    ctx.arc(
      margin + radiu,
      height - radiu,
      radiu,
      (Math.PI / 180) * 90,
      (Math.PI / 180) * 180,
      false,
    );
    // 绘制左边线条
    ctx.lineTo(margin, height - radiu);
    // 绘制左上角的圆角
    ctx.arc(
      margin + radiu,
      margin + radiu,
      radiu,
      (Math.PI / 180) * 180,
      (Math.PI / 180) * 270,
      false,
    );
  
    // 设置边框颜色和宽度
    if (showborder) {
      ctx.strokeStyle = '#00B4CB';
      ctx.lineWidth = 2;
      ctx.stroke();
    }
  
    // 给闭合区域设置边框阴影颜色
    ctx.shadowColor = 'rgba(0,255,255,0.8)';
    // 阴影的模糊半径
    ctx.shadowBlur = margin;
  
    // 闭合路径(以上所绘制的闭合区域)
    ctx.closePath();
  
    // 设置闭合区域的填充色,并填充
    ctx.fillStyle = fillStyle;
    ctx.fill();
  
    ctx.shadowBlur = 0;
  
    const titleIconLOrigin = sideWidth + 20;
    /**
     * 绘制标题部分左边ICON
     */
    ctx.beginPath();
    ctx.moveTo(sideWidth + 20, height - 13);
    ctx.lineTo(titleIconLOrigin + 20, height - 13);
    ctx.lineTo(titleIconLOrigin + 15, height - 6);
    ctx.lineTo(titleIconLOrigin + -5, height - 6);
    ctx.closePath();
    ctx.fillStyle = '#2E90FF';
    ctx.fill();
  
    /**
     * 绘制标题部分右边ICON
     */
    ctx.beginPath();
    ctx.moveTo(-30 + titleWidth + titleIconLOrigin, height - 13);
    ctx.lineTo(-10 + titleWidth + titleIconLOrigin, height - 13);
    ctx.lineTo(-5 + titleWidth + titleIconLOrigin, height - 6);
    ctx.lineTo(-25 + titleWidth + titleIconLOrigin, height - 6);
    ctx.closePath();
    ctx.fillStyle = '#2E90FF';
    ctx.fill();
  
    /**
     * 绘制标题背景
     */
    ctx.beginPath();
    ctx.moveTo(titleIconLOrigin + 25, height - 13);
    ctx.lineTo(titleWidth + titleIconLOrigin - 35, height - 13);
    ctx.lineTo(titleWidth + titleIconLOrigin - 30, height - 6);
    ctx.lineTo(titleWidth + titleIconLOrigin - 30, height + 2);
    ctx.lineTo(titleIconLOrigin + 20, height + 2);
    ctx.lineTo(titleIconLOrigin + 20, height - 6);
    ctx.closePath();
    ctx.fillStyle = '#2E90FF';
    ctx.fill();
    ctx.fillStyle = '#fff';
    ctx.font = '10px Calibri';
    const textWidth = ctx.measureText(title);
    ctx.fillText(title, width / 2 - textWidth.width / 2, height - 1);
  };

  drawCardBg({container: '.container', title: '设备工况'})

</script>

</html>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

顾挽 2022-09-20 01:01:36

整个书写过程是对的,原因在于我再定位这个canvas时使用了transform

使用transform来做居中时,gpu渲染点阵对不上就会模糊

篱下浅笙歌 2022-09-20 01:01:36

在我这里chrome浏览器效果来看,宽高变化时,字体是没有变化,且没有出现不清晰的情况;
按照你说的,目前只能理解为你自身的显示器问题,跟这个程序无关;

如果你需要字体跟随容器大小而改变,就需要动态改变字体大小
image.png
image.png
image.png

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文