Angular 5和OpenLayers 4:无法读取属性'getEventPixel'和'forEachFeatureAtPixel'

时间:2018-05-03 09:12:05

标签: javascript angular typescript openlayers

我正在尝试将OpenLayers与Angular 5一起使用。 我正在测试实现地图的不同方法,我已经在简单的HTML文件中测试了Leaflet和OpenLayers,并且我选择使用OpenLayers,这在我的情况下更有效。

使用此地图我想在不同的图层之间切换(使用ol-layerswitcher),根据GeoJSON文件放置标记并显示弹出窗口。 所有这些功能都在我的HTML文件中运行良好,现在,我想用Angular 5做同样的事情(不是使用angular-openlayers-directive)!

我已经在我的app.component.ts文件中调整了Angular中的HTML代码,标记是根据我的GeoJSON文件显示的,我的图层切换器也是如此,但我遇到了两个函数问题:forEachFeatureatPixel和getEventPixel ...... < / p>

这是我的src / app / app.component.ts:

import { Component, OnInit } from '@angular/core';

import OlMap from 'ol/map';
import OlWMS from 'ol/source/tilewms';
import OlTileLayer from 'ol/layer/tile';
import OlView from 'ol/view';
import olProj from 'ol/proj';
import VectorLayer from 'ol/layer/vector';
import VectorSource from 'ol/source/vector';
import Point from 'ol/geom/point';
import Style from 'ol/style/style';
import IconStyle from 'ol/style/icon';
import WFS from 'ol/format/wfs';
import GeoJSON from 'ol/format/geojson';
import Overlay from 'ol/overlay';
import feature from 'ol/feature';
import OlSwitch from 'ol-layerswitcher/src/ol-layerswitcher';
import CanvasMap from 'ol/canvasmap';
//import evt from 'ol/mapbrowserevent';
//import mbe from 'ol/mapbrowsereventtype';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent implements OnInit {

  map: OlMap;
  gny_bright: OlWMS;
  gny_bright_mobile: OlWMS;
  layer: OlTileLayer;
  view: OlView;
  layerSwitcher: OlSwitch;
  WFS: WFS;
  vectorLayer: VectorLayer;
  sourceLayer: VectorSource;
  feature: feature;
  evt: evt;
  mbe: mbe;
  //parkvert: IconStyle;
  //parkorange: Style;
  //parkrouge: Style;
  //parknoir: Style;

  constructor() {
  }

  ngOnInit() {

    this.gny_bright = new OlWMS({
      url: '...',
      params: {...},
      attributions: '...'
    });

    this.gny_bright_mobile = new OlWMS({
      url: '...',
      params: {...},
      attributions: '...'
    });

    var parkvert = new Style({
      image: new IconStyle(({
        anchor: [0.5, 46],
        anchorXUnits: 'fraction',
        anchorYUnits: 'pixels',
        src: 'assets/image/parking-vert.png'
      }))
    });

    var parkorange = new Style({
      image: new IconStyle(({
        anchor: [0.5, 46],
        anchorXUnits: 'fraction',
        anchorYUnits: 'pixels',
        src: 'assets/image/parking-orange.png'
      }))
    });

    this.view = new OlView({
      center: [689805.19, 6222389.4],
      minZoom: 1,
      maxZoom: 19,
      zoom: 2
    });

    this.sourceLayer = new VectorSource({
      url: 'url_to_my_geojson_file',
      format: new GeoJSON()
    });

    this.vectorLayer = new VectorLayer({
      source: this.sourceLayer
    });

    this.map = new OlMap({
      target: 'map',
      layers: [
        new OlTileLayer({
          title: 'gny_bright_mobile',
          source: this.gny_bright_mobile,
          type: 'base',
          attributions: '...'
        }),
        new OlTileLayer({
          title: 'gny_bright',
          source: this.gny_bright,
          type: 'base',
          attributions: '...'
        })
      ],
      view: this.view
    });

    var markers = function style(feature, resolution) {
      if (feature.get('PLACES') == null) {
        return parknoir;

      } else if(feature.get('PLACES') <= feature.get('CAPACITE') * 0.05) {
        return parkrouge;

      } else if(feature.get('PLACES') <= feature.get('CAPACITE') * 0.15){
        return parkorange;

      } else if(feature.get('PLACES') > feature.get('CAPACITE') * 0.15) {
        return parkvert;
      }
    }

    this.vectorLayer.setStyle(markers);

    //popup

    var element = document.getElementById('popup');

    var popup = new Overlay({
      element: element,
      autoPan: true,
      offset: [0, -30]
    });

  this.map.addOverlay(popup);

  var content_element = document.getElementById('popup-content');
  var closer = document.getElementById('popup-closer');

  closer.onclick = function() {
        popup.setPosition(undefined);
        closer.blur();
        return false;
    };

    this.map.on('click', function(evt){
        this.feature = this.map.forEachFeatureAtPixel(evt.pixel,
          function(feature) {
            return this.feature;
          });
          if (this.feature) {
            var geometry = this.feature.getGeometry();
            var coord = geometry.getCoordinates();

            if(this.feature.get('NOM')!=null) {
              var content = '<center><h2>' + this.feature.get('NOM') + '</h2></center>' + '<br>';
            }

            if(this.feature.get('ADRESSE')!=null) {
              content += '<h5>' + '<i>Adresse : </i>' + this.feature.get('ADRESSE') + '</h5>';
            }

            if(this.feature.get('CAPACITE')!=null) {
              content += '<h5>' + '<i>Capacité : </i>' + this.feature.get('CAPACITE') + '</h5>';
            }

            if(this.feature.get('PLACES')!=null) {
              content += '<h5>' + '<i>Places disponibles : </i>' + this.feature.get('PLACES') + '<h5>';
            }

            content_element.innerHTML = content;
            popup.setPosition(coord);
        }
    });

    this.map.on('pointermove', function(e) {
        if (e.dragging) {
          return;
        };

        var pixel = this.map.getEventPixel(e.originalEvent);
        var hit = this.map.hasFeatureAtPixel(pixel);

        this.map.getViewport().style.cursor = hit ? 'pointer' : '';
    });

    this.map.addControl(this.vectorLayer);
    this.layerSwitcher = new OlSwitch();
    this.map.addControl(this.layerSwitcher);
  }
}

