[英]Exporting Leaflet map with geojson layers to png in Angular 5
我有一张包含大量 geojson 的传单地图。 我希望能够将地图图像导出为 png。 我试过leaflet-image插件,它导出底图,我也试过(独立)html2canvas库将地图div的内容输出到png文件。
不幸的是,使用 Leaflet-image 输出只显示背景层(地图)而不是任何 geojson 区域,而使用 html2canvas 输出结果显示层而不是背景地图。
我不认为传单图像插件是可行的,因为它有太多的限制。 它需要将所有图层渲染到画布上,但这样做时,性能会下降 - 它似乎无法处理这么多地理区域。 我对服务器也没有太多控制权,并且那里没有安装 nodejs。
html2canvas 更有前途。 使用它和文件保护程序,我能够输出完整的图像和区域,如下所示:
html2canvas(myMap, {
allowTaint:false,
useCORS: true,
width: 650,
height: 500,
}).then(canvas => {
canvas.toBlob((blob) => {
saveAs(blob, "my-map.png");
});
});
这非常有效,除了一个问题 - 区域在画布上呈现在错误的位置上。 即区域偏移量是错误的。 这是一个例子。 地图的底部和右侧应该用彩色的等值线区域覆盖到边缘:
如何让区域在地图上正确渲染,而不是在错误的地方被剪裁?
编辑:我在 html2canvas 网站上查看了一个看起来很有希望的问题。 我的似乎没有这样的变换问题,但是有人遇到了我认为是图层偏移问题的问题。 我在这里实施了他们的解决方案:
function redraw() {
var lat_tmp = map.getCenter().lat;
var lng_tmp = map.getCenter().lng;
map.setView([-66.22149259832975, -1.142578125]);
setTimeout(function () {
waitForTilesToLoad()
}, 50000);
map.setView([lat_tmp, lng_tmp]);
}
但它也不起作用,所以我仍在努力解决这个问题。 我遇到的并不是真正的图层偏移问题,而是图层剪切问题。
最近遇到了同样的问题,在尝试管理 html2canvas 时也转到了相同的引用主题。
在我的情况下(也许你也是),地图是动态的,承载了太多的图块和元素(markeclusters、饼图等)。 使用 CraigVA 给出的技巧把它搞砸了。
最后,我尝试了其他几个插件,发现这个非常令人满意:
没有故障,干净的 png 导出。
我从上面的 html2canvas 链接中,在移动 geojson 以将视口与背景图块结合起来方面做了大量工作。 如果我移动地图,我确实让它正确映射,但当我放大时却没有。 这是非常棘手的事情,如果我可以避免的话,我宁愿不这样做。 这可能是更糟糕的方法,好像传单改变了,解决方案就会失效。
dom-to-image 为我提供了从 dom 生成图像所需的一切。 Leaflet Easy Print 比 dom-to-image 给了我什么。 控制台有dom-to-image的错误,使用leaflet easy print时出现同样的错误。 我也想自己控制图像导出。 dom-to-image 的缺点是它只适用于 chrome 和 firefox。 没有 IE,没有 Edge,没有 Safari。 因此,我已将此发布为不需要担心这些限制的人的可能解决方案,同时希望以后能提出更好的解决方案。
dom-to-image 是一个很好的发现,因为我也可以将它与其他对象一起使用,例如图表。 感谢 Potemkin 的帮助,让我沿着这条路走下去。
这是使用 domtoimage 和文件保护程序的解决方案:
import { saveAs } from "file-saver";
import domtoimage from "dom-to-image";
domtoimage.toPng(myMapDomObject).then((myImage: string) => {
const commaPos = myImage.indexOf(",");
if (commaPos > 0) myImage = myImage.substring(commaPos + 1);
const byteArray = Util.encodeByteArray(myImage);
const blob = new Blob([byteArray], { type: "image/png" });
saveAs(blob, "mymap.png");
});
Util.encodeByteArray 方法是我自己的方法,用于将图像字符串转换为字节数组以创建可用于导出的 blob。 如果图像明显变大就会出现问题,尽管我从未发生过这种情况。 可能有更好的方法来做到这一点,我目前不知道。
export class Util {
static encodeByteArray(bytes: string) {
const byteCharacters = atob(bytes);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
return byteArray;
}
}
顺便说一句,我正在研究 Leaflet.browser.print 是如何工作的。 它似乎能够产生相同的结果并且是跨浏览器的,但仅提供打印功能。 如果我能弄清楚如何导出内部图像,那么在 GitHub 上对其代码的调查可能会提供更多跨浏览器的解决方案。
语气 说:
地图的底部和右侧应该用彩色的等值线区域覆盖到边缘:
我找到了解决这个问题的简单方法!
我希望这可以帮助你! 祝你好运。
尝试从地图中删除渲染器填充,然后导出。 它对我有用。
在你的情况下,类似的东西
myMap.getRenderer(myMap).options.padding = 0;
html2canvas(...
自从写这个问题以来,已经过去了一段时间。 最终对我有用的解决方案是购买 Telerik Reporting 并在其中实施我需要的任何映射解决方案。 这是一个非常好的选择并且一直对我有用,所以如果你有机会这样做,我强烈推荐它。 您还可以立即使用多种不同的文件格式,并且该解决方案看起来更加专业。 只是一个可以考虑的选择。
我最终使用了 dom-to-image 库,因为我将平铺图像裁剪到边界框,而传单图像没有使用 css clip 属性。
// Need an arrow function to preserve this context since this is being used as a callback.
private _maskTileLayer = (layer: TileLayer, bounds: LatLngBounds): void => {
const northWest = bounds.getNorthWest(); // top-left px latLng
const southEast = bounds.getSouthEast(); // bottom-right px latlng
const northWestPoint = this._map.latLngToLayerPoint(northWest);
const southEastPoint = this._map.latLngToLayerPoint(southEast);
const container = layer.getContainer();
container.style.position = 'absolute';
container.style.clip = `rect(${northWestPoint.y}px, ${southEastPoint.x}px, ${southEastPoint.y}px, ${northWestPoint.x}px)`;
};
我得到了一个更大的地图图像,里面有黑框。 我认为这是地图窗格的缓冲区。 即使使用
map.getRenderer(map as any).options.padding = 0;
没有为我工作。
我发现我必须设置图像宽度和高度选项以匹配地图容器客户端宽度/高度。
public mapAsJpegDataUrl(map: Map): Promise<string> {
const mapPane = map.getPane('mapPane');
const container = map.getContainer();
const width = container.clientWidth;
const height = container.clientHeight;
const dataUrl = domToImage.toJpeg(mapPane, { width, height });
return dataUrl;
}
这个库明显比传单图像慢,但它也做得更多。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.