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

Next.js中Chart.js绘制到Canvas时图表不显示的问题求助

问题修复方案

核心问题分析

  1. 手动修改Canvas的width/height并缩放上下文后,Chart.js的渲染逻辑与手动操作的上下文状态冲突,导致图表无法正确绘制。
  2. 图表未被定位到背景图的区域内,且未适配背景图的尺寸。

具体修改步骤

1. 调整Canvas上下文状态管理

修改drawCanvas函数,在绘制图表前保存并调整上下文状态,确保图表绘制在背景图的区域内:

const drawCanvas = (canvasWidth, canvasHeight) => {
  const dpr = window.devicePixelRatio || 1;

  canvas.width = canvasWidth * dpr;
  canvas.height = canvasHeight * dpr;
  ctx.scale(dpr, dpr);

  // 用逻辑像素清除画布,适配已缩放的上下文
  ctx.clearRect(0, 0, canvasWidth, canvasHeight);

  const imgAspectRatio = bgImage.width / bgImage.height;
  const canvasAspectRatio = canvasWidth / canvasHeight;

  let imgWidth, imgHeight;
  if (canvasAspectRatio > imgAspectRatio) {
    imgHeight = canvasHeight;
    imgWidth = imgHeight * imgAspectRatio;
  } else {
    imgWidth = canvasWidth;
    imgHeight = imgWidth / imgAspectRatio;
  }

  const xOffset = (canvasWidth - imgWidth) / 2;
  const yOffset = (canvasHeight - imgHeight) / 2;

  ctx.drawImage(bgImage, xOffset, yOffset, imgWidth, imgHeight);

  // 保存当前上下文状态,准备绘制图表
  ctx.save();
  // 将坐标系平移到背景图的左上角
  ctx.translate(xOffset, yOffset);
  // 设置裁剪区域,确保图表仅在背景图范围内绘制
  ctx.beginPath();
  ctx.rect(0, 0, imgWidth, imgHeight);
  ctx.clip();

  // 调用图表绘制函数,传入背景图的尺寸(此时坐标系已平移,x/y偏移为0)
  lineChart(0, 0, imgWidth, imgHeight);

  // 恢复上下文状态,避免影响后续绘制
  ctx.restore();
};

2. 调整Chart.js配置

修改lineChart函数,禁用响应式自动调整,强制使用指定尺寸,并适配上下文:

const lineChart = (x, y, width, height) => {
  // 避免重复初始化图表,先销毁已存在的实例
  if (window.chartInstance) {
    window.chartInstance.destroy();
  }

  window.chartInstance = new Chart(ctx, {
    type: 'line',
    data: {
      labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
      datasets: [{
        label: 'Sales',
        data: [12, 19, 3, 5, 2],
        borderColor: '#ff0000',
        fill: false
      }]
    },
    options: {
      // 禁用响应式,使用手动指定的尺寸
      responsive: false,
      maintainAspectRatio: false,
      // 设置图表的宽高为背景图的尺寸
      width: width,
      height: height,
      // 移除布局内边距,让图表填满目标区域
      layout: {
        padding: 0
      },
      // 适配设备像素比,确保图表清晰
      devicePixelRatio: window.devicePixelRatio || 1
    }
  });
};

3. Next.js客户端渲染适配

在Next.js中,确保Chart.js和Canvas操作仅在客户端执行:

  • 使用动态导入禁用SSR:
import dynamic from 'next/dynamic';
const Chart = dynamic(() => import('chart.js/auto'), { ssr: false });
  • 在useEffect中初始化画布和图表,确保DOM已加载:
import { useEffect, useRef } from 'react';

export default function CanvasPage() {
  const canvasRef = useRef(null);
  const bgImageRef = useRef(new Image());

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');

    // 加载背景图,确保加载完成后再绘制
    bgImageRef.current.src = '/your-background-image.jpg';
    bgImageRef.current.onload = () => {
      drawCanvas(canvas.clientWidth, canvas.clientHeight);
    };

    // 窗口 resize 时重新绘制
    window.addEventListener('resize', () => {
      drawCanvas(canvas.clientWidth, canvas.clientHeight);
    });

    return () => {
      window.removeEventListener('resize', () => {});
      if (window.chartInstance) {
        window.chartInstance.destroy();
      }
    };
  }, []);

  return <canvas ref={canvasRef} style={{ width: '100%', height: '400px' }} />;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 13:07:28