Knouckout js connection with google map - google-maps

I am new here. I currently on a project trying to create a list that makes the markers on the map do an effect by using knockout.
I have created the map with markers on it based on the data from an array.
Then by using a ViewModel and knockoutjs I create an observable array and on the left sidebar a list with the titles from that observable array.
Now I am trying to connect the titles from the left sidebar to the marker and make them bounce when the title of the list and the title of the marker are equal.
I am trying to do that with a loop, since when I use click with KO.js I get back the object that it was clicked.
Basically I am stuck here:
this.setLoc = function(clickedLoc){
for(var i = 0; i < self.locList.length; i++){
if(clickedLoc.title == markers[i].title){
markers[i].setAnimation(google.maps.Animation.BOUNCE);
} else {
console.log("hi");
}
}
};
My GitHub for this project is https://github.com/Aimpotis/map_project
I am a new developer, could you help a new guy please and please use simple terms since I don't have much of experience.

I think you need to unwrap your observables. I pulled down your code and got it working. here is the changed function.
this.setLoc = function (clickedLoc) {
var unwrappedLoc = ko.toJS(clickedLoc);
var unwrappedLocList = ko.toJS(self.locList);
for (var i = 0; i < unwrappedLocList.length; i++) {
if (unwrappedLoc.title == markers[i].title) {
markers[i].setAnimation(google.maps.Animation.BOUNCE);
}
}
};
here is the whole thing.
the javascript (app2.js)
var map;
var markers = [];
var locations = [
{ title: 'White Tower', location: { lat: 40.626446, lng: 22.948426 } },
{ title: 'Museum of Photography', location: { lat: 40.632874, lng: 22.935479 } },
{ title: 'Teloglion Fine Arts Foundation', location: { lat: 40.632854, lng: 22.941567 } },
{ title: 'War Museum of Thessaloniki', location: { lat: 40.624308, lng: 22.95953 } },
{ title: 'Jewish Museum of Thessaloniki', location: { lat: 40.635132, lng: 22.939538 } }
];
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: { lat: 40.6401, lng: 22.9444 },
zoom: 14
});
for (var i = 0; i < locations.length; i++) {
// Get the position from the location array.
var position = locations[i].location;
var title = locations[i].title;
// Create a marker per location, and put into markers array.
var marker = new google.maps.Marker({
position: position,
title: title,
map: map,
animation: google.maps.Animation.DROP,
id: i
});
markers.push(marker);
};
var Loc = function (data) {
this.title = ko.observable(data.title);
this.location = ko.observable(data.location);
};
var place = function (data) {
this.name = ko.observable(data.name);
};
var stringStartsWith = function (string, startsWith) {
string = string || "";
if (startsWith.length > string.length)
return false;
return string.substring(0, startsWith.length) === startsWith;
};
var ViewModel = function () {
var self = this;
this.query = ko.observable('');
this.locList = ko.observableArray('');
this.filteredlocList = ko.computed(function () {
var filter = self.query().toLowerCase();
console.log(filter);
var unwrappedLocList = ko.toJS(self.locList);
if (!filter) {
return unwrappedLocList
} else {
return ko.utils.arrayFilter(unwrappedLocList, function (item) {
return stringStartsWith(item.title.toLowerCase(), filter);
});
}
}, this);
this.setLoc = function (clickedLoc) {
var unwrappedLoc = ko.toJS(clickedLoc);
var unwrappedLocList = ko.toJS(self.locList);
for (var i = 0; i < unwrappedLocList.length; i++) {
if (unwrappedLoc.title == markers[i].title) {
markers[i].setAnimation(google.maps.Animation.BOUNCE);
}
}
};
};
var vm = new ViewModel();
ko.applyBindings(vm);
locations.forEach(function (locItem) {
vm.locList.push(new Loc(locItem))
});
};
and here is your html (project.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Tha gamiso ton Map</title>
<style>
html, body {
width: 100%;
height: 100%;
}
.container {
width: 100%;
height: 100%;
display: flex;
}
.sidebar {
width: 20%;
}
#map {
width: 80%;
}
</style>
</head>
<body>
<div class="container">
<div class="sidebar">
<div>
<input placeholder="Search…" type="search" data-bind="textInput: query" autocomplete="off">
<ul data-bind="foreach: filteredlocList">
<li data-bind="text: title, click: $parent.setLoc"></li>
</ul>
</div>
</div>
<div id="map">
</div>
</div>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBhBhCpY58VPkKqX96p2JxfQxL12A-DkZg&callback=initMap"
async defer></script>
<script src="knockout-3.4.2.js"></script>
<script src="app2.js"></script>
</body>
</html>

Related

Google Maps MarkerClusterer not showing any default images

