Angular ArcGIS esri-loader 中的 geographicToWebMercator 和投影多边形

geographicToWebMercator and Projected polygon in Angular ArcGIS esri-loader

如何使用 'geographicToWebMercator' in Angular 10 绘制具有环值的多边形。我指的是文档中提供的示例, https://developers.arcgis.com/documentation/core-concepts/features-and-geometries/#polygons 并尝试将 Angular 中的功能与 ArcGIS esri-loader 一起使用。 这是我所指的文档。 https://developers.arcgis.com/javascript/latest/guide/angular/

我试图获取投影的多边形点。但是 returns 错误的值。

import {
  Component,
  OnInit,
  ViewChild,
  ElementRef,
  Input,
  Output,
  EventEmitter,
  OnDestroy,
} from '@angular/core';
import { loadModules } from 'esri-loader';
import esri = __esri; // Esri TypeScript Types
import { empty } from 'rxjs';

@Component({
  selector: 'app-esri-map',
  templateUrl: './esri-map.component.html',
  styleUrls: ['./esri-map.component.css'],
})
export class EsriMapComponent implements OnInit, OnDestroy {
  @Output() mapLoadedEvent = new EventEmitter<boolean>();

  @ViewChild('mapViewNode', { static: true }) private mapViewEl: ElementRef;

  /**
   * _zoom sets map zoom
   * _center sets map center
   * _basemap sets type of map
   * _loaded provides map loaded status
   */
  private _zoom = 20;

  private _basemap = 'hybrid';
  private _loaded = false;
  private _view: esri.MapView = null;
  private _nextBasemap = 'streets';

  get mapLoaded(): boolean {
    return this._loaded;
  }

  @Input()
  set zoom(zoom: number) {
    this._zoom = zoom;
  }

  get zoom(): number {
    return this._zoom;
  }

  @Input()
  set basemap(basemap: string) {
    this._basemap = basemap;
  }

  get basemap(): string {
    return this._basemap;
  }

  @Input()
  set nextBasemap(nextBasemap: string) {
    this._nextBasemap = nextBasemap;
  }

  get nextBasemap(): string {
    return this._nextBasemap;
  }

  constructor() {}

  async getProjectedpolygon(params: any) {
    const [GeometryService] = await loadModules(['esri/tasks/GeometryService']);

    console.log(`input polygon: ${JSON.stringify(params.toJSON())}`);

    const geomSer = new GeometryService(
      'http://sampleserver6.arcgisonline.com/arcgis/rest/services/Utilities/Geometry/GeometryServer'
    );
    geomSer.project(params).then(function (result) {
      const projectedPoly = result[0];

      if (!projectedPoly) {
        return;
      }

      console.log(
        `Projected Polygon: ${JSON.stringify(projectedPoly.toJSON())}`
      );
      // return projectedPoly;
    });
  }

