0

I'm running an Angular application that displays a map using Leaflet, and has a custom print where the user can set some options before sending a request to the ArcGIS Online print service (https://utility.arcgisonline.com/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export%20Web%20Map%20Task/execute). The issue is that the resultant exported map always appears stretched horizontally, so that a polygon that was square will be clearly rectangular. The entire map - basemap and all polygons - are all stretched the same amount, not just the polygons.

Here is the the code that builds the request:

let requestParams: any = {
  f: 'json',
  Web_Map_as_JSON: {
    "mapOptions":
      {
        "showAttribution": true,
        "extent": {
          "xmin": map.getBounds().getWest(),
          "ymin": map.getBounds().getSouth(),
          "xmax": map.getBounds().getEast(),
          "ymax": map.getBounds().getNorth(),
          "spatialReference": {"wkid": 4326}
        },
        "spatialReference": {"wkid": 4326},
      },
    "operationalLayers": this.getOperationalLayers(map),
    "exportOptions": {"dpi": printOption.printQualityDPI},
    "layoutOptions":
      {
        "titleText": printOption.title,
        "authorText": printOption.author,
        "copyrightText": printOption.copyright,
        "customTextElements": [{"Date": new DateTimePipe(this.userPreferencesService).transform(new Date())}],
        "legendOptions": {"operationalLayers": []}
      }
  },
  Format: printOption.format,
  Layout_Template: printOption.getParsedLayout(),
  printFlag: true
};

switch (printOption.scalebarUnit) {
  case 'Feet':
  case 'Meters':
    requestParams.Web_Map_as_JSON.layoutOptions.scaleBarOptions = {
      "metricUnit": "esriMeters", "metricLabel": "m", "nonMetricUnit": "esriFeet", "nonMetricLabel": "ft"
    };
    break;
  case 'Kilometers':
  case 'Miles':
  default:
    requestParams.Web_Map_as_JSON.layoutOptions.scaleBarOptions = {
      "metricUnit": "esriKilometers", "metricLabel": "km", "nonMetricUnit": "esriMiles", "nonMetricLabel": "mi"
    };
    break;
}

switch (printOption.preserveOpt) {
  case 'extent':
    // don't do anything. We always set the extent as all options require it (scale uses the center)
    break;
  case 'forceScale':
    requestParams.Web_Map_as_JSON.mapOptions.scale = printOption.forceScaleValue;
    break;
  case 'scale':
  default:
    requestParams.Web_Map_as_JSON.mapOptions.scale = MapUtil.SCALE_ZOOM_LEVEL_MAP[map.getZoom() + 3];
    break;
}

if (requestParams.Layout_Template == 'MAP_ONLY') {
  if (printOption.mapOnlyWidth && printOption.mapOnlyHeight) {
    requestParams.Web_Map_as_JSON.exportOptions.outputSize = [printOption.mapOnlyWidth, printOption.mapOnlyHeight];
  } else {
    requestParams.Web_Map_as_JSON.exportOptions.outputSize = [map.getContainer().clientWidth, map.getContainer().clientHeight];
  }
}