I'm adding javascript code snippet to my Wordpress post (Hosted by a 3rd Party). I managed to create an array of Markers, and had them added to the MarkerClusterer and Map. The cluster shows up but as a broken image link and a number.
How do I access the MarkerClusterer default images? I followed the instructions from https://github.com/googlemaps/js-markerclusterer/blob/main/README.md
I'm not sure how to use npm with the 3rd party hosting. I don't use a database with my website. I'm calling src="https://unpkg.com/#googlemaps/markerclusterer/dist/index.min.js" to import MarkerClusterer
<div id="gmap" style="width:100%;height:400px;"></div>
<script src="https://unpkg.com/#googlemaps/markerclusterer/dist/index.min.js"</script>
var mymap;
var markers = [];
function initMap() {
var centerpoint = { lat: 38.5, lng: -98 }; //centered around Kansas
mymap = new google.maps.Map(document.getElementById('gmap'), {
zoom: 4,
center: centerpoint
});
}
/** fetching a cvs file on the server side with a list of locations */
fetch("https://mywebsite.com/wp-content/uploads/2022/03/stores.csv")
.then(
function(response) {
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' +
response.status);
return;
}
// Examine the text in the response
response.text().then(function(data) {
count = 0;
console.log("fetch called successfully");
initMap();
processCSV(data);
});
}
)
.catch(function(err) {
console.log('Fetch Error :-S', err);
});
function processCSV(allData){
const rows = allData.split('\n');
var storename, storephone, storeaddress, storelat, storelng;
for(let i=0; i<rows.length; i++){
var line = rows[i];
storename = line.split(",")[1];
storephone = line.split(",")[3];
storeaddress = String(line.split(",")[2]);
storeaddress = replaceAll(storeaddress, "^", ",");
storelat = line.split(",")[4];
storelng = line.split(",")[5];
createMarker(storename, storephone, storeaddress, storelat, storelng);
}
createCluster();
}
function replaceAll(string, search, replace) {
return string.split(search).join(replace);
}
function createCluster(){
var mcluster =new MarkerClusterer( mymap , markers);
}
function createMarker(name, phone, address, latstr, lngstr) {
var contentString = "<b>" + name + "</b><br><br><i>" + phone + "</i><br><br>" + address;
var latLng = { lat: Number(latstr) , lng: Number(lngstr)};
var infowindow = new google.maps.InfoWindow({
content: contentString,
});
var marker = new google.maps.Marker({
position: latLng,
map: mymap,
title: name
});
markers.push(marker);
console.log("added marker to map" + name);
marker.addListener("click", () => {
infowindow.open({
anchor: marker,
map: mymap,
shouldFocus: false,
});
});
}
<script src="https://maps.googleapis.com/maps/api/js?key=<PRIVATEKEY>;callback=initMap"></script>
The version of MarkerClusterer you are using doesn't require ClusterIcons (unless you want to change them), they default to SVG icons coded inline.
When I run the posted code I get a javascript error: Uncaught (in promise) ReferenceError: MarkerClusterer is not defined.
That is because according to the documentation when you include the library the way you are (<script src="https://unpkg.com/#googlemaps/markerclusterer/dist/index.min.js"></script>), the constructor for the MarkerClusterer is accessed as:
When adding via unpkg, the MarkerClusterer can be accessed at markerClusterer.MarkerClusterer.
Changing that, makes the clusters appear.
proof of concept fiddle
code snippet:
var mymap;
var markers = [];
function initMap() {
var centerpoint = {
lat: 40.7127753,
lng: -74.0059728
}; //centered around New York City
mymap = new google.maps.Map(document.getElementById('gmap'), {
zoom: 4,
center: centerpoint
});
processCSV(data);
}
var data = '"","New York","New York^ NY","516-555-5555",40.7127753, -74.0059728\n"","Newark","Newark^ NJ","201-555-5555",40.735657, -74.1723667';
function processCSV(allData) {
console.log(allData);
const rows = allData.split('\n');
var storename, storephone, storeaddress, storelat, storelng;
for (let i = 0; i < rows.length; i++) {
var line = rows[i];
storename = line.split(",")[1];
storephone = line.split(",")[3];
storeaddress = String(line.split(",")[2]);
storeaddress = replaceAll(storeaddress, "^", ",");
storelat = line.split(",")[4];
storelng = line.split(",")[5];
createMarker(storename, storephone, storeaddress, storelat, storelng);
}
createCluster();
}
function replaceAll(string, search, replace) {
return string.split(search).join(replace);
}
function createCluster() {
var mcluster = new markerClusterer.MarkerClusterer({
map: mymap,
markers: markers
});
}
function createMarker(name, phone, address, latstr, lngstr) {
var contentString = "<b>" + name + "</b><br><br><i>" + phone + "</i><br><br>" + address;
var latLng = {
lat: Number(latstr),
lng: Number(lngstr)
};
var infowindow = new google.maps.InfoWindow({
content: contentString,
});
var marker = new google.maps.Marker({
position: latLng,
map: mymap,
title: name
});
markers.push(marker);
console.log("added marker to map" + name);
marker.addListener("click", () => {
infowindow.open({
anchor: marker,
map: mymap,
shouldFocus: false,
});
});
}
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#gmap {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
<!DOCTYPE html>
<html>
<head>
<title>Simple Map</title>
<script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
<!-- jsFiddle will insert css and js -->
</head>
<body>
<div id="gmap"></div>
<script src="https://unpkg.com/#googlemaps/markerclusterer/dist/index.min.js"></script>
<!-- Async script executes immediately and must be after any DOM elements used in callback. -->
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap&v=weekly&channel=2" async></script>
</body>
</html>

Fusiontable Layer alternative for Google Maps

