How to build a theme using jaredpalmer/presspack with Google Maps integration? - javascript

Introducing the problem
Building this theme using jaredpalmer/presspack for docker, I'm struggling for a few days now as I try to insert this pair of Google Maps instances within an element that will be called in every page. The maps won't load and Chrome tells me my function is not there.
Some context
Presspack is serving the DB and uses yarn to make a environment. It keeps scripts separately for general purposes and specific ones, as it has a common.js - where I code everything it should load on every page - and a .js - which loads only on specific pages. I'm working on common now, since I believe this contact section will be used on every page and blog post of this site. The calling function for this section is WP basic <?php get_template_part( 'content', 'contato-std' ); ?>
I've added a code in functions.php to load the API key script after the footer of my pages.
It's important to mention that I've tried the js code I'm using in common.js on another HTML only environment.
My files
common.js
export default {
init() {
// JavaScript to be fired on all pages
console.log('common');
},
finalize() {
// JavaScript to be fired on all pages, after page specific JS is fired
var isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
if (isMobile) { // Tudo o que for pra navegadores mobile
(...)
} else { // Tudo o que for pra navegadores padrão
(...)
// GOOGLE MAPS LOAD
var markers = [{
GPS1: -15.7954901,
GPS2: -47.8926766,
client_address: "Corpus - Fisioterapia & Pilates, Unidade Asa Sul"
}];
function initialize() {
initMap();
initMap2();
};
function initMap() {
var latlng = new google.maps.LatLng(-15.7954901, -47.8926766); // default location
var myOptions = {
zoom: 16,
center: latlng,
mapTypeId: google.maps.MapTypeId.MAP,
mapTypeControl: true
};
var map = new google.maps.Map(document.getElementById('mapaAsaSul'), myOptions);
var infowindow = new google.maps.InfoWindow(),
marker, lat, lng;
for (i = 0; i < markers.length; i++) {
lat = (markers[i].GPS1);
lng = (markers[i].GPS2);
name = (markers[i].client_address);
marker = new google.maps.Marker({
position: new google.maps.LatLng(lat, lng),
name: name,
map: map
});
google.maps.event.addListener(marker, 'click', function(e) {
infowindow.setContent(this.name);
infowindow.open(map, this);
}.bind(marker));
}
}
var markers2 = [{
GPS1: -15.7187167,
GPS2: -47.8867326,
client_address: "Corpus - Fisioterapia & Pilates, Unidade Lago norte"
}];
function initMap2() {
var latlng = new google.maps.LatLng(-15.7187167, -47.8867326); // default location
var myOptions = {
zoom: 16,
center: latlng,
mapTypeId: google.maps.MapTypeId.MAP,
mapTypeControl: true
};
var map = new google.maps.Map(document.getElementById('mapaLagoNorte'), myOptions);
var infowindow = new google.maps.InfoWindow(),
marker, lat, lng;
for (i = 0; i < markers2.length; i++) {
lat = (markers2[i].GPS1);
lng = (markers2[i].GPS2);
name = (markers2[i].client_address);
marker = new google.maps.Marker({
position: new google.maps.LatLng(lat, lng),
name: name,
map: map
});
google.maps.event.addListener(marker, 'click', function(e) {
infowindow.setContent(this.name);
infowindow.open(map, this);
}.bind(marker));
}
}
},
};
function.php
<?php
...
function add_google_maps() {
wp_enqueue_script(
'my-google-maps',
'http://maps.googleapis.com/maps/api/js?key=KEY&callback=initialize',
NULL,
NULL,
true
);
add_filter( 'script_loader_tag', function ( $tag, $handle ) {
if ( 'my-google-maps' !== $handle )
return $tag;
return str_replace( ' src', ' async defer src', $tag );
}, 10, 2 );
}
add_action('wp_enqueue_scripts', 'add_google_maps');
?>
The JS handling the routing from common.js and .js is index.js
import jQuery from 'jquery';
import './style.scss';
import Router from './util/Router';
import common from './routes/common';
import home from './routes/home';
/**
* Populate Router instance with DOM routes
* #type {Router} routes - An instance of our router
*/
const routes = new Router({
/** All pages */
common,
/** Home page */
home
/** About Us page, note the change from about-us to aboutUs. */
});
/** Load Events */
jQuery(document).ready(() => routes.loadEvents());
Bad response
It should load both instances of maps within the respective div's #mapaAsaSul and #mapaLagoNorte, but it won't and Chrome's console returns this:
(index):1
Uncaught (in promise) Xc {message: "initialize is not a function", name: "InvalidValueError", stack: "Error↵ at new Xc (http://maps.googleapis.com/ma…KEY&callback=initialize:125:107"}message: "initialize is not a function"name: "InvalidValueError"stack: "Error↵ at new Xc (http://maps.googleapis.com/maps/api/js?key=KEY&callback=initialize:56:227)↵ at Object._.Yc (http://maps.googleapis.com/maps/api/js?key=KEY&callback=initialize:56:337)↵ at Uh (http://maps.googleapis.com/maps/api/js?key=KEY&callback=initialize:125:221)↵ at http://maps.googleapis.com/maps/api/js?key=KEY&callback=initialize:125:107"__proto__: Error
Promise.then (async)
Vh # js?key=KEY&callback=initialize:125
google.maps.Load # js?key=KEY&callback=initialize:21
(anonymous) # js?key=KEY&callback=initialize:212
(anonymous) # js?key=KEY&callback=initialize:212
This initialize is written in common.js. The file is listed in console, red by webpack (which presspack uses).
I'm running this #localhost so won't be able to provide a link for this page.
And I'm sorry if I've done any mistakes formatting this post or provide wrong info. Not really experienced at creating posts here in stack. :(
Any thoughts and ideas on this problem will be most welcome.
Edit: corrected that mistake as Evan suggested in the comments, where the calling was for maps.google.com and not maps.googleapis.com
Edit2: As Evan kept helping me on the comment section, I've made some additions to my code as follows.
The callback function that was returning a problem in console, was removed and I replaced it as a new callback for initialize function that appears on common.js.
var markers = [{(...)}];
function initialize() {(...)};
function initMap() {(...)};
var markers = [{(...)}];
function initMap2() {(...)};
google.maps.event.addDomListener(window, 'load', initialize); //This is the new callback for my maps
This did solved something, since the first map appeared. Still, there was still some error which console would point at:
"Uncaught ReferenceError: i is not defined at initMap (common.js?a395:77) at initialize (common.js?a395:56)" pointing at this line of common.js: for (i = 0; i < markers.length; i++) {.
I didn't get it. Just guessed that it had something to do with my markers code, since the first map appeared after the callback being made in common.js but with no marker.
Then, Evan pointed that if i was initialized globally, that error made sense. So he suggested changing the code to for (let i = 0; i < markers.length; i++) {, which did it for me. Adding it to both instances of markers in the code, made both maps appear properly and with markers.
Thanks for your help, Evan!

First of all, the JavaScript API should be called via https://maps.googleapis.com/, not http://maps.google.com/.
The "initialize is not a function" scope error can be worked around by loading the Maps API script synchronously on page load, e.g. by using google.maps.event.addDomListener(window, 'load', initialize), but in general the recommended approach is to load the API asynchronously via a callback:
<script async defer src="https://maps.googleapis.com/maps/api/js?key=KEY&callback=initialize"></script>
Then there's an issue with both markers loops, e.g. for (i = 0; i < markers.length; i++), as they're missing i initialization. Try using for (let i = 0; i < markers.length; i++).
You can find here a working jsbin that shows both your maps and markers loading successfully after the above code changes.

Related

ASP.Net MVC -- "Google’s MarkerManager"

Been chasing a rabbit, and time to ask for help before I get any further down this rabbit hole. I have been trying to implement a Google Map with multiple markers. I was trying to use the code I found on ChangSu’s Tech blog at https://csjlsolutions.wordpress.com/2013/07/11/how-to-put-multiple-markers-in-google-map-in-mvc-4/. I managed to get my google map to display, but none of the markers displayed. By using the browsers' development tool, I saw that the java script could not find Google’s MarkerManager. After looking around some more, I used the Package Manager Console to install Jmelosegui.Mvc.Googlemap (version 0.8.0.0) (see http://www.jmelosegui.com/map/).
After installing this package, I started getting a new error:
Conflicting versions of ASP.NET Web Pages detected: specified version is “1.0.0.0”, but version in bin is “3.0.0.0”. To continues remove files from application’s bin directory or remove the version specification in web.config
More looking around, and updated my web.config to version 3 (it was version 1.0.0.0)
<appSettings>
add key="webpages:Version" value="3.0.0.0" /
Now I have syntax error.
#foreach (var place in Model) {
var myLatLng = new google.maps.LatLng("#place.MonumentLocationLat", "#place.MonumentLocationLong");
Not sure which way to turn on this. Should I start from scratch?
I think when I installed Jmelosegui.Mvc.Googlemap it really messed up something somewhere. I was getting errors about version mismatches and all kinds of strange things. I have fallen back to a previous version of my code (aren't backups nice) and have managed to get my map to displays. I
My Solution
Controller
// -------------------- Display a Map of the Battlefield showing the location of all of the monuments that have been entered to the DB -------------------------------------------------
public ActionResult MapMonuments(string battleRecID)
{
var monumentMap = from s in db.Monuments
where ((s.MonumentBattleRecID == battleRecID) &&
(s.MonumentStatus == "A"))
select s;
ViewBag.avgLat = monumentMap.Average(s => s.MonumentLocationLat);
ViewBag.avgLong = monumentMap.Average(s => s.MonumentLocationLong);
return PartialView(monumentMap.ToList());
}
View
#model IEnumerable<CWBFM.Models.Monument>
// avgLat = the average of all of the latitudes
// avgLong = the average of all of the longitudes
Int_Map("#ViewBag.avgLat", "#ViewBag.avgLong");
// Where all the fun happens
function Int_Map(avgLat, avgLong) {
var latlng = new google.maps.LatLng(avgLat, avgLong);
// These are options that set initial zoom level, where the map is centered globally to start, and the type of map to show
var mapOptions = {
zoom: 15,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP,
panControl: true,
zoomControl: true,
streetViewControl: true,
mapTypeControl: true,
zoomControlOptions: {
style: google.maps.ZoomControlStyle.SMALL
}
}
// This makes the div with id "map_canvas" a google map
var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
// place a marker on the map for each monument
#foreach (var place in Model) {
<text>
var myLatLng = new google.maps.LatLng("#place.MonumentLocationLat", "#place.MonumentLocationLong");
var markerTitle = "#place.MonumentName"; // input the monuments name from the database
var URL = "http://cwbfm.org/Monument/MonumentDetails/" + "#place.MonumentID"; // create the url to link to the monuments detail page
// set the marker icon based on the Allegiance
switch ("#place.MonumentAllegiance") {
case "B":
var image = 'http://maps.google.com/mapfiles/kml/paddle/grn-circle.png';
break;
case "C":
var image = 'http://maps.google.com/mapfiles/kml/paddle/red-circle.png';
break;
case "U":
var image = 'http://maps.google.com/mapfiles/kml/paddle/blu-circle.png';
break;
default:
var image = 'http://maps.google.com/mapfiles/kml/paddle/ylw-circle.png';
}
var myMarker = new google.maps.Marker({
position: myLatLng,
icon: image,
title: markerTitle,
url: URL,
map: map
});
// on click, go to the monuments detail page
google.maps.event.addListener(myMarker, "click", function () {
window.location.href = this.url;
});
</text>
} return
}
This works fine for me.

The function does not run in an external file

I work on a wordpress page, using the google maps api.
my file functions:
function liceoucatolica_estilo() {
// API google maps
wp_enqueue_script('maps', 'https://maps.googleapis.com/maps/api/js?key=AIzaSyAJq5xO31rYRAqv5h6yUZTOaHwDX2zjNlo&callback=initMap', array(), false);
// Cargar scripts
wp_enqueue_script('main', get_template_directory_uri() . '/js/main.js',null,false);
}
add_action( 'wp_enqueue_scripts','liceoucatolica_estilo');
my file main.js (In which is the function of the map):
window.onload = function(){
function initMap(){
var campus = {lat: 4.634241, lng: -74.068513};
// Create a map object and specify the DOM element for display.
var map = new google.maps.Map(document.getElementById('mi_mapa'), {
center: campus,
scrollwheel: false,
zoom: 17
});
var marker = new google.maps.Marker({
position: campus,
map: map,
title: 'Liceo de la Universidad Católica'
});
}
};
If I copy the function in the header or footer if it works, but if I only leave it in Main.js does not work
There can be two causes:
1.- You're declaring the function when the window.onload event has already happened, so it keeps listening for something that will never happen.
2.- Google maps's script resolves before you get the chance to declare function initMap.
I'd try switching the order of the scripts, and removing window.onload at all. Just declare the initMap function in the global scope.

Google map on page loaded by AJAX - how to initialize?

I'm having a bit of trouble getting a google map to initialize on a page loaded by AJAX.
Live test page (in dev): http://dma.nz/practice/
The map is near the bottom of the page.
Currently it works - the map initializes when page it loaded directly or via AJAX, however it's giving me the following error in console:
Uncaught TypeError: Cannot read property 'firstChild' of null
In my footer I have:
<script src="/js/map.js"></script>
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBpC5JE9ZmQduEXiGbiNxZsws8OLMiC-Bw&callback=initMap" async defer></script>
<script src="/js/init.js"></script>
map.js contains:
function initMap() {
var mapOptions = {
zoom: 17,
center: new google.maps.LatLng(-36.85855, 174.754944),
disableDefaultUI: true,
styles: [
{"featureType":"administrative",
"elementType":"labels.text.fill",
"stylers":[{"gamma":"0.00"},{"weight":"0.01"},{"visibility":"off"}]
},
{"featureType":"landscape",
"elementType":"all",
"stylers":[{"color":"#ffffff"}]
},
{"featureType":"landscape.natural",
"elementType":"geometry",
"stylers":[{"visibility":"on"}]
},
{"featureType":"landscape.natural.terrain",
"elementType":"geometry.stroke",
"stylers":[{"visibility":"on"}]
},
{"featureType":"poi",
"elementType":"all",
"stylers":[{"visibility":"off"}]
},
{"featureType":"road",
"elementType":"all",
"stylers":[{"saturation":"-100"},{"lightness":"32"},{"visibility":"on"}]
},
{"featureType":"road",
"elementType":"labels.text",
"stylers":[{"visibility":"off"}]
},
{"featureType":"road.highway",
"elementType":"all",
"stylers":[{"visibility":"simplified"}]
},
{"featureType":"road.highway",
"elementType":"geometry",
"stylers":[{"visibility":"on"},{"lightness":"63"}]
},
{"featureType":"road.highway",
"elementType":"labels.text",
"stylers":[{"visibility":"off"}]
},
{"featureType":"road.highway",
"elementType":"labels.icon",
"stylers":[{"visibility":"off"}]
},
{"featureType":"road.arterial",
"elementType":"labels.icon",
"stylers":[{"visibility":"off"}]
},
{"featureType":"transit",
"elementType":"all",
"stylers":[{"visibility":"off"}]
},
{"featureType":"transit.station",
"elementType":"all",
"stylers":[{"visibility":"off"}]
},
{"featureType":"water",
"elementType":"all",
"stylers":[{"visibility":"on"},{"color":"#eeeeee"}]
}
]
};
// Get the HTML DOM element that will contain your map
var mapElement = document.getElementById('google-map');
// Create the Google Map using our element and options defined above
var map = new google.maps.Map(mapElement, mapOptions);
// Add marker
var marker = new google.maps.Marker({
icon: '/img/icons/map-pin.svg',
position: new google.maps.LatLng(-36.858749, 174.754944),
map: map,
title: 'DMA'
});
}
And then the related part of init.js
ajaxLoad = function(html) {
init();
// init google map
initMap();
// change html title
var HTMLtitle = $(".content > section:first-of-type").attr("data-title");
$(document).prop('title', HTMLtitle);
document.title = HTMLtitle;
// Used for popState event (back/forward browser buttons)
changedPage = true; }
The callback on my google maps API script call appears to properly initialize the map if page is loaded directly. If page is loaded by AJAX that doesn't work so I added the line initMap(); there to load the map after the new content is loaded via AJAX.
This is working, but throwing an error and I'm worried that this error is causing other script on my page not to work properly.
Any ideas on how to modify this so that the map initializes regardless of whether the page is loaded directly or by AJAX, and doesn't create any JS errors? Thanks!
I reproduced the error when I switched from the http://dma.nz/practice/ page to http://dma.nz/projects/ page.
As I can see you try to initialize map instance in line 82 of your map.js. The problem here is missing element with id "google-map". You don't have any DOM element with id "google-map" when you load the projects page. So you try to pass null in map constructor.
To avoid this error add a check that DOM element with id "google-map" exists.
// Get the HTML DOM element that will contain your map
var mapElement = document.getElementById('google-map');
if (mapElement) {
// Create the Google Map using our element and options defined above
var map = new google.maps.Map(mapElement, mapOptions);
// Add marker
var marker = new google.maps.Marker({
icon: '/img/icons/map-pin.svg',
position: new google.maps.LatLng(-36.858749, 174.754944),
map: map,
title: 'DMA'
});
}

How to iterate data to create markers for Google Maps (using express/jquery/ajax) currently getting SyntaxError

I initialize a google map here: (which is working fine, but I'll include for background)
this entire code comes inside of a .ejs file
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://maps.google.com/maps/api/js?sensor=true"></script>
<script type="text/javascript">
var map;
var loadMap = function() {
var myOptions = {
center: new google.maps.LatLng(39.952335, -75.163789),
zoom: 11,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map"), myOptions);
};
</script>
</head>
<body onload="loadMap()">
then when I try to iterate over my date to add my markers - I get an error (code works without this segment in it)
This is what I have so far:
Also note that because of express (I think it's express at least) I can use the <% code code code %> to write javascript inside of an html file.
<!-- data is an array of arrays [name, lat, lon, description, creator] -->
<% for (var i = 0; i < array[0].length; i++) {
var info = new google.maps.InfoWindow();
info.setContent( %><b><% "Name: "+array[0][i] %></b><% +". Description: "+array[3][i] %><i><% +". Creator: "+array[4][i] %></i><% );
var newCoords = new google.maps.LatLng(array[1][i], array[2][i]);
var marker = new google.maps.Marker({
position: newCoords,
map: map,
title: array[0][i],
if (message == array[0][i]) { // if the creator is currently signed in (his additions should be yellow on map)
icon: 'http://maps.google.com/mapfiles/ms/icons/yellow-dot.png'
}
});
google.maps.event.addListener(marker, 'click', (function(info, marker) {
return function() {
info.open(map, marker);};
})(info, marker))
}; %>
I'm getting a Unexpected Token : ';'
In case there's any confusion there I'm trying to add new markers for the data in my array, have it be clickable and display text in there that's partly bolded, partly italicized.
also, im using closure at the end there to make sure each event listener is unique (copied from here: Javascript: Looping through an array to create listeners, issue with call by reference and value?)
Hope eyes more experienced than I can spot my error or suggest a better alternative... I've tried taking out every single non-essential semi-colon but it accomplished nothing..
Syntax error, marker should be:
var marker = new google.maps.Marker({
position: newCoords,
map: map,
title: array[0][i],
icon : (message == array[0][i])? //use ternary
'http://maps.google.com/mapfiles/ms/icons/yellow-dot.png'
: undefined
});
You can't have if statements in an object literal but you can assign icon with a ternary expression. If it's a problem that icon is undefined you can do it outside the object literal:
var info = new google.maps.InfoWindow(),
markerDetails;
//...code
markerDetails = {
position: newCoords,
map: map,
title: array[0][i]
};
if (message == array[0][i]) {
markerDetails.icon = 'http://maps.google.com/mapfiles/ms/icons/yellow-dot.png';
}
var marker = new google.maps.Marker(markerDetails);

Retrieve position of a google maps v3 marker to Qt in a desktop app with QtWebKit

I'm building a Qt app with Python where you can point and click at a (google) map and get the coordinates of the location. The map is shown through a QWebView loading a simple HTML page and the user can create markers by clicking. Screenshot of the widget after clicking on the map.
However, I'm having trouble to retrieve the just-clicked location coordinates back to Qt (so that I can use them as variables -- and, for example, show them in the QLineEdits on the topleft corner above, as current location of the marker).
This is the relevant part of the HTML file:
<script type="text/javascript">
var map;
function initialize() {
var local = new google.maps.LatLng(-23.4,-40.3);
var myOptions = {
zoom: 5,
center: local,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
google.maps.event.addListener(map, 'rightclick', function(event) {
placeMarker(event.latLng);
});
}
function placeMarker(location) {
var clickedLocation = new google.maps.LatLng(location);
var marker = new google.maps.Marker({
position: location,
map: map
});
map.setCenter(location);
}
function dummyTxt() {
return 'This works.';
}
</script>
I've been trying with evaluateJavaScript, but was not able to retrieve the coordinates. I tried to created a function to access the position with marker.getPosition(), but with no luck. The dummy below works though..
newplace = QWebView.page().mainFrame().evaluateJavaScript(QString('dummyTxt()'))
>>> print newplace.toString()
This works.
Any suggestions on how to get the coordinates back to Qt?
Edit:
Here is the code that worked for me:
def update_geo(self):
# Capture coordinates of the last marker on the map.
mark = self.map.page().mainFrame().evaluateJavaScript('document.getElementById("markerlocation").value').toString()
# Convert string to list of floats, stripping parentheses.
marker = str(mark).strip('()').split(', ')
decimals = [float(c) for c in marker]
Full source in https://github.com/nelas/veliger/blob/master/veliger.py#L2374
I found a work around to make it work but I'm not pretty sure that it will be the right approach. Anyway, this is what I did:
Create a hidden input in the body section of your html document to save the position data of the marker:
<body>
(...)
<input id="locationData" type="hidden">
(...)
</body>
In the javascript code, save the position of the marker in the hidden input every time it's created:
function placeMarker(location) {
(...)
document.getElementById("locationData").value = marker.position;
(...)
}
In your Qt code, read the value of the hidden input with the instruction:
webView->page()->mainFrame()->findFirstElement("#locationData").evaluateJavaScript("this.value").toString();
I hope it helps!
Source: http://opendocs.net/qt/4.6/webkit-formextractor.html

Categories

Resources