  async initializeMap() {
    try {
      // Load the modules for the ArcGIS API for JavaScript
      const [
        EsriMap,
        EsriMapView,
        FeatureLayer,
        BasemapToggle,
        BasemapGallery,
        webMercatorUtils,
        Polygon,
        Graphic,
        SimpleFillSymbol,
        GeometryService,
        ProjectParameters,
        SpatialReference,
      ] = await loadModules([
        'esri/Map',
        'esri/views/MapView',
        'esri/layers/FeatureLayer',
        'esri/widgets/BasemapToggle',
        'esri/widgets/BasemapGallery',
        'esri/geometry/support/webMercatorUtils',
        'esri/geometry/Polygon',
        'esri/Graphic',
        'esri/symbols/SimpleFillSymbol',
        'esri/tasks/GeometryService',
        'esri/tasks/support/ProjectParameters',
        'esri/geometry/SpatialReference',
      ]);

      const poly = Polygon.fromJSON({
        rings: [
          [
            [2755899.9999897182, 542357.7692040652],
            [2755880.0069194734, 542356.78593830764],
            [2755881.7250918895, 542323.36310489476],
            [2755825.535899803, 542319.92347922921],
            [2755846.6395321339, 541826.4208573103],
            [2755848.0673508048, 541783.2063768059],
            [2755849.6063897163, 541736.63199488819],
            [2755853.2533640563, 541637.62366272509],
            [2755853.747457549, 541624.21063180268],
            [2755844.9098768085, 541604.88324263692],
            [2755840.0076556355, 541604.63127464056],
            [2755840.858703807, 541584.26386131346],
            [2755696.7467873096, 541576.85377115011],
            [2755695.3304515481, 541630.02623698115],
            [2755695.2727088928, 541632.78771439195],
            [2755693.2822273076, 541727.9331934005],
            [2755692.2743553072, 541778.09352613986],
            [2755691.192008391, 541827.82735055685],
            [2755685.6582268029, 542074.87574097514],
            [2755683.43447797, 542124.91665139794],
            [2755676.4262898862, 542274.51674589515],
            [2755689.3068415523, 542275.07809647918],
            [2755688.1060565561, 542301.07771639526],
            [2755718.8845383078, 542345.19869114459],
            [2755808.4171676338, 542473.54521922767],
            [2755824.3219914734, 542498.22528797388],
            [2755834.2757117152, 542498.80697973073],
            [2755854.8573634773, 542526.09924797714],
            [2755868.594868809, 542578.80485123396],
            [2755868.6171784699, 542578.83765955269],
            [2755899.9999897182, 542624.7959009707],
            [2755920.8641212136, 542655.35030181706],
            [2756017.1844666302, 542660.17968848348],
            [2756013.8029117137, 542710.30819714069],
            [2756010.1959635466, 542763.77626605332],
            [2755899.9999897182, 542757.74018889666],
            [2755858.8612924665, 542755.48691256344],
            [2755856.16346322, 542804.39462314546],
            [2755899.9999897182, 542806.61312264204],
            [2756006.9410488009, 542812.02584147453],
            [2756021.3320961446, 542812.82603672147],
            [2756073.078383714, 542815.70299947262],
            [2756156.5181774646, 542820.34242589772],
            [2756161.6395583004, 542717.00962731242],
            [2756171.2474787235, 542523.15535622835],
            [2756053.1381348819, 542512.12617881596],
            [2756041.1913083941, 542508.49495247006],
            [2756026.1532807201, 542503.48676039279],
            [2756011.1966177225, 542498.69838413596],
            [2755984.824951306, 542480.93496823311],
            [2755968.4503121376, 542464.29556581378],
            [2755964.7866055518, 542457.93402998149],
            [2755936.9047715515, 542405.95185047388],
            [2755918.0816464722, 542358.65863797069],
            [2755899.9999897182, 542357.7692040652],
          ],
        ],
        spatialReference: {
          wkid: 102704,
        },
      });

      const geomSer = new GeometryService(
        'http://sampleserver6.arcgisonline.com/arcgis/rest/services/Utilities/Geometry/GeometryServer'
      );

      const outSpatialReference = new SpatialReference({ wkid: 102704 });

      const params = new ProjectParameters({
        geometries: [poly],
        outSpatialReference,
      });

      // let geomser = await geomSer.project(params);
      let geomser = await Promise.all([this.getProjectedpolygon(params)]);
      console.log(geomser);

      // Configure the Map
      const mapProperties: esri.MapProperties = {
        basemap: this._basemap,
      };

      const map: esri.Map = new EsriMap(mapProperties);

      // Initialize the MapView
      const mapViewProperties: esri.MapViewProperties = {
        container: this.mapViewEl.nativeElement,
        // center: this._center,
        zoom: this._zoom,
        map: map,
        extent: webMercatorUtils.geographicToWebMercator(
          poly.extent.clone().expand(3)
        ),
      };

      this._view = new EsriMapView(mapViewProperties);

      // this._view.graphics.add(graphic);

      await this._view.when();
      return this._view;
    } catch (error) {
      console.log('EsriLoader: ', error);
    }
  }

  ngOnInit() {
    this.initializeMap().then((mapView) => {
      console.log('mapView ready: ', this._view.ready);
      this._loaded = this._view.ready;
      this.mapLoadedEvent.emit(true);
    });
  }

  ngOnDestroy() {
    if (this._view) {
      this._view.container = null;
    }
  }
}