I have the following code available for Google Maps which works with FusionTable Layer.
It changes based on the zoom level of the user.
The array draw_str and draw_str_zoom are dynamic and gets generated based on the API calls we make and the response we receive.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0">
<meta charset="utf-8">
<title>KML Layers</title>
<style>
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 90%;
}
/* Optional: Makes the sample page fill the window. */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
var layerState = [];
var draw_str = '27089,27013,27053,27029,27035,27067,27081,27069,27155,27153,27131,27123,27109,27051,27043,27031,27027,27007,27005,27003,27001';
var draw_str_zoom = '48131,48197,48459,48497,48163,48379,48403,48471,48499,48505,48067,48249,48289,48323,48351,48399,48467,48481,48485,48507,48031,48139,48187,48303,48315,48355,48409,48419,48429,48483,48489,48021,48027,48035,48053,48099,48143,48145,48157,48195,48225,48251,48271,48317,48319,48361,48427,48431,48463,48479,48043,48155,48215,48321,48343,48381,48425,48451,48469,48079,48135,48347,48363,48407,48477,48085,48201,48299,48325,48339,48413,48453,48503,48177,48291,48401,48423,48475,48089,48439,48095,48117,48253,48275,48329,48397,48441,48465,48259,48279,48335,48437,48487,48003,48045,48061,48121,48161,48209,48245,48281,48313,48375,48395,48445,48457,48473,48491,48501,48449,48435,48415,48405,48391,48387,48373,48371,48357,48349,48345,48337,48331,48309,48307,48293,48285,48277,48273,48265,48257,48255,48241,48231,48227,48223,48221,48219,48217,48213,48193,48189,48185,48183,48181,48175,48171,48167,48153,48151,48149,48147,48141,48133,48123,48119,48115,48113,48105,48097,48093,48091,48087,48077,48073,48071,48063,48059,48057,48055,48051,48049,48047,48041,48039,48037,48029,48025,48019,48015,48009,48005';
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 5,
center: {lat: 41.876, lng: -87.624}
});
layerState[0] = new google.maps.FusionTablesLayer({
query: {
select: '\'geometry\'',
from: '1fio1qgy5HkinUDKqYvREIlSoBaHjl2RBe3DLJa38'
},
options: {suppressInfoWindows: true},
styles: [{
polygonOptions: {
fillColor: '#000000',
fillOpacity: 0.001
}
}, {
where: "'GEO_ID2' IN (" + draw_str_zoom + ")",
polygonOptions: {
fillOpacity: 0.3
}
}]
});
layerState[0].setMap(map);
google.maps.event.addListener(map, 'zoom_changed', function () {
var zoom_level = map.getZoom();
if (zoom_level >= 6 && zoom_level < 7) {
clearRegion(zoom_level);
layerState[0] = new google.maps.FusionTablesLayer({
query: {
select: '\'geometry\'',
from: '1fio1qgy5HkinUDKqYvREIlSoBaHjl2RBe3DLJa38'
},
options: {suppressInfoWindows: true},
styles: [{
polygonOptions: {
fillColor: '#000000',
fillOpacity: 0.001
}
}, {
where: "'GEO_ID2' IN (" + draw_str + ")",
polygonOptions: {
fillOpacity: 0.3
}
}]
});
layerState[0].setMap(map);
}
});
function clearRegion(level) {
layerState.forEach(function(kml) {
kml.setMap(null);
});
}
}
// }
</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBMtoh9P3UkoxbXndKu_HOP7KsVwTRvxGU&callback=initMap">
</script>
</body>
</html>
Google Fusion Table is going down - https://support.google.com/fusiontables/answer/9185417
Is there a way I could create this similar map with all the functionality without using FusionTable layer?
Since Fusion Tables will not be available after Dec. 3, 2019, I suggest:
Download your tables as KML files,
https://support.google.com/fusiontables/answer/2548807?hl=en
Host your KML files at a publicly accessible URL that does not require authentication to access. This is because Maps JavaScript API uses a Google hosted service to retrieve and parse KML files for rendering.
https://developers.google.com/maps/documentation/javascript/kmllayer
Finally, display the information of your KML files in a Google map and sidebar.
https://developers.google.com/maps/documentation/javascript/kml
Alternatively, you can host your KML files in the same domain where your webpage is, but for that you'll need a library like GeoXML3:
Examples:
http://www.dyasdesigns.com/geoxml/GeoXmlSamples.html
Repository that I used, EDIT 1 below:
https://github.com/geocodezip/geoxml3/tree/master/kmz
EDIT1: With GeoXML3, dynamically styling from draw_str would be:
<div id="map"></div>
<script src="geoxml3.js"></script>
<script>
var draw_str = [/* your array */];
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 5,
center: {lat: 41.876, lng: -87.624}
});
var myParser = new geoXML3.parser({map: map,zoom: false}); // zoom needs to be set to false to keep mapOptions intact.
myParser.parse('Counties.kml'); // our Document (myParser.docs[0]) is the only parsed kml
google.maps.event.addListener(map, 'zoom_changed', function () {
var polygonOptions = {fillColor: "#000000" , fillOpacity: 0.001};
var polygonOptionsID2 = {fillOpacity: 0.3};
var zoom_level = map.getZoom();
if (zoom_level >= 6 && zoom_level < 7) {
for (var i = 0; i < draw_str.length; i++) {
for (var j = 0; j < myParser.docs[0].placemarks.length; j++) {
if (draw_str[i] == myParser.docs[0].placemarks[j].vars.val.GEO_ID2) { // GEO_ID2 is stored as Extended Data for every placemark (myParser.docs[0].placemarks is an array with 3250 entries)
myParser.docs[0].gpolygons[j].setOptions(polygonOptionsID2); // myParser.docs[0].gpolygons is an array with 3250 polygons
} else {
myParser.docs[0].gpolygons[j].setOptions(polygonOptions);
}
}
}
}
});
}
</script>
It will be a bit slow since the KML downloaded from Fusion Tables has more than 15 MB
EDIT2: fully functional demo consuming both draw_str and draw_str_zoom, dependent on having both GeoXML3.js and the KML downloaded from the Fusion Table page, referenced in the code.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0">
<meta charset="utf-8">
<title>KML Layers</title>
<style>
#map {
height: 100%;
}
html, body {
height: 100%;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="static/geoxml3.js"></script>
<script>
var draw_str = "27089,27013,27053,27029,27035,27067,27081,27069,27155,27153,27131,27123,27109,27051,27043,27031,27027,27007,27005,27003,27001";
var draw_str_zoom = "48131,48197,48459,48497,48163,48379,48403,48471,48499,48505,48067,48249,48289,48323,48351,48399,48467,48481,48485,48507,48031,48139,48187,48303,48315,48355,48409,48419,48429,48483,48489,48021,48027,48035,48053,48099,48143,48145,48157,48195,48225,48251,48271,48317,48319,48361,48427,48431,48463,48479,48043,48155,48215,48321,48343,48381,48425,48451,48469,48079,48135,48347,48363,48407,48477,48085,48201,48299,48325,48339,48413,48453,48503,48177,48291,48401,48423,48475,48089,48439,48095,48117,48253,48275,48329,48397,48441,48465,48259,48279,48335,48437,48487,48003,48045,48061,48121,48161,48209,48245,48281,48313,48375,48395,48445,48457,48473,48491,48501,48449,48435,48415,48405,48391,48387,48373,48371,48357,48349,48345,48337,48331,48309,48307,48293,48285,48277,48273,48265,48257,48255,48241,48231,48227,48223,48221,48219,48217,48213,48193,48189,48185,48183,48181,48175,48171,48167,48153,48151,48149,48147,48141,48133,48123,48119,48115,48113,48105,48097,48093,48091,48087,48077,48073,48071,48063,48059,48057,48055,48051,48049,48047,48041,48039,48037,48029,48025,48019,48015,48009,48005";
var draw_strArray = draw_str.replace(/, +/g, ",").split(",").map(Number);
var zoomArray = draw_str_zoom.replace(/, +/g, ",").split(",").map(Number);
var tempOptions = {fillColor: "#FFFF00", strokeColor: "#000000", fillOpacity: 0.9, strokeWidth: 10};
var geoXmlDoc;
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 5,
center: {lat: 41.876, lng: -87.624}
});
var myParser = new geoXML3.parser({map: map,zoom: false, afterParse: useTheData });
myParser.parse('static/Counties.kml');
google.maps.event.addListener(map, 'zoom_changed', function () {
var zoom_level = map.getZoom();
if (zoom_level >= 6 && zoom_level < 7) {
for ( i = 0; i < draw_strArray.length; i++) {
for (var j = 0; j < geoXmlDoc.placemarks.length; j++) {
if (draw_strArray[i] == geoXmlDoc.placemarks[j].vars.val.GEO_ID2) {
geoXmlDoc.gpolygons[j].setOptions(tempOptions);
}
}
}
} else {
for ( i = 0; i < draw_strArray.length; i++) {
for (var j = 0; j < geoXmlDoc.placemarks.length; j++) {
if (draw_strArray[i] == geoXmlDoc.placemarks[j].vars.val.GEO_ID2) {
geoXmlDoc.gpolygons[j].setOptions({fillOpacity: 0.0});
}
}
}
}
});
function useTheData(doc) {
geoXmlDoc= doc[0];
for ( i = 0; i < zoomArray.length; i++) {
for (var j = 0; j < geoXmlDoc.placemarks.length; j++) {
if (zoomArray[i] == geoXmlDoc.placemarks[j].vars.val.GEO_ID2) {
geoXmlDoc.gpolygons[j].setOptions(tempOptions);
}
}
}
};
}
</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBMtoh9P3UkoxbXndKu_HOP7KsVwTRvxGU&callback=initMap">
</script>
</body>
</html>

