使用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地图:

现寻求以下问题的解决方案:
- 如何确保Puppeteer捕获完整的可见地图?
- 如何确保所有Leaflet瓦片在捕获PDF前完全加载?
这是工作的概念验证(PoC),后续将集成到大型项目中,恳请技术帮助。
内容的提问来源于stack exchange,提问作者Jihed Ben Zarb
相关产品推荐
相关产品推荐

