Multiple custom Streetview generation - google-maps-api-3

I want to show another streetview pane on the screen.
I bound the "redraw()" function to the button onclick event.
The calling of redraw() function from the onclick event failed to draw another streetview.
When redraw() function is called in the initialize() function it works well.
Q1. Why does this redraw() fucnction behaves differently ?
Q2. How can I make it work as I wanted ?
<!DOCTYPE html>
<html>
<head>
<title>Google Maps JavaScript API v3 Example: Simple Custom StreetView</title>
<meta charset="utf-8">
<link href="/default.css" rel="stylesheet">
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script>
<script>
var tileSize, worldSize;
var panorama = null;
var panorama1 = null;
var panoOptions = null;
var panoOptions1 = null;
function initialize() {
// Set up Street View and initially set it visible. Register the
// custom panorama provider function. Set the StreetView to display
// the custom panorama 'reception' which we check for below.
panoOptions = {
pano: 'reception',
visible: true,
panoProvider: getCustomPanorama
};
tileSize = 1024;
worldSize = 1024;
panorama = new google.maps.StreetViewPanorama(
document.getElementById('pano_canvas'), panoOptions);
//redraw();
}
function redraw() {
// Set up Street View and initially set it visible. Register the
// custom panorama provider function. Set the StreetView to display
// the custom panorama 'reception' which we check for below.
tileSize = 1024;
worldSize = 1024;
panoOptions1 = {
pano: 'reception1',
visible: true,
panoProvider: getCustomPanorama1
};
panorama1 = new google.maps.StreetViewPanorama(
document.getElementById('pano_canvas1'), panoOptions1);
}
// Return a pano image given the panoID.
function getCustomPanoramaTileUrl(pano, zoom, tileX, tileY) {
// Note: robust custom panorama methods would require tiled pano data.
// Here we're just using a single tile, set to the tile size and equal
// to the pano "world" size.
return 'panoReception1024-0.jpg';
}
// Return a pano image given the panoID.
function getCustomPanoramaTileUrl1(pano, zoom, tileX, tileY) {
// Note: robust custom panorama methods would require tiled pano data.
// Here we're just using a single tile, set to the tile size and equal
// to the pano "world" size.
return 'panoReception1024-0.jpg';
}
// Construct the appropriate StreetViewPanoramaData given
// the passed pano IDs.
function getCustomPanorama(pano, zoom, tileX, tileY) {
if (pano == 'reception') {
return {
location: {
pano: 'reception',
description: 'Google Sydney - Reception'
},
links: [],
// The text for the copyright control.
copyright: 'Imagery (c) 2010 Google',
visible: true,
// The definition of the tiles for this panorama.
tiles: {
tileSize: new google.maps.Size(tileSize, 512),
worldSize: new google.maps.Size(worldSize, 512),
// The heading in degrees at the origin of the panorama
// tile set.
centerHeading: 105,
getTileUrl: getCustomPanoramaTileUrl
}
};
}
}
// Construct the appropriate StreetViewPanoramaData given
// the passed pano IDs.
function getCustomPanorama1(pano, zoom, tileX, tileY) {
if (pano == 'reception1') {
return {
location: {
pano: 'reception1',
description: 'Google Sydney - Reception'
},
links: [],
visible: true,
// The text for the copyright control.
copyright: 'Imagery (c) 2010 Google',
// The definition of the tiles for this panorama.
tiles: {
tileSize: new google.maps.Size(tileSize, 512),
worldSize: new google.maps.Size(worldSize, 512),
// The heading in degrees at the origin of the panorama
// tile set.
centerHeading: 105,
getTileUrl: getCustomPanoramaTileUrl1
}
};
}
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div>
<b>Tile Size: </b>
<select id="tileSize" >
<option value="256">256</option>
<option value="512">512</option>
<option value="768">768</option>
<option value="1024" selected>1024</option>
<option value="2048">2048</option>
</select>
<b>World Size: </b>
<select id="worldSize" >
<option value="256">256</option>
<option value="512">512</option>
<option value="768">768</option>
<option value="1024" selected>1024</option>
<option value="2048">2048</option>
</select>
<input type="button" value="Redraw" id="redraw" onclick="redraw()" />
</div>
<div id="pano_canvas" style="width: 500px; height: 380px"></div>
<div id="pano_canvas1" style="width: 500px; height: 380px"></div>
</body>
</html>

I found how to make it work but still am not sure why.
In the redraw() function, I added setPano() as below.
panorama1 = new google.maps.StreetViewPanorama(document.getElementById('pano_canvas1'), panoOptions1);
panorama1.setPano('reception1');
Then the redraw() function worked as expected.
Without that, the custom panoProvider function was not called.
I suppose setPano calls the custom panoProvider function internally.

Related

Recent change in result/behavior of getPanoramaByLocation

I've just noticed a recent change in the results returned by getPanoramaByLocation for calls with radius of 10. After identifying a place object for the streetview, in the past this code would return a custom, interior view of the space if available:
streetViewService.getPanoramaByLocation(place.geometry.location, 10, function(streetViewPanoramaData, status) {
Now, however, this call returns the same streetview as setting the radius to 50, which is to say, the standard google external streetview of the place... In this standard outside streetview, there is a navigation arrow that can be clicked to provide access to the interior custom view of the place, so it is still there. However, the objective of my site is to first display the custom interior view if one is available...
Any idea of how/why this behavior might have changed? Or if it is possible to somehow directly the getPanoramaByLocation to return a custom interior panorama by directly?
UPDATED with HTML and Javascript below
HTML
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"> </script>
<body>
<div id="pano1" style="height:500px; width:600px;"></div>
<div id="pano1_info"></div>
<div id="pano2" style="height:500px; width:600px;"></div>
<div id="pano2_info"></div>
</body>
Javascript
var panoramaService = new google.maps.StreetViewService();
panoramaService.getPanoramaById('aZooFPuMASQAAAQIt5H7Ug', function (res, stat) {
var loc = res.location.latLng;
var panoramaOptions = {
position: loc,
pov: {
heading: 270,
pitch: 0
},
visible: true
};
var panorama1 = new google.maps.StreetViewPanorama(document.getElementById('pano1'), panoramaOptions);
document.getElementById('pano1_info').innerHTML = res.location.pano;
panorama1.setPano(res.location.pano);
alert(loc.lat()+','+loc.lng());
});
var loc2 = new google.maps.LatLng(30.248133,-97.75047899999998);
// var loc2 = new google.maps.LatLng(30.2481325,-97.7504791);
panoramaService.getPanoramaByLocation(
loc2,
10,
// 50,
function (streetViewPanoramaData, streetViewStatus) {
if (streetViewStatus != "OK") {
alert("no street view at this location I'm afraid");
} else {
var panoramaOptions = {
position: loc2,
pov: {
heading: 270,
pitch: 0
},
visible: true
};
var panorama2 = new google.maps.StreetViewPanorama(document.getElementById('pano2'), panoramaOptions);
document.getElementById('pano2_info').innerHTML = streetViewPanoramaData.location.pano;
panorama2.setPano(streetViewPanoramaData.location.pano);
//alert(streetViewPanoramaData.location.pano);
}
});

Using google places api with google geocode api together

I am using google places autocomplete api and now I want to get the geocode of that address and display that area on map.This is my code...
<head>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&libraries=places"></script>
<script>
// This example adds a search box to a map, using the Google Place Autocomplete
// feature. People can enter geographical searches. The search box will return a
// pick list containing a mix of places and predicted search terms.
function initialize() {
var input = document.getElementById('searchTextField');
var autocomplete = new google.maps.places.Autocomplete(input);
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<input id="searchTextField" type="text" size="50">
</body>
I know there is google geocde api but I really dont know how to do that.
I m doing all this in wordpress. Anybody has idea about this???
Looks like that's what you need:
<style>
#map-canvas {
width: 500px;
height: 500px;
}
</style>
Then, the JS
function initialize() {
// initial zoom and position
var myOptions = {
zoom: 14,
center: new google.maps.LatLng(-25.3, 133.8)
};
// create Map instance
var map = new google.maps.Map(document.getElementById('map-canvas'), myOptions);
// get input reference
var input = document.getElementById('searchTextField');
// create instance of autocomplete
var autocomplete = new google.maps.places.Autocomplete(input);
// listen for changes
google.maps.event.addListener(autocomplete, 'place_changed', function() {
// get the selected place
var place = this.getPlace();
// if there's a geometry available
if (place.geometry) {
// move the map to the position
map.panTo(place.geometry.location);
// update the zoom
map.setZoom(15);
// log the position
console.log(place.geometry.location.lat(),place.geometry.location.lng() )
}
})
}
More info: https://developers.google.com/maps/documentation/javascript/places-autocomplete

Capture Coordinates in Google Map on User Click

I'm using this code to capture the co-ordinates when user clicks on the map by using below event listener:
google.maps.event.addListener(map, 'click', function(event) {
placeMarker(event.latLng);
});
However this function doesn't get called when user click on already marked location in Map.
Meaning this function is not called for points where mouse pointer changes to hand icon on Google Map.
Need help on capturing these kind of locations.
You should add the click listener on marker will give you the position of marker.
//Add listener
google.maps.event.addListener(marker, "click", function (event) {
var latitude = event.latLng.lat();
var longitude = event.latLng.lng();
console.log( latitude + ', ' + longitude );
}); //end addListener
Edit:
You need something like this
//Add listener
google.maps.event.addListener(marker, "click", function (event) {
var latitude = event.latLng.lat();
var longitude = event.latLng.lng();
console.log( latitude + ', ' + longitude );
radius = new google.maps.Circle({map: map,
radius: 100,
center: event.latLng,
fillColor: '#777',
fillOpacity: 0.1,
strokeColor: '#AA0000',
strokeOpacity: 0.8,
strokeWeight: 2,
draggable: true, // Dragable
editable: true // Resizable
});
// Center of map
map.panTo(new google.maps.LatLng(latitude,longitude));
}); //end addListener
Another solution is to place a polygon over the map, same size as the map rectangle, and collect this rectangles clicks.
function initialize() {
var mapDiv = document.getElementById('map-canvas');
var map = new google.maps.Map(mapDiv, {
center: new google.maps.LatLng(37.4419, -122.1419),
zoom: 13,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
google.maps.event.addListener(map, 'bounds_changed', function() {
var lat1 = 37.41463623043073;
var lat2 = 37.46915383933881;
var lng1 = -122.1848153442383;
var lng2 = -122.09898465576174;
var rectangle = new google.maps.Polygon({
paths : [
new google.maps.LatLng(lat1, lng1),
new google.maps.LatLng(lat2, lng1),
new google.maps.LatLng(lat2, lng2),
new google.maps.LatLng(lat1, lng2)
],
strokeOpacity: 0,
fillOpacity : 0,
map : map
});
google.maps.event.addListener(rectangle, 'click', function(args) {
console.log('latlng', args.latLng);
});
});
}
Now you get LatLng's for places of interest (and their likes) also.
demo -> http://jsfiddle.net/qmhku4dh/
You're talking about the Point of Interest icons that Google puts on the map.
Would it work for you to remove these icons entirely? You can do that with a Styled Map. To see what this would look like, open the Styled Map Wizard and navigate the map to the area you're interested in.
Click Point of interest under Feature type, and then click Labels under Element type. Finally, click Visibility under Stylers and click the Off radio button under that.
This should remove all of the point of interest icons without affecting the rest of the map styling. With those gone, clicks there will respond to your normal map click event listener.
The Map Style box on the right should show:
Feature type: poi
Element type: labels
Visibility: off
If the result looks like what you want, then click Show JSON at the bottom of the Map Style box. The resulting JSON should like this this:
[
{
"featureType": "poi",
"elementType": "labels",
"stylers": [
{ "visibility": "off" }
]
}
]
You can use that JSON (really a JavaScript object literal) using code similar to the examples in the Styled Maps developer's guide. Also see the MapTypeStyle reference for a complete list of map styles.
This example demonstrates the use of click event listeners on POIs (points of interest). It listens for the click event on a POI icon and then uses the placeId from the event data with a directionsService.route request to calculate and display a route to the clicked place. It also uses the placeId to get more details of the place.
Read the google documentation.
<!DOCTYPE html>
<html>
<head>
<title>POI Click Events</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<style>
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
.title {
font-weight: bold;
}
#infowindow-content {
display: none;
}
#map #infowindow-content {
display: inline;
}
</style>
</head>
<body>
<div id="map"></div>
<div id="infowindow-content">
<img id="place-icon" src="" height="16" width="16">
<span id="place-name" class="title"></span><br>
Place ID <span id="place-id"></span><br>
<span id="place-address"></span>
</div>
<script>
function initMap() {
var origin = {lat: -33.871, lng: 151.197};
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 18,
center: origin
});
var clickHandler = new ClickEventHandler(map, origin);
}
/**
* #constructor
*/
var ClickEventHandler = function(map, origin) {
this.origin = origin;
this.map = map;
this.directionsService = new google.maps.DirectionsService;
this.directionsDisplay = new google.maps.DirectionsRenderer;
this.directionsDisplay.setMap(map);
this.placesService = new google.maps.places.PlacesService(map);
this.infowindow = new google.maps.InfoWindow;
this.infowindowContent = document.getElementById('infowindow-content');
this.infowindow.setContent(this.infowindowContent);
// Listen for clicks on the map.
this.map.addListener('click', this.handleClick.bind(this));
};
ClickEventHandler.prototype.handleClick = function(event) {
console.log('You clicked on: ' + event.latLng);
// If the event has a placeId, use it.
if (event.placeId) {
console.log('You clicked on place:' + event.placeId);
// Calling e.stop() on the event prevents the default info window from
// showing.
// If you call stop here when there is no placeId you will prevent some
// other map click event handlers from receiving the event.
event.stop();
this.calculateAndDisplayRoute(event.placeId);
this.getPlaceInformation(event.placeId);
}
};
ClickEventHandler.prototype.calculateAndDisplayRoute = function(placeId) {
var me = this;
this.directionsService.route({
origin: this.origin,
destination: {placeId: placeId},
travelMode: 'WALKING'
}, function(response, status) {
if (status === 'OK') {
me.directionsDisplay.setDirections(response);
} else {
window.alert('Directions request failed due to ' + status);
}
});
};
ClickEventHandler.prototype.getPlaceInformation = function(placeId) {
var me = this;
this.placesService.getDetails({placeId: placeId}, function(place, status) {
if (status === 'OK') {
me.infowindow.close();
me.infowindow.setPosition(place.geometry.location);
me.infowindowContent.children['place-icon'].src = place.icon;
me.infowindowContent.children['place-name'].textContent = place.name;
me.infowindowContent.children['place-id'].textContent = place.place_id;
me.infowindowContent.children['place-address'].textContent =
place.formatted_address;
me.infowindow.open(me.map);
}
});
};
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initMap"
async defer></script>
</body>
</html>
If you are using npm load-google-maps-api with webpack this worked for me:
const loadGoogleMapApi = require("load-google-maps-api");
loadGoogleMapApi({ key: process.env.GOOGLE_MAP_API_KEY }).then(map => {
let mapCreated = new map.Map(mapElem, {
center: { lat: lat, lng: long },
zoom: 7
});
mapCreated.addListener('click', function(e) {
console.log(e.latLng.lat()); // this gives you access to the latitude value of the click
console.log(e.latLng.lng()); // gives you access to the latitude value of the click
var marker = new map.Marker({
position: e.latLng,
map: mapCreated
});
mapCreated.panTo(e.latLng); // finally this adds red marker to the map on click.
});
});
Next if you are integrating openweatherMap in your app you can use the value of e.latLng.lat() and e.latLng.lng() which I console logged above in your api request. This way:
http://api.openweathermap.org/data/2.5/weather?lat=${e.latLng.lat()}&lon=${e.latLng.lng()}&APPID=${YOUR_API_KEY}
I hope this helps someone as it helped me.
Cheers!

How to save map drawing state (Polygon, Polyline, Markers)

I want to enable drawing on Google Maps like (see this example)
When user finish with drawings he will click on save button to save his drawings in Database or KML file, anything :) .. I do not know how to the save part? Could anyone help me
Here, http://jsfiddle.net/X66L4/1/ try drawing some circles, click on SAVE, then edit the circles by switching to the hand cursor and SAVE again to see the changes.
I show an example to save circles' data, the main idea is to keep a global array for each drawing type (line, polygon, marker, circle), and use a listener on the drawing manager to detect each type being drawn (complete).
var circles = [];
google.maps.event.addDomListener(drawingManager, 'circlecomplete',
function(circle) {
circles.push(circle);
});
The reason to save the entire reference to the drawn object is to continue tracking changes. So you will need an array and listener for each type of drawing.
Then, when you want to save the data (you may wish to do so at every edit), iterate through the arrays and extract the minimum information to rebuild it (center, radius, path, latLng, and so on.)
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
html, body, #map_canvas { margin: 0; padding: 0; height: 100% }
</style>
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false&libraries=drawing"></script>
<script type="text/javascript">
var myOptions = {
center: new google.maps.LatLng(-25,177.5),
zoom: 3,
mapTypeId: google.maps.MapTypeId.SATELLITE
};
var map;
function initialize() {
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
var drawingManager = new google.maps.drawing.DrawingManager({
drawingMode: google.maps.drawing.OverlayType.CIRCLE,
drawingControl: true,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_CENTER,
drawingModes: [google.maps.drawing.OverlayType.CIRCLE]
},
circleOptions: {
editable: true
}
});
drawingManager.setMap(map);
var circles = [];
google.maps.event.addDomListener(drawingManager, 'circlecomplete', function(circle) {
circles.push(circle);
});
google.maps.event.addDomListener(savebutton, 'click', function() {
document.getElementById("savedata").value = "";
for (var i = 0; i < circles.length; i++) {
var circleCenter = circles[i].getCenter();
var circleRadius = circles[i].getRadius();
document.getElementById("savedata").value += "circle((";
document.getElementById("savedata").value +=
circleCenter.lat().toFixed(3) + "," + circleCenter.lng().toFixed(3);
document.getElementById("savedata").value += "), ";
document.getElementById("savedata").value += circleRadius.toFixed(3) + ")\n";
}
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<button id="savebutton">SAVE</button>
<textarea id="savedata" rows="8" cols="40"></textarea>
<div id="map_canvas"></div>
</body>
</html>
In my experience, it's easier to use map's dataLayer then the drawing manager.
Try out this fiddle.
FiddleLink
Showing the controls:
map.data.setControls(['Polygon']);
map.data.setStyle({
editable: true,
draggable: true
});
in this function you can see the Create, Read (localStorage) and Remove (not in that order):
function loadPolygons(map) {
var data = JSON.parse(localStorage.getItem('geoData'));
map.data.forEach(function (f) {
map.data.remove(f);
});
console.log(data);
map.data.addGeoJson(data)
}

click listeners conflict w/ infowindow

I'm attempting to create a map that allows users to report a trailwork
problem by clicking and filling a form in an infowindow (similar to
seeclickfix.com). I haven't built in the php/SQL that will actually
save the information provided by the user yet.
The problem: I have a button in the html of my infowindow for users to
submit information and close the window. Instead of just closing the
window though, my event listener for new markers receives clicks
through the infowindow, creating an unwanted marker behind the button.
Google avoids this problem somehow; no click is registered on their
top right-exit 'x'.
I've attempted to create a Boolean signal variable ('infopen') to let
my addMarker function know if an infowindow is open, but it's not
functioning.... Any ideas why?
Any other suggestions regarding the code would be appreciated!
(My task is creating a system to organizing and store multiple
infowindows/markers...)
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Test Reporter </title>
<script type="text/javascript" src="http://maps.google.com/maps/
api/js?sensor=false"></script>
<script type="text/javascript">
var map;
var marker;
var markers = [];
var infowindow;
var infopen = false;
var edit = true;
var pos = new google.maps.LatLng(44.021, -71.831102);
function initialize() {
var mapOptions = {
zoom: 14,
center: pos,
mapTypeControl: true,
panControl: false,
zoomControl: true,
mapTypeId: google.maps.MapTypeId.TERRAIN
};
map = new google.maps.Map(document.getElementById("map_canvas"),
mapOptions);
var table = "<table>" +
"<tr><td>Problem:</td> <td><input type='text'
id='prob'/> </td> </tr>" +
"<tr><td>Description:</td> <td><input type='text'
size='30' id='desc'/></td> </tr>" +
"<tr><td align=right ><input type='button'
value='Save & Close' onclick='saveData()' /></td>" +
"<td><input type='button' value='Cancel & Delete'
onclick='cancel()' /></td></tr>";
infowindow = new google.maps.InfoWindow({
content: table
});
google.maps.event.addListener(map, "click", function(event) {
addMarker(event.latLng);
});
} //end initialize
// Add a marker to the map and push to the array, open an infowindow listener.
function addMarker(location) {
if (editon.editT[0].checked) edit = true; //check 'edit' radio buttons
if (editon.editT[1].checked) edit = false;
alert('infopen is ' + infopen);
if (edit== true && infopen== false) {
//if edit toggle is selected and infowindow not open
marker = new google.maps.Marker({
position: location, //from event.latLng
map: map,
draggable: true,
});
markers.push(marker); //add to markers array
google.maps.event.addListener(marker, "click", function() {
//listener for infowindow
infowindow.open(map, marker);
infopen = true; // stop the creation of new markers *in theory...
//alert('infopen is ' + infopen);
});
}// end if
} //end addMarker()
// Sets the map on all markers in the array. (only used when clearing)
function setAllMap(map) {
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(map);
}
}
// Deletes all markers in the array by removing references to
them.
function deleteOverlays() {
setAllMap(null);
markers = [];
}
//would passes along info to php... not yet
function saveData() {
infowindow.close();
infopen = false; //reallow marker creation from click
}
//closes window and clears marker
function cancel() {
infowindow.close();
infopen = false; // reallow marker creation ***click still
heard by event listener***
marker.setMap(null); //just clears from map
}
</script>
</head>
<body onload="initialize()">
<br> </br>
<form name="editon"> Turn on editing:
<input type="radio" name="editT" value='true' checked/>Yes
<input type="radio" name="editT" value='false' />No
</form>
<div id="map_canvas" style="width:100%; height:70%"></div>
<p>If too cluttered:
<input onclick="deleteOverlays();" type=button value="Clear Map"/>
</body>
</html>
My contrived hack: add a setTimeout() around infowindow.close(). There is a rationale, explained below.
function saveData() {
setTimeout(function() { infowindow.close(); }, 100);
}
//closes window and clears marker
function cancel() {
setTimeout(function() { infowindow.close(); marker.setMap(null); }, 100);
}
100 ms seems reasonable. Strangely, setting the marker to a null map in cancel() also has to be timed out. I don't think you need infopen anymore.
I got the idea from this code sample:
http://code.google.com/apis/maps/articles/phpsqlinfo_v3.html
In this sample, the infoWindow is only closed (in a callback) after a database request is made and ensuring the response was good. Of course, this must take some milliseconds. So, under these assumptions, once you have your DB part working, you can replace the ugly setTimeout and everything should work! :)

Resources