我的src / app / app.component.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
  </head>

    <body>
        <div id="map" class="map"></div>
        <div id="popup" class="ol-popup">
          <a href="#" id="popup-closer" class="ol-popup-closer"></a>
          <div id="popup-content"></div>
        </div>
    </body>

</html>

我的src / app / app.component.css:

#map {
    width: 100%;
    height: 100vh;
}

我的styles.css:

html, body {
  margin: 0px;
}

/* You can add global styles to this file, and also import other style files */
.ol-box {
  box-sizing: border-box;
  border-radius: 2px;
  border: 2px solid blue;
}

.ol-mouse-position {
  top: 8px;
  right: 8px;
  position: absolute;
}

.ol-scale-line {
  background: rgba(0,60,136,0.3);
  border-radius: 4px;
  bottom: 8px;
  left: 8px;
  padding: 2px;
  position: absolute;
}
.ol-scale-line-inner {
  border: 1px solid #eee;
  border-top: none;
  color: #eee;
  font-size: 10px;
  text-align: center;
  margin: 1px;
  will-change: contents, width;
}
.ol-overlay-container {
  will-change: left,right,top,bottom;
}

.ol-unsupported {
  display: none;
}
.ol-viewport, .ol-unselectable {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: rgba(0,0,0,0);
}
.ol-selectable {
  -webkit-touch-callout: default;
  -webkit-user-select: auto;
  -moz-user-select: auto;
  -ms-user-select: auto;
  user-select: auto;
}
.ol-grabbing {
  cursor: -webkit-grabbing;
  cursor: -moz-grabbing;
  cursor: grabbing;
}
.ol-grab {
  cursor: move;
  cursor: -webkit-grab;
  cursor: -moz-grab;
  cursor: grab;
}
.ol-control {
  position: absolute;
  background-color: rgba(255,255,255,0.4);
  border-radius: 4px;
  padding: 2px;
}
.ol-control:hover {
  background-color: rgba(255,255,255,0.6);
}
.ol-zoom {
  top: .5em;
  left: .5em;
}
.ol-rotate {
  top: .5em;
  right: .5em;
  transition: opacity .25s linear, visibility 0s linear;
}
.ol-rotate.ol-hidden {
  opacity: 0;
  visibility: hidden;
  transition: opacity .25s linear, visibility 0s linear .25s;
}
.ol-zoom-extent {
  top: 4.643em;
  left: .5em;
}
.ol-full-screen {
  right: .5em;
  top: .5em;
}
@media print {
  .ol-control {
    display: none;
  }
}