/更新代码*****/

  import {
  Component,
  OnInit,
  ViewChild,
  ElementRef,
  Input,
  Output,
  EventEmitter,
  OnDestroy,
} from '@angular/core';
import { loadModules } from 'esri-loader';
import esri = __esri; // Esri TypeScript Types
import { empty } from 'rxjs';
import { __asyncValues } from 'tslib';

@Component({
  selector: 'app-esri-map',
  templateUrl: './esri-map.component.html',
  styleUrls: ['./esri-map.component.css'],
})
export class EsriMapComponent implements OnInit, OnDestroy {
  // The <div> where we will place the map
  @ViewChild('mapViewNode', { static: true }) private mapViewEl: ElementRef;
  // view: any;

  // to keep loaded esri modules
  esriModules = {
    geometry: {
      Polygon: null,
      SpatialReference: null,
      support: { webMercatorUtils: null },
    },
    tasks: {
      GeometryService: null,
      support: { ProjectParameters: null },
    },
  };
  private _zoom = 20;
  private _center: Array<number> = [-95.937187, 41.258652];
  private _basemap = 'hybrid';
  private _loaded = false;
  private _view: esri.MapView = null;
  private _nextBasemap = 'streets';
  public _selectedLayer: Array<string>;

  public onLayerChange(val: Array<string>) {
    this._selectedLayer = val;
    this.initializeMap();
  }

  constructor() {}

  async initializeMap() {
    try {
      // Load the modules for the ArcGIS API for JavaScript
      const [
        EsriMap,
        EsriMapView,
        Polygon,
        SpatialReference,
        webMercatorUtils,
        GeometryService,
        ProjectParameters,
      ] = await loadModules([
        'esri/Map',
        'esri/views/MapView',
        'esri/geometry/Polygon',
        'esri/geometry/SpatialReference',
        'esri/geometry/support/webMercatorUtils',
        'esri/tasks/GeometryService',
        'esri/tasks/support/ProjectParameters',
      ]);

      // save the modules on a property for later
      this.esriModules.geometry.Polygon = Polygon;
      this.esriModules.geometry.SpatialReference = SpatialReference;
      this.esriModules.geometry.support.webMercatorUtils = webMercatorUtils;
      this.esriModules.tasks.GeometryService = GeometryService;
      this.esriModules.tasks.support.ProjectParameters = ProjectParameters;

      // Configure the Map
      const mapProperties: esri.MapProperties = {
        basemap: this._basemap,
      };

      const map: esri.Map = new EsriMap(mapProperties);

      // Initialize the MapView
      const mapViewProperties: esri.MapViewProperties = {
        container: this.mapViewEl.nativeElement,
        center: this._center,
        zoom: this._zoom,
        map: map,
      };

      this._view = new EsriMapView(mapViewProperties);

      // const map = new Map(mapProperties);

      // Initialize the MapView
      // const mapViewProperties = {
      //   container: this.mapViewEl.nativeElement,
      //   map,
      // };

      // this.view = new MapView(mapViewProperties);
      // this._view = new EsriMapView(mapViewProperties);

      await this._view.when();
      return this._view;
    } catch (error) {
      console.error('EsriLoader: ', error);
    }
  }

  // be carefull does not handle point geometries
  // point geometry extent is null
  public zoomToGeometry(geom) {
    console.log('in zoomToGeometry');

    console.log(`Original Geometry: ${JSON.stringify(geom.toJSON())}`);

    const geomSer = new this.esriModules.tasks.GeometryService(
      'http://sampleserver6.arcgisonline.com/arcgis/rest/services/Utilities/Geometry/GeometryServer'
    );

    const outSpatialReference = new this.esriModules.geometry.SpatialReference({
      wkid: 102100,
    });

    const params = new this.esriModules.tasks.support.ProjectParameters({
      geometries: [geom],
      outSpatialReference,
    });

    geomSer.project(params).then(function (result) {
      const projectedGeom = result[0];

      if (!projectedGeom) {
        console.log('projection geom');

        return;
      }

      console.log(
        `Projected Geometry: ${JSON.stringify(projectedGeom.toJSON())}`
      );

      this._view.extent = projectedGeom.extent.clone().expand(3);
    });
  }

