【问题标题】:Show OverlayView marker in street view在街景中显示 OverlayView 标记
【发布时间】:2020-06-19 17:26:33
【问题描述】:

我想为谷歌地图创建自定义“HTMLMarker”,但我刚刚发现,它显示在街景中。我搜索了文档,但那里没有写任何内容。 (谷歌搜索:“在街景中显示 OverlayView 标记”)

interface HTMLMarkerOptions {
    position: google.maps.LatLng | google.maps.LatLngLiteral;
    content: HTMLElement;
}

class HTMLMarker extends google.maps.OverlayView {
    private _element: HTMLElement;
    private _isAppended = false;

    private _position: google.maps.LatLng;

    constructor(options: HTMLMarkerOptions) {
        super();

        this._position = this._createLatLng(options.position)

        this._element = document.createElement('div');
        this._element.style.position = 'absolute';
        this._element.appendChild(options.content);
    }

    _appendDivToOverlay() {
        const panes = this.getPanes();
        panes.overlayMouseTarget.appendChild(this._element);
        this._isAppended = true;
    }

    _positionDiv() {
        const map = this.getMap();
        if (map instanceof google.maps.StreetViewPanorama) {
            //  TODO: Render in StreetView
            return;
        } else {
            const projection = this.getProjection();
            const point = projection.fromLatLngToDivPixel(this._position);
            if (point) {
                this._element.style.left = `${point.x - this._offset.left}px`;
                this._element.style.top = `${point.y - this._offset.top}px`;
            }
        }

    }

    setMap(map: google.maps.Map | google.maps.StreetViewPanorama | null) {
        super.setMap(map);
    }

    draw() {
        if (!this._isAppended) {
            this._appendDivToOverlay();
        }
        this._positionDiv();
    }

    remove(): void {
        this._element.parentNode?.removeChild(this._element);
        this._isAppended = false;
    }

    setPosition(position: google.maps.LatLng | google.maps.LatLngLiteral): void {
        if (!this._LatLngEquals(this._position, position)) {
            this._position = this._createLatLng(position);
        }
    }

    getPosition(): google.maps.LatLng {
        return this._position;
    }

    getDraggable(): boolean {
        return false;
    }

    private _createLatLng(
        position: google.maps.LatLng | google.maps.LatLngLiteral,
    ): google.maps.LatLng {
        if (position instanceof google.maps.LatLng) {
            return position;
        } else {
            return new google.maps.LatLng(position);
        }
    }

    private _LatLngEquals(
        positionA: google.maps.LatLng | undefined,
        positionB: google.maps.LatLng | google.maps.LatLngLiteral,
    ): boolean {
        if (!positionA) {
            return false;
        }

        if (positionB instanceof google.maps.LatLng) {
            return positionA.equals(positionB);
        } else {
            return positionA.lat() == positionB.lat && positionA.lng() == positionB.lng;
        }
    }
}

example fiddle (compiled TS to ESNext)

