我正在使用谷歌地图API创建邻居地图。我添加了一些位置并创建了标记。我想添加搜索过滤器功能,以便用户可以按名称搜索这些位置。它应包括一个文本输入字段或下拉菜单,用于过滤地图标记和列表项以匹配文本输入或选择的位置。 列表项过滤工作正常但标记(位置)未过滤。 所以我想问一下如何使用setVisible()属性来隐藏和显示代码中的标记。
这是过滤器模块:
function viewModel(markers) {
var self = this;
self.filter = ko.observable(''); // this is for the search box
self.items = ko.observableArray(locations);
self.filteredItems = ko.computed(function() {
var filter = self.filter().toLowerCase();
if (!filter) {
return self.items();
} else {
return ko.utils.arrayFilter(self.items(), function(id) {
return stringStartsWith(id.title.toLowerCase(), filter);
});
}
});
这是我的.js文件的完整代码。
var map;
var locations = [
{title: 'The Red Fort', location: {lat: 28.6562, lng: 77.2410}},
{title: 'Humayun\'s Tomb', location: {lat: 28.5933, lng: 77.2507}},
{title: 'India Gate', location: {lat: 28.6129, lng: 77.2295}},
{title: 'Lotus Temple', location: {lat: 28.5535, lng: 77.2588}},
{title: 'Akshardham Temple', location: {lat: 28.6127, lng: 77.2773}},
{title: 'Lodhi Gardens', location: {lat: 28.5931, lng: 77.2179}},
{title: 'Raj Ghat', location: {lat: 28.6406, lng: 77.2495}},
{title: 'Jama Masjid', location: {lat: 28.6507, lng: 77.2334}},
{title: 'Gurudwara Bangla Sahib', location: {lat: 28.6264, lng:
77.2091}},
{title: 'Qutub Minar', location: {lat: 28.5244, lng: 77.1855}},
];
var center =[{lat : 28.5244, lng : 77.1855}];
var markers = []; // Creating a new blank array for all the listing markers.
var styles = [
{
featureType: 'water',
stylers: [
{ color: '#19a0d8' }
]
},{
featureType: 'administrative',
elementType: 'labels.text.stroke',
stylers: [
{ color: '#ffffff' },
{ weight: 6 }
]
},{
featureType: 'administrative',
elementType: 'labels.text.fill',
stylers: [
{ color: '#e85113' }
]
},{
featureType: 'road.highway',
elementType: 'geometry.stroke',
stylers: [
{ color: '#efe9e4' },
{ lightness: -40 }
]
},{
featureType: 'transit.station',
stylers: [
{ weight: 9 },
{ hue: '#e85113' }
]
},{
featureType: 'road.highway',
elementType: 'labels.icon',
stylers: [
{ visibility: 'off' }
]
},{
featureType: 'water',
elementType: 'labels.text.stroke',
stylers: [
{ lightness: 100 }
]
},{
featureType: 'water',
elementType: 'labels.text.fill',
stylers: [
{ lightness: -100 }
]
},{
featureType: 'poi',
elementType: 'geometry',
stylers: [
{ visibility: 'on' },
{ color: '#f0e4d3' }
]
},{
featureType: 'road.highway',
elementType: 'geometry.fill',
stylers: [
{ color: '#efe9e4' },
{ lightness: -25 }
]
}
];
function initMap() {
// Constructor creates a new map
map = new google.maps.Map(document.getElementById('map'), {
center: center[0],
zoom: 13,
styles: styles,
mapTypeControl: false
});
var largeInfowindow = new google.maps.InfoWindow();
var bounds = new google.maps.LatLngBounds();
var defaultIcon = makeMarkerIcon('0091ff'); // this is the default marker icon.
var highlightedIcon = makeMarkerIcon('FFFF24'); // this is the state of the marker when highlighted.
var activeIcon = makeMarkerIcon('0F0');
for (var i = 0; i < locations.length; i++) {
var position = locations[i].location; // Get the position from the location array.
var title = locations[i].title;
marker(locations);
}
// Create a marker per location, and put into markers array.
function marker(locations)
{var marker = new google.maps.Marker({
map: map,
position: position,
title: title,
animation: google.maps.Animation.DROP,
id: i,
});
locations[i].marker = marker; // we made marker a property of the locations and stored info of each marker
wikiLink(locations[i]);
markers.push(marker); // Push the marker to our array of markers.
// Create an onclick event to open an infowindow at each marker.
marker.addListener('click', function() {
populateInfoWindow(this, largeInfowindow);
this.setIcon(activeIcon);
});
bounds.extend(markers[i].position);
/*
marker.addListener('mouseover', function() {
this.setIcon(highlightedIcon);
});
*/
marker.addListener('mouseout', function() {
this.setIcon(defaultIcon);
});
}
// Extend the boundaries of the map for each marker
map.fitBounds(bounds);
function wikiLink(location) {
location.url = '';
var wikiUrl = 'https://en.wikipedia.org/w/api.php?action=opensearch&search=' + title + '&format=json&callback=wikiCallback';
//If you cant get a wiki request, throw an error message.
/*
var wikiError = setTimeout(function() {
location.url = 'Unable to find the request';
}, 8000);
*/
$.ajax({
url: wikiUrl,
dataType: "jsonp",
jsonp: "callback",
success: function(response) {
console.log(response);
var url = response[3][0];
console.log(url);
location.marker.wikiurl = url;
console.log(location.url);
//clearTimeout(wikiError);
}
})
.fail(function (jqXHR, textStatus, error) {
error = 'Unable to find the request';
alert("Post error: " + error);
});
}
}
// This function populates the infowindow when the marker is clicked. We'll only allow
// one infowindow which will open at the marker that is clicked, and populate based
// on that markers position.
function populateInfoWindow(marker, infowindow) {
// Check to make sure the infowindow is not already opened on this marker.
if (infowindow.marker != marker) {
infowindow.setContent(''); // Clearing the infowindow content to give the streetview time to load.
infowindow.marker = marker;
// Making sure the marker property is cleared if the infowindow is closed.
infowindow.addListener('closeclick', function() {
infowindow.marker = null;
});
// In case the status is OK, which means the pano was found, computing the position of the streetview image, then calculate the heading, then get a
// panorama from that and set the options
var getStreetView = function(data, status) {
if (status == google.maps.StreetViewStatus.OK) {
var nearStreetViewLocation = data.location.latLng;
var heading = google.maps.geometry.spherical.computeHeading(
nearStreetViewLocation, marker.position);
infowindow.setContent('<div>' + marker.title + '</div><hr><div id="pano"></div><div><a href=' + marker.wikiurl + '> Click here for more info </a></div>');
var panoramaOptions = {
position: nearStreetViewLocation,
pov: {
heading: heading,
pitch: 30
}
};
var panorama = new google.maps.StreetViewPanorama(
document.getElementById('pano'), panoramaOptions);
} else {
infowindow.setContent('<div>' + marker.title + '</div><hr>' + '<div>No Street View Found</div>');
}
};
var streetViewService = new google.maps.StreetViewService();
var radius = 500;
// Use streetview service to get the closest streetview image within 50 meters of the markers position
streetViewService.getPanoramaByLocation(marker.position, radius, getStreetView);
infowindow.open(map, marker); // Open the infowindow on the correct marker.
}
}
// This function takes in a COLOR, and then creates a new marker icon of that color.
// The icon will be 21 px wide by 34 high, have an origin of 0, 0 and be anchored at 10, 34).
function makeMarkerIcon(markerColor) {
var markerImage = new google.maps.MarkerImage(
'http://chart.googleapis.com/chart?chst=d_map_spin&chld=1.15|0|'+ markerColor +
'|40|_|%E2%80%A2',
new google.maps.Size(21, 34),
new google.maps.Point(0, 0),
new google.maps.Point(10, 34),
new google.maps.Size(21,34));
return markerImage;
}
function viewModel(markers) {
var self = this;
self.filter = ko.observable(''); // this is for the search box, takes value in it and searches for it in the array
self.items = ko.observableArray(locations); // we have made the array of locations into a ko.observableArray
self.filteredItems = ko.computed(function() {
var filter = self.filter().toLowerCase();
if (!filter) {
return self.items();
} else {
return ko.utils.arrayFilter(self.items(), function(id) {
return stringStartsWith(id.title.toLowerCase(), filter);
});
}
});
var stringStartsWith = function (string, startsWith) {
string = string || "";
if (startsWith.length > string.length)
return false;
return string.substring(0, startsWith.length) === startsWith;
};
// this should show the infowindow if any place on the list is clicked
this.showInfoWindow = function(place) {
google.maps.event.trigger(place.marker, 'click');
};
}
$(function(){
ko.applyBindings(new viewModel());
});
这是.html文件
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Map of my favourite city - New Delhi</title>
<link href="css/map_styles.css" rel="stylesheet">
<link href="css/styles.css" rel="stylesheet">
<script src="js/jquery-3.1.1.min.js"></script>
<script src="js/knockout-3.4.1.js"></script>
</head>
<body>
<div id="mySidenav" class="sidenav">
<span class="menu-title">List of places</span>
<input type="text" data-bind="textInput: filter" placeholder="Search from the list">
<ul class="" style="list-style-type: none;" data-bind="foreach: filteredItems">
<li>
<a href="#"><span data-bind="text: title, click: $parent.showInfoWindow"></span></a>
</li>
</ul>
<a href="javascript:void(0)" class="closebtn" onclick="closeNav()">×</a>
</div>
<div id="main">
<h2>Famous places in New Delhi</h2>
<span style="font-size:30px;cursor:pointer" onclick="openNav()">☰ Click here</span>
</div>
<div id="map"></div>
<div id="map-error" class="map-error"></div>
<script src="js/newmap.js"></script>
<script src="js/maperror.js"></script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCwUdUoC9ZiRbFC3et89fPK3tXIVO8D2sI&callback=initMap"
onerror="mapError()"></script>
<script>
function openNav() {
document.getElementById("mySidenav").style.width = "250px";
}
function closeNav() {
document.getElementById("mySidenav").style.width = "0";
}
</script>
</body>
</html>
答案 0 :(得分:0)
感谢您提出这个问题:)这是一项有趣的练习。我不确定我的答案是否会让您满意,因为每次完成过滤后它都会重新初始化地图。我不确定如何解决这个问题,因为viewModel和initMap方法是分开的。但它符合你的要求。
修改了initMap()
方法以获取数组参数,保持布尔值。如果数组没有定义标记&#39;可见性默认为true
修改了viewModel,创建了一个数组来保存布尔值。每次调用viewModel时都会清空数组,并且拼接标记只保留原始值(我确定你可以改进的其中一个区域)。在ko.utils.arrayFilter()
方法内,如果返回的值为true
,我也会将true
值推送到数组中。在数组的末尾,我再次调用initMap()
方法,将此数组作为输入。现在,只有在重新初始化时才能看到在搜索中过滤为true
的位置。
在应用绑定时,我提供了markers
变量作为viewModel的输入。 (我想你已经打算这样做,但忘了)。
<强>更新强>
<script src="js/newmap.js"></script>
<script src="js/maperror.js"></script>
带有一个空<script>
标记,并将整个JS代码放在那里。为避免混淆,我将删除上面提到的所有代码片段并在此处显示整个文件:
<html>
<head>
<title>TODO supply a title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type='text/javascript' src='knockout-3.4.2.js'></script>
<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
<style>
#map {
height: 400px;
width: 100%;
}
</style>
</head>
<body>
<div id="mySidenav" class="sidenav">
<span class="menu-title">List of places</span>
<input type="text" data-bind="textInput: filter" placeholder="Search from the list">
<ul class="" style="list-style-type: none;" data-bind="foreach: filteredItems">
<li>
<a href="#"><span data-bind="text: title, click: $parent.showInfoWindow"></span></a>
</li>
</ul>
<a href="javascript:void(0)" class="closebtn" onclick="closeNav()">×</a>
</div>
<div id="main">
<h2>Famous places in New Delhi</h2>
<span style="font-size:30px;cursor:pointer" onclick="openNav()">☰ Click here</span>
</div>
<div id="map"></div>
<div id="map-error" class="map-error"></div>
<script>
var map;
var locations = [
{title: 'The Red Fort', location: {lat: 28.6562, lng: 77.2410}},
{title: 'Humayun\'s Tomb', location: {lat: 28.5933, lng: 77.2507}},
{title: 'India Gate', location: {lat: 28.6129, lng: 77.2295}},
{title: 'Lotus Temple', location: {lat: 28.5535, lng: 77.2588}},
{title: 'Akshardham Temple', location: {lat: 28.6127, lng: 77.2773}},
{title: 'Lodhi Gardens', location: {lat: 28.5931, lng: 77.2179}},
{title: 'Raj Ghat', location: {lat: 28.6406, lng: 77.2495}},
{title: 'Jama Masjid', location: {lat: 28.6507, lng: 77.2334}},
{title: 'Gurudwara Bangla Sahib', location: {lat: 28.6264, lng:
77.2091}},
{title: 'Qutub Minar', location: {lat: 28.5244, lng: 77.1855}},
];
var center = [{lat: 28.5244, lng: 77.1855}];
var markers = []; // Creating a new blank array for all the listing markers.
var styles = [
{
featureType: 'water',
stylers: [
{color: '#19a0d8'}
]
}, {
featureType: 'administrative',
elementType: 'labels.text.stroke',
stylers: [
{color: '#ffffff'},
{weight: 6}
]
}, {
featureType: 'administrative',
elementType: 'labels.text.fill',
stylers: [
{color: '#e85113'}
]
}, {
featureType: 'road.highway',
elementType: 'geometry.stroke',
stylers: [
{color: '#efe9e4'},
{lightness: -40}
]
}, {
featureType: 'transit.station',
stylers: [
{weight: 9},
{hue: '#e85113'}
]
}, {
featureType: 'road.highway',
elementType: 'labels.icon',
stylers: [
{visibility: 'off'}
]
}, {
featureType: 'water',
elementType: 'labels.text.stroke',
stylers: [
{lightness: 100}
]
}, {
featureType: 'water',
elementType: 'labels.text.fill',
stylers: [
{lightness: -100}
]
}, {
featureType: 'poi',
elementType: 'geometry',
stylers: [
{visibility: 'on'},
{color: '#f0e4d3'}
]
}, {
featureType: 'road.highway',
elementType: 'geometry.fill',
stylers: [
{color: '#efe9e4'},
{lightness: -25}
]
}
];
function initMap(array) {
// Constructor creates a new map
map = new google.maps.Map(document.getElementById('map'), {
center: center[0],
zoom: 13,
styles: styles,
mapTypeControl: false
});
var largeInfowindow = new google.maps.InfoWindow();
var bounds = new google.maps.LatLngBounds();
var defaultIcon = makeMarkerIcon('0091ff'); // this is the default marker icon.
var highlightedIcon = makeMarkerIcon('FFFF24'); // this is the state of the marker when highlighted.
var activeIcon = makeMarkerIcon('0F0');
for (var i = 0; i < locations.length; i++) {
var position = locations[i].location; // Get the position from the location array.
var title = locations[i].title;
marker(locations);
}
// Create a marker per location, and put into markers array.
function marker(locations)
{
var marker = new google.maps.Marker({
map: map,
position: position,
title: title,
animation: google.maps.Animation.DROP,
id: i,
visible: (array ? array[i] : true)
});
locations[i].marker = marker; // we made marker a property of the locations and stored info of each marker
wikiLink(locations[i]);
markers.push(marker); // Push the marker to our array of markers.
// Create an onclick event to open an infowindow at each marker.
marker.addListener('click', function () {
populateInfoWindow(this, largeInfowindow);
this.setIcon(activeIcon);
});
bounds.extend(markers[i].position);
/*
marker.addListener('mouseover', function() {
this.setIcon(highlightedIcon);
});
*/
marker.addListener('mouseout', function () {
this.setIcon(defaultIcon);
});
}
// Extend the boundaries of the map for each marker
map.fitBounds(bounds);
function wikiLink(location) {
location.url = '';
var wikiUrl = 'https://en.wikipedia.org/w/api.php?action=opensearch&search=' + title + '&format=json&callback=wikiCallback';
//If you cant get a wiki request, throw an error message.
/*
var wikiError = setTimeout(function() {
location.url = 'Unable to find the request';
}, 8000);
*/
$.ajax({
url: wikiUrl,
dataType: "jsonp",
jsonp: "callback",
success: function (response) {
console.log(response.length);
var url = response[3][0];
//console.log(url);
location.marker.wikiurl = url;
//console.log(location);
//clearTimeout(wikiError);
}
})
.fail(function (jqXHR, textStatus, error) {
error = 'Unable to find the request';
alert("Post error: " + error);
});
}
}
// This function populates the infowindow when the marker is clicked. We'll only allow
// one infowindow which will open at the marker that is clicked, and populate based
// on that markers position.
function populateInfoWindow(marker, infowindow) {
// Check to make sure the infowindow is not already opened on this marker.
if (infowindow.marker != marker) {
infowindow.setContent(''); // Clearing the infowindow content to give the streetview time to load.
infowindow.marker = marker;
// Making sure the marker property is cleared if the infowindow is closed.
infowindow.addListener('closeclick', function () {
infowindow.marker = null;
});
// In case the status is OK, which means the pano was found, computing the position of the streetview image, then calculate the heading, then get a
// panorama from that and set the options
var getStreetView = function (data, status) {
if (status == google.maps.StreetViewStatus.OK) {
var nearStreetViewLocation = data.location.latLng;
var heading = google.maps.geometry.spherical.computeHeading(
nearStreetViewLocation, marker.position);
infowindow.setContent('<div>' + marker.title + '</div><hr><div id="pano"></div><div><a href=' + marker.wikiurl + '> Click here for more info </a></div>');
var panoramaOptions = {
position: nearStreetViewLocation,
pov: {
heading: heading,
pitch: 30
}
};
var panorama = new google.maps.StreetViewPanorama(
document.getElementById('pano'), panoramaOptions);
} else {
infowindow.setContent('<div>' + marker.title + '</div><hr>' + '<div>No Street View Found</div>');
}
};
var streetViewService = new google.maps.StreetViewService();
var radius = 500;
// Use streetview service to get the closest streetview image within 50 meters of the markers position
streetViewService.getPanoramaByLocation(marker.position, radius, getStreetView);
infowindow.open(map, marker); // Open the infowindow on the correct marker.
}
}
// This function takes in a COLOR, and then creates a new marker icon of that color.
// The icon will be 21 px wide by 34 high, have an origin of 0, 0 and be anchored at 10, 34).
function makeMarkerIcon(markerColor) {
var markerImage = new google.maps.MarkerImage(
'http://chart.googleapis.com/chart?chst=d_map_spin&chld=1.15|0|' + markerColor +
'|40|_|%E2%80%A2',
new google.maps.Size(21, 34),
new google.maps.Point(0, 0),
new google.maps.Point(10, 34),
new google.maps.Size(21, 34));
return markerImage;
}
function viewModel(markers) {
var self = this;
self.filter = ko.observable(''); // this is for the search box, takes value in it and searches for it in the array
self.items = ko.observableArray(locations); // we have made the array of locations into a ko.observableArray
var arrayofMarkersForVisibility = [];
self.filteredItems = ko.computed(function () {
if (markers.length>10) markers.splice(10,10);
var filter = self.filter().toLowerCase();
if (!filter || filter =="") {
arrayofMarkersForVisibility = [];
for (var i in markers){
//markers[i].setVisible(true);
arrayofMarkersForVisibility.push(true);
}
initMap(arrayofMarkersForVisibility);
return self.items();
} else {
arrayofMarkersForVisibility = [];
for (var i in markers){
arrayofMarkersForVisibility.push(false);
//markers[i].setVisible(false);
}
return ko.utils.arrayFilter(self.items(), function (id) {
var somestring = stringStartsWith(id.title.toLowerCase(), filter);
if (somestring){
arrayofMarkersForVisibility[id.marker.id]=true;
//markers[i].setVisible(true);
}
if (id.marker.id ==markers.length-1) initMap(arrayofMarkersForVisibility);
return somestring;
});
}
});
var stringStartsWith = function (string, startsWith) {
string = string || "";
if (startsWith.length > string.length)
return false;
return string.substring(0, startsWith.length) === startsWith;
};
// this should show the infowindow if any place on the list is clicked
this.showInfoWindow = function(place) {
google.maps.event.trigger(place.marker, 'click');
};
}
$(function(){
ko.applyBindings(new viewModel(markers));
});
</script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCwUdUoC9ZiRbFC3et89fPK3tXIVO8D2sI&callback=initMap"></script>
<script>
function openNav() {
document.getElementById("mySidenav").style.width = "250px";
}
function closeNav() {
document.getElementById("mySidenav").style.width = "0";
}
</script>
</body>
</html>