【问题标题】:ngx-openlayer zoom to show all intesting pointsngx-openlayers 缩放以显示所有有趣的点
【发布时间】:2018-03-13 08:41:27
【问题描述】:

在我们的 Angular 5 项目中,我们包含了一个带有 ngx-openlayer 的 openstreetmap。 我有一张包含 POI 列表的地图。该列表可以按不同的标准进行过滤。我想更改缩放级别,以便显示列表中的所有 POI。

我发现我们可以使用

this.map.instance.getView().fit(extent1, this.map.instance.getSize());

这样做,但我无法获得正确的范围。

 <aol-map #map [width]="'100%'" [height]="'100%'">
    <aol-control-defaults></aol-control-defaults>
    <aol-control-scaleline></aol-control-scaleline>
    <aol-interaction-default></aol-interaction-default>
    <aol-interaction-select (onSelect)="onClick($event)"></aol-interaction-select>
    <aol-view #view [zoom]="zoom">
      <aol-coordinate [x]="centerlong" [y]="centerlat" [srid]="'EPSG:4326'"></aol-coordinate>
    </aol-view>
    <!-- aol-layer-tile  [postcompose]="onPostcompose" -->
    <aol-layer-tile>
      <aol-source-osm></aol-source-osm>
    </aol-layer-tile>
   <!-- List of POIs  --> 
    <aol-layer-vector [opacity]="1" (click)="onClick('Layer')">
      <aol-source-vector #source>
        <ng-container *ngFor="let item of api.datapoints">
          <aol-feature *ngIf="item.icon" [id]="item.uuid">
            <aol-geometry-point>
              <aol-coordinate [x]="item.longitude" [y]="item.latitude" [srid]="'EPSG:4326'"></aol-coordinate>
            </aol-geometry-point>
            <aol-style>
              <aol-style-icon [src]="'./assets/img/'+item.icon" [anchor]="[0.5, 1]" [anchorXUnits]="'fraction'"
                              [anchorYUnits]="'fraction'" [scale]="1" [anchorOrigin]="'top-left'"></aol-style-icon>
            </aol-style>
          </aol-feature>
        </ng-container>
      </aol-source-vector>
    </aol-layer-vector>
    <aol-overlay *ngIf="this.api.datapoints.length == 0">
      <aol-coordinate
        [x]="centerlong"
        [y]="centerlat"
        [srid]="'EPSG:4326'"
      >
      </aol-coordinate>
      <aol-content>
        <div class="alert alert-danger" i18n>No data points found!</div>
      </aol-content>
    </aol-overlay>
  </aol-map>

在 Typescript 上,我尝试在源 (extent1) 上获得所需的范围,但它给了我从 -infinity 到无穷大的范围。我还尝试从我的坐标中获取 minX、maxX、minY 和 maxY。 (范围)这将放大到中心。我认为这是我需要将我们的坐标从 EPSG:4326 转换为一些内部坐标的问题。但我该怎么做呢?

import {Component, OnInit, ViewChild} from '@angular/core';
import {ApiGatewayService} from '../../../service/apigateway.service';

@Component({
  selector: 'app-data-map',
  templateUrl: './data-map.component.html',
  styleUrls: ['./data-map.component.css']
})
export class DataMapComponent implements OnInit {

  @ViewChild('view') view: any;
  @ViewChild('map') map: any;
  @ViewChild('source') source: any;
  centerlong = 14.8;
  centerlat = 52.50;
  zoom = 7;


  constructor(public api: ApiGatewayService) {
  }


  ngOnInit() {
    console.log('MAP', this.view);
  }