Google maps Snap to road demo not working | Google Maps API error: MissingKeyMapError

I am trying to get the Snap to Road demo working that is supplied here but I keep getting the error: Google Maps API error: MissingKeyMapError. I already searched around and this is the error Google gives you for either supplying no key or a invalid key but even if I generate a brand new key it won't work. It just gives me a blank screen.
Why is it throwing this error even though I supply the code with the API key?
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Roads API Demo</title>
<style>
html,
body,
#map {
height: 100%;
margin: 0px;
padding: 0px
}
#panel {
position: absolute;
top: 5px;
left: 50%;
margin-left: -180px;
z-index: 5;
background-color: #fff;
padding: 5px;
border: 1px solid #999;
}
#bar {
width: 240px;
background-color: rgba(255, 255, 255, 0.75);
margin: 8px;
padding: 4px;
border-radius: 4px;
}
#autoc {
width: 100%;
box-sizing: border-box;
}
</style>
<script src="jquery-3.2.1.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?libraries=drawing,places"></script>
<script>
var apiKey = 'AIzaSyB3kpx3fgR9VT3WL2tp49QrbnyDdgygGeo';
var map;
var drawingManager;
var placeIdArray = [];
var polylines = [];
var snappedCoordinates = [];
function initialize() {
var mapOptions = {
zoom: 17,
center: {
lat: -33.8667,
lng: 151.1955
}
};
map = new google.maps.Map(document.getElementById('map'), mapOptions);
// Adds a Places search box. Searching for a place will center the map on that
// location.
map.controls[google.maps.ControlPosition.RIGHT_TOP].push(
document.getElementById('bar'));
var autocomplete = new google.maps.places.Autocomplete(
document.getElementById('autoc'));
autocomplete.bindTo('bounds', map);
autocomplete.addListener('place_changed', function() {
var place = autocomplete.getPlace();
if (place.geometry.viewport) {
map.fitBounds(place.geometry.viewport);
} else {
map.setCenter(place.geometry.location);
map.setZoom(17);
}
});
// Enables the polyline drawing control. Click on the map to start drawing a
// polyline. Each click will add a new vertice. Double-click to stop drawing.
drawingManager = new google.maps.drawing.DrawingManager({
drawingMode: google.maps.drawing.OverlayType.POLYLINE,
drawingControl: true,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_CENTER,
drawingModes: [
google.maps.drawing.OverlayType.POLYLINE
]
},
polylineOptions: {
strokeColor: '#696969',
strokeWeight: 2
}
});
drawingManager.setMap(map);
// Snap-to-road when the polyline is completed.
drawingManager.addListener('polylinecomplete', function(poly) {
var path = poly.getPath();
polylines.push(poly);
placeIdArray = [];
runSnapToRoad(path);
});
// Clear button. Click to remove all polylines.
$('#clear').click(function(ev) {
for (var i = 0; i < polylines.length; ++i) {
polylines[i].setMap(null);
}
polylines = [];
ev.preventDefault();
return false;
});
}
// Snap a user-created polyline to roads and draw the snapped path
function runSnapToRoad(path) {
var pathValues = [];
for (var i = 0; i < path.getLength(); i++) {
pathValues.push(path.getAt(i).toUrlValue());
}
$.get('https://roads.googleapis.com/v1/snapToRoads', {
interpolate: true,
key: apiKey,
path: pathValues.join('|')
}, function(data) {
processSnapToRoadResponse(data);
drawSnappedPolyline();
getAndDrawSpeedLimits();
});
}
// Store snapped polyline returned by the snap-to-road service.
function processSnapToRoadResponse(data) {
snappedCoordinates = [];
placeIdArray = [];
for (var i = 0; i < data.snappedPoints.length; i++) {
var latlng = new google.maps.LatLng(
data.snappedPoints[i].location.latitude,
data.snappedPoints[i].location.longitude);
snappedCoordinates.push(latlng);
placeIdArray.push(data.snappedPoints[i].placeId);
}
}
// Draws the snapped polyline (after processing snap-to-road response).
function drawSnappedPolyline() {
var snappedPolyline = new google.maps.Polyline({
path: snappedCoordinates,
strokeColor: 'black',
strokeWeight: 3
});
snappedPolyline.setMap(map);
polylines.push(snappedPolyline);
}
// Gets speed limits (for 100 segments at a time) and draws a polyline
// color-coded by speed limit. Must be called after processing snap-to-road
// response.
function getAndDrawSpeedLimits() {
for (var i = 0; i <= placeIdArray.length / 100; i++) {
// Ensure that no query exceeds the max 100 placeID limit.
var start = i * 100;
var end = Math.min((i + 1) * 100 - 1, placeIdArray.length);
drawSpeedLimits(start, end);
}
}
// Gets speed limits for a 100-segment path and draws a polyline color-coded by
// speed limit. Must be called after processing snap-to-road response.
function drawSpeedLimits(start, end) {
var placeIdQuery = '';
for (var i = start; i < end; i++) {
placeIdQuery += '&placeId=' + placeIdArray[i];
}
$.get('https://roads.googleapis.com/v1/speedLimits',
'key=' + apiKey + placeIdQuery,
function(speedData) {
processSpeedLimitResponse(speedData, start);
}
);
}
// Draw a polyline segment (up to 100 road segments) color-coded by speed limit.
function processSpeedLimitResponse(speedData, start) {
var end = start + speedData.speedLimits.length;
for (var i = 0; i < speedData.speedLimits.length - 1; i++) {
var speedLimit = speedData.speedLimits[i].speedLimit;
var color = getColorForSpeed(speedLimit);
// Take two points for a single-segment polyline.
var coords = snappedCoordinates.slice(start + i, start + i + 2);
var snappedPolyline = new google.maps.Polyline({
path: coords,
strokeColor: color,
strokeWeight: 6
});
snappedPolyline.setMap(map);
polylines.push(snappedPolyline);
}
}
function getColorForSpeed(speed_kph) {
if (speed_kph <= 40) {
return 'purple';
}
if (speed_kph <= 50) {
return 'blue';
}
if (speed_kph <= 60) {
return 'green';
}
if (speed_kph <= 80) {
return 'yellow';
}
if (speed_kph <= 100) {
return 'orange';
}
return 'red';
}
$(window).on('load', function() {
initialize
});
</script>
</head>
<body>
<div id="map"></div>
<div id="bar">
<p class="auto"><input type="text" id="autoc" /></p>
<p><a id="clear" href="#">Click here</a> to clear map.</p>
</div>
</body>
</html>
If you haven't got an API KEY:
The script element that loads the API is missing the required authentication parameter. If you are using the standard Maps JavaScript API, you must use a key parameter with a valid API key.
Step 1: Get a Key from this URL
https://developers.google.com/maps/documentation/javascript/get-api-key
Step 2: Include your script with the API KEY
<script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"
type="text/javascript"></script>
Or replace
var apiKey = 'YOUR_API_KEY';
If you got an API KEY
Google maps Snap to Road demo
Full Code
html, body, #map {
height: 100%;
margin: 0px;
padding: 0px
}
#panel {
position: absolute;
top: 5px;
left: 50%;
margin-left: -180px;
z-index: 5;
background-color: #fff;
padding: 5px;
border: 1px solid #999;
}
#bar {
width: 240px;
background-color: rgba(255, 255, 255, 0.75);
margin: 8px;
padding: 4px;
border-radius: 4px;
}
#autoc {
width: 100%;
box-sizing: border-box;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Roads API Demo</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="/_static/js/jquery-bundle.js"></script>
<script
src="https://maps.googleapis.com/maps/api/js?libraries=drawing,places"></script>
<script>
var apiKey = 'AIzaSyB3kpx3fgR9VT3WL2tp49QrbnyDdgygGeo';
var map;
var drawingManager;
var placeIdArray = [];
var polylines = [];
var snappedCoordinates = [];
function initialize() {
var mapOptions = {
zoom: 17,
center: {lat: -33.8667, lng: 151.1955}
};
map = new google.maps.Map(document.getElementById('map'), mapOptions);
// Adds a Places search box. Searching for a place will center the map on that
// location.
map.controls[google.maps.ControlPosition.RIGHT_TOP].push(
document.getElementById('bar'));
var autocomplete = new google.maps.places.Autocomplete(
document.getElementById('autoc'));
autocomplete.bindTo('bounds', map);
autocomplete.addListener('place_changed', function() {
var place = autocomplete.getPlace();
if (place.geometry.viewport) {
map.fitBounds(place.geometry.viewport);
} else {
map.setCenter(place.geometry.location);
map.setZoom(17);
}
});
// Enables the polyline drawing control. Click on the map to start drawing a
// polyline. Each click will add a new vertice. Double-click to stop drawing.
drawingManager = new google.maps.drawing.DrawingManager({
drawingMode: google.maps.drawing.OverlayType.POLYLINE,
drawingControl: true,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_CENTER,
drawingModes: [
google.maps.drawing.OverlayType.POLYLINE
]
},
polylineOptions: {
strokeColor: '#696969',
strokeWeight: 2
}
});
drawingManager.setMap(map);
// Snap-to-road when the polyline is completed.
drawingManager.addListener('polylinecomplete', function(poly) {
var path = poly.getPath();
polylines.push(poly);
placeIdArray = [];
runSnapToRoad(path);
});
// Clear button. Click to remove all polylines.
$('#clear').click(function(ev) {
for (var i = 0; i < polylines.length; ++i) {
polylines[i].setMap(null);
}
polylines = [];
ev.preventDefault();
return false;
});
}
// Snap a user-created polyline to roads and draw the snapped path
function runSnapToRoad(path) {
var pathValues = [];
for (var i = 0; i < path.getLength(); i++) {
pathValues.push(path.getAt(i).toUrlValue());
}
$.get('https://roads.googleapis.com/v1/snapToRoads', {
interpolate: true,
key: apiKey,
path: pathValues.join('|')
}, function(data) {
processSnapToRoadResponse(data);
drawSnappedPolyline();
getAndDrawSpeedLimits();
});
}
// Store snapped polyline returned by the snap-to-road service.
function processSnapToRoadResponse(data) {
snappedCoordinates = [];
placeIdArray = [];
for (var i = 0; i < data.snappedPoints.length; i++) {
var latlng = new google.maps.LatLng(
data.snappedPoints[i].location.latitude,
data.snappedPoints[i].location.longitude);
snappedCoordinates.push(latlng);
placeIdArray.push(data.snappedPoints[i].placeId);
}
}
// Draws the snapped polyline (after processing snap-to-road response).
function drawSnappedPolyline() {
var snappedPolyline = new google.maps.Polyline({
path: snappedCoordinates,
strokeColor: 'black',
strokeWeight: 3
});
snappedPolyline.setMap(map);
polylines.push(snappedPolyline);
}
// Gets speed limits (for 100 segments at a time) and draws a polyline
// color-coded by speed limit. Must be called after processing snap-to-road
// response.
function getAndDrawSpeedLimits() {
for (var i = 0; i <= placeIdArray.length / 100; i++) {
// Ensure that no query exceeds the max 100 placeID limit.
var start = i * 100;
var end = Math.min((i + 1) * 100 - 1, placeIdArray.length);
drawSpeedLimits(start, end);
}
}
// Gets speed limits for a 100-segment path and draws a polyline color-coded by
// speed limit. Must be called after processing snap-to-road response.
function drawSpeedLimits(start, end) {
var placeIdQuery = '';
for (var i = start; i < end; i++) {
placeIdQuery += '&placeId=' + placeIdArray[i];
}
$.get('https://roads.googleapis.com/v1/speedLimits',
'key=' + apiKey + placeIdQuery,
function(speedData) {
processSpeedLimitResponse(speedData, start);
}
);
}
// Draw a polyline segment (up to 100 road segments) color-coded by speed limit.
function processSpeedLimitResponse(speedData, start) {
var end = start + speedData.speedLimits.length;
for (var i = 0; i < speedData.speedLimits.length - 1; i++) {
var speedLimit = speedData.speedLimits[i].speedLimit;
var color = getColorForSpeed(speedLimit);
// Take two points for a single-segment polyline.
var coords = snappedCoordinates.slice(start + i, start + i + 2);
var snappedPolyline = new google.maps.Polyline({
path: coords,
strokeColor: color,
strokeWeight: 6
});
snappedPolyline.setMap(map);
polylines.push(snappedPolyline);
}
}
function getColorForSpeed(speed_kph) {
if (speed_kph <= 40) {
return 'purple';
}
if (speed_kph <= 50) {
return 'blue';
}
if (speed_kph <= 60) {
return 'green';
}
if (speed_kph <= 80) {
return 'yellow';
}
if (speed_kph <= 100) {
return 'orange';
}
return 'red';
}
$(window).load(initialize);
</script>
</head>
<body>
<div id="map"></div>
<div id="bar">
<p class="auto"><input type="text" id="autoc"/></p>
<p><a id="clear" href="#">Click here</a> to clear map.</p>
</div>
</body>
</html>

