我正在制作一个带有传单地图的 Angular4 应用程序,我需要将地图的当前视图导出到一张 JPG 图像中。 就像截屏一样,但只是带有标记和折线的地图。
因此,首先我将标记和折线放入传单地图中,然后我必须按下一个按钮,将当前视图(包括标记和折线)导出为 JPG 或 PNG 图像,然后询问我将图像保存在哪里。
有什么办法可以做到吗? 我可以使用一些插件吗?
请帮忙
这是一个粗略的实现,替换成你自己的相关代码。
最后一个函数
saveSvgAsPng()
来自这个库https://github.com/exupero/saveSvgAsPng,它允许您将<svg>
元素保存到PNG或数据url中
function convertToPng() {
const mapContainerRect = yourLeafletMapInstance.getContainer().getBoundingClientRect();
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
const mapTiles = document.querySelectorAll('classe-of-map-tile-image');
const markers = document.querySelectorAll('classe-of-marker');
const polylines = document.querySelectorAll('polyline-element-class');
svg.setAttribute('width', mapContainerRect.width;
svg.setAttribute('height', mapContainerRect.height);
mapTiles.forEach(tile => {
const image = document.createElementNS('http://www.w3.org/2000/svg', 'image');
const tileRect = tile.getBoundingClientRect();
image.setAttribute('width', tileRect.width);
image.setAttribute('height', tileRect.height);
image.setAttribute('x', tileRect.left - mapContainerRect.left);
image.setAttribute('y', tileRect.top - mapContainerRect.top);
image.setAttribute('xlink:href', tile.src);
svg.appendChild(image);
});
markers.forEach(marker => {
const image = document.createElementNS('http://www.w3.org/2000/svg', 'image');
const markerRect = marker.getBoundingClientRect();
image.setAttribute('width', markerRect.width);
image.setAttribute('height', markerRect.height);
image.setAttribute('x', markerRect.left - mapContainerRect.left);
image.setAttribute('y', markerRect.top - mapContainerRect.top);
image.setAttribute('xlink:href', marker.src);
svg.appendChild(image);
});
polylines.forEach(polyline => {
const copy = polyline.cloneNode();
svg.appendChild(copy);
});
saveSvgAsPng(svg, "map.png");
}
有同样的问题,但由于 html5 字体下载和处理,使用一些库将 dom 节点转换为图像会造成严重的性能损失。
我需要调整上面@Trash Can 的出色工作。我的用例还将最终的 png 作为 blob 上传。
// Save the map as a png image
async mapToBlob() {
let defaultNameSpace = 'http://www.w3.org/2000/svg';
let xlinkNameSpace = 'http://www.w3.org/1999/xlink';
let mapContainerRect = this.map.getContainer().getBoundingClientRect();
var svg = document.createElementNS(defaultNameSpace,'svg');
svg.setAttribute('height',mapContainerRect.height);
svg.setAttribute('width',mapContainerRect.width);
svg.setAttribute('id','svgMap');
svg.setAttributeNS(xlinkNameSpace, "xlink:href", "link")
let mapTiles = document.querySelectorAll('.leaflet-tile-loaded');
let markers = document.querySelectorAll('.leaflet-marker-icon');
mapTiles.forEach((tile, index) => {
const image = document.createElementNS(defaultNameSpace, 'image');
const tileRect = tile.getBoundingClientRect();
image.setAttribute('width', tileRect.width.toString());
image.setAttribute('height', tileRect.width.toString());
image.setAttribute('x', (tileRect.left - mapContainerRect.left).toString());
image.setAttribute('y', (tileRect.top - mapContainerRect.top).toString());
image.setAttributeNS(xlinkNameSpace, 'href', (tile as any)?.src);
svg.appendChild(image);
});
markers.forEach(marker => {
const image = document.createElementNS(defaultNameSpace, 'image');
const markerRect = marker.getBoundingClientRect();
image.setAttribute('width', markerRect.width.toString());
image.setAttribute('height', markerRect.height.toString());
image.setAttribute('x', (markerRect.left - mapContainerRect.left).toString());
image.setAttribute('y', (markerRect.top - mapContainerRect.top).toString());
image.setAttributeNS(xlinkNameSpace, 'href',(marker as any)?.src);
svg.appendChild(image);
});
// Hide the live map, and replace it with the SVG we want to render
this.hideLiveMap = true;
// Actually add the svg to the form (useful for debugging to see we have output)
let form = document.querySelector('#dataForm');
form.appendChild(svg);
// Create an element for the conversion library to generate png from
let svgElement = document.querySelector("#svgMap");
//await saveSvgAsPng(svgElement, "test.png");
let data = await svgAsPngUri(svgElement);
//console.log("data", data);
return data;
}
...
async save(form: NgForm) {
let pngData = await this.mapToBlob();
fetch(pngData)
.then(res => res.blob())
.then(async blob => {
...
<form (ngSubmit)="save(dataForm)" #dataForm="ngForm" class="sign_in_form" id="dataForm">
<div class="input_element" [class.hide]="viewOnly">
<div class="search_box">
<i class="fa-solid fa-magnifying-glass"></i>
<input type="text" (focus)="searchTextControlFocussed()"
#searchTextControl placeholder="Search..."
data-test-id="location-selector-search-text-input">
</div>
<div class="results-chooser" >
<div class="results-chooser-dropdown" [class.hide]="!osmSearchResults?.length || hideSearchResults"
data-test-id="location-selector-search-results">
<a *ngFor="let result of osmSearchResults; let i = index" (click)="searchResultClicked(result)" [attr.data-test-id]="'location-selector-search-result-' + i">
{{result.display_name}}
</a>
</div>
</div>
</div>
<div class="map"
leaflet
#mapContainer
[style.display]="hideLiveMap ? 'none' : 'block'"
[style.opacity]="busy? 0.5 : 1"
[(leafletCenter)]="leafletCenter"
[leafletOptions]="options"
(leafletClick)="mapClicked($event)"
(leafletMouseDown)="mapMouseDown()"
(leafletMapReady)="onMapReady($event)">
</div>
</form>