Openlayers:在单个页面上对具有多个 maps/views 的点击事件使用 for 循环
Openlayers: Using for loop for click events with multiple maps/views on single page
我正在尝试将包含多张地图的页面放在一起(一张地图包含一组所有路线,每条路线各一张),每张地图都位于不同的 (Bootstrap) 选项卡中。我让它与最重复的代码一起工作,通过重复并独立地为每个地图分配我想要的 click 和 pointermove 事件,但理想情况下我会在某种循环中分配这些事件。
我的尝试是我在下面粘贴的内容,它有效,但仅适用于最终地图 - 如果我更改地图的顺序,它们中的任何一个都将有效,但前提是它是最后一个。我找不到关于我正在寻找的东西的太多方向,,它提到了同样的问题,即只在最后一张地图上工作,尽管我无法充分利用所提供的答案. 有没有办法遍历这些事件并让它们处理多个 views/maps?
非常感谢任何方向!
Javascript:
//----------/MAP 0/----------//
var myView0 = new ol.View({
center: ol.proj.fromLonLat([-87.068669, 8.470072]),
zoom: 3,
});
var map0 = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
vectorLayerJNY10,
vectorLayerJNY11,
vectorLayerJNY12,
hoverLayers['route'],
],
target: 'map0',
view: myView0,
});
//----------/MAP 1/----------//
var myView1 = new ol.View({
center: ol.proj.fromLonLat([-94.803044, 36.719405]),
zoom: 3.5,
});
var map1 = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
vectorLayerJNY10,
hoverLayers['route'],
],
target: 'map1',
view: myView1,
});
//----------/MAP 2/----------//
var myView2 = new ol.View({
center: ol.proj.fromLonLat([-114.778097, 32.698996]),
zoom: 4,
});
var map2 = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
vectorLayerJNY11,
hoverLayers['route'],
],
target: 'map2',
view: myView2
});
//----------/MAP 3/----------//
var myView3 = new ol.View({
center: ol.proj.fromLonLat([-93.988196, 19.253431]),
zoom: 4
});
var map3 = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
vectorLayerJNY12,
hoverLayers['route'],
],
target: 'map3',
view: myView3
});
var maps = [map0, map1, map2, map3];
var views = [myView0, myView1, myView2, myView3]
var mapOnClick = function (event) {
if (event.map.hasFeatureAtPixel(event.pixel) === true) {
var name = event.map.forEachFeatureAtPixel(event.pixel, function(feature) {
return feature.get('name');
})
var coordinate = event.coordinate;
content.innerHTML = name;
olay.setPosition(coordinate);
} else {
olay.setPosition(undefined);
closer.blur();
}
};
var elmHover = function(evt) {
if (evt.dragging) {
return;
}
var pixel = evt.map.getEventPixel(evt.originalEvent);
var map = elem;
hover(pixel, map);
};
var cursor = function(evt) {
elem.getTargetElement().style.cursor = elem.hasFeatureAtPixel(evt.pixel) ? 'pointer' : '';
};
var mapResize = function(event){
setTimeout(function() {
elem.updateSize();
}, 200);
};
for(var i = 0; i < maps.length; i++){
var elem = maps[i];
var container = document.getElementById('popup' + i);
var content = document.getElementById('popup-content' + i);
var closer = document.getElementById('popup-closer' + i);
var overlays = [];
overlays[i] = new ol.Overlay({
element: container,
autoPan: true,
autoPanAnimation: {
duration: 250
}
});
elem.addOverlay(overlays[i]);
olay = overlays[i];
view = views[i];
elem.on('pointermove', elmHover);
elem.on('singleclick', mapOnClick);
elem.on('pointermove', cursor);
closer.onclick = function() {
layover.setPosition(undefined);
closer.blur();
return false;
};
$('.nav-tabs').on('shown.bs.tab', mapResize)
$('.nav-tabs').on('hide.bs.tab', function(event){
elem.setView(view);
olay.setPosition(undefined);
});
}
HTML(以防万一:3):
<ul class="nav nav-tabs nav-justified" role="tablist">
<li class="nav-item" >
<a class="nav-link active" data-toggle="tab" href="#About">About</a>
</li>
<li class="nav-item" >
<a class="nav-link" data-toggle="tab" href="#Journey-I">Journeys I</a>
</li>
<li class="nav-item" >
<a class="nav-link" data-toggle="tab" href="#Journey-II">Journey II</a>
</li>
<li class="nav-item" >
<a class="nav-link" data-toggle="tab" href="#Journey-III">Journey III</a>
</li>
</ul>
<div class="tab-content">
<div id="About" class="tab-pane fade show active" role="tabpanel">
<h3>About</h3>
<div id="map0" class="map"></div>
<div id="popup0" class="ol-popup">
<a href="#" id="popup-closer0" class="ol-popup-closer"></a>
<div id="popup-content0"></div>
</div>
</div>
<div id="Journey-I" class="tab-pane fade" role="tabpanel">
<h3>Journey I</h3>
<div id="map1" class="map"></div>
<div id="popup1" class="ol-popup">
<a href="#" id="popup-closer1" class="ol-popup-closer"></a>
<div id="popup-content1"></div>
</div>
</div>
<div id="Journey-II" class="tab-pane fade" role="tabpanel">
<h3>Journey II</h3>
<div id="map2" class="map"></div>
<div id="popup2" class="ol-popup">
<a href="#" id="popup-closer2" class="ol-popup-closer"></a>
<div id="popup-content2"></div>
</div>
</div>
<div id="Journey-III" class="tab-pane fade" role="tabpanel">
<h3>Journey III</h3>
<div id="map3" class="map"></div>
<div id="popup3" class="ol-popup">
<a href="#" id="popup-closer3" class="ol-popup-closer"></a>
<div id="popup-content3"></div>
</div>
</div>
<script src="{{ url_for('static', filename='JS/OLmap_ajall.js') }}" type="text/javascript"></script>
</div>
就像你查的问题说的,是上下文的问题
在每个事件的处理程序中,您正在使用在循环中取值的变量,elem
、olay
、view
。问题是,当事件发生时,这些变量的值引用它们各自数组的最后一张地图、叠加层和视图。
有几种方法可以解决这个问题。我会建议你使用 bind
函数方法 (JavaScript - function bind).
var mapOnClick = function (event) {
if (this.map.hasFeatureAtPixel(event.pixel) === true) {
var name = this.map.forEachFeatureAtPixel(event.pixel, function(feature) {
return feature.get('name');
})
var coordinate = event.coordinate;
this.content.innerHTML = name;
this.overlay.setPosition(coordinate);
} else {
this.overlay.setPosition(undefined);
this.closer.blur();
}
};
var elmHover = function(evt) {
if (evt.dragging) {
return;
}
var pixel = this.map.getEventPixel(evt.originalEvent);
// var map = elem; <- what is this for?
hover(pixel, this.map); // <- this function is not defined, look out
};
var cursor = function(evt) {
this.map.getTargetElement().style.cursor =
this.map.hasFeatureAtPixel(evt.pixel) ? 'pointer' : '';
};
var mapResize = function(event){
var self = this;
setTimeout(function() {
self.map.updateSize();
}, 200);
};
var closerOnClick = function() {
this.overlay.setPosition(undefined); // I am guessing is overlay
this.closer.blur();
return false;
}
var onHide = function(event){
this.map.setView(this.view); // <- don't understand this
this.overlay.setPosition(undefined);
}
var contexts = [
{ map: map0, view: myView0 },
{ map: map1, view: myView1 },
{ map: map2, view: myView2 },
{ map: map3, view: myView3 }
];
for(var i = 0; i < contexts.length; i++){
contexts[i].container = document.getElementById('popup' + i);
contexts[i].content = document.getElementById('popup-content' + i);
contexts[i].closer = document.getElementById('popup-closer' + i);
contexts[i].overlay = new ol.Overlay({
element: contexts[i].container,
autoPan: true,
autoPanAnimation: {
duration: 250
}
});
contexts[i].map.addOverlay(contexts[i].overlay);
contexts[i].mapOnClick = mapOnClick.bind(contexts[i]);
contexts[i].elmHover = elmHover.bind(contexts[i]);
contexts[i].cursor = cursor.bind(contexts[i]);
contexts[i].mapResize = mapResize.bind(contexts[i]);
contexts[i].map.on('singleclick', contexts[i].mapOnClick);
contexts[i].map.on('pointermove', contexts[i].cursor);
contexts[i].closer.onclick = contexts[i].closerOnClick;
// don't understand why these are in the loop
$('.nav-tabs').on('shown.bs.tab', contexts[i].mapResize);
$('.nav-tabs').on('hide.bs.tab', contexts[i].onHide);
}
注意:
有几件事我不理解你的代码,再加上你在每次迭代中初始化覆盖数组,而且你有错误的变量名称。这是很长的代码,没有检查它,所以请注意可能存在一些问题。只是为了让你出主意。
我注意到您正在使用 jQuery,您也可以使用 proxy
来保持上下文。虽然我注意到它已被弃用。
我正在尝试将包含多张地图的页面放在一起(一张地图包含一组所有路线,每条路线各一张),每张地图都位于不同的 (Bootstrap) 选项卡中。我让它与最重复的代码一起工作,通过重复并独立地为每个地图分配我想要的 click 和 pointermove 事件,但理想情况下我会在某种循环中分配这些事件。
我的尝试是我在下面粘贴的内容,它有效,但仅适用于最终地图 - 如果我更改地图的顺序,它们中的任何一个都将有效,但前提是它是最后一个。我找不到关于我正在寻找的东西的太多方向,
非常感谢任何方向!
Javascript:
//----------/MAP 0/----------//
var myView0 = new ol.View({
center: ol.proj.fromLonLat([-87.068669, 8.470072]),
zoom: 3,
});
var map0 = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
vectorLayerJNY10,
vectorLayerJNY11,
vectorLayerJNY12,
hoverLayers['route'],
],
target: 'map0',
view: myView0,
});
//----------/MAP 1/----------//
var myView1 = new ol.View({
center: ol.proj.fromLonLat([-94.803044, 36.719405]),
zoom: 3.5,
});
var map1 = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
vectorLayerJNY10,
hoverLayers['route'],
],
target: 'map1',
view: myView1,
});
//----------/MAP 2/----------//
var myView2 = new ol.View({
center: ol.proj.fromLonLat([-114.778097, 32.698996]),
zoom: 4,
});
var map2 = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
vectorLayerJNY11,
hoverLayers['route'],
],
target: 'map2',
view: myView2
});
//----------/MAP 3/----------//
var myView3 = new ol.View({
center: ol.proj.fromLonLat([-93.988196, 19.253431]),
zoom: 4
});
var map3 = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
vectorLayerJNY12,
hoverLayers['route'],
],
target: 'map3',
view: myView3
});
var maps = [map0, map1, map2, map3];
var views = [myView0, myView1, myView2, myView3]
var mapOnClick = function (event) {
if (event.map.hasFeatureAtPixel(event.pixel) === true) {
var name = event.map.forEachFeatureAtPixel(event.pixel, function(feature) {
return feature.get('name');
})
var coordinate = event.coordinate;
content.innerHTML = name;
olay.setPosition(coordinate);
} else {
olay.setPosition(undefined);
closer.blur();
}
};
var elmHover = function(evt) {
if (evt.dragging) {
return;
}
var pixel = evt.map.getEventPixel(evt.originalEvent);
var map = elem;
hover(pixel, map);
};
var cursor = function(evt) {
elem.getTargetElement().style.cursor = elem.hasFeatureAtPixel(evt.pixel) ? 'pointer' : '';
};
var mapResize = function(event){
setTimeout(function() {
elem.updateSize();
}, 200);
};
for(var i = 0; i < maps.length; i++){
var elem = maps[i];
var container = document.getElementById('popup' + i);
var content = document.getElementById('popup-content' + i);
var closer = document.getElementById('popup-closer' + i);
var overlays = [];
overlays[i] = new ol.Overlay({
element: container,
autoPan: true,
autoPanAnimation: {
duration: 250
}
});
elem.addOverlay(overlays[i]);
olay = overlays[i];
view = views[i];
elem.on('pointermove', elmHover);
elem.on('singleclick', mapOnClick);
elem.on('pointermove', cursor);
closer.onclick = function() {
layover.setPosition(undefined);
closer.blur();
return false;
};
$('.nav-tabs').on('shown.bs.tab', mapResize)
$('.nav-tabs').on('hide.bs.tab', function(event){
elem.setView(view);
olay.setPosition(undefined);
});
}
HTML(以防万一:3):
<ul class="nav nav-tabs nav-justified" role="tablist">
<li class="nav-item" >
<a class="nav-link active" data-toggle="tab" href="#About">About</a>
</li>
<li class="nav-item" >
<a class="nav-link" data-toggle="tab" href="#Journey-I">Journeys I</a>
</li>
<li class="nav-item" >
<a class="nav-link" data-toggle="tab" href="#Journey-II">Journey II</a>
</li>
<li class="nav-item" >
<a class="nav-link" data-toggle="tab" href="#Journey-III">Journey III</a>
</li>
</ul>
<div class="tab-content">
<div id="About" class="tab-pane fade show active" role="tabpanel">
<h3>About</h3>
<div id="map0" class="map"></div>
<div id="popup0" class="ol-popup">
<a href="#" id="popup-closer0" class="ol-popup-closer"></a>
<div id="popup-content0"></div>
</div>
</div>
<div id="Journey-I" class="tab-pane fade" role="tabpanel">
<h3>Journey I</h3>
<div id="map1" class="map"></div>
<div id="popup1" class="ol-popup">
<a href="#" id="popup-closer1" class="ol-popup-closer"></a>
<div id="popup-content1"></div>
</div>
</div>
<div id="Journey-II" class="tab-pane fade" role="tabpanel">
<h3>Journey II</h3>
<div id="map2" class="map"></div>
<div id="popup2" class="ol-popup">
<a href="#" id="popup-closer2" class="ol-popup-closer"></a>
<div id="popup-content2"></div>
</div>
</div>
<div id="Journey-III" class="tab-pane fade" role="tabpanel">
<h3>Journey III</h3>
<div id="map3" class="map"></div>
<div id="popup3" class="ol-popup">
<a href="#" id="popup-closer3" class="ol-popup-closer"></a>
<div id="popup-content3"></div>
</div>
</div>
<script src="{{ url_for('static', filename='JS/OLmap_ajall.js') }}" type="text/javascript"></script>
</div>
就像你查的问题说的,是上下文的问题
在每个事件的处理程序中,您正在使用在循环中取值的变量,elem
、olay
、view
。问题是,当事件发生时,这些变量的值引用它们各自数组的最后一张地图、叠加层和视图。
有几种方法可以解决这个问题。我会建议你使用 bind
函数方法 (JavaScript - function bind).
var mapOnClick = function (event) {
if (this.map.hasFeatureAtPixel(event.pixel) === true) {
var name = this.map.forEachFeatureAtPixel(event.pixel, function(feature) {
return feature.get('name');
})
var coordinate = event.coordinate;
this.content.innerHTML = name;
this.overlay.setPosition(coordinate);
} else {
this.overlay.setPosition(undefined);
this.closer.blur();
}
};
var elmHover = function(evt) {
if (evt.dragging) {
return;
}
var pixel = this.map.getEventPixel(evt.originalEvent);
// var map = elem; <- what is this for?
hover(pixel, this.map); // <- this function is not defined, look out
};
var cursor = function(evt) {
this.map.getTargetElement().style.cursor =
this.map.hasFeatureAtPixel(evt.pixel) ? 'pointer' : '';
};
var mapResize = function(event){
var self = this;
setTimeout(function() {
self.map.updateSize();
}, 200);
};
var closerOnClick = function() {
this.overlay.setPosition(undefined); // I am guessing is overlay
this.closer.blur();
return false;
}
var onHide = function(event){
this.map.setView(this.view); // <- don't understand this
this.overlay.setPosition(undefined);
}
var contexts = [
{ map: map0, view: myView0 },
{ map: map1, view: myView1 },
{ map: map2, view: myView2 },
{ map: map3, view: myView3 }
];
for(var i = 0; i < contexts.length; i++){
contexts[i].container = document.getElementById('popup' + i);
contexts[i].content = document.getElementById('popup-content' + i);
contexts[i].closer = document.getElementById('popup-closer' + i);
contexts[i].overlay = new ol.Overlay({
element: contexts[i].container,
autoPan: true,
autoPanAnimation: {
duration: 250
}
});
contexts[i].map.addOverlay(contexts[i].overlay);
contexts[i].mapOnClick = mapOnClick.bind(contexts[i]);
contexts[i].elmHover = elmHover.bind(contexts[i]);
contexts[i].cursor = cursor.bind(contexts[i]);
contexts[i].mapResize = mapResize.bind(contexts[i]);
contexts[i].map.on('singleclick', contexts[i].mapOnClick);
contexts[i].map.on('pointermove', contexts[i].cursor);
contexts[i].closer.onclick = contexts[i].closerOnClick;
// don't understand why these are in the loop
$('.nav-tabs').on('shown.bs.tab', contexts[i].mapResize);
$('.nav-tabs').on('hide.bs.tab', contexts[i].onHide);
}
注意: 有几件事我不理解你的代码,再加上你在每次迭代中初始化覆盖数组,而且你有错误的变量名称。这是很长的代码,没有检查它,所以请注意可能存在一些问题。只是为了让你出主意。
我注意到您正在使用 jQuery,您也可以使用 proxy
来保持上下文。虽然我注意到它已被弃用。