Fusiontable Layer alternative for Google Maps - 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>

Related

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>

Knouckout js connection with google map

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>

How to show duration trip in google map api

I'm using google map API to show the distance betewenn to points depending on the transportation and I like to show the duration of the trip like in the google map site (see the image). I'm using the v3 of google map and also the DirectionsRenderer function:
so far:
self.renderDirections = function (directions, status) {
self.cleanDisplayedDirections();
for (var i = 0, len = directions.routes.length; i < len && i < 3; i++) {
var direction = new google.maps.DirectionsRenderer({
map: map,
directions: directions,
routeIndex: i,
draggable: true,
suppressInfoWindows: false,
suppressMarkers: true
});
displayedDirections.push(direction);
}
};
Like in the image I would like to show, for instance, that is 13 min for the walk of 1 km.
Also, it is possible to change the polylineOptions for one route to be "dotted" like in the image?
EDIT: Okay, I have an answer to most of the components of your question.
(I kind of need this myself. I might as well write it now and post it here)
So I added a function that calculates a point, at a given distance, along a route. This is quite useful to place that infoWindow where you want it.
(probably a more elegant function could be written, but it does the trick)
You can take it from here, I guess. Just make var content as you need it to be. Add Walking/Driving image, ...
<!DOCTYPE html>
<html>
<head>
<title>How to show duration trip in google map api</title>
<meta name="viewport" content="initial-scale=1.0">
<meta charset="utf-8">
<style>
html, body {
height: 90%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<input id="start" placeholder="start" value="Lausanne Gare">
<input id="end" placeholder="end" value="Chemin de Bellerive 32, 1007 Lausanne">
<input type="button" onclick="submit_form()" value="Calculate Route">
<script>
var directionsDisplayDriving;
var directionsDisplayWalking;
var infowindowDriving;
var infowindowWalking;
var directionsService;
var map;
// returns a polyline. Depending on the travelMode
function getPolylineOptions(travelMode) {
switch(travelMode) {
default:
case 'DRIVING':
return {
strokeColor: '#808080', // grey'ish
strokeOpacity: 1.0,
strokeWeight: 3
};
break;
case 'WALKING':
// Define a symbol using SVG path notation, with an opacity of 1.
var lineSymbol = {
path: 'M 0,-1 0,1',
strokeOpacity: 1,
scale: 3
};
// Create the polyline, passing the symbol in the 'icons' property.
// Give the line an opacity of 0.
// Repeat the symbol at intervals of 20 pixels to create the dashed effect.
return {
strokeColor: '#0099ff',
strokeOpacity: 0,
strokeWeight: 3,
icons: [{
icon: lineSymbol,
offset: '0',
repeat: '15px'
}]
};
break;
}
}
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 46.5138527, lng: 6.6260286}, // Lausanne
zoom: 12
});
directionsService = new google.maps.DirectionsService();
}
// reads the inputs and calculates the route
function submit_form() {
// remove previous routes
if(directionsDisplayDriving) {
directionsDisplayDriving.setMap(null);
directionsDisplayDriving = null;
}
if(directionsDisplayWalking) {
directionsDisplayWalking.setMap(null);
directionsDisplayWalking = null;
}
// calculate the route, both Driving and Walking
calcRoute(
document.getElementById('start').value,
document.getElementById('end').value,
'DRIVING',
function(display) {
// we put an infoWindow, 20% along the Driving route, and display the total length and duration in the content.
directionsDisplayDriving = display;
var point = distanceAlongPath(display, null, .2);
var content = 'Driving - total distance: ' + getTotalDistance(display) + 'm <br/> total duration: ' + getTotalDuration(display) +'s';
if(infowindowDriving) {
infowindowDriving.setMap(null);
}
infowindowDriving = new google.maps.InfoWindow({
content: content,
map: map,
position: point
});
}
);
calcRoute(
document.getElementById('start').value,
document.getElementById('end').value,
'WALKING',
function(display) {
// we put an infoWindow, 40% along the Walking route, and display the total length and duration in the content.
directionsDisplayWalking = display;
var point = distanceAlongPath(display, null, .4);
var content = 'Walking - total distance: ' + getTotalDistance(display) + 'm <br/> total duration: ' + getTotalDuration(display) +'s';
if(infowindowWalking) {
infowindowWalking.setMap(null);
}
infowindowWalking = new google.maps.InfoWindow({
content: content,
map: map,
position: point
});
}
);
////absolute (in meter)
//var point = distanceAlongPath(directionsDisplay, 100000);
// as a ratio (0 to 1) of the route
//var point = distanceAlongPath(directionsDisplay, null, 0.3); // at 30% from the origin
}
function calcRoute(start, end, travelMode, onReady) {
// alert(travelMode);
var mode = google.maps.TravelMode[travelMode];
var request = {
origin: start,
destination: end,
travelMode: mode
};
directionsService.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
var polylineOptions = getPolylineOptions(travelMode);
var directionsDisplay = new google.maps.DirectionsRenderer({
suppressMarkers: true,
map: map,
polylineOptions: polylineOptions,
preserveViewport: false
});
directionsDisplay.setDirections(response);
if(typeof onReady == 'function') {
onReady(directionsDisplay);
}
}
else {
console.log('status: ' + status);
}
});
}
function getTotalDuration(directionsDisplay) {
var directionsResult = directionsDisplay.getDirections();
var route = directionsResult.routes[0];
var totalDuration = 0;
var legs = route.legs;
for(var i=0; i<legs.length; ++i) {
totalDuration += legs[i].duration.value;
}
return totalDuration;
}
function getTotalDistance(directionsDisplay) {
var directionsResult = directionsDisplay.getDirections();
var route = directionsResult.routes[0];
var totalDistance = 0;
var legs = route.legs;
for(var i=0; i<legs.length; ++i) {
totalDistance += legs[i].distance.value;
}
return totalDistance;
}
// Returns a point along a route; at a requested distance ( either absolute (in meter) or as a ratio (0 to 1) of the route)
// example : you have a random route ( 100km long), and you want to put a marker, 30km from the origin.
// we add the distances of the waypoints and stop when we reach the requested total length.
// nothing stops you from making it even more precise by interpolling.
// the function returns a location (LatLng) along the route
function distanceAlongPath(directionsDisplay, distanceFromOrigin, ratioFromOrigin) {
var directionsResult = directionsDisplay.getDirections();
var route = directionsResult.routes[0];
var totalDistance = getTotalDistance(directionsDisplay);
var tempDistanceSum = 0;
var dist = 0;
if(ratioFromOrigin) {
distanceFromOrigin = ratioFromOrigin * totalDistance;
}
// we prepare the object
var result = new Object();
result.routes = new Array();
result.routes[0] = route;
for(var i in result.routes[0].overview_path) {
if (i>0) {
dist = google.maps.geometry.spherical.computeDistanceBetween (result.routes[0].overview_path[i], result.routes[0].overview_path[i - 1]);
}
tempDistanceSum += dist;
if (tempDistanceSum > distanceFromOrigin) {
return result.routes[0].overview_path[i];
}
// console.log(dist+' '+tempDistanceSum);
}
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?callback=initMap&libraries=geometry" async defer></script>
</body>
</html>
(FIRST submitted, might be interesting for the details of the dashed polylines)
Also, it is possible to change the polylineOptions for one route to be "dotted" like in the image?
Here is part of your question.
A Select box has
DRIVING: with a normal polyline (I gave it some color)
WALKING: with a dashed polyline. I suppose you should try out different numbers, to get the lineType right.
<!DOCTYPE html>
<html>
<head>
<title>Google Maps - Dashed polylines</title>
<meta name="viewport" content="initial-scale=1.0">
<meta charset="utf-8">
<style>
html, body {
height: 90%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<input id="start" placeholder="start" value="Brussels">
<input id="end" placeholder="end" value="Paris">
<select id="mode">
<option value="DRIVING">DRIVING</option>
<option value="WALKING">WALKING</option>
</select>
<input type="button" onclick="submit_form()" value="Calculate Route">
<script>
var directionsDisplay;
var directionsService;
var map;
// returns a polyline. Depending on the travelMode
function getPolylineOptions(travelMode) {
// alert(travelMode);
switch(travelMode) {
default:
case 'DRIVING':
return {
strokeColor: '#808080', // grey'ish
strokeOpacity: 1.0,
strokeWeight: 3
};
break;
case 'WALKING':
// Define a symbol using SVG path notation, with an opacity of 1.
var lineSymbol = {
path: 'M 0,-1 0,1',
strokeOpacity: 1,
scale: 4
};
// Create the polyline, passing the symbol in the 'icons' property.
// Give the line an opacity of 0.
// Repeat the symbol at intervals of 20 pixels to create the dashed effect.
return {
strokeColor: '#ff0000', // red
strokeOpacity: 0,
//strokeWeight: 3,
icons: [{
icon: lineSymbol,
offset: '0',
repeat: '20px'
}]
};
break;
}
}
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 50.869754630095834, lng: 4.353812903165801}, // Brussels
zoom: 12
});
directionsService = new google.maps.DirectionsService();
}
// reads the inputs and calculates the route
function submit_form() {
calcRoute(
document.getElementById('start').value,
document.getElementById('end').value,
document.getElementById('mode').value
)
}
function calcRoute(start, end, travelMode) {
// alert(travelMode);
var mode = google.maps.TravelMode[travelMode];
var request = {
origin: start,
destination: end,
travelMode: mode
};
directionsService.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
var polylineOptions = getPolylineOptions(travelMode);
// you might want to remove the previous polyline. If not, don't add this
if(directionsDisplay) {
directionsDisplay.setMap(null);
}
directionsDisplay = new google.maps.DirectionsRenderer({
suppressMarkers: true,
map: map,
polylineOptions: polylineOptions,
preserveViewport: false
});
directionsDisplay.setDirections(response);
}
else {
console.log('status: ' + status);
}
});
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?callback=initMap" async defer></script>
</body>
</html>

