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

如何在html2canvas+pdfmake生成的PDF中添加第二张图片?

解决多Canvas图表+PDF生成的异步处理问题

Hey there! I get you—handling multiple async canvas renders for PDF generation can be tricky, especially when you're switching from backend PHP to frontend work. Let's fix this step by step.

核心问题分析

Your current code uses a single html2canvas call with a callback, but since each html2canvas runs asynchronously, trying to use the myImage variable outside the callback (or handling a second chart) leads to timing issues—your code tries to use the variable before the canvas has finished rendering. Global variables don't work here because the async operation hasn't completed when you access them.

解决方案:用Promise封装异步渲染

We can wrap each html2canvas call in a Promise, then use Promise.all to wait for all your charts (and any other canvas-based elements like the map) to finish rendering before assembling the PDF. This ensures you have all the image data URLs ready at the same time.

Step 1: Create a reusable canvas renderer function

First, make a helper function that returns a Promise for each canvas rendering:

function renderCanvasElement(selector) {
  return new Promise((resolve) => {
    html2canvas(document.querySelector(selector), {
      onrendered: (canvas) => {
        // Resolve the Promise with the image data URL
        resolve(canvas.toDataURL("image/png"));
      }
    });
  });
}

Step 2: Wait for all elements to render, then build the PDF

Use Promise.all to await both your charts (and map/table if they need canvas rendering). Once all data URLs are ready, assemble your docDefinition and generate the PDF:

// Assume your second chart has the selector #chartdiv2
Promise.all([
  renderCanvasElement("#chartdiv"),   // First chart
  renderCanvasElement("#chartdiv2"),  // Second chart
  // Add other elements if needed (e.g., your Leaflet map)
  // renderCanvasElement("#map-container"),
  // renderCanvasElement("#table-container")
])
.then(([chart1Image, chart2Image]) => {
  // Now you have both chart images ready! Build your docDefinition
  const docDefinition = {
    content: [
      // Add first chart
      { image: chart1Image, width: 500 },
      // Add second chart
      { image: chart2Image, width: 500 },
      // Insert your existing table and map content here
      // { text: "Your table content..." },
      // { image: mapImage, width: 500 }
    ],
    // Critical for Cyrillic text: Ensure you're using a supported font
    defaultStyle: {
      font: "Arial" // Make sure pdfMake is configured with a font that supports Cyrillic
    }
  };

  // Generate and download the PDF
  pdfMake.createPdf(docDefinition).download();
})
.catch((error) => {
  console.error("Error rendering canvas elements:", error);
});

关键注意事项

  • Cyrillic Font Support: Since you're dealing with Cyrillic text, double-check that pdfMake is configured with a font that supports these characters. You can define custom fonts in pdfMake like this:

    pdfMake.fonts = {
      Arial: {
        normal: 'Arial.ttf',
        bold: 'ArialBold.ttf',
        italics: 'ArialItalic.ttf',
        bolditalics: 'ArialBoldItalic.ttf'
      },
      // Alternatively, use a Cyrillic-specific font like PT Sans
      PTSans: {
        normal: 'PTSans-Regular.ttf',
        bold: 'PTSans-Bold.ttf'
      }
    };
    

    Then update the defaultStyle.font in docDefinition to match your chosen font.

  • Avoid Global Variables: Using Promises eliminates the need for global variables, as we pass the image data directly through the Promise resolution. This keeps your code cleaner and avoids race conditions.

  • Leaflet Map Tip: If your Leaflet map isn't rendering correctly in the PDF, make sure to use html2canvas on the map container element, and ensure the map has finished loading tiles before rendering (you can listen for the load event on the map if needed).

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:18:49