我正在尝试将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
提前致谢!!
答案 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)。