.ol-control button {
  display: block;
  margin: 1px;
  padding: 0;
  color: white;
  font-size: 1.14em;
  font-weight: bold;
  text-decoration: none;
  text-align: center;
  height: 1.375em;
  width: 1.375em;
  line-height: .4em;
  background-color: rgba(0,60,136,0.5);
  border: none;
  border-radius: 2px;
}
.ol-control button::-moz-focus-inner {
  border: none;
  padding: 0;
}
.ol-zoom-extent button {
  line-height: 1.4em;
}
.ol-compass {
  display: block;
  font-weight: normal;
  font-size: 1.2em;
  will-change: transform;
}
.ol-touch .ol-control button {
  font-size: 1.5em;
}
.ol-touch .ol-zoom-extent {
  top: 5.5em;
}
.ol-control button:hover,
.ol-control button:focus {
  text-decoration: none;
  background-color: rgba(0,60,136,0.7);
}
.ol-zoom .ol-zoom-in {
  border-radius: 2px 2px 0 0;
}
.ol-zoom .ol-zoom-out {
  border-radius: 0 0 2px 2px;
}


.ol-attribution {
  text-align: right;
  bottom: .5em;
  right: .5em;
  max-width: calc(100% - 1.3em);
}

.ol-attribution ul {
  margin: 0;
  padding: 0 .5em;
  font-size: .7rem;
  line-height: 1.375em;
  color: #000;
  text-shadow: 0 0 2px #fff;
}
.ol-attribution li {
  display: inline;
  list-style: none;
  line-height: inherit;
}
.ol-attribution li:not(:last-child):after {
  content: " ";
}
.ol-attribution img {
  max-height: 2em;
  max-width: inherit;
  vertical-align: middle;
}
.ol-attribution ul, .ol-attribution button {
  display: inline-block;
}
.ol-attribution.ol-collapsed ul {
  display: none;
}
.ol-attribution.ol-logo-only ul {
  display: block;
}
.ol-attribution:not(.ol-collapsed) {
  background: rgba(255,255,255,0.8);
}
.ol-attribution.ol-uncollapsible {
  bottom: 0;
  right: 0;
  border-radius: 4px 0 0;
  height: 1.1em;
  line-height: 1em;
}
.ol-attribution.ol-logo-only {
  background: transparent;
  bottom: .4em;
  height: 1.1em;
  line-height: 1em;
}
.ol-attribution.ol-uncollapsible img {
  margin-top: -.2em;
  max-height: 1.6em;
}
.ol-attribution.ol-logo-only button,
.ol-attribution.ol-uncollapsible button {
  display: none;
}

.ol-zoomslider {
  top: 4.5em;
  left: .5em;
  height: 200px;
}
.ol-zoomslider button {
  position: relative;
  height: 10px;
}

.ol-touch .ol-zoomslider {
  top: 5.5em;
}

.ol-overviewmap {
  left: 0.5em;
  bottom: 0.5em;
}
.ol-overviewmap.ol-uncollapsible {
  bottom: 0;
  left: 0;
  border-radius: 0 4px 0 0;
}
.ol-overviewmap .ol-overviewmap-map,
.ol-overviewmap button {
  display: inline-block;
}
.ol-overviewmap .ol-overviewmap-map {
  border: 1px solid #7b98bc;
  height: 150px;
  margin: 2px;
  width: 150px;
}
.ol-overviewmap:not(.ol-collapsed) button{
  bottom: 1px;
  left: 2px;
  position: absolute;
}
.ol-overviewmap.ol-collapsed .ol-overviewmap-map,
.ol-overviewmap.ol-uncollapsible button {
  display: none;
}
.ol-overviewmap:not(.ol-collapsed) {
  background: rgba(255,255,255,0.8);
}
.ol-overviewmap-box {
  border: 2px dotted rgba(0,60,136,0.7);
}

