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

如何使用Chart.js在单个画布绘制多个图表?(chartjs-node服务端场景)

在chartjs-node中实现单画布多图表渲染

嘿,我之前刚好处理过一模一样的需求!因为chartjs-node底层是基于node-canvas的,咱们可以直接操作画布上下文,把单个画布划分成多个区域,然后在每个区域分别渲染独立的Chart.js图表。下面是具体的实现思路和代码示例:

核心思路

chartjs-node默认只支持单个图表,但它暴露了底层的canvas上下文,我们可以利用Canvas API的**裁剪(clip)**功能,把画布分割成多个独立的渲染区域,每个区域对应一个图表。步骤大概是:

  1. 创建一个足够大的画布,容纳所有需要的图表
  2. 为每个图表计算好位置、宽度和高度
  3. 使用画布上下文的裁剪功能,限制当前图表只能在指定区域内渲染
  4. 依次渲染每个图表,完成后恢复画布状态
  5. 最后导出整个画布为PNG

完整代码示例

首先确保你已经安装了chartjs-node:

npm install chartjs-node

然后是实现代码:

const ChartNode = require('chartjs-node');
const fs = require('fs').promises;

async function generateMultiChart() {
  // 1. 创建总画布,设置合适的宽高
  const totalWidth = 800;
  const totalHeight = 600;
  const chartNode = new ChartNode(totalWidth, totalHeight);
  const ctx = chartNode.canvas.getContext('2d');

  // 2. 定义两个图表的配置(你可以根据需求扩展成更多图表)
  const barChartConfig = {
    type: 'bar',
    data: {
      labels: ['一月', '二月', '三月'],
      datasets: [{
        label: '销售额',
        data: [12000, 19000, 35000],
        backgroundColor: '#36A2EB',
        borderColor: '#258cd1',
        borderWidth: 1
      }]
    },
    options: {
      // 关键:必须关闭响应式和宽高比例自动调整
      responsive: false,
      maintainAspectRatio: false,
      title: {
        display: true,
        text: 'Q1 销售数据',
        fontSize: 16
      },
      scales: {
        y: { beginAtZero: true }
      }
    }
  };

  const lineChartConfig = {
    type: 'line',
    data: {
      labels: ['一月', '二月', '三月'],
      datasets: [{
        label: '网站访问量',
        data: [28000, 48000, 40000],
        borderColor: '#FF6384',
        backgroundColor: 'rgba(255,99,132,0.1)',
        fill: true,
        tension: 0.4
      }]
    },
    options: {
      responsive: false,
      maintainAspectRatio: false,
      title: {
        display: true,
        text: 'Q1 网站访问趋势',
        fontSize: 16
      },
      scales: {
        y: { beginAtZero: true }
      }
    }
  };

  // 3. 渲染第一个图表:上半区域(占总高度45%,留5%间距)
  const chart1X = 0;
  const chart1Y = 0;
  const chart1Width = totalWidth;
  const chart1Height = totalHeight * 0.45;

  ctx.save(); // 保存当前画布状态
  ctx.beginPath();
  ctx.rect(chart1X, chart1Y, chart1Width, chart1Height); // 定义裁剪区域
  ctx.clip(); // 启用裁剪,后续渲染只会在这个区域内
  await chartNode.drawChart(barChartConfig); // 渲染图表
  ctx.restore(); // 恢复画布状态,避免影响下一个图表

  // 4. 渲染第二个图表:下半区域(从总高度50%的位置开始)
  const chart2X = 0;
  const chart2Y = totalHeight * 0.5;
  const chart2Width = totalWidth;
  const chart2Height = totalHeight * 0.45;

  ctx.save();
  ctx.beginPath();
  ctx.rect(chart2X, chart2Y, chart2Width, chart2Height);
  ctx.clip();
  await chartNode.drawChart(lineChartConfig);
  ctx.restore();

  // 5. 导出为PNG文件
  const imageBuffer = await chartNode.toBuffer('image/png');
  await fs.writeFile('multi-chart.png', imageBuffer);
  console.log('多图表PNG已生成!');

  // 6. 清理资源
  await chartNode.destroy();
}

// 执行生成函数
generateMultiChart().catch(err => console.error('生成失败:', err));

关键注意事项

  • 必须关闭响应式:所有图表配置里的responsive要设为false,maintainAspectRatio设为false,否则Chart.js会自动把图表拉伸到整个画布,覆盖其他区域。
  • 画布状态管理:每次渲染图表前用ctx.save()保存状态,渲染后用ctx.restore()恢复,这样不同图表的裁剪区域不会互相干扰。
  • 布局灵活调整:你可以随意修改每个图表的x、y、width、height值,实现左右排列、多列多排等任意布局,比如三个图表横向排列,只要计算好每个的宽度即可。
  • 避免内容溢出:如果图表有图例、标题或工具提示,要确保它们不会超出分配的区域,必要时调整options.legend.position、options.layout.padding或者缩小图表的内部边距。
  • 异步顺序渲染:因为drawChart是异步方法,所以要使用await按顺序渲染每个图表,防止上下文冲突导致渲染异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 07:54:16