The google map i am using does not get centered about the mean point i have calculated.
The code for the initialization is given. The map appears to be zoomed out a lot and its center far off from the center i have calculated. The mean appears in the extreme top left of the map. What is the problem here?
I am displaying the map in Bootstrap modal.
function initializeMap()
{
var xMean = 0.0;
var yMean = 0.0;
for(var i=0;i<points.length;i++)
{
xMean += parseFloat(points[i][0]);
yMean += parseFloat(points[i][1]);
}
xMean /= parseFloat(points.length);
yMean /= parseFloat(points.length);
var myMean = new google.maps.LatLng(xMean, yMean);
var mapOptions = {
zoom:17,
center:myMean
}
map = new google.maps.Map(document.getElementById('map'), mapOptions);
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i<points.length;i++) {
path.push(new google.maps.LatLng(points[i][0],points[i][1]));
bounds.extend(path[i]);
};
map.fitBounds(bounds);
//Displaying the markers
var marker;
for (var i = 0; i < path.length; i++) {
marker = new google.maps.Marker({
position: path[i],
map: map
});
}
//Displaying the path
for (var i = 0; i<path.length-1; i++) {
var start = path[i];
var end = path[i+1];
requestDirections(start,end);
}
}
by using:
map.fitBounds(bounds);
map.setCenter(bounds.getCenter());
you seem to overwrite myMean coordinates
Related
I have 2 tables one with markers another with marker icons. The icons are stored in the database as blob, where markers and icons are mapped by the ID's. The issue i am having is mapping the icons by id and markers type to the correct.
for example:
I'm trying to implement something like the following https://developers.google.com/maps/documentation/javascript/custom-markers
what i have done so far is the following
converting the overlay results(which i get via ajax and push to overlayRes object)
var binary = new Array();
for (i = 0; i < overlayRes.length; i++) {
var iconData = overlayRes[i].OverlayData.replace(/[^A-Fa-f0-9]/g, "");
for(var i=0; i< iconData.length / 2; i++){
var h = iconData.substr(i * 2, 2);
binary[i] = parseInt(h, 16);
}
}
byteArray = new Uint8Array(binary);
img = window.URL.createObjectURL(new Blob([byteArray], { type: 'application/octet-stream' }));
var icons = {
K: {
icon: img
},
L: {
icon: img
},
};
//markers
for (var i = 0; i < features.length; i++) {
var marker = new google.maps.Marker({
position: features[i].position,
icon: icons[features[i].type].icon, // need to get different markers per marker type
map: map
});
TIA
I first read a sets of coordinates in my local drive, then put them in
the xcoord and y coord to be start,waypts,destination which will be plotted on Google Map.
But i discovered that, once the coodinates exceeding a certain number,the route is not plotted anymore,but a road map without and route. changing travelmode also changing the number of effective waypoints. What can be done when i have >100 coordinates to be plotted? Also, i would like to change all the marker into default one but not the green one with letters on it.(After 26 points the marker become normal again.) Thank you very much.
I was first using the example provided in a question about 8 waypoints, which is here:
Plotting more than 8 waypoints in Google Maps v3
My code are as follow:
xcoord = [];
ycoord = [];
stops = [] ;
document.getElementById('file').onchange = function(){
alert('4');
var file = this.files[0];
var reader = new FileReader();
reader.onload = function(progressEvent){
var lines = this.result.split('\n');
for(var line = 0; line < lines.length; line++){
//alert(lines[line]);
var split = [];
split = lines[line].split(',');
window.xcoord.push(split[0]);
window.ycoord.push(split[1]);
}
alert('finish');
}
reader.readAsText(file);
};
jQuery(function() {
document.getElementById('button').onclick = function initMap(){
for(i = 0;i<xcoord.length;i++){
window.stops.push({"Geometry":{"Latitude":xcoord[i],"Longitude":ycoord[i]}});}
var map = new window.google.maps.Map(document.getElementById("map"));
// new up complex objects before passing them around
var directionsDisplay = new window.google.maps.DirectionsRenderer();
var directionsService = new window.google.maps.DirectionsService();
Tour_startUp(stops);
window.tour.loadMap(map, directionsDisplay);
window.tour.fitBounds(map);
if (stops.length > 1)
window.tour.calcRoute(directionsService, directionsDisplay);}});
function Tour_startUp(stops) {
if (!window.tour) window.tour = {
updateStops: function (newStops) {
stops = newStops;
},
// map: google map object
// directionsDisplay: google directionsDisplay object (comes in empty)
loadMap: function (map, directionsDisplay) {
var myOptions = {
zoom: 13,
center: new window.google.maps.LatLng(22.2830, 114.200),
mapTypeId: window.google.maps.MapTypeId.ROADMAP
};
map.setOptions(myOptions);
directionsDisplay.setMap(map);
},
fitBounds: function (map) {
var bounds = new window.google.maps.LatLngBounds();
// extend bounds for each record
jQuery.each(stops, function (key, val) {
var myLatlng = new window.google.maps.LatLng(val.Geometry.Latitude, val.Geometry.Longitude);
bounds.extend(myLatlng);
});
map.fitBounds(bounds);
},
calcRoute: function (directionsService, directionsDisplay) {
var batches = [];
var itemsPerBatch = 10; // google API max = 10 - 1 start, 1 stop, and 8 waypoints
var itemsCounter = 0;
var wayptsExist = stops.length > 0;
while (wayptsExist) {
var subBatch = [];
var subitemsCounter = 0;
for (var j = itemsCounter; j < stops.length; j++) {
subitemsCounter++;
subBatch.push({
location: new window.google.maps.LatLng(stops[j].Geometry.Latitude, stops[j].Geometry.Longitude),
stopover: true
});
if (subitemsCounter == itemsPerBatch)
break;
}
itemsCounter += subitemsCounter;
batches.push(subBatch);
wayptsExist = itemsCounter < stops.length;
// If it runs again there are still points. Minus 1 before continuing to
// start up with end of previous tour leg
itemsCounter--;
}
// now we should have a 2 dimensional array with a list of a list of waypoints
var combinedResults;
var unsortedResults = [{}]; // to hold the counter and the results themselves as they come back, to later sort
var directionsResultsReturned = 0;
for (var k = 0; k < batches.length; k++) {
var lastIndex = batches[k].length - 1;
var start = batches[k][0].location;
var end = batches[k][lastIndex].location;
// trim first and last entry from array
var waypts = [];
waypts = batches[k];
waypts.splice(0, 1);
waypts.splice(waypts.length - 1, 1);
var request = {
origin: start,
destination: end,
waypoints: waypts,
optimizeWaypoints: true,
travelMode: window.google.maps.TravelMode.WALKING
};
(function (kk) {
directionsService.route(request, function (result, status) {
if (status == window.google.maps.DirectionsStatus.OK) {
var unsortedResult = { order: kk, result: result };
unsortedResults.push(unsortedResult);
directionsResultsReturned++;
if (directionsResultsReturned == batches.length) // we've received all the results. put to map
{
// sort the returned values into their correct order
unsortedResults.sort(function (a, b) { return parseFloat(a.order) - parseFloat(b.order); });
var count = 0;
for (var key in unsortedResults) {
if (unsortedResults[key].result != null) {
if (unsortedResults.hasOwnProperty(key)) {
if (count == 0) // first results. new up the combinedResults object
combinedResults = unsortedResults[key].result;
else {
// only building up legs, overview_path, and bounds in my consolidated object. This is not a complete
// directionResults object, but enough to draw a path on the map, which is all I need
combinedResults.routes[0].legs = combinedResults.routes[0].legs.concat(unsortedResults[key].result.routes[0].legs);
combinedResults.routes[0].overview_path = combinedResults.routes[0].overview_path.concat(unsortedResults[key].result.routes[0].overview_path);
combinedResults.routes[0].bounds = combinedResults.routes[0].bounds.extend(unsortedResults[key].result.routes[0].bounds.getNorthEast());
combinedResults.routes[0].bounds = combinedResults.routes[0].bounds.extend(unsortedResults[key].result.routes[0].bounds.getSouthWest());
}
count++;
}
}
}
directionsDisplay.setDirections(combinedResults);
var legs = combinedResults.routes[0].legs;
// alert(legs.length);
for (var i=0; i < legs.length;i++){
var markerletter = "A".charCodeAt(0);
markerletter += i;
markerletter = String.fromCharCode(markerletter);
createMarker(directionsDisplay.getMap(),legs[i].start_location,"marker"+i,"some text for marker "+i+"<br>"+legs[i].start_address,markerletter);
}
var i=legs.length;
var markerletter = "A".charCodeAt(0);
markerletter += i;
markerletter = String.fromCharCode(markerletter);
createMarker(directionsDisplay.getMap(),legs[legs.length-1].end_location,"marker"+i,"some text for the "+i+"marker<br>"+legs[legs.length-1].end_address,markerletter);
}
}
});
})(k);
}
}
};
}
The Snap to road thing is done via loading coordinates using PHP and then
using the google api. the code is as follow(for less than 200 points):
<!DOCTYPE html>
<?php
$stringJoin = "";
$stringJoin2 = "";
$index = 0;
$handle = fopen($_GET['fileName'], "r");
if ($handle) {
while (($line = fgets($handle)) !== false) {
$index++;
if ($index ==99 ){
$stringJoin2 .= trim($line)."|";
}
if ($index >= 100) {
$stringJoin2 .= trim($line)."|";
if($index == 200){
break;
}
continue;
}
$stringJoin .= trim($line)."|";
}
fclose($handle); }
echo $index;
echo "<br>";
$stringJoin = substr($stringJoin, 0, -1);
$stringJoin2 = substr($stringJoin2, 0, -1);
echo $stringJoin;
echo "<br>";
echo $stringJoin2; ?>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Roads API Demo</title>
<style>
html, body, #map {
height: 100%;
margin: 0px;
padding: 0px
}
#panel {
position: absolute;
top: 5px;
left: 50%;
margin-left: -180px;
z-index: 5;
background-color: #fff;
padding: 5px;
border: 1px solid #999;
}
#bar {
width: 240px;
background-color: rgba(255, 255, 255, 0.75);
margin: 8px;
padding: 4px;
border-radius: 4px;
}
#autoc {
width: 100%;
box-sizing: border-box;
}
</style>
</head>
<body>
<input type="button" name="button" id="button">
<input type="file" name="file" id="file">
<div id="map"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script
src="https://maps.googleapis.com/maps/api/js?libraries=drawing,places"></script>
<script>
var apiKey = 'AIzaSyCk5PjtR_spPKrVowRS3A7I3IE4gX6Ctec';
var map;
var drawingManager;
var placeIdArray = [];
var placeIdArray2 = [];
var polylines = [];
var polylines2 = [];
var snappedCoordinates = [];
var snappedCoordinates2 = [];
document.getElementById('button').onclick = function initialize() {
alert("Start");
var mapOptions = {
zoom: 13,
center: {lat: 22.3030, lng: 114.200} };
map = new google.maps.Map(document.getElementById('map'), mapOptions);
runSnapToRoad();
runSnapToRoad2();}
// Snap a user-created polyline to roads and draw the snapped path
function runSnapToRoad() {
$.get('https://roads.googleapis.com/v1/snapToRoads', {
interpolate: true,
key: apiKey,
path: <?php echo '"'.$stringJoin.'"';?>}, function(data) {
processSnapToRoadResponse(data);
drawSnappedPolyline();
//getAndDrawSpeedLimits(); });}
// Store snapped polyline returned by the snap-to-road method.
function processSnapToRoadResponse(data) {
snappedCoordinates = [];
placeIdArray = [];
for (var i = 0; i < data.snappedPoints.length; i++) {
var latlng = new google.maps.LatLng(
data.snappedPoints[i].location.latitude,
data.snappedPoints[i].location.longitude);
snappedCoordinates.push(latlng);
placeIdArray.push(data.snappedPoints[i].placeId); }}
// Draws the snapped polyline (after processing snap-to-road response).
function drawSnappedPolyline() {
var snappedPolyline = new google.maps.Polyline({
path: snappedCoordinates,
strokeColor: 'black',
strokeWeight: 3 });
snappedPolyline.setMap(map);
polylines.push(snappedPolyline);}
</script>
<div id="bar">
<p class="auto"><input type="text" id="autoc"/></p>
<p><a id="clear" href="#">Click here</a> to clear map.</p>
</div>
I have this controller for AngularJS Framework.
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $http) {
var locations =[]; var map; var markers = [];
$scope.mappa = function(){
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 37.507033, lng: 15.080257},
zoom: 8
});
}
$scope.insert = function(){
$http.get("http://localhost:8080/SistemiDistribuiti/rest/Point/Trovati")
.success(function(data)
{locations = data;});
var marker, i;
for (i = 0; i < locations.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][0], locations[i][1]),
map: map
});
markers.push(marker);
}
for (i = 0; i<markers.length; i++){
markers[i].setVisible(true);
}
};
In html file, i have a button that calls the insert function.
But if I run this code, the button works at the second time only. Instead if the http request is out of the function, the button works immediatly. Why?
$http.get("http://localhost:8080/SistemiDistribuiti/rest/Point/Trovati")
.success(function(data)
{locations = data;});
$scope.insert = function(){
var marker, i;
for (i = 0; i < locations.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][0], locations[i][1]),
map: map
});
markers.push(marker);
}
for (i = 0; i<markers.length; i++){
markers[i].setVisible(true); }
};
It's asynchronous method. Move the code insert into callback success.
$http.get("http://localhost:8080/SistemiDistribuiti/rest/Point/Trovati")
.success(function(data) {
var marker, i;
for (i = 0; i < data.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(data[i][0], data[i][1]),
map: map
});
markers.push(marker);
}
for (i = 0; i<markers.length; i++){
markers[i].setVisible(true); }
}
});
But if I run this code, the button works at the second time only.
It works at the first time, it's just AJAX request is asynchronous, so the location variable is not populated yet by the time your are trying to use it. When you click next time, it turns out that data has already loaded and location is set and "cached".
You need to do your stuff in callback function:
$scope.insert = function () {
$http.get("http://localhost:8080/SistemiDistribuiti/rest/Point/Trovati").success(function (data) {
var marker, i, locations = data;
for (i = 0; i < locations.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][0], locations[i][1]),
map: map
});
markers.push(marker);
}
for (i = 0; i < markers.length; i++) {
markers[i].setVisible(true);
}
});
};
And finally, when you make it work, consider moving your request logic into reusable service, making requests in controller is not the best design:
$scope.insert = function () {
locations.get().then(function(data) {
var marker, i, locations = data;
// ...
});
};
I want to get NE and SW corners of a set of markers on a google map. Here I iterate over each marker. Does google or javascript provide a function that gets this with less iteration?
function fnSetBounds(){
var lowLat = 90;
var highLat = -90;
var lowLng = 180;
var highLng = -180;
for (var i = 0; i < myMarkers.length; i++) {
var myLat = myMarkers[i].position['k'];
var myLng = myMarkers[i].position['B'];
// catch low LAT
if (lowLat > myLat){
lowLat = myLat;
}
// catch high LAT
if (highLat < myLat) {
highLat = myLat;
}
// catch low LNG
if (lowLng > myLng){
lowLng = myLng;
}
// catch high lng
if (highLng < myLng) {
highLng = myLng;
}
}
var southWestCorner = new google.maps.LatLng(highLat, lowLng);
var northEastCorner = new google.maps.LatLng(lowLat, highLng);
var bounds = new google.maps.LatLngBounds();
bounds.extend(southWestCorner);
map.fitBounds(bounds);
bounds.extend(northEastCorner);
map.fitBounds(bounds);
}
I would do it this way, add all the positions to an empty bounds:
function fnSetBounds(){
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < myMarkers.length; i++) {
bounds.extend(myMarkers[i].getPosition());
}
map.fitBounds(bounds);
}
I have a lot of markers and I m using markerClusterer to display them on the map.Additionally on click of a checkbox I need to display a rectangular overlay (title) near all these markers.
I have written 2 functions as follows for creating the overlay and deleting it.
function createLabel(posi,name){
posicion = etiquetaNombre.length;
etiquetaNombre[posicion] = name;
var label = new Label({
position:posi,
map: map,
text:name
});
rectangleNombre[posicion]=label;
rectangleNombre[posicion].setMap(map);
console.log("add: etiquetaNombre",etiquetaNombre);
myfun();
}
function deletelabel(name){
for(var i = 0; i < etiquetaNombre.length; i++){
if(etiquetaNombre[i] == name){
rectangleNombre[i].setMap(null);
rectangleNombre.splice(i, 1);
etiquetaNombre.splice(i, 1);
}
}
console.log("delete marker"+name);
console.log("delete: etiquetaNombre",etiquetaNombre);
myfun();
}
I m invoking the createLabel function as follows:
var markerImage = new google.maps.MarkerImage(imageUrl,
new google.maps.Size(24, 32));
var latLng = new google.maps.LatLng(40, -100);
map = new google.maps.Map(document.getElementById('map'), {
zoom: 2,
center: new google.maps.LatLng(40, -100),
mapTypeId: google.maps.MapTypeId.ROADMAP
});
for (var i = 0; i < 10; ++i) {
var latLng = new google.maps.LatLng(data.photos[i].latitude,
data.photos[i].longitude);
var div=document.createElement('div');
var marker = new google.maps.Marker({
position: latLng,
draggable: false,
map: map,
title:"marker"+i
});
posi=marker.position;
name=marker.title;
createLabel(latLng,name);
markers.push(marker);
}
markerClusterer = new MarkerClusterer(map, markers);
Since I am using markerClusterer I had to customize it for my above requirement.I had done it as below.
Cluster.prototype.addMarker = function(marker) {
/// some lines
if (len < this.minClusterSize_ && marker.getMap() != this.map_) {
// Min cluster size not reached so show the marker.
marker.setMap(this.map_);
posi=marker.position;
name=marker.title;
createLabel(posi,name);
}
if (len == this.minClusterSize_) {
// Hide the markers that were showing.
for (var i = 0; i < len; i++) {
this.markers_[i].setMap(null);
name=this.markers_[i].title;
deletelabel(name);
}
}
if (len >= this.minClusterSize_) {
marker.setMap(null);
name=marker.title;
deletelabel(name);
}
this.updateIcon();
return true;
};
The myfun() is called on click of check box is as below.
function myfun(){
var element=document.getElementById('id1');
if(element.checked){
for(var i = 0; i < etiquetaNombre.length; i++){
var div = document.getElementById('normal-'+etiquetaNombre[i]);
if(div!=null){
div.style.display = "";
}
}
console.log("in my fun element checked",etiquetaNombre);
}
google.maps.event.addListener(map, 'bounds_changed', function () {
if(element.checked){
for(var i=0; i<etiquetaNombre.length; i++){
var div = document.getElementById('normal-'+etiquetaNombre[i]);
if(div!=null){
div.style.display = "";
}
}
}
});
}
The problem which I m facing here is that on zooming when the clustered markers are disintegrated the rectangular overlays do not appear for them.But on simply dragging the map it appears.Can anybody guide what I m doing wrong here.
[Edited]
function createLabel(xCenter , yCenter, nombre,banderaPersonalizada){
posicion = etiquetaNombre.length;
etiquetaNombre[posicion] = nombre;
var RectangleBounds = new google.maps.LatLngBounds(new google.maps.LatLng(yCenter,xCenter), new google.maps.LatLng((yCenter+1),(xCenter+1)));
rectangleNombre[posicion] = new RectangleNombre(RectangleBounds);
rectangleNombre[posicion].setMap(map);
}
function RectangleNombre(bounds, opt_weight, opt_color) {
this.bounds_ = bounds;
this.weight_ = opt_weight || 2;
this.color_ = opt_color || "#888888";
}
RectangleNombre.prototype = new google.maps.OverlayView();
RectangleNombre.prototype.onAdd = function(map) {
var idDiv = "normal-"+etiquetaNombre[posicion];
var div = document.createElement("div");
div.id = idDiv;
div.innerHTML = '<span style=" color:blue; font-family:arial; font-size:7.5pt; font-weight:900" > '+etiquetaNombre[posicion]+'</span>';
div.style.position = "absolute";
console.log("banderaCheckEtiqueta"+banderaCheckEtiqueta);
if(banderaCheckEtiqueta){
div.style.display = "";
} else {
div.style.display = "none";
}
this.getPanes().mapPane.appendChild(div);
this.map_ = map;
this.div_ = div;
}
RectangleNombre.prototype.draw = function() {
var proj = this.getProjection();
var c1 = proj.fromLatLngToDivPixel(this.bounds_.getSouthWest());
var c2 = proj.fromLatLngToDivPixel(this.bounds_.getNorthEast());
this.div_.style.width = "0px";
this.div_.style.height = "0px";
this.div_.style.left = c1.x - 12;
this.div_.style.top = c1.y + 2;
}