.ol-overviewmap .ol-overviewmap-box:hover {
  cursor: move;
}

.layer-switcher.shown.ol-control {
  background-color: transparent;
}

.layer-switcher.shown.ol-control:hover {
  background-color: transparent;
}

.layer-switcher {
  position: absolute;
  top: 3.5em;
  right: 0.5em;
  text-align: left;
}

.layer-switcher.shown {
  bottom: 3em;
}

.layer-switcher .panel {
  padding: 0 1em 0 0;
  margin: 0;
  border: 4px solid #eee;
  border-radius: 4px;
  background-color: white;
  display: none;
  max-height: 100%;
  overflow-y: auto;
}

.layer-switcher.shown .panel {
  display: block;
}

.layer-switcher button {
  float: right;
  width: 38px;
  height: 38px;
  background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAACE1BMVEX///8A//8AgICA//8AVVVAQID///8rVVVJtttgv98nTmJ2xNgkW1ttyNsmWWZmzNZYxM4gWGgeU2JmzNNr0N1Rwc0eU2VXxdEhV2JqytQeVmMhVmNoydUfVGUgVGQfVGQfVmVqy9hqy9dWw9AfVWRpydVry9YhVmMgVGNUw9BrytchVWRexdGw294gVWQgVmUhVWPd4N6HoaZsy9cfVmQgVGRrytZsy9cgVWQgVWMgVWRsy9YfVWNsy9YgVWVty9YgVWVry9UgVWRsy9Zsy9UfVWRsy9YgVWVty9YgVWRty9Vsy9aM09sgVWRTws/AzM0gVWRtzNYgVWRuy9Zsy9cgVWRGcHxty9bb5ORbxdEgVWRty9bn6OZTws9mydRfxtLX3Nva5eRix9NFcXxOd4JPeINQeIMiVmVUws9Vws9Vw9BXw9BYxNBaxNBbxNBcxdJexdElWWgmWmhjyNRlx9IqXGtoipNpytVqytVryNNrytZsjZUuX210k5t1y9R2zNR3y9V4lp57zth9zdaAnKOGoaeK0NiNpquV09mesrag1tuitbmj1tuj19uktrqr2d2svcCu2d2xwMO63N+7x8nA3uDC3uDFz9DK4eHL4eLN4eIyYnDX5OM5Z3Tb397e4uDf4uHf5uXi5ePi5+Xj5+Xk5+Xm5+Xm6OY6aHXQ19fT4+NfhI1Ww89gx9Nhx9Nsy9ZWw9Dpj2abAAAAWnRSTlMAAQICAwQEBgcIDQ0ODhQZGiAiIyYpKywvNTs+QklPUlNUWWJjaGt0dnd+hIWFh4mNjZCSm6CpsbW2t7nDzNDT1dje5efr7PHy9PT29/j4+Pn5+vr8/f39/f6DPtKwAAABTklEQVR4Xr3QVWPbMBSAUTVFZmZmhhSXMjNvkhwqMzMzMzPDeD+xASvObKePPa+ffHVl8PlsnE0+qPpBuQjVJjno6pZpSKXYl7/bZyFaQxhf98hHDKEppwdWIW1frFnrxSOWHFfWesSEWC6R/P4zOFrix3TzDFLlXRTR8c0fEEJ1/itpo7SVO9Jdr1DVxZ0USyjZsEY5vZfiiAC0UoTGOrm9PZLuRl8X+Dq1HQtoFbJZbv61i+Poblh/97TC7n0neCcK0ETNUrz1/xPHf+DNAW9Ac6t8O8WH3Vp98f5lCaYKAOFZMLyHL4Y0fe319idMNgMMp+zWVSybUed/+/h7I4wRAG1W6XDy4XmjR9HnzvDRZXUAYDFOhC1S/Hh+fIXxen+eO+AKqbs+wAo30zDTDvDxKoJN88sjUzDFAvBzEUGFsnADoIvAJzoh2BZ8sner+Ke/vwECuQAAAABJRU5ErkJggg==') /*logo.png*/;
  background-repeat: no-repeat;
  background-position: 2px;
  background-color: white;
  border: none;
}

