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

使用Puppeteer生成PDF:地图视图未完整捕获、Leaflet瓦片加载不全

Leaflet地图PDF捕获问题求助

我开发了一个仅包含Leaflet地图的Angular应用,搭建了基于Puppeteer的Express.js服务,用于捕获地图并生成PDF。通过URL参数传递缩放级别和地图图层时,遇到两个核心问题:

  • PDF仅捕获地图的部分视图,无法完整呈现;
  • 部分Leaflet瓦片未完全加载,出现灰色、半透明或缺失的情况。

调试时将Puppeteer的headless选项设为false,打开的浏览器窗口中地图可完整显示,但生成的PDF与窗口内容不符。

以下是我的Express.js代码:

app.get('/print', async (req, res) => {
    try {
    const { zoom, layer } = req.query;

    console.log(`Generating PDF with Zoom: ${zoom}, Layer: ${layer}`);

    const browser = await puppeteer.launch({
      headless: false,
      args: ['--start-maximized'], // Start the browser in maximized mode
    });

    const page = await browser.newPage();

    await page.setViewport({ width: 1920, height: 1080,deviceScaleFactor: 2});

    const mapUrl = `http://localhost:4200/?zoom=${zoom}&layer=${encodeURIComponent(layer)}`;
    await page.emulate('screen'); //<--
    await page.goto(mapUrl, { waitUntil: 'networkidle0' }); 


    // Wait for the map element (#map) to be available
    await page.waitForSelector('#map');

    // Change layer and zoom level dynamically in the page context
    await page.evaluate((zoom, layer) => {
      if (window.leafletMap) {
        // Set the zoom level
        window.leafletMap.setZoom(parseInt(zoom));

        // Remove all layers
        window.leafletMap.eachLayer((l) => window.leafletMap.removeLayer(l));

        // Add the new layer
        const newLayer = L.tileLayer(layer);
        newLayer.addTo(window.leafletMap);

        // Wait for the new layer to be loaded before proceeding
        return new Promise((resolve) => {
          newLayer.on('load', resolve); // Wait until the layer is loaded
        });
      }
    }, zoom, layer);

    // Ensure the map is fully rendered before capturing the PDF
    await page.waitForFunction(() => document.querySelectorAll('.leaflet-tile-loaded').length > 0, {
      timeout: 18000, // extended timeout to ensure the tiles are fully loaded
    });

    // Wait for the map to stabilize by checking if tiles are loaded
    await page.waitForSelector('.leaflet-tile-loaded', { timeout: 10000 });

    // Ensure the tiles are loaded properly by waiting for the 'load' event of all tiles
    await page.evaluate(() => {
      return new Promise((resolve) => {
        let tilesLoaded = 0;
        const totalTiles = document.querySelectorAll('.leaflet-tile').length;
        const interval = setInterval(() => {
          tilesLoaded = document.querySelectorAll('.leaflet-tile-loaded').length;
          if (tilesLoaded === totalTiles) {
            clearInterval(interval);
            resolve();
          }
        }, 100);
      });
    });

    // Generate the PDF with higher scale for better resolution
    const pdfPath = path.join(__dirname, 'map.pdf');
    await page.pdf({
      path: pdfPath,
      format: 'A4',
      printBackground: true,
      scale: 1.5, 
      landscape: true, 
    });


    // await browser.close();

    // Send the PDF as a download response
    res.download(pdfPath, 'map.pdf', (err) => {
      if (err) {
        console.error('Error sending PDF:', err);
        res.status(500).send('Error generating PDF');
      } else {
        fs.unlinkSync(pdfPath); 
      }
    });
  } catch (error) {
    console.error('Error generating PDF:', error);
    res.status(500).send('Error generating PDF');
  }
});

截图对比

  • 期望打印的原始地图:
    期望打印的原始地图
  • 服务生成的PDF地图:
    服务生成的PDF地图

现寻求以下问题的解决方案:

  1. 如何确保Puppeteer捕获完整的可见地图?
  2. 如何确保所有Leaflet瓦片在捕获PDF前完全加载?

这是工作的概念验证(PoC),后续将集成到大型项目中,恳请技术帮助。


内容的提问来源于stack exchange,提问作者Jihed Ben Zarb

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 23:29:55