google map javascript api transit

My requirement is, need to show all Transit Bus stations of a particular location(like state, city) and should able to mark only transit bus stations and show the infoWindow of that Transit Bus station using google map javascript api.
below is my html code, javascript marker logic also marks all the locations on the map i need to mark only transit bus stations
<!DOCTYPE html>
<html>
<head>
<title>Add/Remove Markers</title>
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 50%;
width:50%;
position:inherit !important;
margin-top:50px !important;
}
#floating-panel {
position: absolute;
top: 10px;
left: 25%;
z-index: 5;
background-color: #fff;
padding: 5px;
border: 1px solid #999;
text-align: center;
font-family: 'Roboto','sans-serif';
line-height: 30px;
padding-left: 10px;
}
#map > div{
height:70% !important;
width:70% !important;
margin-top:50px !important;
}
a[href^="https://maps.google.com/maps"]{
display: none !important;
}
.gmnoprint a, .gmnoprint span, .gm-style-cc div {
display: none !important;
}
.gmnoprint div {
background: none !important;
}
</style>
</head>
<body>
<div id="floating-panel">
<input onclick="clearMarkers();" type=button value="Hide Markers">
<input onclick="showMarkers();" type=button value="Show All Markers">
<input onclick="deleteMarkers();" type=button value="Delete Markers">
</div>
<div id="map"></div>
<p>Click on the map to add markers.</p>
<script>
// In the following example, markers appear when the user clicks on the map.
// The markers are stored in an array.
// The user can then click an option to hide, show or delete the markers.
var map;
var markers = [];
function initMap() {
var haightAshbury = {lat: 37.769, lng: -122.446};
map = new google.maps.Map(document.getElementById('map'), {
zoom: 12,
center: haightAshbury,
disableDefaultUI: true
});
// This event listener will call addMarker() when the map is clicked.
map.addListener('click', function (event) {
addMarker(event.latLng);
});
// Adds a marker at the center of the map.
addMarker(haightAshbury);
}
// Adds a marker to the map and push to the array.
function addMarker(location) {
var marker = new google.maps.Marker({
position: location,
map: map
});
markers.push(marker);
//This code is to remove the marker from the map and the array
marker.addListener('click', function (e) {
var latIndex = markers.findIndex(x=>x.position.lat() == e.latLng.lat());
var lngIndex = markers.findIndex(x=>x.position.lng() == e.latLng.lng());
if ((latIndex != -1 && lngIndex != -1) && (latIndex == lngIndex)) {
markers[latIndex].setMap(null); // To remove the marker from the Map
markers.splice(latIndex, 1); // to remove the marker from the list of array
}
});
marker.addListener('mouseover', function (e) {
infowindow.open(map, this);
});
// assuming you also want to hide the infowindow when user mouses-out
marker.addListener('mouseout', function (e) {
infowindow.close();
});
}
// Sets the map on all markers in the array.
function setMapOnAll(map) {
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(map);
}
}
// Removes the markers from the map, but keeps them in the array.
function clearMarkers() {
setMapOnAll(null);
}
// Shows any markers currently in the array.
function showMarkers() {
setMapOnAll(map);
}
// Deletes all markers in the array by removing references to them.
function deleteMarkers() {
clearMarkers();
markers = [];
}
</script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=APIKEY&callback=initMap">
</script>
</body>
</html>
var map;
var infowindow;
var service;
var markers = [];
var availableMarkers = [];
var unAvailableMarkers = [];
var selectedMarkers = [];
var globalResults = [];
function initialize(lat,lng)
{
var origin = new google.maps.LatLng(lat,lng);
map = new google.maps.Map(document.getElementById('map'), {
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: origin,
zoom: 15,
disableDefaultUI: true
});
var request = {
location: origin,
radius: 2500,
types: ['bus_station']
};
infowindow = new google.maps.InfoWindow();
service = new google.maps.places.PlacesService(map);
service.search(request, callback);
map.addListener('click', function (event) {
initialize(event.latLng.lat(), event.latLng.lng())
});
}
function callback(results, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
globalResults = results;
for (var i = 0; i < results.length; i++) {
if (i < 11)
createMarker(results[i], 'green');
else
createMarker(results[i], 'red');
}
}
}
function createMarker(place,color) {
var placeLoc = place.geometry.location;
var icon;
if (color == 'green')
icon = 'http://maps.google.com/mapfiles/ms/icons/green-dot.png';
else if (color == 'red')
icon = 'http://maps.google.com/mapfiles/ms/icons/red-dot.png';
else
icon = 'http://maps.google.com/mapfiles/ms/icons/yellow-dot.png';
resizeIcon = icon;
var marker = null;
if (color == 'green') {
marker = new google.maps.Marker({
map: map,
position: place.geometry.location,
icon: resizeIcon
});
availableMarkers.push(marker);
}
else if (color == 'red') {
marker = new google.maps.Marker({
map: map,
position: place.geometry.location,
icon: resizeIcon
});
unAvailableMarkers.push(marker);
}
else {
marker = new google.maps.Marker({
map: map,
position: place.geometry.location,
icon: resizeIcon
});
selectedMarkers.push(marker);
}
markers.push(marker);
var content = '<div><strong>' + place.name + '</strong><br>' +
'Place ID: ' + place.place_id;
var more_content = '<img src="../Content/Images/1475150806_map-marker.png"/>'; // this is to show the image r any additional content
//make a request for further details
service.getDetails({ reference: place.reference }, function (place, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
more_content = '<hr/><strong>Details';
if (place.website) {
more_content += '<br/><br/><strong>' + place.website + '';
}
}
});
google.maps.event.addListener(marker, 'mouseover', function () {
//infowindow.setContent(content + more_content);
infowindow.setContent(content);
infowindow.open(map, this);
});
// assuming you also want to hide the infowindow when user mouses-out
//google.maps.event.addListener(marker, 'mouseout', function (e) {
// infowindow.close();
//});
google.maps.event.addListener(marker, 'click', function (e) {
var latIndex = markers.findIndex(x=>x.position.lat() == e.latLng.lat());
var lngIndex = markers.findIndex(x=>x.position.lng() == e.latLng.lng());
var isAvailLat = availableMarkers.findIndex(x=>x.position.lat() == e.latLng.lat());
var isAvailLng = availableMarkers.findIndex(x=>x.position.lng() == e.latLng.lng());
var isUnAvailLat = unAvailableMarkers.findIndex(x=>x.position.lat() == e.latLng.lat());
var isUnAvailLng = unAvailableMarkers.findIndex(x=>x.position.lng() == e.latLng.lng());
var isSelectedLat = selectedMarkers.findIndex(x=>x.position.lat() == e.latLng.lat());
var isSelectedLng = selectedMarkers.findIndex(x=>x.position.lng() == e.latLng.lng());
if ((latIndex != -1 && lngIndex != -1) && (latIndex == lngIndex)) {
if ((isSelectedLat != -1 && isSelectedLng != -1) && (isSelectedLat == isSelectedLng)) {
selectedMarkers.splice(isSelectedLat, 1);
availableMarkers.push(markers[latIndex]);
marker.setIcon('http://maps.google.com/mapfiles/ms/icons/green-dot.png');
}
else if ((isAvailLat != -1 && isAvailLng != -1) && (isAvailLat == isAvailLng)) {
availableMarkers.splice(isAvailLat, 1);
selectedMarkers.push(markers[latIndex]);
marker.setIcon('http://maps.google.com/mapfiles/ms/icons/yellow-dot.png');
}
else if ((isUnAvailLat != -1 && isUnAvailLng != -1) && (isUnAvailLat == isUnAvailLng)) {
alert('This Transit is not avaliable, pls select a valid transit');
}
}
});
}
google.maps.event.addDomListener(window, 'load', function () { initialize(39.759444, -84.191667); });
/*These styles area added to hide the google footer*/
a[href^="http://maps.google.com/maps"] {
display: none !important;
}
a[href^="https://maps.google.com/maps"] {
display: none !important;
}
.gmnoprint a, .gmnoprint span, .gm-style-cc {
display: none;
}
.gmnoprint div {
background: none !important;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Transit</title>
</head>
<body>
<div id="map" style="height:600px;"></div>
<script type="text/javascript" src="//maps.googleapis.com/maps/api/js?key=API_KEY&libraries=places"></script>
</body>
</html>

Getting values of cursor from indexedDB

I'm trying to put markers on a google location map API using data I put on an inedexedDB. I'm able to put the markers accurately using the data I get from the DB, but the markers' infowindow doesn't get them accurately.
Here is my code:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>Google Maps Multiple Markers</title>
<script src="http://maps.google.com/maps/api/js?sensor=true"></script>
<style type="text/css">
#map {
width: 700px;
height: 700px;
}
</style>
</head>
<body>
<div id="map"></div>
<button onclick="showMarker()">Show Markers </button>
<script type="text/javascript">
//prefixes of implementation that we want to test
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
//prefixes of window.IDB objects
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction;
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange
if (!window.indexedDB) {
window.alert("Your browser doesn't support a stable version of IndexedDB.")
}
var db;
var request = window.indexedDB.open("mapDB", 1);
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 7,
center: new google.maps.LatLng(11.980433, 121.918866),
mapTypeId: google.maps.MapTypeId.HYBRID
});
const locData = [
{ id: "00-01", name: "Boracay", lat: 11.980433, lng: 121.918866 },
{ id: "00-02", name: "Baguio City", lat: 16.402333, lng: 120.596007 },
{ id: "00-03", name: "Isdaan", lat: 15.475479, lng: 120.596349 },
{ id: "00-04", name: "Mount Pinatubo", lat: 15.142973, lng: 120.349302 }
];
request.onerror = function(event) {
console.log("error: ");
};
request.onsuccess = function(event) {
db = request.result;
console.log("success: "+ db);
};
request.onupgradeneeded = function(event) {
var db = event.target.result;
var objectStore = db.createObjectStore("location", {keyPath: "id"});
for (var i in locData) {
objectStore.add(locData[i]);
}
db.onsuccess = function(event) {
showMarker();
};
}
function showMarker() {
var infowindow = new google.maps.InfoWindow();
var marker, i;
var objectStore = db.transaction("location").objectStore("location");
objectStore.openCursor().onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(cursor.value.lat, cursor.value.lng),
map: map
});
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent(cursor.value.name);
infowindow.open(map, marker);
}
})(marker, i));
cursor.continue();
}
};
}
</script>
</body>
</html>
I have tried searching and reading other sources but I can't seem to find what's the problem. Help is very much appreciated.
This is a duplicate of Google Maps JS API v3 - Simple Multiple Marker Example. You need function closure on the name of the marker.
function showMarker() {
var infowindow = new google.maps.InfoWindow();
var marker;
var objectStore = db.transaction("location").objectStore("location");
objectStore.openCursor().onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(cursor.value.lat, cursor.value.lng),
map: map
});
google.maps.event.addListener(marker, 'click', (function(marker, name) {
return function() {
infowindow.setContent(name);
infowindow.open(map, marker);
}
})(marker, cursor.value.name));
cursor.continue();
}
};
}
proof of concept fiddle