如何设置一个google.maps.OverlayView?(将JS原型翻译成Typescript)



我想创建一个像这样工作的谷歌地图组件:https://jsfiddle.net/gvvy5vxz/2/

它是基于这个:https://developers.google.com/maps/documentation/javascript/examples/overlay-simple

我是typescript的新手,我被原型实现困住了,特别是这个JS片段:

USGSOverlay.prototype = new google.maps.OverlayView();
USGSOverlay(bounds, image, map) {
    // Initialize all properties.
    this.bounds_ = bounds;
    this.image_ = image;
    this.map_ = map;
    // Define a property to hold the image's div. We'll
    // actually create this div upon receipt of the onAdd()
    // method so we'll leave it null for now.
    this.div_ = null;
    // Explicitly call setMap on this overlay.
    this.setMap(map);
  }

我不知道如何以typescript的方式翻译,以及如何正确声明事物。

我想我应该创建一个类usgoverlay扩展google.maps.OverlayView,但它不工作。

class USGSOverlay extends google.maps.OverlayView{
  bounds_;
  image_;
  map_;
  div_;
  constructor(bounds, image, map){
    // Initialize all properties.
    this.bounds_ = bounds;
    this.image_ = image;
    this.map_ = map;
    // Define a property to hold the image's div. We'll
    // actually create this div upon receipt of the onAdd()
    // method so we'll leave it null for now.
    this.div_ = null;
    // Explicitly call setMap on this overlay.
    this.setMap(map);
  }
}

这是我的工作基组件。它在#map:

内部创建了一个简单的映射
import { Component } from '@angular/core';
declare const google: any;
/*
/*  Component Map
*/
@Component({
  selector: 'map',
  template: `
    <div id="map"></div>
  `,
  styles: [
    `#map{ width:100%; height:100%; position: absolute; width:100%; height:100%; top:0; left:0;}`
  ],
})
export class MapComponent {
  ngOnInit(){
    google.maps.event.addDomListener(window, 'load', this.initMap);
  }
  initMap() {
    const map = new google.maps.Map(document.getElementById('map'), {
      zoom: 11,
      center: {lat: 62.323907, lng: -150.109291},
      mapTypeId: google.maps.MapTypeId.SATELLITE
    });
    const bounds = new google.maps.LatLngBounds(
        new google.maps.LatLng(62.281819, -150.287132),
        new google.maps.LatLng(62.400471, -150.005608));
  }
}