.layer-switcher.shown button {
  display: none;
}

.layer-switcher button:focus, .layer-switcher button:hover {
  background-color: white;
}

.layer-switcher ul {
  padding-left: 1em;
  list-style: none;
}

.layer-switcher li.group {
  padding-top: 5px;
}

.layer-switcher li.group > label {
  font-weight: bold;
}

.layer-switcher li.layer {
  display: table;
}

.layer-switcher li.layer label, .layer-switcher li.layer input {
  display: table-cell;
  vertical-align: sub;
}

.layer-switcher label.disabled {
  opacity:0.4;
}

.layer-switcher input {
  margin: 6px;
}

.layer-switcher.touch ::-webkit-scrollbar {
  width: 4px;
}

.layer-switcher.touch ::-webkit-scrollbar-track {
  -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
  border-radius: 10px;
}

.layer-switcher.touch ::-webkit-scrollbar-thumb {
  border-radius: 10px;
  -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.5);
}

/** Popup */

.ol-popup {
  position: absolute;
  min-width: 260px;
  background-color: white;
  -webkit-filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2));
  filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2));
  padding: 15px;
  border-radius: 10px;
  border: 1px solid #ccc;
  bottom: 12px;
  left: -50px;
}
.ol-popup:after, .ol-popup:before {
  top: 100%;
  border: solid transparent;
  content: " ";
  height: 0;
  width: 0;
  position: absolute;
  pointer-events: none;
}
.ol-popup:after {
  border-top-color: white;
  border-width: 10px;
  left: 48px;
  margin-left: -10px;
}
.ol-popup:before {
  border-top-color: #cccccc;
  border-width: 11px;
  left: 48px;
  margin-left: -11px;
}
.ol-popup-closer {
  text-decoration: none;
  position: absolute;
  top: 2px;
  right: 8px;
}
.ol-popup-closer:after {
  color: red;
  content: "✖";
}

所有代码都在Angular中工作,直到scr / app / app.component.ts中的'// popup'行!

在那行之后我有两个错误,当我用鼠标飞过地图时getEventPixel和当我点击标记时forEachFeatureAtPixel ...

Errors with forEachFeature at Pixel and getEventPixel

提前致谢!!

2 个答案:

答案 0 :(得分:3)

JavaScript不是Java。您没有将函数绑定到组件,因此this不是您认为的那样。阅读关于mozilla的full article about this

  

在箭头函数之前,每个新函数都定义了它自己的这个值。

但使用arrow function来轻松解决这个问题!

  

箭头功能没有自己的功能;使用封闭执行上下文的this值。

请考虑以下代码:

this.map.on('click', function(evt){ 
  this.map.getEventPixel
});

上面的代码试图访问它没有的事件函数function(evt)的属性映射。要修复它,只需将其更改为箭头功能:

this.map.on('click', (evt) => { 
  this.map.getEventPixel
});

在上面的代码中,this实际上是组件的上下文,因此map是组件的属性。

答案 1 :(得分:0)

我找到了“无法读取未定义的属性'forEachFeatureAtPixel”错误的解决方案。

我的初始代码(将引发错误):

this.map.on('click', function(evt){
   var feature = this.map.forEachFeatureAtPixel(evt.pixel, function(feature) {
                    return feature;
                 });
   if (feature) {
      console.log("Feature found");
   }
});

工作代码:

this.map.on('click', function(evt){
   var feature = evt.map.forEachFeatureAtPixel(evt.pixel, function(feature) {
                    return feature;
                 });
   if (feature) {
     console.log("Feature found");
   }
});

说明: 使用点击事件( evt .map.forEachFeatureAtPixel)中的地图实例,而不是根实例( this .map.forEachFeatureAtPixel)。