The code that builds the operational layers is as follows:

  getOperationalLayers(map) {
let pointLayerSpec = {
  "layerDefinition": {
    "name": "pointLayer",
    "geometryType": "esriGeometryPoint",
    "drawingInfo": {
      "renderer": {
        "type": "simple",
        "symbol": {
          "type": "esriPMS",
          // The following is the map pin icon, converted first to a PNG then to base64. Map Print hates SVG.
          "imageData": "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAABwlBMVEUAAAAAAAAAAABAQEAzMzMrKyskJCQgICBAQEA5OTkzMzMuLi4rKysnJyc3NzcrKysoKCgxMTEuLi4zMzMvLy8uLi4zMzMwMDAtLS0zMzMyMjIvLy8uLi4yMjIxMTEvLy8uLi4tLS0yMjIxMTEwMDAvLy8uLi4yMjIxMTEwMDAvLy8uLi4uLi4yLi4xLS0xMTEwMDA0MDAvLy8uLi4yMjI2LjJBMTVFMTVILjVIMTlTLThRMDtPLzlOKzVRLjVcLjxQLTRULThXLThbLTtTLTdaLTtYLDpmLT1rLD9vK0F3LEGQKUiRKUeWK0mXKkiYKkqbKUqrKU2uKU+6JlG8JlG8JVC+JVLEJVLFJVPFJlTIJlTKJVXJJVTMJFTOJFXPJVbRJFbSJlbTJVfUJVjVJFfXJFbXI1fZI1ffJFneIljfJFjeI1jgI1rgI1ngJFniJFriJFriI1nkI1vlJFvnI1vpJFzrIlvsIlzuIl3uIlzvI13vI13wI17xI17yI17yI17yIl3yIl7yIl3yI13zIl7zIl30Il7zI170I1/1I171Il72Il/2I1/1Il72Il/2Il72Il73Il/4Il/4Il/4Il/////ycNrEAAAAlHRSTlMAAQIEBQYHCAgJCgsMDQ4SExUWGRscHiAiIyQmJykqKywtLi8wMTIzNDU2Nzg4OTk6Ozw9PT0/Q0NDREVHSEhISUlJSUpKS1BRU1ZjZGZnaGt3d4WIiYmPkJKVlpianKCho6SmqKutrbe5uby8vb/AwcLEx8zQ19re4ODh5OXm5+nq6+zt7vHy8vP09ff4+Pn7/f3+W5jqtQAAAAFiS0dElQhgeoMAAAGASURBVBgZfcGLO1NhAAfgn9lWwyZJK81t1rIZlrt0cSukdKGrUnRxydwiJo5UVkqK/f7gvvM9Ht85Z5v3hYGjqDJSXx8JnHEgHXtx21BsPfFT+/jkxrlspPDUPdrioR/Pa3JhkdM6TYPJZhdMbFUxmkyFs2HkHabF0HkY2K98o6TNz2uUvrY7oBQ+pi450uT3N71IUjdcCKVigbpXATvguDhO3VwZlGqNQqLNCcHZ/Y/CxiUojXsUloKQgmsU/lRDafhNYbkKUmiDwq8wlNAKhd2bbgju20kKn/xQfBPUzdS4AU/tInVvvVBO3af0oTca7Y1RuuuGknV5ndLB5uYBpc8hGBWP0uLlWRjl3dqhyU6XEyblb2gydgFmnv6/NNjrc8EiME6D12Wwyuvc5pHv13OQouQZjzz1IZWrJc5Dqy0nkYb33j6l/UEv0rGF31N6F7EhrfyeLxS0qwXIoPwhhQeVyMQenSNnG04go9Md8fi1IhzDd2egBMfJKi21weQ/SGPVKkttvyQAAAAASUVORK5CYII=",
          "contentType": "image/png",
          "width": 16,
          "height": 16
        }
      }
    }
  },
  "featureSet": {"features": []}
};
let polygonLayerSpec = {
  "layerDefinition": {
    "name": "polygonLayer",
    "geometryType": "esriGeometryPolygon",
    "drawingInfo": {
      "renderer": {
        "type": "simple",
        "symbol": {
          "type": "esriSFS",
          "color": MapUtil.PRINT_FILL_COLOR,
          "outline": {"color": MapUtil.PRINT_LINE_COLOR, "width": 1}
        }
      }
    }
  },
  "featureSet": {"features": []}
};
let lineLayerSpec = {
  "layerDefinition": {
    "name": "lineLayer",
    "geometryType": "esriGeometryPolyline",
    "drawingInfo": {
      "renderer": {
        "type": "simple",
        "symbol": {
          "type": "esriSLS",
          "color": MapUtil.PRINT_LINE_COLOR,
          "width": 1
        }
      }
    }
  },
  "featureSet": {"features": []}
};
let layers = [pointLayerSpec, polygonLayerSpec, lineLayerSpec];

let addPointFeature = (geoJSON) => {
  pointLayerSpec.featureSet.features.push({
    "geometry": {
      "x": geoJSON.geometry.coordinates[0],
      "y": geoJSON.geometry.coordinates[1],
      "spatialReference": {
        "wkid": 4326
      }
    }
  });
};
let addPolygonFeature = (geoJSON) => {
  polygonLayerSpec.featureSet.features.push({
    "geometry": {
      "rings": geoJSON.geometry.coordinates,
      "hasZ": false,
      "hasM": false,
      "spatialReference": {
        "wkid": 4326
      }
    }
  });
};
let addMultiPolygonFeature = (geoJSON) => {
  geoJSON.geometry.coordinates.forEach(coordinates => {
    polygonLayerSpec.featureSet.features.push({
      "geometry": {
        "rings": coordinates,
        "hasZ": false,
        "hasM": false,
        "spatialReference": {
          "wkid": 4326
        }
      }
    });
  });
};
let addLineFeature = (geoJSON) => {
  lineLayerSpec.featureSet.features.push({
    "geometry": {
      "paths": geoJSON.geometry.coordinates,
      "hasZ": false,
      "hasM": false,
      "spatialReference": {
        "wkid": 4326
      }
    }
  });
};
let addFeature = (geoJSON) => {
  if (geoJSON.geometry.type === "Point") {
    addPointFeature(geoJSON);
  } else if (geoJSON.geometry.type === "Polygon") {
    addPolygonFeature(geoJSON);
  } else if (geoJSON.geometry.type === "MultiPolygon") {
    addMultiPolygonFeature(geoJSON);
  } else if (geoJSON.geometry.type === "LineString" || geoJSON.geometry.type === "MultiLineString") {
    addLineFeature(geoJSON);
  }
};

map.eachLayer((layer) => {
  if (layer.toGeoJSON) {
    let geoJSON = layer.toGeoJSON();
    if (geoJSON.type === "Feature") {
      addFeature(geoJSON);
    } else if (geoJSON.type === "FeatureCollection") {
      _.forEach(geoJSON.features, (geoJSONFeature) => {
        addFeature(geoJSONFeature);
      });
    }
  }
});
return [
  {
    "id": "defaultBasemap",
    "title": "World Topographic Map",
    "opacity": 1,
    "minScale": 0,
    "maxScale": 0,
    "url": "https://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"
  },
  {
    "id": "map_graphics",
    "featureCollection": {
      "layers": layers
    }
  }
];
}

I don't think there's anything wrong with the request, but every single time the map is exported it is stretched. Is there something I need to be doing to the leaflet map before this stage to prevent the stretching? I'm pretty new to these plugins, I don't know where to start.

Map as viewed in app

Map as viewed in export

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.