在 typescript Angular 4 中将传单地图导出为 JPG

问题描述 投票:0回答:2

我正在制作一个带有传单地图的 Angular4 应用程序,我需要将地图的当前视图导出到一张 JPG 图像中。 就像截屏一样,但只是带有标记和折线的地图。

因此,首先我将标记和折线放入传单地图中,然后我必须按下一个按钮,将当前视图(包括标记和折线)导出为 JPG 或 PNG 图像,然后询问我将图像保存在哪里。

有什么办法可以做到吗? 我可以使用一些插件吗?

请帮忙

angular typescript leaflet screenshot export-to-image
2个回答
3
投票

这是一个粗略的实现,替换成你自己的相关代码。

最后一个函数

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");
}

0
投票

有同样的问题,但由于 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> 
© www.soinside.com 2019 - 2024. All rights reserved.