  updateZoom() {
    if (this.api.datapoints.length > 1) {
      console.log("updateZoom")
      let minlong = 200;
      let maxlong = -200;
      let minlat = 100;
      let maxlat = -100;
      for (const item of this.api.datapoints) {
        console.log('Item', item);
        if (item.latitude < minlat) {
          minlat = item.latitude;
        }
        if (item.latitude > maxlat) {
          maxlat = item.latitude;
        }

        if (item.longitude < minlong) {
          minlong = item.longitude;
        }
        if (item.longitude > maxlong) {
          maxlong = item.longitude;
        }

        console.log('Box', minlat, minlong, maxlat, maxlong);
      }
      this.centerlong = (minlong + maxlong) / 2;
      this.centerlat = (minlat + maxlat) / 2;

      const extent = [minlong, minlat, maxlong, maxlat];
      if (this.map.instance) {
        var extent1 = this.source.instance.getExtent();
        console.log('Set zoom level', extent1);
        this.map.instance.getView().fit(extent1,
this.map.instance.getSize());
      }
    }
  }
}

看来我需要 ol.proj.transformExtent()。 但是如何从 ngx-openlayer 访问 ol.proj? 什么是目的地坐标系统来进行转换?

【问题讨论】:

    标签: angular openlayers openstreetmap


    【解决方案1】:

    我想我已经找到了解决办法。

    首先ngx-openlayer依赖于openlayer,所以我们也可以直接导入openlayer:

    import {proj} from 'openlayers';
    

    所以现在我们可以在需要调用 ol.proj 时调用 proj。

    Openstreetmap 使用的投影是 EPSG:3857。 为了将我的范围转移到这个坐标系统,我现在将调用

    const extent1 = proj.transformExtent(extent, 'EPSG:4326', 'EPSG:3857'); 
    

    整个打字稿作为参考:

    import {AfterViewInit, Component, OnDestroy, OnInit, ViewChild} from '@angular/core';
    import {MapEvent, proj} from 'openlayers';
    import {Subscription} from 'rxjs';
    import {ApiGatewayService} from '../../../service/apigateway.service';
    
    
    @Component({
      selector: 'app-data-map',
      templateUrl: './data-map.component.html',
      styleUrls: ['./data-map.component.css']
    })
    export class DataMapComponent implements OnInit, OnDestroy, AfterViewInit {
    
      subscription: Subscription;
      @ViewChild('map', {static: true}) map: any;
      centerlong = 10.447683;
      centerlat = 51.163375;
    
      datapoints = [];
      tempZoom = 0;
      zoom = 7;
    
    
      constructor(public api: ApiGatewayService) {
      }
    
      ngOnInit() {
        this.subscription = this.api.datapointsChanged
          .subscribe(item => {
            console.log('DataMapComponent::DatapointsChanged', item);
            this.datapoints = this.api.datapoints;
            this.updateZoom();
          });
        this.updateZoom();
      }
    
      ngOnDestroy() {
        if (this.subscription) {
          this.subscription.unsubscribe();
        }
      }
    
      onMoveEnd(e: MapEvent) {
        console.log('DataMapComponent::onMoveEnd::getZoom' + e.map.getView().getZoom());
        this.zoom = e.map.getView().getZoom();
        if (this.tempZoom > 0) {
          if (this.zoom > this.tempZoom) {
            const zoom = this.tempZoom;
            this.tempZoom = 0;
            this.zoom = zoom;
          }
        }
      }
    
      updateZoom() {
        console.log('DataMapComponent::updateZoom');
        if (this.api.datapoints.length > 0) {
          console.log('DataMapComponent::updateZoom::Lenght', this.api.datapoints.length);
          let minlong = 200;
          let maxlong = -200;
          let minlat = 100;
          let maxlat = -100;
          for (const item of this.api.datapoints) {
            if (this.useCoord(item.longitude, item.longitude)) {
              if (item.latitude < minlat) {
                minlat = item.latitude;
              }
              if (item.latitude > maxlat) {
                maxlat = item.latitude;
              }
    
              if (item.longitude < minlong) {
                minlong = item.longitude;
              }
              if (item.longitude > maxlong) {
                maxlong = item.longitude;
              }
            }
          }
          this.centerlong = (minlong + maxlong) / 2;
          this.centerlat = (minlat + maxlat) / 2;
    
          if (this.map.instance) {
            if (this.api.datapoints.length > 1) {
              const extent: [number, number, number, number] = [minlong, minlat, maxlong, maxlat];
              console.log('DataMapComponent::updateZoom::Extent1', extent);
    
              console.log('DataMapComponent::updateZoom::Map', this.map.instance);
              const extent1 = proj.transformExtent(extent, 'EPSG:4326', 'EPSG:3857');
              // var extent1 = this.source.instance.getExtent();
              console.log('DataMapComponent::updateZoom::Extent2', extent1);
              this.map.instance.getView().fit(extent1, this.map.instance.getSize());
              this.tempZoom = 10;
    
            } else {
              this.map.instance.getView().setCenter(proj.transform([this.centerlong, this.centerlat], 'EPSG:4326', 'EPSG:3857'));
              this.zoom = 10;
            }
          } else {
            console.log('DataMapComponent::updateZoom Map not ready!');
            setTimeout(_ => {
              this.updateZoom();
            }, 200);
          }
        }
      }
    
      useCoord(lat, long): boolean {
        const result = !Number.isNaN(Number(lat)) && !Number.isNaN(Number(long)) && (Number(lat) !== 0.0 || Number(long) !== 0.0);
        // console.log('DataDetailJobComponent::useCoord::lat,long,result', lat, Number.isNaN(lat), long, Number.isNaN(long), result);
        return result;
      }
    }
    

    在 html 代码上我们需要监听 onMoveEnd 事件

      <aol-map #map [width]="'100%'" [height]="'100%'" (onMoveEnd)="onMoveEnd($event)">
      <aol-control-defaults > </aol-control-defaults>
      <!-- [units]="'degrees', 'imperial', 'nautical', 'metric', 'us'" -->
      <aol-control-scaleline></aol-control-scaleline>
      <aol-interaction-default></aol-interaction-default>
      <aol-view [zoom]="zoom" [maxZoom]="20">
        <aol-coordinate [x]="centerlong" [y]="centerlat" [srid]="'EPSG:4326'"></aol-coordinate>
      </aol-view>
      <!-- aol-layer-tile  [postcompose]="onPostcompose" -->
      <aol-layer-tile [zIndex]="1">
        <aol-source-osm></aol-source-osm>
      </aol-layer-tile>
      <aol-layer-tile [zIndex]="2">
        <aol-source-osm ></aol-source-osm>
      </aol-layer-tile>
      <aol-layer-vector  [opacity]="1"  [zIndex]="3">
        <aol-source-vector>
          <ng-container *ngFor="let item of api.datapoints">
            <ng-container *ngIf="useCoord(item.latitude , item.longitude)">
              <aol-feature [id]="item.uuid">
                <aol-geometry-point>
                  <aol-coordinate [x]="item.longitude" [y]="item.latitude" [srid]="'EPSG:4326'"></aol-coordinate>
                </aol-geometry-point>
                <aol-style>
                  <aol-style-icon [src]="'./assets/img/'+item.icon" [anchor]="[0.5, 0.5]"
                                  [anchorXUnits]="'fraction'"
                                  [anchorYUnits]="'fraction'" [scale]="1" [anchorOrigin]="'top-left'">
                  </aol-style-icon>
                </aol-style>
              </aol-feature>
            </ng-container>
          </ng-container>
        </aol-source-vector>
      </aol-layer-vector>
    </aol-map>
    

    【讨论】:

    • @SatyaRam 是的,它有一些麻烦。我已经用我们的最新版本更新了我的答案。还有一点我需要提一下:该项目已有 2 年历史,我们使用 Angular 8 和 ngx-openlayewr 0.8.22。我不再从事那个项目,所以我不知道它是否适用于较新的环境。
    • 确认使用 angular 10 和 ngx-openlayers@1.0.0-next.16。这为我节省了很多时间。非常感谢;)
    猜你喜欢
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-25
    • 2013-01-27
    • 1970-01-01
    相关资源
    最近更新 更多