  ngOnInit() {
    this.initializeMap();

    const geom = new this.esriModules.geometry.Polygon({
      spatialReference: {
        wkid: 102704,
      },
      rings: [
        [
          [2744913.4668447226, 541568.06113781035],
          [2744917.4038447142, 541499.65215389431],
          [2744864.2454864681, 541496.82210706174],
          [2744813.6648789644, 541494.12952713668],
          [2744810.2104895562, 541563.64283956587],
          [2744860.4905727208, 541565.79441006482],
          [2744913.4668447226, 541568.06113781035],
        ],
      ],
    });

    this.zoomToGeometry(geom);
  }

  ngOnDestroy() {
    if (this._view) {
      // destroy the map view
      this._view.container = null;
    }
  }
}

首先是让您获得 esri-loader 和 angular 协同工作的基本示例。如果您还没有,请查看文档,在指南部分 (ArcGIS Guide - Angular) 中有几个简单的示例可以开始。

现在,你有了一个基本的例子,你只需要加载 webMercatorUtils 模块并使用它。使用 ArcGIS Guide 中的示例作为基础,您可以执行如下操作,

import { Component, OnInit, OnDestroy, ViewChild, ElementRef } from "@angular/core";
import { loadModules } from "esri-loader";

@Component({
  selector: "app-esri-map",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.scss"]
})
export class MapComponent implements OnInit, OnDestroy {
  // The <div> where we will place the map
  @ViewChild("mapViewNode", { static: true }) private mapViewEl: ElementRef;
  view: any;

  constructor() {}

  async initializeMap() {
    try {
      // Load the modules for the ArcGIS API for JavaScript
      const [Map, MapView, webMercatorUtils, Polygon] = await loadModules(["esri/Map", "esri/views/MapView", "esri/geometry/support/webMercatorUtils", "esri/geometry/Polygon"]);

      // now do your thing with the modules
      // or save the modules on a property for later
      
      // btw, this json is from the link of the question
      // I am gonna use it for the initial extent
      const poly = Polygon.fromJSON({
        "rings":[
          [
            [ -118.38516, 34.01270 ],
            [ -118.38827, 34.01489 ],
            [ -118.38813, 34.01602 ],
            [ -118.38797, 34.01648 ],
            [ -118.38760, 34.01712 ],
            [ -118.38733, 34.01696 ],
            [ -118.38696, 34.01749 ],
            [ -118.38662, 34.01789 ],
            [ -118.38689, 34.01805 ],
            [ -118.38683, 34.01812 ],
            [ -118.38295, 34.01592 ],
            [ -118.38516, 34.01270 ]
          ],
          [
            [ -118.38661, 34.01486 ],
            [ -118.38634, 34.01498 ],
            [ -118.38652, 34.01563 ],
            [ -118.38670, 34.01559 ],
            [ -118.38679, 34.01595 ],
            [ -118.38699, 34.01591 ],
            [ -118.38707, 34.01507 ],
            [ -118.38661, 34.01486 ]
          ]
        ],
        "spatialReference": {
          "wkid": 4326
        }
      });
      const extent = webMercatorUtils.geographicToWebMercator(
        // you need to clone the polygon extent because is readonly
        // besides why would you change it
        poly.extent.clone().expand(3)
      );

      // Configure the Map
      const mapProperties = {
        basemap: "streets-vector"
      };

      const map = new Map(mapProperties);

      // Initialize the MapView
      const mapViewProperties = {
        container: this.mapViewEl.nativeElement,
        extent, // use extent
        map
      };

      this.view = new MapView(mapViewProperties);
      await this.view.when(); // wait for map to load
      return this.view;
    } catch (error) {
      console.error("EsriLoader: ", error);
    }
  }

  ngOnInit() {
    this.initializeMap();
  }

  ngOnDestroy() {
    if (this.view) {
      // destroy the map view
      this.view.container = null;
    }
  }
}

更新

这里是前面的示例,并进行了一些更改以帮助您理解或处理您的案例。您会看到我将加载的模块保存在组件的 属性 中。那我以后就用了。

import { Component, OnInit, OnDestroy, ViewChild, ElementRef } from "@angular/core";
import { loadModules } from "esri-loader";