这是我的工作(使用离子2):

  1. 使用以下命令:

    npm install typings --global
    typings install dt~google.maps --global --save
    typings install google.maps --global
    
  2. 添加"输入/* .d。在你的tsconfig.json:

    "include": [
      "src/**/*.ts",
      "typings/*.d.ts"
    ]
    
  3. 下面是TypeScript代码:

    import { Component, ViewChild, ElementRef } from '@angular/core';
    import { NavController } from 'ionic-angular';
    // import typings
    import { } from '@types/googlemaps';
    /*
    /*  Component Map
    */
    @Component({
        selector: 'page-overlay',
        templateUrl: 'overlay.html'
    })
    export class OverlayPage {
        @ViewChild('map') mapElement: ElementRef;
        map: any;
        // weird syntax, I know, but it works
        constructor(public navCtrl: NavController) {
        }
        USGSOverlay = class extends google.maps.OverlayView {
            bounds_: any;
            image_: any;
            map_: any;
            div_: any;
            constructor(bounds, image, private map) {
                super();
                // Initialize all properties.
                this.bounds_ = bounds;
                this.image_ = image;
                this.map_ = map;
                // Define a property to hold the image's div. We'll
                // actually create this div upon receipt of the onAdd()
                // method so we'll leave it null for now.
                this.div_ = null;
                // Explicitly call setMap on this overlay.
                this.setMap(map);
                this.set
            }
            /**
             * onAdd is called when the map's panes are ready and the overlay has been
             * added to the map.
             */
            onAdd() {
                const div = document.createElement('div');
                div.style.borderStyle = 'none';
                div.style.borderWidth = '0px';
                div.style.position = 'absolute';
                // Create the img element and attach it to the div.
                const img = document.createElement('img');
                img.src = this.image_;
                img.style.width = '100%';
                img.style.height = '100%';
                img.style.position = 'absolute';
                div.appendChild(img);
                this.div_ = div;
                // Add the element to the "overlayLayer" pane.
                const panes = this.getPanes();
                panes.overlayLayer.appendChild(div);
            };
            draw() {
                // We use the south-west and north-east
                // coordinates of the overlay to peg it to the correct position and size.
                // To do this, we need to retrieve the projection from the overlay.
                const overlayProjection = this.getProjection();
                // Retrieve the south-west and north-east coordinates of this overlay
                // in LatLngs and convert them to pixel coordinates.
                // We'll use these coordinates to resize the div.
                const sw = overlayProjection.fromLatLngToDivPixel(this.bounds_.getSouthWest());
                const ne = overlayProjection.fromLatLngToDivPixel(this.bounds_.getNorthEast());
                // Resize the image's div to fit the indicated dimensions.
                const div = this.div_;
                div.style.left = sw.x + 'px';
                div.style.top = ne.y + 'px';
                div.style.width = (ne.x - sw.x) + 'px';
                div.style.height = (sw.y - ne.y) + 'px';
            };
            // The onRemove() method will be called automatically from the API if
            // we ever set the overlay's map property to 'null'.
            onRemove() {
                this.div_.parentNode.removeChild(this.div_);
                this.div_ = null;
            };
        };
        ngOnInit() {
            this.loadMap();
            var bounds = new google.maps.LatLngBounds(
                new google.maps.LatLng(62.281819, -150.287132),
                new google.maps.LatLng(62.400471, -150.005608));
            // The photograph is courtesy of the U.S. Geological Survey.
            var srcImage = 'https://developers.google.com/maps/documentation/' +
                'javascript/examples/full/images/talkeetna.png';
            const overlay = new this.USGSOverlay(bounds, srcImage, this.map);
            //overlay.setMap(this.map);
        }
        ionViewDidLoad() {
            this.loadMap();
            var bounds = new google.maps.LatLngBounds(
                new google.maps.LatLng(62.281819, -150.287132),
                new google.maps.LatLng(62.400471, -150.005608));
            // The photograph is courtesy of the U.S. Geological Survey.
            var srcImage = 'https://developers.google.com/maps/documentation/' +
                'javascript/examples/full/images/talkeetna.png';
            const overlay = new this.USGSOverlay(bounds, srcImage, this.map);
            //overlay.setMap(this.map);
        }
        loadMap() {        
            let latLng = new google.maps.LatLng(62.323907, -150.109291);
            var mapOptions = {
                zoom :15,
                center : latLng,
                enableHighAccuracy: true,
                timeout: 5000,
                maximumAge: 0
            };
            this.map = new google.maps.Map(this.mapElement.nativeElement, mapOptions);
        }
    }
    

我的工作方式很好…

import { Component } from '@angular/core';
declare const google: any;
class USGSOverlay extends google.maps.OverlayView{
  bounds_;
  image_;
  map_;
  div_;
  constructor(bounds, image, map){
    // Initialize all properties.
    this.bounds_ = bounds;
    this.image_ = image;
    this.map_ = map;
    // Define a property to hold the image's div. We'll
    // actually create this div upon receipt of the onAdd()
    // method so we'll leave it null for now.
    this.div_ = null;
    // Explicitly call setMap on this overlay.
    this.setMap(map);
  }
  /**
   * onAdd is called when the map's panes are ready and the overlay has been
   * added to the map.
   */
  onAdd(){
    const div = document.createElement('div');
    div.style.borderStyle = 'none';
    div.style.borderWidth = '0px';
    div.style.position = 'absolute';
    // Create the img element and attach it to the div.
    const img = document.createElement('img');
    img.src = this.image_;
    img.style.width = '100%';
    img.style.height = '100%';
    img.style.position = 'absolute';
    div.appendChild(img);
    this.div_ = div;
    // Add the element to the "overlayLayer" pane.
    const panes = this.getPanes();
    panes.overlayLayer.appendChild(div);
  };
  draw(){
    // We use the south-west and north-east
    // coordinates of the overlay to peg it to the correct position and size.
    // To do this, we need to retrieve the projection from the overlay.
    const overlayProjection = this.getProjection();
    // Retrieve the south-west and north-east coordinates of this overlay
    // in LatLngs and convert them to pixel coordinates.
    // We'll use these coordinates to resize the div.
    const sw = overlayProjection.fromLatLngToDivPixel(this.bounds_.getSouthWest());
    const ne = overlayProjection.fromLatLngToDivPixel(this.bounds_.getNorthEast());
    // Resize the image's div to fit the indicated dimensions.
    const div = this.div_;
    div.style.left = sw.x + 'px';
    div.style.top = ne.y + 'px';
    div.style.width = (ne.x - sw.x) + 'px';
    div.style.height = (sw.y - ne.y) + 'px';
  };
  // The onRemove() method will be called automatically from the API if
  // we ever set the overlay's map property to 'null'.
  onRemove(){
    this.div_.parentNode.removeChild(this.div_);
    this.div_ = null;
  };
};

