Trying to create a new version of the map functions seen here: http://www.daftlogic.com/projects-google-maps-distance-calculator.htm
but using the v3 api.
So far I am able to set markers on click and can draw the geodesic polyline.
The issues I am currently running into are:
Updating the poly-line on marker drag
I'm pretty sure I have to put each marker in an array and do a for
loop so that I can keep clicking and adding points that will add to
the total distance.
Properly displaying distance.
I have created a jsfiddle: http://jsfiddle.net/wyZyS/
EDIT: I realize I have nothing calling the "update" function. I am trying to create the array for each marker currently. The calculation you see is converting meters to nautical miles.
I wrote something like this a while ago as an exercise. Sadly it works properly only in Chrome, it has strange bugs in other browsers. The distance function should work in IE9.
The idea I had was to add drag listeners to your markers and keep a single polyline representing the path, updating its paths as the markers are dragged.
DEMO http://freezoo.alwaysdata.net/freezoomaps/freezoomaps.html
google.maps.event.addListener(tmpNode, 'drag', function(event) {
distance.drawPath();
});
distance.drawPath = function() {
distance.countNodes();
var coords = [];
for (var i = 0; i < distance.nodes.length; i++) {
coords.push(distance.nodes[i].getPosition());
}
distance.line.setPath(coords);
meters = google.maps.geometry.spherical.computeLength(coords);
$("#distance_km").val((meters/1000).toFixed(3));
$("#distance_mi").val((meters/1609.344).toFixed(3));
}
distance.countNodes = function() {
var count = 0;
for (var i = distance.nodes.length - 1; i >= 0; i--) {
if (distance.nodes[i].getMap() == null) {
distance.nodes.splice(i, 1);
}
else {
count++;
}
}
return count;
}
distance.clearNodes = function() {
for(var i = 0; i < distance.nodes.length; i++) {
distance.nodes[i].setMap(null);
}
distance.drawPath();
}
Related
Need some help with google maps polygon areas. I have a many markers plotted across the google map. Have some polygon areas plotted on map too. I want to find the total of marker points covered by a polygon, whenever the polygon area is clicked. Kindly guide or provide some good links in this direction
Thanks.
You could try ray casting algorithm. The implementation would be something like this:
var markers = []; // list of your markers
var polygonPath = polygon.getPath();
var location;
for (var i = 0; i < markers.length; i++) {
location = markers[i].getPosition();
console.log(isPositionInside(location.lat, location.lng, polygonPath));
}
function isPositionInside(mLat, mLng, polygonPoints) {
var isInside = false;
for (var a = 0, b = polygonPoints.length - 1; a < polygonPoints.length; b = a++) {
var aLng = polygonPoints[a].lng,
aLat = polygonPoints[a].lat,
bLng = polygonPoints[b].lng,
bLat = polygonPoints[b].lat;
if ((aLng > mLng) != (bLng > mLng) && (mLat < (bLat - aLat) * (mLng - aLng) / (bLng - aLng) + aLat)) {
isInside = !isInside;
}
}
return isInside;
};
This isn't the most optimal solution, as you can read in the wiki article, but in most cases it will get the job done.
I'm using code found here: Integrating Spiderfier JS into markerClusterer V3 to explode multi-markers with exact same long / lat to restrict zoom levels when clicking on MarkerClusterer created clusters containing points at the same location.
Live example is here:
http://www.adultlearnersfestival.com/newsite/yourarea/map.html
I'm getting an error in Firebug however:
Error: TypeError: markers is undefined
and can't work out what's causing it. The specific code is:
var minClusterZoom = 14;
mc.setMaxZoom(minClusterZoom);
gm.event.addListener(mc, 'clusterclick', function(cluster) {
map.fitBounds(cluster.getBounds()); // Fit the bounds of the cluster clicked on
if( map.getZoom() > minClusterZoom+1 ) // If zoomed in past 15 (first level without clustering), zoom out to 15
map.setZoom(minClusterZoom+1);
});
Any help much appreciated.
- Tom
I took a different approach suggested here: markerClusterer on click zoom and edited the MarkerClusterer source as follows
from this
/**
* Triggers the clusterclick event and zoom's if the option is set.
*/
ClusterIcon.prototype.triggerClusterClick = function() {
var markerClusterer = this.cluster_.getMarkerClusterer();
// Trigger the clusterclick event.
google.maps.event.trigger(markerClusterer, 'clusterclick', this.cluster_);
if (markerClusterer.isZoomOnClick()) {
// Zoom into the cluster.
this.map_.fitBounds(this.cluster_.getBounds());
}
};
to this
/**
* Triggers the clusterclick event and zoom's if the option is set.
*/
ClusterIcon.prototype.triggerClusterClick = function() {
var markerClusterer = this.cluster_.getMarkerClusterer();
// Trigger the clusterclick event.
google.maps.event.trigger(markerClusterer, 'clusterclick', this.cluster_);
if (markerClusterer.isZoomOnClick()) {
// Zoom into the cluster.
this.map_.fitBounds(this.cluster_.getBounds());
// modified zoom in function
if( this.map_.getZoom() > markerClusterer.getMaxZoom()+1 )
this.map_.setZoom(markerClusterer.getMaxZoom()+1);
}
};
Looks like an error in the MarkerClusterer to me. Inside this function in the for loop, markers is undefined, which means this.getMarkers() is returning undefined, looks to me like it is just wrong:
/**
* Returns the bounds of the cluster.
*
* #return {google.maps.LatLngBounds} the cluster bounds.
*/
Cluster.prototype.getBounds = function() {
var bounds = new google.maps.LatLngBounds(this.center_, this.center_);
var markers = this.getMarkers();
for (var i = 0, marker; marker = markers[i]; i++) {
bounds.extend(marker.getPosition());
}
return bounds;
};
probably should be something like (not tested):
/**
* Returns the bounds of the cluster.
*
* #return {google.maps.LatLngBounds} the cluster bounds.
*/
Cluster.prototype.getBounds = function() {
var bounds = new google.maps.LatLngBounds(this.center_, this.center_);
var markers = this.getMarkers();
if (markers && markers.length)
{
for (var i = 0; i < markers.length; i++) {
bounds.extend(markers[i].getPosition());
}
}
return bounds;
};
Works using MarkerClustererPlus
I solved the issue changing this:
Cluster.prototype.getBounds = function() {
var bounds = new google.maps.LatLngBounds(this.center_, this.center_);
var markers = this.getMarkers();
for (var i = 0, marker; marker = markers[i]; i++) {
bounds.extend(marker.getPosition());
}
return bounds;
};
to this:
Cluster.prototype.getBounds = function() {
var bounds = new google.maps.LatLngBounds(this.center_, this.center_);
var markers = this.getMarkers();
var minZoom =10
mc.setMaxZoom(minZoom);//The maximum zoom level that a marker can be part of a cluster
for (var i = 0; i < markers.length; i++) {
bounds.extend(marker.getPosition());//Extends this bounds to contain the given point.
}
if( map.getZoom() > minZoom+1 ){// If zoomed in past 11, the first level without clustering, zoom out to 11.
map.setZoom(minZoom+1);
}
return bounds;
};
In Google maps API v2, map of our country was nicely fitted to 700x400px map with the following:
map.getBoundsZoomLevel(<bounds of our country>)
But in API v3, the map.fitBounds() method doesn't fit it at that zoom level to 700x400 - it zooms out one level.
This means that map.fitBounds() counts with some "grace margin" or something.
How can I affect the size of this margin?
Here's a solution that will zoom into the map as far as possible without a custom margin. You should be able to adapt it to account for some margin if you want to.
My solution is based on this comment in a Google Groups thread. Unfortunately, the call to helper.getProjection() always returned undefined, so I adapted the above answer a bit and came up with this working code.
Just replace your existing calls to map.fitBounds(bounds) with myFitBounds(map, bounds):
function myFitBounds(myMap, bounds) {
myMap.fitBounds(bounds);
var overlayHelper = new google.maps.OverlayView();
overlayHelper.draw = function () {
if (!this.ready) {
var projection = this.getProjection(),
zoom = getExtraZoom(projection, bounds, myMap.getBounds());
if (zoom > 0) {
myMap.setZoom(myMap.getZoom() + zoom);
}
this.ready = true;
google.maps.event.trigger(this, 'ready');
}
};
overlayHelper.setMap(myMap);
}
// LatLngBounds b1, b2 -> zoom increment
function getExtraZoom(projection, expectedBounds, actualBounds) {
var expectedSize = getSizeInPixels(projection, expectedBounds),
actualSize = getSizeInPixels(projection, actualBounds);
if (Math.floor(expectedSize.x) == 0 || Math.floor(expectedSize.y) == 0) {
return 0;
}
var qx = actualSize.x / expectedSize.x;
var qy = actualSize.y / expectedSize.y;
var min = Math.min(qx, qy);
if (min < 1) {
return 0;
}
return Math.floor(Math.log(min) / Math.log(2) /* = log2(min) */);
}
// LatLngBounds bnds -> height and width as a Point
function getSizeInPixels(projection, bounds) {
var sw = projection.fromLatLngToContainerPixel(bounds.getSouthWest());
var ne = projection.fromLatLngToContainerPixel(bounds.getNorthEast());
return new google.maps.Point(Math.abs(sw.y - ne.y), Math.abs(sw.x - ne.x));
}
Now, the method fitBounds has a second parameter that represents the size of the padding. For those who want to remove it, you just need to pass 0.
Map.map.fitBounds(bounds, 0);
New method signature: fitBounds(bounds:LatLngBounds|LatLngBoundsLiteral, padding?:number)
I am having a map with some polylines with the distance [api v3]. I want that when someone drag the polyline at the same time the distance also get updated but dont know how to do. Please help me, any good tutorial or another threads are most welcome
Thanks for helping me
Naveen
This page describes using draggable markers and updating the distance when a marker is moved.
http://exploregooglemaps.blogspot.com.br/2012/02/measuring-distance-with-markers.html
There is a attribute which makes your polyline editable.
polyPath.setEditable(true);
Now use a listener to check the editing.
google.maps.event.addListener(polyPath, 'capturing_changed', function() {
var array = polyPath.getPath(); //getPath() gives u array of current markers latlng over map
var tempDistance = 0;
var tempPathArray = [];
for(i = 0; i < array.length; i++){
tempPathArray.push(array.getAt(i));
}
for(k = 1; k < tempPathArray.length; k++)
{
var calculateNewDistance=google.maps.geometry.spherical.computeDistanceBetween(tempPathArray[k-1],tempPathArray[k]);
tempDistance += calculateNewDistance;
}
}
// make sure to add the following script to compute the distance between two latlngs
I have a google maps app which plots markers as it loads. One of the new requirment is to to add a Polygon overlay encompassing a selection of markers by the user. I was able to achieve that using the Geometry Controls of the GMaps Utility Library
Now, the next step is to form a group of the selected markers for which I would need to determine if the lat lngs of the markers falls within the lat lngs of the polygon? Is there a way to determine the lat lngs of a polygon and compute if the marker's lat lng is within its boundaries?
I have never directly messed around with Google Maps, but you can store the points that make up the polygon and then use the Point-In-polygon Algorithm to check if a given longitude and latitude point is within a polygon or not.
// Create polygon method for collision detection
GPolygon.prototype.containsLatLng = function(latLng) {
// Do simple calculation so we don't do more CPU-intensive calcs for obvious misses
var bounds = this.getBounds();
if(!bounds.containsLatLng(latLng)) {
return false;
}
// Point in polygon algorithm found at http://msdn.microsoft.com/en-us/library/cc451895.aspx
var numPoints = this.getVertexCount();
var inPoly = false;
var i;
var j = numPoints-1;
for(var i=0; i < numPoints; i++) {
var vertex1 = this.getVertex(i);
var vertex2 = this.getVertex(j);
if (vertex1.lng() < latLng.lng() && vertex2.lng() >= latLng.lng() || vertex2.lng() < latLng.lng() && vertex1.lng() >= latLng.lng()) {
if (vertex1.lat() + (latLng.lng() - vertex1.lng()) / (vertex2.lng() - vertex1.lng()) * (vertex2.lat() - vertex1.lat()) < latLng.lat()) {
inPoly = !inPoly;
}
}
j = i;
}
return inPoly;
};
Following npinti's suggestion, you may want to check out the following point-in-polygon implementation for Google Maps:
Check if a polygon contains a coordinate in Google Maps
This has been updated in v3. You can do this calculation via the google.maps.geometry.poly namespace API Documentation