@Component({
  selector: 'app-esri-map',
  templateUrl: './esri-map.component.html',
  styleUrls: ['./esri-map.component.scss']
})
export class EsriMapComponent implements OnInit, OnDestroy {

  @ViewChild("mapViewNode", { static: true }) private mapViewEl: ElementRef;
  view: any;

  // to keep loaded esri modules
  esriModules = {
    geometry: {
      Polygon: null,
      SpatialReference: null,
      support: { webMercatorUtils: null }
    },
    tasks: {
      GeometryService: null,
      support: { ProjectParameters: null }
    }
  };

  constructor() {}

  async initializeMap() {
    try {
      // Load the modules for the ArcGIS API for JavaScript
      const [
        Map,
        MapView,
        Polygon,
        SpatialReference,
        webMercatorUtils,
        GeometryService,
        ProjectParameters
      ] = await loadModules([
        "esri/Map",
        "esri/views/MapView",
        "esri/geometry/Polygon",
        "esri/geometry/SpatialReference",
        "esri/geometry/support/webMercatorUtils",
        "esri/tasks/GeometryService",
        "esri/tasks/support/ProjectParameters"
      ]);

      // save the modules on a property for later
      this.esriModules.geometry.Polygon = Polygon;
      this.esriModules.geometry.SpatialReference = SpatialReference;
      this.esriModules.geometry.support.webMercatorUtils = webMercatorUtils;
      this.esriModules.tasks.GeometryService = GeometryService;
      this.esriModules.tasks.support.ProjectParameters = ProjectParameters;

      // Configure the Map
      const mapProperties = {
        basemap: "streets"
      };

      const map = new Map(mapProperties);

      // Initialize the MapView
      const mapViewProperties = {
        container: this.mapViewEl.nativeElement,
        map
      };

      this.view = new MapView(mapViewProperties);
      await this.view.when(); // wait for map to load
      return this.view;
    } catch (error) {
      console.error("EsriLoader: ", error);
    }
  }

  // be carefull does not handle point geometries
  // point geometry extent is null
  zoomToGeometry(geom) {
    console.log(`Original Geometry: ${JSON.stringify(geom.toJSON())}`);

    const geomSer = new this.esriModules.tasks.GeometryService(
      "http://sampleserver6.arcgisonline.com/arcgis/rest/services/Utilities/Geometry/GeometryServer"
    );

    const outSpatialReference = new this.esriModules.geometry.SpatialReference({ wkid: 102100 });

    const params = new this.esriModules.tasks.support.ProjectParameters({
      geometries: [geom],
      outSpatialReference
    });

    const self = this;

    geomSer.project(params).then(function(result) {
      const projectedGeom = result[0];

      if (!projectedGeom) {
        return;
      }

      console.log(`Projected Geometry: ${JSON.stringify(projectedGeom.toJSON())}`);

      self.view.extent = projectedGeom.extent.clone().expand(3);

    });
  }

  ngOnInit() {
    this.initializeMap().then(_ => {
      // The map has been initialized
      console.log("mapView ready: ", this.view.ready);
      const geom = new this.esriModules.geometry.Polygon({
        spatialReference: {
          wkid: 102704
        },
        rings: [
          [
            [
              2744913.4668447226,
              541568.06113781035
            ],
            [
              2744917.4038447142,
              541499.65215389431
            ],
            [
              2744864.2454864681,
              541496.82210706174
            ],
            [
              2744813.6648789644,
              541494.12952713668
            ],
            [
              2744810.2104895562,
              541563.64283956587
            ],
            [
              2744860.4905727208,
              541565.79441006482
            ],
            [
              2744913.4668447226,
              541568.06113781035
            ]
          ]
        ]
      });

      this.zoomToGeometry(geom);
    });
  }

  ngOnDestroy() {
    if (this.view) {
      // destroy the map view
      this.view.container = null;
    }
  }

}

在代码中,我将加载的模块保存在 属性 esriModules 中。为了跟踪模块名称,我决定使用 来构造对象值。例如几何模块的Polygonclass,路径esri/geometry/Polygon,是通过this.esriModules.geometry.Polygon.

访问的