/*
/*  Component Map
*/
@Component({
  selector: 'map',
  template: `
    <div id="map"></div>
  `,
  styles: [
    `#map{ width:100%; height:100%; position: absolute; width:100%; height:100%; top:0; left:0;}`
  ],
})
export class MapComponent {
  overlay;
  ngOnInit(){
    google.maps.event.addDomListener(window, 'load', this.initMap);
  }
  initMap() {
    const map = new google.maps.Map(document.getElementById('map'), {
      zoom: 11,
      center: {lat: 62.323907, lng: -150.109291},
      mapTypeId: google.maps.MapTypeId.SATELLITE
    });
    const bounds = new google.maps.LatLngBounds(
        new google.maps.LatLng(62.281819, -150.287132),
        new google.maps.LatLng(62.400471, -150.005608));
    // The photograph is courtesy of the U.S. Geological Survey.
    const srcImage = 'https://developers.google.com/maps/documentation/' +
        'javascript/examples/full/images/talkeetna.png';
    // The custom USGSOverlay object contains the USGS image,
    // the bounds of the image, and a reference to the map.
    this.overlay = new USGSOverlay(bounds, srcImage, map);
  }
}

我也遇到了很多麻烦,但最终还是解决了。至关重要的是,谷歌地图脚本是预加载的(我在我的路由解析器中加载了我的),否则你会得到一个"谷歌"没有定义的错误。在这里查看我是如何安装类型和导入库的。

至于语法,我最终使用了一个内部类。这是因为,如果它是一个顶级类,WebPack尝试(不成功)在编译时找到google maps库:
// import typings
import {} from '@types/googlemaps';
@Component({...})
export class MapComponent implements OnInit {
  // weird syntax, I know, but it works
  USGSOverlay = class extends google.maps.OverlayView {
    constructor(bounds, image, private map){
      super();
      ...
      this.setMap(this.map);
    }
    onAdd(){...}
    draw(){...}
  }
  ngOnInit() {
    const overlay = new this.Overlay(bounds, image, map);
  }
}

由于我的代码异步加载谷歌地图API,上述答案对我不起作用。我的问题是typescript使用谷歌变量之前加载谷歌API。

这是我找到的一个解决方案。

要查看异步地图加载器代码,请参见在组件[Angular]中加载Google Maps JS API

