I´m working a dynamic way to map certain locations, I´m basing my code on an example by Googlemaps, in this example they map locations statically, using an external file (week) where you write the call to the function, an online initialization and mapping functions, like this:
function initialize() {
map = new google.maps.Map(document.getElementById('map_canvas'), {
zoom: 16,
center: new google.maps.LatLng(19.43,-99.15),
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var script = document.createElement('script');
script.src = 'week';
document.getElementsByTagName('head')[0].appendChild(script);
}
function eqfeed_callback(results){
mapping code
}
the content of week, the external file, is:
eqfeed_callback({"type":"FeatureCollection","features":[{feature01, feature02,... feature_n}]});
I´m able to generate dinamically the features content of week (in fact, the whole content, with the very same structure), but now I need to pass it to the initialization function, now that is the value of a global variable instead of an external file´s content, what I´ve made is to rewrite initialize as a parameter dependant function, in order to make it wait for its parameter to be generated, like this:
function initialize(scriptSource){
map = new google.maps.Map(document.getElementById('map_canvas'), { zoom: 16, center: new google.maps.LatLng(19.43,-99.15), mapTypeId:google.maps.MapTypeId.ROADMAP});
var script = document.createElement('script');
script.src = scriptSource;
document.getElementsByTagName('head')[0].appendChild(script);
}
when initialize is called, scriptSource will be the value of a global variable, with its value being exactly the same as the content of the external file (but now generated dinamically) week; I´ve been trying to make it work, but I think there´s a problem with the way I´m passing the src, how do I do this correctly?
It appears you are attempt to load javascript into a script tag.
Rather than setting the src member, instead set the innerHtml.
The src member is actually the url, not the content, of a script tag.
Also, be weary of other places you are setting the src.
script.src = 'week'; will not work as a uri
script.src = 'week.js'; will work as a uri
Related
I want to create a div using javascript to put my google map into.
It creates a div, but doesnt put the map api into it. Please help.
You need to make sure the Google Maps API script has loaded before running your code. Currently, you are trying to build the map before the browser has downloaded the map API.
The simplest way to fix this is to change your HTML to this:
<script src="https://maps.googleapis.com/maps/api/js?key="Entered key here deleted it for stackoverflow"&callback=initMap">
<script src="javascript.js"></script>
You could also remove the Google Maps script tag and load it dynamically in javascript.js using jQuery’s $.getScript() or with plain JS using https://github.com/filamentgroup/loadJS, running your code as the callback.
initMap is firing when the script loads, but create isn't getting called until you click that p tag. Here's a way to get around that issue, but still wait for the script to load before allowing clicks:
var mapready = false, createcalled = false;
function create()
{
createcalled = true;
if(mapready){
var newDiv = document.createElement("map");
newDiv.id = "map";
newDiv.style.border="solid";
document.body.appendChild(newDiv);
var uluru = {lat: 54.278556, lng: -8.460095};
var map = new google.maps.Map(document.getElementById('map'), {zoom: 16,center: uluru});
var marker = new google.maps.Marker({position: uluru,map: map});
}
}
function initMap()
{
mapready = true;
if(createcalled) create();
}
In this scenario, if the user clicks the p tag before the map is ready, the create function will fire as soon as the map API finishes loading.
I am trying to load a map by using leaflet. when i refresh the map, I get the above error. I studied other proposed answers for this question. But, non of them worked for me.
I am trying to load a map inside a function which is run by a onclick event. Here is the code:
function load_map_and_analyze_data(){
var mymap = L.map('mapid',{ center: new L.LatLng(the_center_splitted[0],the_center_splitted[1]),maxZoom: 17, minZoom:11, zoom: 14}); //creating the map
//the rest of analyze and code goes here
}
The tested proposed answers:
1- Check if my map is initialized, if yes remove it, and define it once again.
console.log(mymap);
if(mymap != 'undefined' || mymap != null) {
mymap.remove();
}
Result: mymap is undefined whenever i refresh the function and just the same error.
2- Defining this variable as a general variable outside of function just when mapdiv dom is ready. then i used jquery.
$( "#mapid" ).load(function() {
var mymap= L.map('mapid');
});
Result: this error: Map container not found.
3- Removing the mydiv dom and just trying to recreate it inside of the function.
console.log(mymap);
if(mymap != undefined || mymap != null){
mymap.remove();
$("#mapdiv").html("");
$( "<div id=\"mapdiv\" style=\"height: 500px;\"></div>" ).appendTo(document);
}
Result: mymap is undefined and just the code has not run to test its efficiency.
Any idea or suggestion is appreciated. Thank you.
I have a suggestion that you need to create a reference in outer scope of a function you use to instantiate a Leaflet map. For example, you have a function
function load_map_and_analyze_data(){
var mymap = L.map('mapid',{ center: new L.LatLng(the_center_splitted[0],the_center_splitted[1]),maxZoom: 17, minZoom:11, zoom: 14}); //creating the map
//the rest of analyze and code goes here
}
that encapsulates mymap in it. After you execute this function, you have no chance to access the instance of Leaflet you just created. Any reference to mymap outside of this function's scope will refer to another variable. So, the idea is to keep this variable outside of the scope of this function:
var mymap = null;
function load_map_and_analyze_data() {
mymap = L.map('mapid',{ center: new L.LatLng(the_center_splitted[0],the_center_splitted[1]),maxZoom: 17, minZoom:11, zoom: 14}); //creating the map
//the rest of analyze and code goes here
}
Now, you can refer to mymap from anywhere within the scope this variable is defined. If it is the global scope, then you're not limited in it.
Next, do
console.log(mymap); // should output the object that represents instance of Leaflet
if (mymap !== undefined && mymap !== null) {
mymap.remove(); // should remove the map from UI and clean the inner children of DOM element
console.log(mymap); // nothing should actually happen to the value of mymap
}
and see if it works.
Don't forget that if you declare a new variable with the same name as in outer scope of a function, it's a new variable with a new reference, so you will not be able to refer to the variable in outer scope anymore. So be careful with vars.
https://designlimbo.com/leaflet-ionic-3-and-map-container-is-already-initialized/
Dug hours through SO and Google and found the above to be the only method to work reliably. No messing with remove() or off().
A tiny bit of fiddling with ViewChild / ViewChildren to get DOM references but all my maps load reliably on any page no matter how the pages transition.
I'm using the Play Framework to build a Website, that shows some Markers on a Google Map. For that I create and save some Models in the Application.class controller. But when I render these Models i couldn't find out how to get these use these Model-Objects in javascript. Does anyone know, how to use the Play Framework Tags on Javascript?
My problem was, I wanted to use the "Play-Tags" in my JavaScript-File. For example like this:
#{list items: all, as:'object'}
addMarkerFromRendered("${object.name}", "${object.lat}", "${object.lng}", "${object.type}", "${object.description}", "/public/img/${object.type}.png");
#{/list}
But the Play Tags are not defined for Javascript so the compiler stops at "${" and throws an error.
To solve the problem I wrote a function in my Javascript file:
var addMarkerFromRendered = function(name, lat, lng, category, description, icon){
var latLng = new google.maps.LatLng(lat,lng);
addMarker(latLng, name, category,description, icon);
};
And then I used the function in my HTML-File to render my data:
<script>
$('#map').ready(function(){
#{list items: all, as:'object'}
addMarkerFromRendered("${object.name}", "${object.lat}", "${object.lng}", "${object.type}", "${object.description}", "/public/img/${object.type}.png");
#{/list}
});
</script>
I'm trying to create a Ember View for Google Maps, and load the script in a on-demand manner, i.e. asynchronously Loading the API.
I have two functions inside the view, one is used to load the Google Maps API and the other is to initialize the map. But since Google requires me to call the callback function through the link that requires the API. But in Ember.JS, I couldn't get the right result. All I've got is an ERROR message saying that the object "google" is undefined when trying to initialize the map.
Here is the Ember view code for now.
App.MapsView = Ember.View.extend({
templateName: 'maps',
map: null,
didInsertElement: function() {
this._super();
this.loadGoogleMapsScript();
},
initiateMaps:function(){
var mapOptions = {
zoom: 8,
center: new google.maps.LatLng(-34.397, 150.644),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(this.$().get(0), mapOptions);
this.set('map',map);
},
loadGoogleMapsScript: function(){
var map_callback = this.initiateMaps();
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&callback=map_callback';
document.body.appendChild(script);
},
});
Any ideas how to solve this callback problem? And, what is the optimal way to initialize the map? Should it be in the template or from the JS?
Thanks in advance.
There are two problems here. One is that you're calling your initiateMaps() function in this line:
var map_callback = this.initiateMaps();
This call is made before the Maps API is loaded, leading to the undefined google error.
The other problem is that map_callback is local to this function. The callback used in the Maps API script URL has to be a global function.
(You solved this problem yourself; I'm just adding it here for the benefit of future visitors.)
The fix for both of these problems is to change that line to:
var self = this;
window.map_callback = function() {
self.initiateMaps();
}
There may be a more "native" Ember way to do this, but that should do the trick in any case.
Also, since you're using jQuery along with Ember, you can replace this code:
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&callback=map_callback';
document.body.appendChild(script);
with:
$.getScript( 'https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&callback=map_callback' );
Nothing I've tried seems to work.
I found these two links and thought they'd be helpful, but that hasn't worked either.
Dynamically load JavaScript with JavaScript
https://developers.google.com/loader/
Here's roughly what my Greasemonkey script looks like currently:
var init_map = function() {
new google.maps.Geocoder().geocode({address:'1125 NW 12th Ave, Portland, OR'},function(result){
alert(result);
});
}
function loadMaps() {
GM_log("loadMaps called");
google.load("maps", "3", {"callback" : init_map, "other_params":"key=foo&sensor=false"});
}
function loadScript(filename,callback){
var fileref=document.createElement('script');
fileref.setAttribute("type","text/javascript");
fileref.onload = callback;
fileref.setAttribute("src", filename);
if (typeof fileref!="undefined"){
document.getElementsByTagName("head")[0].appendChild(fileref);
}
}
$(document).ready(
function() {
GM_log("document ready");
loadScript('http://www.google.com/jsapi?key=ABQIAAAAfoo',function(){
loadMaps();
});
}
);
I've found that if I don't include
// #require http://www.google.com/jsapi?key=ABQIAAAAfoo
in the Greasemonkey script, I get a google is undefined error. If I do include it, init_map() never gets called. Any suggestions?
var init_map defines a local variable in the GreaseMonkey context.
If you want to run JavaScript in the context of a webpage, I recommend to inject two <script> tags in the web page (another method is to prefix all of your global variables with unsafeWindow.):
Google's map API
Your script.
Example:
// ==UserScript==
// #name Name of script
// #namespace YourNameSpaceHere
// #match http://blabla.com/*
// #version 1.0
// #run-at document-end
// ==/UserScript==
var head = document.head || document.documentElement;
var script = document.createElement('script');
script.src = 'http://www.google.com/jsapi?key=ABQIAAAAfoo';
head.appendChild(script);
var script2 = document.createElement('script');
script2.textContent = '... code here ..';
head.appendChild(script2);
// Clean-up:
script.parentNode.removeChild(script);
script2.parentNode.removeChild(script2);
E4X instead of a plain string
The easiest option to embed a string of JavaScript code in your GreaseMonkey script, without escaping quotes and newlines is to use the E4X format:
script2.textContent = <x><![CDATA[
alert("test");
]]></x>.toString();
I flagged this question as duplicate of how to use the google maps api with greasemonkey to read a table of addresses and trace the route? but the mod "found no evidence to support it".
So i will just copy-paste what i did in my question, since its not a duplicate...
Nah, just kidding :)
Lets start with your last statement:
I've found that if I don't include // #require
http://www.google.com/jsapi?key=ABQIAAAAfoo in the Greasemonkey
script, I get a google is undefined error. If I do include it,
init_map() never gets called. Any suggestions?
Yes.
First, the google maps API should not be loaded as a #require. Instead, do it like this
API_js_callback = "http://maps.google.com/maps/api/js?sensor=false®ion=BR&callback=initialize";
var script = document.createElement('script');
script.src = API_js_callback;
var head = document.getElementsByTagName("head")[0];
(head || document.body).appendChild(script);
Second, add google = unsafeWindow.google, otherwise you get the "google is undefined" error.
So, your code should start like this
var init_map = function() {
google = unsafeWindow.google
new google.maps.Geocoder().geocode . . . . . .
About the rest of your code... well, just click on the link above and there you will find how to create a DIV on the fly, add the map to it, append the DIV to the page in a fixed position, etc.
Feel free to copy whatever you want.
Greasemonkey scripts are free anyway :)
I tested the answers here and in many other places and nothing would work. Maybe because the API is now v3 or who knows.
I am going to post the answer that worked for me, which is quite different from the others I found, and I believe can be used for many other cases. It's arguably a bit ugly, but after all this is script injection and nobody likes injections.
I don't copy the whole thing in jsbin / codepen / etc. because they simply cannot replicate the GS (Greasemonkey) environment (at least yet) and inner workings.
LOADING API
I had control over the destination webpage so this was there instead of being added via GS.
<script src="https://maps.googleapis.com/maps/api/js?key=my-personal-key"></script>
On my experience, if you don't add the key, after a few requests it will fail and you will have to wait some time until it works again.
I also have there a div whith a floating window where I would create my map.
<div style="overflow:hidden; height:500px; width:700px; position:fixed; top:20px; right:20px; border:3px solid #73AD21;">
<div id="gmap_canvas" style="height:500px;width:700px;"></div>
<style>#gmap_canvas img{max-width:none!important;background:none!important}</style>
<div id="Content_Title"></div>
</div>
GS SCRIPT
// Pass whatever data you need to the window
unsafeWindow.mapdata=JSON.stringify(mapdata);
// Define content of script
var script2 = document.createElement('script');
script2.textContent = `
// Get data
mapdata=JSON.parse(window.mapdata);
// Create map and use data
function initializeX2() {
// some stuff ...
// Create map
var mapCanvas = document.getElementById('gmap_canvas');
var myLatLng = {lat: parseFloat(mapdata[max].latitude), lng: parseFloat(mapdata[max].longitude)};
var mapOptions = {
center: myLatLng,
zoom: 15,
mapTypeControl: false,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(mapCanvas, mapOptions);
var marker=[];
var contentInfoWindow=[];
var infowindow=[];
// Create markers
for (var i = max ; i > max-iterations ; i--) {
// Create marker
var BLatLng={lat: parseFloat(mapdata[i].latitude), lng: parseFloat(mapdata[i].longitude)};
console.log(BLatLng);
marker[i] = new google.maps.Marker({
position: BLatLng,
map: map
});
// Create infowindow
contentInfoWindow[i]=mapdata[i].number + " - " + mapdata[i].name;
infowindow[i] = new google.maps.InfoWindow({content: contentInfoWindow[i] });
// The function has this strange form to take values of references instead of references (pointers)
google.maps.event.addListener(marker[i], 'click', function(innerKey) {
return function() {
infowindow[innerKey].open(map, marker[innerKey]);
}
}(i));
// Open markers
infowindow[i].open(map, marker[i]);
}; // end of for
}; // end of initializeX2
initializeX2();
`; // End of string to be added to page
// Add script to the page
var head = document.head || document.documentElement;
head.appendChild(script2);
// Clean-up:
script2.parentNode.removeChild(script2);
Some explanations
In my case the markers are opened when created, and multiple may stay open. That is my desired behaviour. If you want something else you have to search around.
This may help you.
Create only ONE window to have only one infowindow open at a time ( http://www.aspsnippets.com/Articles/Google-Maps-API-V3-Open-Show-only-one-InfoWindow-at-a-time-and-close-other-InfoWindow.aspx )
If someone has got the other solutions working with API v3 (via google = unsafeWindow.google ) I would be very interested to know.