I have a challenge of trying to embed the Google StreetView for a specific location in on a web page. Normally, I would just use Google's iFrame embed but the platform on which the page is hosted doesn't allow iFrames.
So if I can't use an iFrame, I have to go the traditional way of using a pure HTML document and Google's true StreetView embed approach. That's fine except that I want to parameterize the URL so that the user can pass in a query string to tell the StreetView what location to display.
http://my.site.com/streetview.html&y=37.869260&x=-122.254811
Google's StreetView embed document gives me a great example of dropping StreetView right into an HTML Document.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Street View</title>
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#street-view {
height: 100%;
}
</style>
</head>
<body>
<div id="street-view"></div>
<script>
var panorama;
function initialize() {
panorama = new google.maps.StreetViewPanorama(
document.getElementById('street-view'),
{
position: {lat: 37.869260, lng: -122.254811},
pov: {heading: 165, pitch: 0},
zoom: 1
});
}
</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=[YourAPIKey]&callback=initialize">
</script>
</body>
</html>
I'm trying to modify the Script section to write the values passed to the 'y' and 'x' query strings into the StreetView element's 'lat' and 'lng' variables so that the StreetView will always be at whatever location I pass in as the y and x query strings in the URL.
<script>
var panorama;
function initialize() {
panorama = new google.maps.StreetViewPanorama(
document.getElementById('street-view'),
{
position: {lat: 37.869260, lng: -122.254811},
pov: {heading: 165, pitch: 0},
zoom: 1
});
}
</script>
If I got your question right, you want to get the lattitude and longitude values from Query string.
First, you need to get query params, add this function-
function getParameterByName(name, url) {
if (!url) url = window.location.href;
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)", "i"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
Then modify your script as follows -
<script>
var panorama;
var latt,longg;
latt = parseFloat(getParameterByName('y'));
longg = parseFloat(getParameterByName('x'));
function initialize() {
panorama = new google.maps.StreetViewPanorama(
document.getElementById('street-view'),
{
position: {lat: latt, lng: longg},
pov: {heading: 165, pitch: 0},
zoom: 1
});
}
</script>
Let me know If I misunderstood your question.
Related
I have to create a map that returns the location of a client using Google Maps API, it's for an assignment.
The code works fine, it locates the longitude and latitude and prints it on screen, pbut when it's time to create the map throws me this error: message: "Map: Expected mapDiv of type Element but was passed null. name: InvalidValueError"
Does anyone know why that appears since I did specify mapDiv
map = new google.maps.Map(document.getElementById("map"), {center: {lat: latitud, lng: longitud}, zoom: 14});...
var longitud;
var latitud;
var options = {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
};
function success(pos) {
var crd = pos.coords;
latitud = crd.latitude
longitud = crd.longitude
document.getElementById("latitud").innerHTML = latitud
document.getElementById("longitud").innerHTML = longitud
};
function error(err) {
document.getElementById("map").innerHTML = ('ERROR(' + err.code + '): ' + err.message);
};
navigator.geolocation.getCurrentPosition(success, error);
function initMap(){
map = new google.maps.Map(document.getElementById("map"), {
center: {lat: latitud, lng: longitud},
zoom: 14
});
}
.map{
margin: 0 auto;
width: 300px;
height: 300px;
}
<head>
<meta charset="utf-8">
<script type="text/javascript" src="funciones.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?key=KEY&callback=initMap"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title>Tcuida</title>
</head>
<div class="paginaPrinc" id="paginaPrinc">
<div id="latitud"></div>
<div id="longitud"></div>
<div id="map" class="map"></div>
</div>
This occurs when document.getElementById("map") returns null or type other than div.
map = new google.maps.Map(element, options)
The 1st parameter in the function expects element of div type
I get a different error with the posted code: InvalidValueError: setCenter: not a LatLng or LatLngLiteral with finite coordinates: in property lat: not a number, because the geolocation service is asynchronous, and the map is created before it returns a result.
You have a race condition between two asynchronous operations:
the load of the Google Maps Javascript API v3, which calls initMap
the return of the results of the geolocation service, which calls success
Best would be to remove the race condition, either have the geolocation function call initMap or have the initMap function make the geolocation request.
Example of the second option:
function initMap(){
navigator.geolocation.getCurrentPosition(success, error);
}
function success(pos) {
var crd = pos.coords;
latitud = crd.latitude
longitud = crd.longitude
document.getElementById("latitud").innerHTML = latitud
document.getElementById("longitud").innerHTML = longitud
map = new google.maps.Map(document.getElementById("map"), {
center: {lat: latitud, lng: longitud},
zoom: 14
});
};
working example
proof of concept fiddle
code snippet:
var longitud;
var latitud;
var options = {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
};
function success(pos) {
var crd = pos.coords;
latitud = crd.latitude
longitud = crd.longitude
document.getElementById("latitud").innerHTML = latitud
document.getElementById("longitud").innerHTML = longitud
map = new google.maps.Map(document.getElementById("map"), {
center: {
lat: latitud,
lng: longitud
},
zoom: 14
});
};
function error(err) {
document.getElementById("map").innerHTML = ('ERROR(' + err.code + '): ' + err.message);
};
function initMap() {
navigator.geolocation.getCurrentPosition(success, error);
}
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
.map,
.paginaPrinc {
height: 80%;
}
/* Optional: Makes the sample page fill the window. */
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
<div class="paginaPrinc" id="paginaPrinc">
<div id="latitud"></div>
<div id="longitud"></div>
<div id="map" class="map"></div>
</div>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap" async defer></script>
You need to add a div with id "map". Else document.getElementById("map") will return null so you will get that error.
<div id="map" style="width: auto; height: 550px; position: relative; overflow: hidden;"></div>
when you try to get the element ID, need to fully load the page. Otherwise, in the script part, it cannot find the html element.
Correction: window.onload=function(){ inimap(){}}
I'm trying to write a little web app that will map some locations on a map using Google's Maps JavaScript API. Working with the API is going well, but I'm trying to manipulate their example code and I cannot get the array of data to work unless it's declared withing the Map initialization function. I've been digging for what I am not understanding about Javascript variable access, but I can't figure it out. Ideally I would like to put the array of data in a separate <script> tag so I can load it from another file, but I can't even get the data to work if placed right above the function within the same <script> tag.
I here is a simplified version of the code that I cannot get to work. It won't run because I removed my key from the call to the API, but if that's needed to find the problem I can give it out too.
<html>
<head>
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
// <script src="...">
// where I really want to load let locations = .... from a file
// </script>
<script>
// where i tried to move let locations = .... without success
function initMap() {
const map = new google.maps.Map(document.getElementById("map"), {
zoom: 2.7,
center: new google.maps.LatLng(18,0)
});
let locations = [
{
name: 'MJ Cave',
position: new google.maps.LatLng(47.517869, 19.036026)
}, {
name: 'Protec Tulum',
position: new google.maps.LatLng(20.216557, -87.460052)
}, {
name: 'Giraffe Manor',
position: new google.maps.LatLng(-1.375528, 36.744634)
}
];
function placeMarker( loc ) {
const marker = new google.maps.Marker({
position : loc.position,
map : map
});
}
// ITERATE ALL LOCATIONS. Pass every location to placeMarker
locations.forEach( placeMarker );
}
</script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=MYKEY&callback=initMap">
</script>
</body>
</html>
Problem solved.
Taking the new google.maps.latlng() calls out of the initMap() function was the problem because that datatype isn't necessarily defined at the time that code runs apparently. Changed the location position object to be defined by an array of two numbers and then made them into a google.maps.latlng in function. Works as desired now. For postarity here's my changed code:
<script>
let locations = [
{
name: 'MJ Cave',
position: [47.517869, 19.036026]
}, {
name: 'Protec Tulum',
position: [20.216557, -87.460052]
}, {
name: 'Giraffe Manor',
position: [-1.375528, 36.744634]
}
];
</script>
<script type="text/javascript">
function initMap() {
const infowindow = new google.maps.InfoWindow();
const map = new google.maps.Map(document.getElementById("map"), {
zoom: 2.7,
center: new google.maps.LatLng(18,0)
});
function placeMarker( loc ) {
const marker = new google.maps.Marker({
position : { lat: loc.position[0], lng: loc.position[1]},
icon: icons[loc.type].icon,
map : map
});
// ITERATE ALL LOCATIONS. Pass every location to placeMarker
locations.forEach( placeMarker );
}
</script>
In my application, I have a form on one side and google maps on the other side. To display google maps, I'm using their javascript api. The javascript is writing as a string and part of the html which gets gets called by QWebView. My objective is for the user to click and drag the pin. After the pin has stopped dragging, it would update 2 text boxes on the right side through qt which will populate with the latitude and longitude of the dropped pin. I am having trouble figuring out how to send the data between javascript and python. I am using python3 with pyside qt bindings.
Here is what I have so far.
webView = QWebView()
webView.setHtml(html)
self.central_widget_grid.addWidget(webView,1,0)
Html is a constant defined in another file
#!/usr/bin/python
jscode = """
var map;
var marker;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 40.793697, lng: -77.8586},
zoom: 10
});
map.addListener('click', function(e) {
placeMarkerAndPanTo(e.latLng, map);
});
}
function placeMarkerAndPanTo(latLng, map) {
if (marker === undefined) {
marker = new google.maps.Marker({
position: latLng,
map: map,
title: "Station Location",
draggable: true
});
map.panTo(latLng);
marker.addListener('dragend', function() { draggedMarker(); });
}
}
function draggedMarker() {
alert(marker.getPosition());
statLoc.updateLoc(marker.getPosition().lat(), marker.getPosition().lng());
}
"""
html = """<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<style type="text/css">
html { height: 100% }
body { height: 100%; margin: 0px; padding: 0px }
#map_canvas { height: 100% }
</style>
<script type="text/javascript"
src="http://maps.google.com/maps/api/js?sensor=false&callback=initMap">
</script>
<script type="text/javascript">""" + jscode + """
</script>
</head>
<body onload="initMap();">
<div id="map" style="width:100%; height:100%"></div>
</body>
</html>"""
I have tried creating a class which holds the latitude and longitude and then passing that by calling addToJavaScriptWindowObject.
class StationLocation(QObject):
latitude = 0.0
longitude = 0.0
def __init__(self):
super(StationLocation, self).__init__()
def updateLoc(self,lat,long):
self.latitude = lat
self.longitude = long
print(self.latitude, self.longitude)
With the following changes to my webView
webView = QWebView()
webView.setHtml(html)
frame = webView.page().mainFrame()
frame.addToJavaScriptWindowObject('statLoc', self.station_location)
self.central_widget_grid.addWidget(webView, 1, 0)
With that added. With the print statement inside StationLocations, I expect to see the latitude and longitude printed in the console every time that function is called. I can't find out why this isn't the case.
There are two things you are doing wrong. Firstly, you need to wait until the page is loaded before adding the object. Secondly, the javascript must only call methods of the added object that are decorated as slots.
Below is a working demo. But one caveat: the PySide implementation of addToJavaScriptWindowObject is buggy. It should be possible to use self (i.e. the main window) as the added object, but when I try that with PySide, it hangs on exit for several seconds and then dumps core. For this reason, I used a proxy object in the demo - but with PyQt, the proxy wouldn't be needed.
import sys
from PySide import QtCore, QtGui, QtWebKit
html = '''
<html><head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<style type="text/css">
html { height: 100% }
body { height: 100%; margin: 0; padding: 0 }
#map { width: 100%; height: 100% }
</style>
<script src="https://maps.googleapis.com/maps/api/js"></script>
<script type="text/javascript">
var map, marker
function initialize() {
map = new google.maps.Map(document.getElementById("map"), {
center: {lat: 40.793697, lng: -77.8586},
zoom: 10
})
marker = new google.maps.Marker({
map: map,
position: map.getCenter(),
draggable: true
})
marker.addListener("dragend", function () {
var pos = marker.getPosition()
qt.showLocation(pos.lat(), pos.lng())
console.log("dragend: " + pos.toString())
})
}
google.maps.event.addDomListener(window, "load", initialize)
</script>
</head>
<body><div id="map"/></body>
</html>
'''
class WebPage(QtWebKit.QWebPage):
def javaScriptConsoleMessage(self, message, line, source):
if source:
print('line(%s) source(%s): %s' % (line, source, message))
else:
print(message)
class Proxy(QtCore.QObject):
#QtCore.Slot(float, float)
def showLocation(self, latitude, longitude):
self.parent().edit.setText('%s, %s' % (latitude, longitude))
class MainWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.view = QtWebKit.QWebView(self)
self.view.setPage(WebPage(self))
self.edit = QtGui.QLineEdit(self)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.view)
layout.addWidget(self.edit)
self.map = self.view.page().mainFrame()
self.map.loadFinished.connect(self.handleLoadFinished)
self.view.setHtml(html)
self._proxy = Proxy(self)
def handleLoadFinished(self, ok):
self.map.addToJavaScriptWindowObject('qt', self._proxy)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.setGeometry(500, 300, 800, 600)
window.show()
sys.exit(app.exec_())
I found a simple example, but this works only if the map and the link on the same page.
HTML
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry,visualization,drawing,places"></script>
<script type="text/javascript">
function initialize() {
var latlng = new google.maps.LatLng(51.522387,-0.173501);
var myOptions = {
zoom: 15,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map_canvas"),
myOptions);
var marker2 = new google.maps.Marker(
{
position: new google.maps.LatLng(51.5262405, -0.074549),
map: map,
title: "my 2nd title"
}
);
google.maps.event.addDomListener(
document.getElementById("marker2"), "click", function() {
map.setCenter(marker2.getPosition());
return false;
}
);
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas" style="width:310px; height:260px"></div>
Second place
</body>
</html>
Is there a way to jump to a specific location (LatLong) or directly to a marker with marker.getPosition() from another website to my self created GM Map?
Maybe with an anchor? Ex: http://www.example.com/map#marker2
Here example to get value of query from URL jquery get querystring from URL
Use this to inserted your code and use
map.setCenter(new gooogle.map.latlng(0,0));
for setting center map to location of marker
Parse location.hash to get the desired value
var hash=location.hash.substr(1);
To trigger the click use the ID of the link(e.g. #marker2).
I would suggest to use a list with IDs of clickable links to prevent abuse:
if(['marker2']//array with IDs of clickable links
.indexOf(hash)>-1){
google.maps.event.trigger( document.getElementById(hash),'click');
}
Demo: http://run.plnkr.co/plunks/ia7uUFOuG5L1tzsrayw3/#marker2
For a latLng you may for example use latitude and longitude separated by a comma: #52.549,13.425
split the string by comma, validate the numbers(a latitude must be between -85 and 85 and a longitude between -180 and 180 )
When the validation was successfull create a LatLng based on the values and call map.setCenter with the LatLng as argument.
Demo: http://run.plnkr.co/plunks/ia7uUFOuG5L1tzsrayw3/#52.549,13.425
complete code(run it at the end of initialize):
(function(h) {
var hash = String(h),
latLng = {};
if (!!hash) {
hash = hash.substr(1);
if (['marker2'] //array with IDs of clickable links
.indexOf(hash) > -1) {
google.maps.event.trigger(document.getElementById(hash), 'click');
} else {
hash = hash.split(',');
if (hash.length == 2) {
[
['lat', 85],
['lng', 180]
].forEach(function(o, i) {
if (!latLng || isNaN(hash[i]) || Math.abs(hash[i]) > o[1]) {
latLng = null;
return;
}
latLng[o[0]] = parseFloat(hash[i]);
if (i === 1) {
map.setCenter(latLng);
}
});
}
}
}
}(location.hash));
EDIT: SOLVED. Correct code below the problem code.
I'm having trouble getting my code to work. What I want to do is to use geolocation to determine the users location. I then want to do a search to locate something from a string (in this case, "Systembolaget", in a radius of 2000, and show the results on a google map. I get my own location on the map, but i'm having big trouble getting the places results.
What am I doing wrong? I don't have that much experience from javascript, so all help is good help.
If you're wondering about the cordova script, it's necessary since I'm doing a phonegap application.
<!DOCTYPE html>
<meta charset="UTF-8">
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<script src="cordova-1.6.0.js"></script>
<style type="text/css">
html { height: 100% }
body { height: 100%; margin: 0; padding: 0 }
#map_canvas { height: 100% }
</style>
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?key=MYAPIKEY&sensor=true"></script>
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?libraries=places&sensor=false"></script>
<script type="text/javascript">
// Determine support for Geolocation and get location or give error
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(displayPosition, errorFunction);
} else {
alert('It seems like Geolocation, which is required for this page, is not enabled in your browser. Please use a browser which supports it.');
}
// Success callback function
function displayPosition(pos) {
var mylat = pos.coords.latitude;
var mylong = pos.coords.longitude;
//Load Google Map
var latlng = new google.maps.LatLng(mylat, mylong);
var myOptions = {
zoom: 16,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
// Places
var request = {
location: latlng,
radius: '2000',
name: ['Systembolaget']
};
var service = new google.maps.places.PlacesService(map);
service.search( request, callback );
function callback(results, status)
{
if (status == google.maps.places.PlacesServiceStatus.OK)
{
for ( var i = 0; i < results.length; i++ )
{
var place = results[i];
var loc = place.geometry.location;
var marker = new google.maps.Marker
({
position: new google.maps.LatLng(loc.Pa,loc.Qa)
});
marker.setMap(map);
}
}
}
var marker = new google.maps.Marker({
position: latlng,
map: map,
title:"You are here"
});
}
// Error callback function
function errorFunction(pos) {
alert('It seems like your browser or phone has blocked our access to viewing your location. Please enable this before trying again.');
}
</script>
</head>
<body>
<div id="map_canvas"></div>
</body>
SOLVED! CORRECT CODE!
<!DOCTYPE html>
<meta charset="UTF-8">
<html>
<head>
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" />
<title name="title"></title>
<link rel="stylesheet" type="text/css" href="style.css">
<script src="cordova-1.6.0.js"></script>
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?libraries=places&sensor=false"></script>
<script type="text/javascript">
// Determine support for Geolocation and get location or give error
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(displayPosition, errorFunction);
} else {
alert('It seems like Geolocation, which is required for this page, is not enabled in your browser. Please use a browser which supports it.');
}
// Success callback function
function displayPosition(pos) {
var mylat = pos.coords.latitude;
var mylong = pos.coords.longitude;
//Load Google Map
var latlng = new google.maps.LatLng(mylat, mylong);
var myOptions = {
zoom: 16,
center: latlng,
mapTypeId: google.maps.MapTypeId.HYBRID
};
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
// Places
var request = {
location: latlng,
radius: '20000',
name: ['whatever']
};
var service = new google.maps.places.PlacesService(map);
service.search( request, callback );
function callback(results, status)
{
if (status == google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
var place = results[i];
createMarker(results[i]);
}
}
}
function createMarker(place) {
var placeLoc = place.geometry.location;
var marker = new google.maps.Marker({
map: map,
position: place.geometry.location
});
}
var marker = new google.maps.Marker({
position: latlng,
map: map,
title:"You're here"
});
}
// Error callback function
function errorFunction(pos) {
alert('It seems like your browser or phone has blocked our access to viewing your location. Please enable this before trying again.');
}
</script>
</head>
<body>
<div id="map_canvas"></div>
</body>
It's hard to give you specific help, because you haven't really described exactly how you are failing. But one thing I notice right away is that you appear to be trying to load the google.maps script twice, with different sensor information in each. In your first google.maps script tag you include the literal text MYAPIKEY which is has to be incorrect. If you had a real key in a variable, I would expect something like:
src="http://maps.googleapis.com/maps/api/js?key=" + MYAPIKEY + "&sensor=true"
And then in your second script tag you appear to load the places library correctly, but then your sensor tag is set as: sensor-false. Your 2nd script tag appears more correct to me, so I would suggest removing the first script tag as a start.
From there, can you provide more detail about how your page is failing and maybe a link to the page?
Some additional observations:
Your initial if-else looks as if it will call the displayPosition function, but the code within displayPosition will not load the google map; it simply creates some vars that then go out of scope when the function ends.
Outside of the displayPosition function, you create a new instance of the google Map, but it references myOptions, which no longer exists at this point in the code, because it only existed within the scope of the displayPosition function.
I would suggest changing the code related to Map creation to something like:
var map = null;
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(displayPosition, errorFunction);
} else {
alert('It seems like Geolocation, which is required for this page, is not enabled in your browser. Please use a browser which supports it.');
}
// Success callback function
function displayPosition(pos) {
var mylat = pos.coords.latitude;
var mylong = pos.coords.longitude;
//Load Google Map
var latlng = new google.maps.LatLng(mylat, mylong);
var myOptions = {
zoom: 16,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
}