//map.service.ts
import { Injectable } from '@angular/core';
...
declare var google;    
export let MyOverlay; // declare and use this from other ts file
@Injectable({ providedIn: 'root' })
export class MapService {
    private static promise;
    map: any;
    public static load() {
        if (!MapService.promise) {
            MapService.promise = new Promise((resolve) => {
              //load google api asynchronously
            });
        }
        return MapService.promise;
    }
    async initMap(gmapElement, lat = -33.92, lng = 151.25) {
        return MapService.load()  
            .then((gapi) => {
                //map init
                this.map = new google.maps.Map(gmapElement.nativeElement, {
                   //map options
                })
                /*** before init MyOverlay, 
                1. Google API should be loaded
                2. AFTER MAP init(rendering), Overlay Object has Projection to calculate Overlay location
                ***/
                this.initMyOverlay()
            })
            .catch(console.log)
    }
    initMyOverlay(){            
        class MyOverlayCls extends google.maps.OverlayView {    
         //omitted for code readability
        }
        MyOverlay = MyOverlayCls ; //assign class to variable
    }
}
<<p> 组件/strong>
//map.component.ts
import { MapService, MyOverlay} from 'map.service';
...
  @ViewChild('gmap') gmapElement: any
  ...
  ngOnInit() {
    console.log("maps init")
    this.mapSvc.initMap(this.gmapElement).then(_ => {
      //At this time, google API has been loaded and assigned MyOverlay as MyOverlayCls
      let overlay= new MyOverlay(...)    
    })

在我的情况下,我不能在同一个类中有一个内部类负责加载map。我花了一些时间才弄明白怎么做。我是这样做的

export class mapTextOverlayService {
  //Overlay is creatd in an inner-class because if it is at top-level class google maps library may not be available at the class load time
  mapTextOverlay = class extends google.maps.OverlayView {
    pos_;
    text_;
    map_;
    div_;
    constructor(pos, text, map) {
      super();
      // Initialize all properties.
      this.pos_ = pos;
      this.text_ = text;
      this.map_ = map;
      // Define a property to hold the text's div. We'll
      // actually create this div upon receipt of the onAdd()
      // method so we'll leave it null for now.
      this.div_ = null;
      // Explicitly call setMap on this overlay.
      this.setMap(map);
    }
    /**
     * onAdd is called when the map's panes are ready and the overlay has been
     * added to the map.
     */
    onAdd() {
      const div = document.createElement('div');
      div.style.borderStyle = 'none';
      div.style.borderWidth = '0px';
      div.style.position = 'absolute';
      div.innerHTML = this.text_;
      this.div_ = div;
      // Add the element to the "overlayLayer" pane.
      const panes = this.getPanes();
      panes.overlayLayer.appendChild(div);
    };
    draw() {
      // We are using bounds centre to peg it to the correct position.
      // To do this, we need to retrieve the projection from the overlay.
      const overlayProjection = this.getProjection();
      // Convert the centre coordinates of this overlay from LatLngs to pixel coordinates.
      // We'll use these coordinates to provide the dimensions of div.
      const pixelPos = overlayProjection.fromLatLngToDivPixel(this.pos_);
      const div = this.div_;
      div.style.left = pixelPos.x + 'px';
      div.style.top = pixelPos.y + 'px';
    };
    // The onRemove() method will be called automatically from the API if
    // we ever set the overlay's map property to 'null'.
    onRemove() {
      this.div_.parentNode.removeChild(this.div_);
      this.div_ = null;
    };
    onHide() {
      if (this.div_) {
        this.div_.style.visibility = 'hidden';
      } 
    };
  }
  createMapTextOverlay(pos, text, map) {
    return new this.mapTextOverlay(pos, text, map);
  }
};

然后在我想要创建文本叠加的组件中:

let mtos = new mapTextOverlayService();
let label = mtos.createMapTextOverlay(boundsCenter, description, this.map.mapobject);

使用这个简单的代码创建一个自定义的覆盖。

    // this.userPositionDiv is defined as variable
    let overlayView = new google.maps.OverlayView();
    overlayView.draw = () => {
        if (!this.userPositionDiv) {
            this.userPositionDiv = document.createElement('div');
            this.userPositionDiv.className = 'marker';
            this.userPositionDiv.style.cssText = `width: 35px; height: 35px; text-align: center; line-height: 35px; position: absolute; cursor: pointer; border-radius: 50%; color: #fff; background: #000`;
            this.userPositionDiv.innerHTML = `<span class="number-id">Hello</span>`;
            const panes = overlayView.getPanes();
            panes.overlayImage.appendChild(this.userPositionDiv);
        }
        const point = this.overlayView.getProjection().fromLatLngToDivPixel(this.latLng);
        if (point) {
            this.userPositionDiv.style.left = (point.x - 10) + 'px';
            this.userPositionDiv.style.top = (point.y - 10) + 'px';
        }
    }
    overlayView.setMap(this.gmap);

最新更新