You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chart.js 3.x:如何在tooltip内设置不同字号(非外部HTML tooltip)

Chart.js 3.x 实现Tooltip内部分文本字号差异化(无需外部HTML Tooltip)

问题背景

当前使用Chart.js 3.x,已通过plugins.tooltip及回调函数自定义Tooltip样式,配置示例如下:

tooltip: {
  callbacks: {
    footer: function (context) {
      return "69%";
    },
    label: function (context) {
      return "TEST";
    }
  },
  backgroundColor: "#FFF",
  borderWidth: 1,
  borderColor: "black",
  titleFont: {
    size: 14,
    weight: "light",
  },
  footerFont: {
    size: 20,
    weight: "bold",
  },
  titleColor: "rgba(51, 51, 51, 1)",
  bodyColor: "rgba(51, 51, 51, 1)",
  footerColor: "black",
  displayColors: false,
  titleAlign: "center",
  bodyAlign: "center",
  footerAlign: "center",
  padding: 8,
},

需求:让Tooltip中类似69%里的%符号使用更小字号,且不想使用外部HTML Tooltip方案。


解决方案:利用tooltip.custom自定义Canvas绘制

Chart.js默认Tooltip的回调仅能返回纯文本,无法单独设置局部样式,但可以通过tooltip.custom函数完全接管Tooltip的渲染逻辑,直接使用Canvas API实现差异化文本样式。

修改后的配置示例

tooltip: {
  // 关闭默认Tooltip渲染,启用自定义逻辑
  enabled: false,
  custom: function(context) {
    const tooltip = context.tooltip;
    // 无内容时不渲染
    if (tooltip.opacity === 0) return;

    const ctx = context.chart.ctx;
    const chart = context.chart;

    // 绘制Tooltip容器(背景+边框)
    ctx.save();
    ctx.fillStyle = '#FFF';
    ctx.strokeStyle = 'black';
    ctx.lineWidth = 1;
    ctx.fillRect(tooltip.x, tooltip.y, tooltip.width, tooltip.height);
    ctx.strokeRect(tooltip.x, tooltip.y, tooltip.width, tooltip.height);

    // 处理Footer文本(拆分数字与%符号)
    if (tooltip.footer && tooltip.footer.length > 0) {
      const footerText = tooltip.footer[0];
      const numPart = footerText.slice(0, -1);
      const symbolPart = footerText.slice(-1);

      // 绘制数字(大字号)
      ctx.font = 'bold 20px sans-serif';
      ctx.fillStyle = 'black';
      const numWidth = ctx.measureText(numPart).width;
      
      // 计算居中位置
      const symbolWidth = ctx.measureText(symbolPart).width;
      const totalTextWidth = numWidth + symbolWidth;
      const startX = tooltip.x + (tooltip.width - totalTextWidth) / 2;
      const centerY = tooltip.y + tooltip.height / 2 + 8; // 垂直居中偏移量

      ctx.fillText(numPart, startX, centerY);

      // 绘制%符号(小字号)
      ctx.font = 'bold 14px sans-serif';
      ctx.fillText(symbolPart, startX + numWidth, centerY - 3); // 垂直对齐调整
    }

    // 如需处理Label文本,可参照上述逻辑添加
    if (tooltip.body && tooltip.body.length > 0) {
      const labelText = tooltip.body[0].lines[0];
      // 此处可按需拆分Label文本并设置不同样式绘制
      ctx.font = '14px light sans-serif';
      ctx.fillStyle = 'rgba(51, 51, 51, 1)';
      ctx.textAlign = 'center';
      ctx.fillText(labelText, tooltip.x + tooltip.width / 2, tooltip.y + 20);
    }

    ctx.restore();
  },
  // 保留原有尺寸相关配置,用于Tooltip容器的自动计算
  padding: 8,
}

关键逻辑说明

  1. 关闭默认渲染:设置enabled: false,让自定义逻辑接管Tooltip绘制
  2. 容器绘制:用Canvas API手动绘制Tooltip的背景和边框,还原原有样式
  3. 文本拆分与绘制:将目标文本拆分为需要大字号的数字部分和小字号的符号部分,分别设置font属性后绘制
  4. 对齐处理:通过measureText计算文本宽度,实现水平居中;调整垂直坐标让不同字号的文本对齐更自然

内容的提问来源于stack exchange,提问作者amu03

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 00:52:50