So am I am using gmaps.js and the gmaps.js along with marker clusterer. In my case I may have multiple markers with the exact same location, but in reality represent different data. To overcome this I am trying to implement the solution found here on SO - in particular the solution by Nathan Colgate.
The idea is when max zoom has reached on a cluster it will execute the multiChoice function. I have this part working. What I cannot get to work is showing an infoWindow with that function.
My goal is to show an infoWindow on this cluster click to display information about each marker (particularly each marker's infoWindow content (this will have additional details specific to it).
JS :
//create the map
var map = new GMaps({
el: '#map_canvas_main',
lat: response.results[0].lat,
lng: response.results[0].lng,
zoom: 5,
maxZoom: 15,
panControl: false,
markerClusterer: function(map) {
markerCluster = new MarkerClusterer(map, [], {
title: 'Location Cluster',
maxZoom: 15
});
// onClick OVERRIDE
markerCluster.onClick = function(clickedClusterIcon) {
return multiChoice(clickedClusterIcon.cluster_);
}
return markerCluster;
}
});
//loop through array
for(var i = 0; i < response.results.length; i++)
{
//create marker image
var markerLoc = {
url: '/custom/plugins/gmaps/images/marker-red.png',
size: new google.maps.Size(24, 30), //size
origin: new google.maps.Point(0, 0), //origin point
anchor: google.maps.Point(9, 30) // offset point
};
//add marker
map.addMarker({
lat: response.results[i].lat,
lng: response.results[i].lng,
icon: markerLoc,
title: response.results[i].ip_address,
infoWindow: {
content: '<p>'+response.results[i].ip_address+'</p>'
//add more details later
}
});
}
//cluster function to do stuff
function multiChoice(clickedCluster)
{
//clusters markers
var markers = clickedCluster.getMarkers();
//console check
console.log(clickedCluster);
console.log(markers);
if (markers.length > 1)
{
//content of info window
var infowindow = new google.maps.InfoWindow({
content: ''+
'<p>'+markers.length+' = length</p>'+
'<p>testing blah blah</p>'
});
//show the window
//infowindow.open(??????????);
return false;
}
return true;
};
Finally figured this out playing around with it some more... it makes sense now, but didn't before. Here is the new 'display' function to be replaced by the one in the OP. Of course, there are a few other change needed yet... showing all clustered marker data in the new info window for example, but this is the gist of getting the window to work.
//cluster function to do stuff
function multiChoice(clickedCluster)
{
//clusters markers
var markers = clickedCluster.getMarkers();
if (markers.length > 1)
{
//create the info window
var infoWindow = new google.maps.InfoWindow({
content: ''+
'<p>'+markers.length+' = length</p>'+
'<p>testing blah blah</p>',
position: clickedCluster.center_
});
//display the infowindow
infoWindow.open(clickedCluster.map_);
return false;
}
return true;
};
Related
Hi I am using Google maps alongside algolia where I have an index 'locations' with 'lat' and 'lng'.
I am getting user location and watching position, I am also displaying markers from database based on lng and lat however I want to add a bit to it:
So I have followed that link:
https://www.algolia.com/doc/guides/geo-search/geo-search-overview/
And came up with:
#extends('master') #section('title', 'Live Oldham')
#section('extrafiles')
<script type="text/javascript" src="https://maps.google.com/maps/api/js?v=3&key=AIzaSyAirYgs4Xnt9QabG9v56jsIcCNfNZazq50&language=en"></script>
<script type="text/javascript" src="{!! asset('js/homesearch.js') !!}"></script>
#endsection
#section('content')
<div id="map_canvas" style="height:600px;"></div>
#endsection
and js:
$(document).ready(function() {
var map;
function initializeMap(){
map = new google.maps.Map(document.getElementById('map_canvas'), {
zoom: 19,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
}
function locError(error) {
// the current position could not be located
alert("The current position could not be found!");
}
function setCurrentPosition(position) {
currentPositionMarker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(
position.coords.latitude,
position.coords.longitude
),
title: "Current Position"
});
map.panTo(new google.maps.LatLng(
position.coords.latitude,
position.coords.longitude
));
}
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
console.log(latitude);
console.log(longitude);
function displayAndWatch(position) {
// set current position
setCurrentPosition(position);
// watch position
watchCurrentPosition(position);
console.log(position);
}
function watchCurrentPosition(position) {
var positionTimer = navigator.geolocation.watchPosition(
function (position) {
setMarkerPosition(
currentPositionMarker,
position,
)
});
}
function setMarkerPosition(marker, position) {
marker.setPosition(
new google.maps.LatLng(
position.coords.latitude,
position.coords.longitude)
);
}
function initLocationProcedure() {
initializeMap();
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(displayAndWatch, locError);
}else{
alert("Your browser does not support the Geolocation API");
}
}
$(document).ready(function() {
initLocationProcedure();
});
var APPLICATION_ID = '75RQSC1OHE';
var SEARCH_ONLY_API_KEY = 'f2f1e9bba4d7390fc61523a04685cf12';
var INDEX_NAME = 'locations';
var PARAMS = { hitsPerPage: 100 };
// Client + Helper initialization
var algolia = algoliasearch(APPLICATION_ID, SEARCH_ONLY_API_KEY);
var algoliaHelper = algoliasearchHelper(algolia, INDEX_NAME, PARAMS);
// Map initialization
var markers = [];
//alert("heelo");
var fitMapToMarkersAutomatically = true;
algoliaHelper.on('result', function(content) {
renderHits(content);
var i;
// Add the markers to the map
for (i = 0; i < content.hits.length; ++i) {
var hit = content.hits[i];
console.log(hit)
var marker = new google.maps.Marker({
position: {lat: hit.longitude, lng: hit.latitude},
map: map,
title: hit.slug
});
markers.push(marker);
}
// Automatically fit the map zoom and position to see the markers
if (fitMapToMarkersAutomatically) {
var mapBounds = new google.maps.LatLngBounds();
for (i = 0; i < markers.length; i++) {
mapBounds.extend(markers[i].getPosition());
}
map.fitBounds(mapBounds);
}
});
function renderHits(content) {
$('#container').html(JSON.stringify(content, null, 2));
}
algoliaHelper.setQueryParameter('aroundRadius', 5000).search(); // 5km Radius
});
However there are few problems with this that I don't know how to tackle:
When user is moving, it doesn't center the map on the marker.
At this moment marker jumps between location when user moves, I would like for the marker to dynamically move on the map when user moves.
I want to use algolia to dynamically set markers, so I want to show markers with 5km radius from user location, and dynamically add or remove markers that are outside it.
I can't help you much with those questions since it's mostly about how to use GMap JS lib and I'm not experienced with it. However, something else catched my eyes:
var marker = new google.maps.Marker({
position: {lat: hit.longitude, lng: hit.latitude},
map: map,
title: hit.slug
});
You should put your coordinates in the _geoloc field in order to be able to use the geo-search features. It looks like this:
_geoloc: {
lat: 40.639751,
lng: -73.778925
}
I'm working on a project where I'd like to show the choosen event on google maps with some additional information. (ex. all gas stations radius 2km).
Google doesn't allow a nearby search with multiple types.
Restricts the results to places matching the specified type. Only one type may be specified (if more than one type is provided, all types following the first entry are ignored).
So for now I'd like to change the type (ex. gas_station or store) if I click to a custom button I added.
(used the google document example)
Screenshot: http://imgur.com/qYwLuw4
Question:
Which is the best way to change the type and refresh the map with the new information?
I'd like to present you our solution.
We wrote a clear() and a showType() function, which will erase all markers and let the right ones appear on click. By the way we give the button a state class called "selected" for CSS styling.
We didn't find a solution to show both (washstation AND fuelstation).
<script type="text/javascript">
var map;
var infowindow;
var service;
var eventLocation = {lat: <?= $arrCoordinates['latitude']?>, lng: <?= $arrCoordinates['longitude']?>};
var markers = [];
var wash = document.getElementById('wash'); //washbutton
var fuel = document.getElementById('fuel'); //fuelstation button
function initMap() {
map = new google.maps.Map(document.getElementById('eventmap'), {
center: eventLocation,
zoom: 13,
});
infowindow = new google.maps.InfoWindow();
service = new google.maps.places.PlacesService(map);
showType('gas_station');
fuel.classList.add("selected");
typeControl(map);
}
// Type control function
function typeControl ( map ) {
google.maps.event.addDomListener(fuel, 'click', function() {
wash.classList.remove("selected");
fuel.classList.remove("selected");
clear()
showType('gas_station')
this.classList.add("selected");
});
google.maps.event.addDomListener(wash, 'click', function() {
wash.classList.remove("selected");
fuel.classList.remove("selected");
clear()
showType('car_wash')
this.classList.add("selected");
});
}
function showType(type) {
service.nearbySearch({
location: eventLocation,
radius: 10000,
type: [type]
}, callback);
}
function clear() {
markers.forEach(marker => marker.setMap(null));
markers = [];
}
function callback(results, status) {
clear()
if (status === google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
createMarker(results[i]);
}
createTuningEventMarker();
}
}
function createTuningEventMarker(place) {
var eventLocation = {lat: <?= $arrCoordinates['latitude']?>, lng: <?= $arrCoordinates['longitude']?>};
var eventIcon = {
url: 'https://www.foo.lol/img/icons/pin.svg',
// This marker is 20 pixels wide by 32 pixels high.
scaledSize: new google.maps.Size(60, 60),
// The origin for this image is (0, 0).
origin: new google.maps.Point(0,0),
// The anchor for this image is the base of the flagpole at (0, 32).
anchor: new google.maps.Point(30,60)
};
var marker = new google.maps.Marker({
map: map,
icon:eventIcon,
position: eventLocation
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent('<?= $event['name']?>');
infowindow.open(map, this);
});
}
function createMarker(place) {
var placeLoc = place.geometry.location;
var marker = new google.maps.Marker({
map: map,
position: place.geometry.location
});
markers.push(marker);
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(place.name + "<br>Adress: " + place.vicinity);
infowindow.open(map, this);
});
}
</script>
Well I'm having this problem, load the map once and everything works perfect. The second time or once update the map does not load ok, but not centered load when navigating on you can see the marks that are made but is deformed or simply lost.
I have tried several ways to solve this problem, first and most common I found was to use google.maps.event.trigger(map 'resize') but it did not work then and logic, try that whenever loading map is executed, create a new map, with the same data and focused but neither worked for me. It may be also the way I use the map. I am using the plugin of the camera in my application, the user takes a photo and this should detect where I draw the picture and display the map. Each time the view is opened, the plug of the camera, in the process of taking and show the picture is where I call the appropriate functions to load the map and this has me a bit tricky immediately loaded I have a good time locked in this problem, I found solutions serve me but only for the browser, the device does not work. I am using ionic framework and plugins cordova.
Controller :
.controller("CamaraCtrl", function($scope,$rootScope, Camera,$cordovaGeolocation,$state,$location,$ionicSideMenuDelegate) {
var posOptions = {timeout: 10000, enableHighAccuracy: false};
$cordovaGeolocation
.getCurrentPosition(posOptions)
.then(function (position) {
var latitud_actual = position.coords.latitude
var longitud_actual = position.coords.longitude
$scope.latitud = latitud_actual;
$scope.longitud = longitud_actual;
//$scope.map = new google.maps.Map(document.getElementById("mapa_ubicacion"), mapOptions);
}, function(err) {
// error
});
function initialize() {
var mapOptions = {
center: new google.maps.LatLng($scope.latitud, $scope.longitud),
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scrollwheel: false
};
var map = new google.maps.Map(document.getElementById("map"),
mapOptions);
$scope.setMarker(map, new google.maps.LatLng($scope.latitud, $scope.longitud), 'Yo', '');
$scope.map = map;
}
$scope.setMarker = function(map, position, title, content) {
var marker;
var markerOptions = {
position: position,
map: map,
title: title
};
marker = new google.maps.Marker(markerOptions);
google.maps.event.addListener(marker, 'click', function () {
// close window if not undefined
if (infoWindow !== void 0) {
infoWindow.close();
}
// create new window
var infoWindowOptions = {
content: content
};
infoWindow = new google.maps.InfoWindow(infoWindowOptions);
infoWindow.open(map, marker);
});
}
$scope.mostrar_form = false;
$scope.mostrar_boton_view = false;
$scope.getPhoto = function() {
Camera.getPicture().then(function(imageURI) {
console.log(imageURI);
$scope.lastPhoto = imageURI;
$scope.mostrar_form = true;
$scope.mostrar_boton_view = false;
google.maps.event.addDomListener(window, 'load', initialize);
initialize();
}, function() {
$scope.mostrar_boton_view = true;
}, {
quality: 75,
targetWidth: 320,
targetHeight: 320,
saveToPhotoAlbum: false
});
};
$scope.getPhoto();
})
The only solution I found was to create a function that executes the map again. It should not be as optimal but at least it solved my problem.
$scope.centrar = function(){
var mapOptions = {
center: new google.maps.LatLng($scope.latitud, $scope.longitud),
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scrollwheel: false
};
var map = new google.maps.Map(document.getElementById("map"),
mapOptions);
$scope.setMarker(map, new google.maps.LatLng($scope.latitud, $scope.longitud), 'Yo', '');
$scope.map = map;
}
i've been trying to implement a new feature on one of my Google maps (MarkerClusterer), but i am not quite there yet.
It is running OK, but not smoothly and it would be great if you would look through the code and give me any tips/advice.
I am running a test here: (Link removed)
Please let me know if you need anymore info.
Any help is appreciated :)
You seem to be doing an awful lot within the loop that creates your markers. For instance you should only need to do var markerCluster = new MarkerClusterer(...) after that loop, not within every iteration of it!
Ok, here I've simply moved that line out of your loop.
for (var i = 0; i < mapLocationsdata.businesses.length; i++) {
var businesses = mapLocationsdata.businesses[i];
var pos = new google.maps.LatLng(businesses.lat, businesses.lng);
var marker = new google.maps.Marker({
position: pos,
map: map,
title: businesses.company,
icon: placemarker[businesses.placemaker],
clickable: true,
draggable:false,
animation: google.maps.Animation.DROP
});
markers.push(marker);
(function(i, marker){
var infobox = new google.maps.InfoWindow({
content:
//This creates the content inside the popup info window when clicked
'<div class="info"><div class="info1"><h4>'
+businesses.company+
'</h4></div><div class="infotel">'
+businesses.itemAdresse+businesses.itemPostBy+businesses.itemTlf+businesses.itemEmail+businesses.itemWeb+
'</div><div class="clearfix"></div></div>',
});
//This function opens the info box and toggles the icon bounce
marker.addListener('click', function() {
infobox.open(map, marker);
toggleBounce(map, marker);
});
//This function stops the bouncs on the icon once the infowindow is closed
infobox.addListener('closeclick', function() {
toggleBounce(map, marker);
});
// POSSIBLY THIS FUNCTION COULD BE MOVED OUT OF THE LOOP TOO
//This makes them bounce when clicked
function toggleBounce() {
if (marker.getAnimation() != null) {
marker.setAnimation(null);
} else {
marker.setAnimation(google.maps.Animation.BOUNCE);
}
}
})
//The marker loop generates all of the markers
// NO IDEA WHAT THE POINT OF THIS LINE IS:
(i, marker);
//Associate the styled map with the MapTypeId and set it to display.
map.mapTypes.set('map_style', styledMap);
map.setMapTypeId('map_style');
}
var markerCluster = new MarkerClusterer(map, markers, {
gridSize: 60,
minimumClusterSize: 2,
calculator: function(markers, numStyles) {
if (markers.length >= 50) return {text: markers.length, index: 3}; // red
if (markers.length >= 5) return {text: markers.length, index: 2}; // yellow
return {text: markers.length, index: 0}; } // blue
});
I'm currently working on an application where various markers are placed with infowindows on a Google Map based on a user's posts. I've also included geocoding so that the user can change their location and view markers/posts in any area.
What I'd like to do is for the user to search through the text info in the infowindows via a form and the map then responds by showing the markers that contain that text window. I've searched through the API and I don't see this ability mentioned, although it seems like it should be achievable.
Any insight or information on how to accomplish this would be much appreciated.
Here's the current code within the application:
function mainGeo()
{
if (navigator.geolocation)
{
navigator.geolocation.getCurrentPosition( mainMap, error, {maximumAge: 30000, timeout: 10000, enableHighAccuracy: true} );
}
else
{
alert("Sorry, but it looks like your browser does not support geolocation.");
}
}
var stories = {{storyJson|safe}};
var geocoder;
var map;
function loadMarkers(stories){
for (i=0;i<stories.length;i++) {
var story = stories[i];
(function(story) {
var pinColor = "69f2ff";
var pinImage = new google.maps.MarkerImage("http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=S|" + pinColor,
new google.maps.Size(21, 34),
new google.maps.Point(0,0),
new google.maps.Point(10, 34));
var point = new google.maps.LatLng(story.latitude, story.longitude);
var marker = new google.maps.Marker({position: point, map: map, icon: pinImage});
var infowindow = new google.maps.InfoWindow({
content: '<div >'+
'<div >'+
'</div>'+
'<h2 class="firstHeading">'+story.headline+'</h2>'+
'<div>'+
'<p>'+story.author+'</p>'+
'<p>'+story.city+'</p>'+
'<p>'+story.topic+'</p>'+
'<p>'+story.date+'</p>'+
'<p>'+story.copy+'</p>'+
'<p><a href='+story.url+'>Click to read story</a></p>'+
'</div>'+
'</div>'
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(map,this);
});
})(story);
}
}
function mainMap(position)
{
geocoder = new google.maps.Geocoder();
// Define the coordinates as a Google Maps LatLng Object
var coords = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
// Prepare the map options
var mapOptions =
{
zoom: 15,
center: coords,
mapTypeControl: false,
navigationControlOptions: {style: google.maps.NavigationControlStyle.SMALL},
mapTypeId: google.maps.MapTypeId.ROADMAP
};
// Create the map, and place it in the map_canvas div
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
// Place the initial marker
var marker = new google.maps.Marker({
position: coords,
map: map,
title: "Your current location!"
});
loadMarkers(stories);
}
function codeAddress() {
var address = document.getElementById("address").value;
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location
});
} else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
function error() {
alert("You have refused to display your location. You will not be able to submit stories.");
}
mainGeo();
Create three empty arrays (e.g., markers, infowindows, and matches)
As you instantiate the marker, reference the marker via an index in the markers array (e.g., markers[i] = marker)
As you instantiate the infowindow, reference it's content via an index in the infowindows array (e.g., infowindows[i] = htmltext [or whatever variable name you store your content in)
Search for the string in the infowindows array, store the indexes of the items that contain the string in the matches array, and then use a for loop with the matches array to add the markers from the markers array (based on the index values of the matches array).