我正在尝试使用Google Maps API和KnockoutJS创建可过滤体育场馆的地图。除了用户键入输入并删除所有字符(搜索栏中没有字符......所有标记应返回到可见性)之外,标记过滤得很好。我已经尝试了几种不同的东西来使所有的标记在这种情况下可见,包括使用setVisible函数的各个地方,但是,似乎无法确定解决方案。我知道这可能很简单,但我有一个障碍。
非常感谢任何帮助。
这是我的代码:
HTML:
<!DOCTYPE html>
<html>
<head>
<link rel='stylesheet' href='css/bootstrap-theme.min.css'>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet">
<link rel='stylesheet' href='css/main.css'>
</head>
<body>
<container>
<nav>
<ul>
<div id='menu'>
<li>
<i class='material-icons'></i>
</li>
</div>
</ul>
</nav>
<div id='overmap'>
<div id='filter'>
<div class='filter-bar'>
<h2>Search Pittsburgh Sports Venues</h2>
<input id='userFilter' data-bind="value:userSearch, valueUpdate: 'input'" placeholder="Type a venue name..."/>
</div>
<ul id="list" data-bind="foreach: filterVenues">
<a href='#'> <li>
<h3 data-bind="text: name, click: $parent.setVenue"></h3>
</li></a>
</ul>
</div>
</div>
</div>
<div id='map'>
</div>
</container>
<script type='text/javascript' src='js/jquery-3.2.1.min.js'></script>
<script type='text/javascript' src='js/knockout-3.4.2.js'></script>
<script type='text/javascript' async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyA_WObUiYD7YpoYufR84re1LZHAJeAGXkY&v=3&callback=initMap">
</script>
<script type='text/javascript' src='js/app.js'></script>
<script type='text/javascript' src='js/menu.js'></script>
</body>
</html>
app.js:
var map;
var marker;
var infowindow;
var wikiURL;
var text;
var venueInfo;
var markers = [];
var markerNames = [];
var wikiURLs = [];
var venueArray = [];
var blackMarker = ('https://www.google.com/mapfiles/marker_black.png');
var yellowMarker = ('https://www.google.com/mapfiles/marker_yellow.png');
var currentMarker;
var currentVenue;
var venueList;
var filterVenues;
var clicker;
var venueMatch;
var venue;
var i;
var userSearch;
var setVenue;
var clickedVenue;
//The Model - Pro/Collegiate Stadiums in PGH, Pa.
var venues = [
{
name: "PNC Park",
lat: 40.446855,
lng: -80.0056666,
marker: '',
info: ''
},
{
name: "Heinz Field",
lat: 40.4466765,
lng: -80.01576,
marker: '',
info: ''
},
{
name: "PPG Paints Arena",
lat: 40.439593,
lng: -79.989338,
marker: '',
info: ''
},
{
name: "Highmark Stadium",
lat: 40.4362358,
lng: -80.00959209999999,
marker: '',
info: ''
},
{
name: "Peterson Events Center",
lat: 40.443828,
lng: -79.962283,
marker: '',
info: ''
}
];
function ajaxCall(i){
var venue = venues[i];
wikiURL = 'http://en.wikipedia.org/w/api.php?action=opensearch&search=' +venue.name+ '&format=json&callback=wikiCallback';
wikiURLs.push(wikiURL);
$.ajax ({
url: wikiURL,
dataType: "jsonp",
success: function(data){
text = data[2];
venues[i].info = text[0];
if (venue.info === undefined) {
venue.info = 'Whoops! Our data never showed up. Check out '+venue.name+' on Wikipedia for more!';
}
marker = new google.maps.Marker({
position: {lat: venue.lat, lng: venue.lng},
icon: blackMarker,
map: map,
name: venue.name,
draggable: false,
content: '<h2>'+venue.name+'</h2><p>'+venue.info+'</p>',
visible: true
});
markers.push(marker);
venue.marker = marker;
markerNames.push(marker.name);
infowindow = new google.maps.InfoWindow({
content: this.content
});
marker.addListener('click', function(){
infowindow.setContent(this.content);
infowindow.open(map, this);
for (var i = 0; i<markers.length; i++){
markers[i].setIcon(blackMarker);
}
this.setIcon(yellowMarker);
});
}
});
}
//capturing locations and names in arrays as we iterate through createMarker function
//marker creator
function createMarker(venue){
for (var i=0; i < venues.length; i++){
ajaxCall(i);
}
}
var viewmodel = function() {
var self = this;
self.userSearch = ko.observable("");
self.venues = ko.observableArray(venues);
this.currentVenue = ko.observable(self.venues()[0]);
this.setVenue = function(clickedVenue) {
self.currentVenue(clickedVenue);
google.maps.event.trigger(clickedVenue.marker, 'click');
};
self.filterVenues = ko.computed(function(venue) {
var search = self.userSearch().toLowerCase();
if (!search) {
return self.venues();
} else {
return ko.utils.arrayFilter(self.venues(), function(venue) {
if (venue.name.toLowerCase().indexOf(search) !== -1) {
venue.marker.setVisible(true);
return true;
} else {
venue.marker.setVisible(false);
return false;
}
});
}
});
};
//Map Initializer
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 40.446855, lng: -80.0056666},
zoom: 14,
mapTypeId: 'satellite'
});
createMarker();
ko.applyBindings(new viewmodel());
}
答案 0 :(得分:0)
一旦过滤器为空,显示所有标记的最简单方法可能是将filterVenues
observable更新为:
self.filterVenues = ko.computed(function (venue) {
var search = self.userSearch().toLowerCase();
return ko.utils.arrayFilter(self.venues(), function (venue) {
if (venue.name.toLowerCase().indexOf(search) !== -1) {
venue.marker.setVisible(true);
return true;
} else {
venue.marker.setVisible(false);
return false;
}
});
});
2)提供的例子还有一个缺陷。由于标记是异步添加,因此无法保证在显示地图时,每个场地都可以使用所有标记。
我建议改变初始化过滤器控件的方式,特别是绑定过滤器控件一旦所有标记初始化。
initMarkers(map, infowindow)
.done(function () {
ko.applyBindings(new viewmodel());
console.log("map is ready");
});
我们引入了一个初始化标记的函数:
function initMarkers(map, infowindow) {
var promises = [];
for (var i = 0; i < venues.length; i++) {
var request = (function (venue) {
return loadDetails(venue)
.then(function (data) {
venue.info = data[2];
if (venue.info === undefined) {
venue.info = 'Whoops! Our data never showed up. Check out ' + venue.name + ' on Wikipedia for more!';
}
createMarker(map, infowindow, venue);
});
})(venues[i]);
}
promises.push(request);
return $.when.apply(null, promises);
}
和使用CORS而不是JSONP(没有callback
参数)加载维基百科数据的函数:
function loadDetails(venue) {
var wikiURL = 'https://en.wikipedia.org/w/api.php?&origin=*&action=opensearch&search=' + venue.name + '&format=json';
return $.ajax({
url: wikiURL
});
}
3)最后但并非最不重要的是,不需要为每个标记创建信息窗口的实例,而是可以创建单个实例。
下面提供了修改示例
var blackMarker = ('https://www.google.com/mapfiles/marker_black.png');
var yellowMarker = ('https://www.google.com/mapfiles/marker_yellow.png');
//The Model - Pro/Collegiate Stadiums in PGH, Pa.
var venues = [
{
name: "PNC Park",
lat: 40.446855,
lng: -80.0056666,
marker: '',
info: ''
},
{
name: "Heinz Field",
lat: 40.4466765,
lng: -80.01576,
marker: '',
info: ''
},
{
name: "PPG Paints Arena",
lat: 40.439593,
lng: -79.989338,
marker: '',
info: ''
},
{
name: "Highmark Stadium",
lat: 40.4362358,
lng: -80.00959209999999,
marker: '',
info: ''
},
{
name: "Peterson Events Center",
lat: 40.443828,
lng: -79.962283,
marker: '',
info: ''
}
];
function loadDetails(venue) {
var wikiURL = 'https://en.wikipedia.org/w/api.php?&origin=*&action=opensearch&search=' + venue.name + '&format=json';
return $.ajax({
url: wikiURL
});
}
function createMarker(map, infowindow, venue) {
var marker = new google.maps.Marker({
position: { lat: venue.lat, lng: venue.lng },
icon: blackMarker,
map: map,
name: venue.name,
draggable: false,
content: '<h2>' + venue.name + '</h2><p>' + venue.info + '</p>',
visible: true
});
//console.log(marker.name);
marker.addListener('click', function () {
if (infowindow.prevMarker)
infowindow.prevMarker.setIcon(blackMarker);
infowindow.setContent(this.content);
infowindow.open(map, this);
this.setIcon(yellowMarker);
infowindow.prevMarker = this;
});
venue.marker = marker;
return marker;
}
function initMarkers(map, infowindow) {
var promises = [];
for (var i = 0; i < venues.length; i++) {
var request = (function (venue) {
return loadDetails(venue)
.then(function (data) {
venue.info = data[2];
if (venue.info === undefined) {
venue.info = 'Whoops! Our data never showed up. Check out ' + venue.name + ' on Wikipedia for more!';
}
return createMarker(map, infowindow, venue);
});
})(venues[i]);
}
promises.push(request);
return $.when.apply(null, promises);
}
var viewmodel = function () {
var self = this;
self.userSearch = ko.observable("");
self.venues = ko.observableArray(venues);
self.currentVenue = ko.observable(self.venues()[0]);
self.setVenue = function (clickedVenue) {
self.currentVenue(clickedVenue);
google.maps.event.trigger(clickedVenue.marker, 'click');
};
self.filterVenues = ko.computed(function (venue) {
var search = self.userSearch().toLowerCase();
return ko.utils.arrayFilter(self.venues(), function (venue) {
if (venue.name.toLowerCase().indexOf(search) !== -1) {
venue.marker.setVisible(true);
return true;
} else {
venue.marker.setVisible(false);
return false;
}
});
});
};
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
center: { lat: 40.446855, lng: -80.0056666 },
zoom: 14,
mapTypeId: 'satellite'
});
var infowindow = new google.maps.InfoWindow({
content: ""
});
initMarkers(map, infowindow)
.done(function () {
ko.applyBindings(new viewmodel());
//console.log("map is ready");
});
}
google.maps.event.addDomListener(window, 'load', initMap);
#map{
width: 100%;
height: 420px;
}
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>
<script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js'></script>
<script type='text/javascript' src="https://maps.googleapis.com/maps/api/js">
</script>
<div id='overmap'>
<div id='filter'>
<div class='filter-bar'>
<h2>Search Pittsburgh Sports Venues</h2>
<input id='userFilter' data-bind="value:userSearch, valueUpdate: 'input'" placeholder="Type a venue name..." />
</div>
<ul id="list" data-bind="foreach: filterVenues">
<a href='#'>
<li>
<h3 data-bind="text: name, click: $parent.setVenue"></h3>
</li>
</a>
</ul>
</div>
</div>
</div>
<div id='map'></div>