Google maps api - Circle sector stop working

I have this code for display circle sector. This code stop working few weeks ago. I am not too familiar with this api and something probably changed. I see only maps without any markers.
Can someone help me find mistake, please ?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Test</title>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp"></script>
<!-- Le styles -->
<style type="text/css">
#map_canvas {
height: 80%;
}
#map_canvas {
height: 400px;
}
#map {
width: 800px;
height: 500px;
}
</style>
<script>
// Create an object containing LatLng, population.
var koordid = {};
var ringid;
var arcs = {};
arcs[0] = {
center : new google.maps.LatLng(50.083666666667, 14.479111111111),
startAngle : 208,
endAngle : 272,
radius : 734,
innerRadius : 0
}
function drawArc(map,arc) {
var points = 36;
var extpoints = new Array();
var deltaAngle = (arc.endAngle - arc.startAngle) / points;
if (arc.innerRadius > 0) {
extpoints.push(new google.maps.geometry.spherical.computeOffset(arc.center, arc.innerRadius, arc.startAngle));
for (var i=0; (i < points + 1); i++) {
extpoints.push(new google.maps.geometry.spherical.computeOffset(arc.center, arc.radius, arc.startAngle + i * deltaAngle));
}
for (var i=points; (i > -1); i--) {
extpoints.push(new google.maps.geometry.spherical.computeOffset(arc.center, arc.innerRadius, arc.startAngle + i * deltaAngle));
}
} else {
extpoints.push(arc.center);
for (var i=0; (i < points + 1); i++) {
extpoints.push(new google.maps.geometry.spherical.computeOffset(arc.center, arc.radius, arc.startAngle + i * deltaAngle));
}
}
var arc = new google.maps.Polygon({
path: [extpoints],
strokeColor: "#FF0000",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#FF0000",
fillOpacity: 0.35,
});
arc.setMap(map);
}
function initialize() {
var mapOptions = {
zoom: 15,
center: new google.maps.LatLng(50.083666666667, 14.479111111111),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
for (var koord in koordid) {
var raadiusOptions = {};
raadiusOptions = {
strokeColor: "#FF0000",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#FF0000",
fillOpacity: 0.35,
map: map,
center: koordid[koord].center,
radius: koordid[koord].raadius
};
if (koord == 'tsoon') {
raadiusOptions.strokeColor = "#000000";
raadiusOptions.fillColor = "#000000";
}
ringid = new google.maps.Circle(raadiusOptions);
}
drawArc(map,arcs[0]);
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas"></div>
</body>
</html>
You didn't include the geometry-library in your code(but I guess in your production-version it's included)
The issue is this(in drawArc):
path: [extpoints]
when you use the path-property, it must be an array with LatLng's, but you provide an array that contains an array with LatLng's(what will work when you provide it as paths-property)
You may either use
path: extpoints
or
paths: [extpoints]
working fiddle

Google geocode is late (still one step behind)

I put there my whole code. Trying to determine location address. My script should create still one marker with geocoded address (in console - variable kktina).
But, unfortunately, there isn't everything OK. Because by script still resolves previous location (or it takes previous coordinates, dunno). Maybe there is an error in code, but I'm not able to do this anymore..
So asking for help, thank you!
<!DOCTYPE html>
<html>
<head>
<title>Google Maps JavaScript API v3 Example: Map Simple</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<style>
html, body, #map_canvas {
margin: 0;
padding: 0;
height: 100%;
}
</style>
<link rel="stylesheet" type="text/css" href="style.css">
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&libraries=places,geometry"></script>
<script src="http://code.jquery.com/jquery-1.7.min.js" type="text/javascript"></script>
<script>
var map,marker;
var geocoder = new google.maps.Geocoder();
var markers = [];
var img,icon,type;
var prenos,pos,address = "5",point;
function clearMarkersFromArray() {
if (markers.length>0){
markers[0].setMap(null);
markers.shift(markers[0]);
}
}
function geocodePosition(pos) {
geocoder.geocode({
latLng: pos
}, function(responses) {
if (responses && responses.length > 0) {
address = responses[0].formatted_address;
} else {
address = 'Cannot determine address at this location.';
}
});
return address;
}
function initialize() {
var mapOptions = {
zoom: 7,
center: new google.maps.LatLng(49,19),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions),
google.maps.event.addListener(map, 'click', function(response) {
clearMarkersFromArray();
point = new google.maps.LatLng(response.latLng.$a,response.latLng.ab);
var kktina = geocodePosition(point);
console.log(kktina);
var marker = new google.maps.Marker({
position: point,
draggable: true
});
markers.push(marker)
marker.setMap(map);
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="map_canvas" style="height:400px;width:700px;"></div>
</body>
</html>
You can't do this:
function geocodePosition(pos) {
geocoder.geocode({
latLng: pos
}, function(responses) {
if (responses && responses.length > 0) {
address = responses[0].formatted_address;
} else {
address = 'Cannot determine address at this location.';
}
});
return address;
}
the Geocoder is asynchronous, the value of address is undefined when it is returned.
Use the returned data inside the callback function instead, something like this (not tested):
var kktina = null;
function geocodePosition(pos) {
geocoder.geocode({
latLng: pos
}, function(responses) {
if (responses && responses.length > 0) {
kktina = responses[0].formatted_address;
} else {
kktina = 'Cannot determine address at this location.';
}
console.log(kktina);
var marker = new google.maps.Marker({
position: point,
draggable: true
});
markers.push(marker)
marker.setMap(map);
});
}