【问题讨论】:

    标签: javascript google-maps


    【解决方案1】:

    虽然the documentation 说:

    此外,在创建具有默认 StreetViewPanorama 的地图时,在地图上创建的任何标记都会自动与地图的关联街景全景图共享,前提是该全景图是可见的。

    HTMLMarker 似乎并非如此。将HTMLMarkermap 属性设置为地图的默认街景全景图:

    marker.setMap(map.getStreetView());
    

    让它可见。

    proof of concept fiddle

    相关问题:Drawing polylines on Google Maps Streetview

    代码 sn-p:

    const map = new google.maps.Map(
      document.querySelector('#map-canvas'), {
        zoom: 18,
        center: new google.maps.LatLng(37.422, -122.084),
        mapTypeId: google.maps.MapTypeId.ROADMAP,
      },
    );
    google.maps.event.addListener(map, 'click', function(e) {
      console.log(e.latLng.toUrlValue(6));
    })
    class HTMLMarker extends google.maps.OverlayView {
      constructor(options) {
        super();
        this._isAppended = false;
        this._position = this._createLatLng(options.position);
        this._element = document.createElement('div');
        this._element.style.position = 'absolute';
        this._element.appendChild(options.content);
      }
      _appendDivToOverlay() {
        const panes = this.getPanes();
        panes.overlayMouseTarget.appendChild(this._element);
        this._isAppended = true;
      }
      _positionDiv() {
        const map = this.getMap();
        const projection = this.getProjection();
        const point = projection.fromLatLngToDivPixel(this._position);
        if (point) {
          this._element.style.left = point.x + 'px';
          this._element.style.top = point.y + 'px';
        }
    
      }
      setMap(map) {
        super.setMap(map);
      }
      draw() {
        if (!this._isAppended) {
          this._appendDivToOverlay();
        }
        this._positionDiv();
      }
      remove() {
        if (this._element.parentNode) {
          this._element.parentNode.removeChild(this._element);
        }
        this._isAppended = false;
      }
      setPosition(position) {
        if (!this._LatLngEquals(this._position, position)) {
          this._position = this._createLatLng(position);
        }
      }
      getPosition() {
        return this._position;
      }
      getDraggable() {
        return false;
      }
      _createLatLng(position) {
        if (position instanceof google.maps.LatLng) {
          return position;
        } else {
          return new google.maps.LatLng(position);
        }
      }
      _LatLngEquals(positionA, positionB) {
        if (!positionA) {
          return false;
        }
        if (positionB instanceof google.maps.LatLng) {
          return positionA.equals(positionB);
        } else {
          return positionA.lat() == positionB.lat && positionA.lng() == positionB.lng;
        }
      }
    }
    
    const marker = new HTMLMarker({
      position: new google.maps.LatLng(37.42197, -122.083627),
      content: document.querySelector('#marker'),
    });
    marker.setMap(map);
    
    const marker1 = new google.maps.Marker({
      position: new google.maps.LatLng(37.42197, -122.083627),
    });
    marker1.setMap(map);
    // We get the map's default panorama and set up some defaults.
    // Note that we don't yet set it visible.
    panorama = map.getStreetView();
    panorama.setPosition({
      lat: 37.421885,
      lng: -122.083662
    });
    panorama.setPov( /** @type {google.maps.StreetViewPov} */ ({
      heading: 0,
      pitch: 0
    }));
    panorama.setVisible(true);
    panorama.setZoom(1);
    marker.setMap(map.getStreetView());
    * {
      box-sizing: border-box;
    }
    
    body {
      margin: 0;
    }
    
    #map-canvas {
      height: 100vh;
      width: 100vw;
      background-color: #CCC;
    }
    
    #marker {
      display: flex;
      height: 50px;
      width: 50px;
      background: white;
      border: 3px solid black;
    }
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
    
    <div id="map-canvas"></div>
    
    <div id="marker">
      ID: 1
    </div>

    【讨论】:

    • 所以我需要在google.maps.StreetViewPanorama 上收听visible_changed 事件并来回更改地图...这是一个解决方案,但它并不好...我想是一个权衡用于在低级别工作...如果太远,我需要在街景中隐藏标记,并将其缩小...
    【解决方案2】:

    我昨天也看过这个,正如 geocodezip 所提到的,documentation 具有误导性(或错误)。它提到了

    如果您将地图的 streetView 属性显式设置为您自己构建的 StreetViewPanorama,您将覆盖默认全景图并禁用自动叠加层共享

    对我而言,这意味着如果您使用您自己构建的全景图(因此是默认全景图),叠加共享应该可以工作,除非 "overlay" 他们的意思是 Marker

    这里证明了标准 Marker 在地图和默认全景图之间共享,无需执行任何操作,而自定义叠加层则不是:

    var map;
    var panorama;
    var htmlMarker;
    
    function initialize() {
    
      function HTMLMarker(lat, lng) {
        this.lat = lat;
        this.lng = lng;
        this.pos = new google.maps.LatLng(lat, lng);
        this.divReference = null;
      }
    
      HTMLMarker.prototype = new google.maps.OverlayView();
    
      HTMLMarker.prototype.onRemove = function() {
        this.divReference.parentNode.removeChild(this.divReference);
        this.divReference = null;
      }
    
      HTMLMarker.prototype.onAdd = function() {
    
        div = document.createElement('DIV');
        div.className = "html-marker";
        div.style.width = '60px';
        div.style.height = '50px';
        div.innerHTML = 'ABC';
    
        var panes = this.getPanes();
        panes.overlayMouseTarget.appendChild(div);
    
        this.divReference = div;
      }
    
      HTMLMarker.prototype.draw = function() {
    
        var overlayProjection = this.getProjection();
        var position = overlayProjection.fromLatLngToDivPixel(this.pos);
        var panes = this.getPanes();
    
        panes.overlayMouseTarget.style.left = position.x - 30 + 'px';
        panes.overlayMouseTarget.style.top = position.y - 25 + 'px';
      }
    
      // Set up the map
      var mapOptions = {
        center: new google.maps.LatLng(40.729884, -73.990988),
        zoom: 18,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        streetViewControl: false
      };
    
      map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
    
      panorama = map.getStreetView();
      panorama.setPosition(new google.maps.LatLng(40.729884, -73.990988));
      panorama.setPov({
        heading: 330,
        zoom: 1,
        pitch: 0
      });
    
      htmlMarker = new HTMLMarker(40.729952, -73.991056);
      htmlMarker.setMap(map);
    
      var marker = new google.maps.Marker({
        position: new google.maps.LatLng(40.729952, -73.991198),
        map: map,
        draggable: true,
        title: 'My marker'
      });
    }
    
    function toggleStreetView() {
      var toggle = panorama.getVisible();
      if (toggle == false) {
        panorama.setVisible(true);
      } else {
        panorama.setVisible(false);
      }
    }
    
    var button = document.getElementsByTagName('input')[0];
    button.onclick = function() {
      toggleStreetView()
    };
    #map-canvas {
      height: 150px;
    }
    
    input {
      margin: 10px;
      background-color: #4CAF50;
      border: none;
      color: white;
      padding: 4px 8px;
    }
    
    .html-marker {
      background-color: red;
      color: white;
      line-height: 50px;
      text-align: center;
      font-size: 18px;
      font-weight: bold;
    }
    <input type="button" value="Toggle Street View">
    <div id="map-canvas"></div>
    
    <!-- Replace the value of the key parameter with your own API key. -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initialize" async defer></script>

    在这里,当从地图更改为默认全景图时,我只是这样做

    htmlMarker.setMap(null);
    htmlMarker.setMap(panorama);
    

    它有效。

    var map;
    var panorama;
    var htmlMarker;
    
    function initialize() {
    
      function HTMLMarker(lat, lng) {
        this.lat = lat;
        this.lng = lng;
        this.pos = new google.maps.LatLng(lat, lng);
        this.divReference = null;
      }
    
      HTMLMarker.prototype = new google.maps.OverlayView();
    
      HTMLMarker.prototype.onRemove = function() {
        this.divReference.parentNode.removeChild(this.divReference);
        this.divReference = null;
      }
    
      HTMLMarker.prototype.onAdd = function() {
    
        div = document.createElement('DIV');
        div.className = "html-marker";
        div.style.width = '60px';
        div.style.height = '50px';
        div.innerHTML = 'ABC';
    
        var panes = this.getPanes();
        panes.overlayMouseTarget.appendChild(div);
    
        this.divReference = div;
      }
    
      HTMLMarker.prototype.draw = function() {
    
        var overlayProjection = this.getProjection();
        var position = overlayProjection.fromLatLngToDivPixel(this.pos);
        var panes = this.getPanes();
    
        panes.overlayMouseTarget.style.left = position.x - 30 + 'px';
        panes.overlayMouseTarget.style.top = position.y - 25 + 'px';
      }
    
      // Set up the map
      var mapOptions = {
        center: new google.maps.LatLng(40.729884, -73.990988),
        zoom: 18,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        streetViewControl: false
      };
    
      map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
    
      panorama = map.getStreetView();
      panorama.setPosition(new google.maps.LatLng(40.729884, -73.990988));
      panorama.setPov({
        heading: 330,
        zoom: 1,
        pitch: 0
      });
    
      htmlMarker = new HTMLMarker(40.729952, -73.991056);
      htmlMarker.setMap(map);
    
      var marker = new google.maps.Marker({
        position: new google.maps.LatLng(40.729952, -73.991198),
        map: map,
        draggable: true,
        title: 'My marker'
      });
    }
    
    function toggleStreetView() {
      var toggle = panorama.getVisible();
      if (toggle == false) {
        panorama.setVisible(true);
        htmlMarker.setMap(null);
        htmlMarker.setMap(panorama);
      } else {
        panorama.setVisible(false);
        htmlMarker.setMap(null);
        htmlMarker.setMap(map);
      }
    }
    
    var button = document.getElementsByTagName('input')[0];
    button.onclick = function() {
      toggleStreetView()
    };
    #map-canvas {
      height: 150px;
    }
    
    input {
      margin: 10px;
      background-color: #4CAF50;
      border: none;
      color: white;
      padding: 4px 8px;
    }
    
    .html-marker {
      background-color: red;
      color: white;
      line-height: 50px;
      text-align: center;
      font-size: 18px;
      font-weight: bold;
    }
    <input type="button" value="Toggle Street View">
    <div id="map-canvas"></div>
    
    <!-- Replace the value of the key parameter with your own API key. -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initialize" async defer></script>

    我在追踪器中打开了a new issue。让我们看看这是 API 中的错误,还是文档(或两者都有)的问题。

    【讨论】:

    • 干得好...虽然似乎有一个错误 :D 如果您更改 fov(街景中的滚轮)并退出街景,标记将消失!看起来,这将需要相当多的工作。我可能会考虑创建 npm 包来解决所有问题(在地图/街景之间切换、在 ST 中远时缩放、在 ST 中很远时隐藏以及(可悲地)其他)
    • 基于距离的缩放将是一个特征请求。我没有看到您提到的标记消失的错误(Mac 上的 Chrome 浏览器)。
    • 您可以在跟踪器中为issue 加注星标,以便在问题更新时收到通知。
    • 我是通过它提供的按钮退出街景,而不是您制作的绿色按钮...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    相关资源
    最近更新 更多