I'm answering my own question (hopefully for your benefit), but this is the issue:
I've created a world map with polylines (in Google maps API v3). Some of these lines span the IDL (international date line). I want to place directional arrows on some of my lines, one arrow in the center of each line. On lines that span the IDL, the arrow center calculated by averaging the 2 end points together:
(latlng1.lat()+latlng2.lat()/2), (latlng1.lng()+latlng2.lng()/2)
draws the line the opposite way around the world leaving a floating arrow on my map instead of in the center of the actual line.
I initially sought a formula for getting the reverse of the line and somehow determining which was used. But it's too dependent on the map display. I even went so far as to see if I could get the center from the end points of the line if I first converted them to pixels, but the data conversion had no effect on the outcome.
So I then thought to look for an intersect method on the polyline, passing a point to check - and if it wasn't, find the center point from the reverse line (which I believe would 180-center.lng()) but there is no intersection method on polylines. So I started looking into the bounds object, because there are some intersection/contains methods on bounds.
So here is a very simple solution for a relatively undocumented problem:
(credit for function to retrieve bounds goes to Ben Appleton, ty):
function getBoundsForPoly(poly) {
var bounds = new google.maps.LatLngBounds;
poly.getPath().forEach(function(latLng) {
bounds.extend(latLng);
});
return bounds;
}
var poly_bounds = MapAbstraction.get_poly_bounds(line);
var center_point =poly_bounds.getCenter();
and then I can pass my center_point to my marker creation tool to generate the arrow in the actual center of the line without worrying about which way it was drawn.
Related
I want to achieve the following: "Place an array of markers that may be distributed across a large range of lat, lng into a fitbounds method that places the fitbounds inside a custom rectangle."
The image below should clarify what I'm trying to achieve. Basically I have an array of markers that I want to make sure always fits within a small box on the right hand side of my page.
The white box contains some information pertaining to the markers, which will always be present, so I don't want any markers hidden behind the white box, and I'd love if I could define that they live within the black box. (Note the black box is just a visual reference for this question).
You can use the containsLocation to ensure a point is inside of a polygon. See here.
As you go through each coordinate pair in your array, verify the location is within the polygon area, then add to the map accordingly. You can also set an attribute to those points to "define" what extent they are in.
var latlng = new google.maps.latLng(array[n]);
if (google.maps.geometry.poly.containsLocation(latlng, polygon)){
marker = new google.maps.Marker({
position: latlng,
map: map
});
marker.dataset.box = 'blackbox';
} else {
alert('Not inside black box');
}
If you're using HTML5, you can add a dataset attribute to markers that are within the polygon.
marker.dataset.box = 'blackbox';
If not, you can use setAttribute.
marker.setAttribute('data-box', 'blackbox');
I need to count and list the markers that are within a figure either a sirculo or a rectangle.
The operation would be that when you insert a figure on the map I list and count how many markers inside it.
The Circle and Rectangle classes have a getBounds() function, which returns a LatLngBounds object. Add your circle/rectangle and get its bounds. Loop over your markers, calling the contains() function on each marker to see if it is contained in that latlng bounds.
You may need to be slightly cleverer with the circle, as its bounds will be for the bounding box that surrounds it, so you might have markers that fall outside the circle but still within that box. In which case you'd need to work something out based on the radius of the circle.
I need to draw a circle in google Maps V3 but I have 2 coordinates, the center and the outter position. Problem is the API expects center and "radius".
For example:
var myCirclePath = [];
myCirclePath.push(new google.maps.LatLng(18.111111,66.111111));
myCirclePath.push(new google.maps.LatLng(18.223344,66.222222));
var myCircle = new google.maps.Circle({
center: myCirclePath[0],
radius: // what do I put here????
map: map
});
I searched around the web and find a lot of stuff about radians, degrees, sin, atan, and what not... however, I'm not good at math and I'm totally lost.
So, the questions are:
a) What should I put in the "radius:" option?
b) How can I center the zoom around the circle? "Bounds.Extend" will not do it
So, the questions are:
a) What should I put in the "radius:" option?
Use the geometry library computeDistanceBetween() to find the radius (passing in your two points)
b) How can I center the zoom around the circle? "Bounds.Extend" will not do it
Once you have created the circle, you can call the getBounds() method on it to get its bounds
Correct me if I am wrong but isn't the radius the distance between center point and outer point of a circle? I would go with this.
function initialize() {
var latlng = new google.maps.LatLng(37.7702429, -122.4245789);
var myOptions = {
zoom: 3,
center: latlng,
disableDefaultUI: false,
mapTypeId: google.maps.MapTypeId.TERRAIN,
};
var map = new google.maps.Map(document.getElementById("map_canvas"),
myOptions);
// Limit panning
// Latitude bounds for map, longitude not important
var southWest = new google.maps.LatLng(-85.000, -122.591);
var northEast = new google.maps.LatLng(85.000, -122.333);
var allowedBounds = new google.maps.LatLngBounds(southWest, northEast);
// Add a move listener to restrict the bounds range
google.maps.event.addListener(map, "center_changed", function() {checkBounds(); });
//If zoom out at bound limit then map breaks; center doesn't change but bounds get broken. Listen for zoom event and try to correct bound break. **Doesn't Work**
google.maps.event.addListener(map, 'zoom_changed', function() {checkBounds(); });
// If the map position is out of range, move it back
function checkBounds() {
// Perform the check and return if OK
if ((allowedBounds.getNorthEast().lat()>(map.getBounds().getNorthEast().lat()))&&(allowedBounds.getSouthWest().lat()<(map.getBounds().getSouthWest().lat()))) {
lastValidCenter = map.getCenter();
lastValidZoom = map.getZoom();
return;
}
// not valid anymore => return to last valid position
map.panTo(lastValidCenter);
map.setZoom(lastValidZoom);
}
}
Basically I don't want the user to be able to see anything outside of the map, so I have restricted the latitudinal bounds. Works normally.
The issue is that if a user we to be viewing close to the bound limits and then zooms out so that the center doesn't change, but now the view-port bounds are outside of the bound limit, it does not correct and the map becomes unpannable.
Any help you geniuses can offer is mucho appreciated .
Ok, so it was very simple. The zoom_changed event was not behaving as expected and bounds_changed on it's own was not satisfactory. This map will not go out of bounds by pan or zoom and is perfect for if you want the user to only see map and no grey background. Not so good if your users want to center the map at a high latitude and low zoom level. Cross that bridge later. Here's the code:
// The allowed region which the whole map must be within
var southWest = new google.maps.LatLng(-85.000, -122.591);
var northEast = new google.maps.LatLng(85.000, -122.333);
var allowedBounds = new google.maps.LatLngBounds(southWest, northEast);
// Add listeners to trigger checkBounds(). bounds_changed deals with zoom changes.
google.maps.event.addListener(map, "center_changed", function() {checkBounds(); });
google.maps.event.addListener(map, 'bounds_changed', function() {checkBounds(); });
// If the map bounds are out of range, move it back
function checkBounds() {
// Perform the check and return if OK
if ((allowedBounds.getNorthEast().lat()>(map.getBounds().getNorthEast().lat()))&&(allowedBounds.getSouthWest().lat()<(map.getBounds().getSouthWest().lat()))) {
lastValidCenter = map.getCenter();
lastValidZoom = map.getZoom();
return
}
// not valid anymore => return to last valid position
map.panTo(lastValidCenter);
map.setZoom(lastValidZoom);
don't try this on a working application or one thats in production make a new map somewhere
local server different test program whatever.
PANING google maps has always been buggy especially around the edges or close to any of the google icons for pan zoom etc .
you need to get back to basics forget functions and scripting just ask simple IF statements
similar to this CAN'T REMEMBER WHAT I DONE A COUPLE OF YEARS AGO bit the gist is this.
1) store 4 variables to represent four lines on a map
left edge west
right edge east
top edge north
bottom edge south
another to keep track of centre LAT LNG( the start centre same as first map displayed on load )
i,e if you pan left or west by X you make the centre / center (for americans) equal to current centre by plus the pan X ditto for all the other pan directions add or subtract the required latitudes and longitudes
test that you have not reached an edge (minus whatever by test trial and error) amount causes the google bug to appear close to icons around edge
or put another way make the LAT's and LNG's you are testing for to be smaller that the displayed map
if left or west edge of displayed map is at longitude x stop panning (by not doing anymore
adjustments s to your centre VARIABLE at X - 10 longitudes same for all other 3 edges by plus or minus the required amount
top edge north will will at lattitude a
bottom edge south will be at lattitude a - whatever you chose
left edge west will be at longitude b
right edge east will be at longitude b- whatever you chose
they will all be within the displayed map but say 0.5 of a latitude or longitude than displayed map
if your pan crosses any of your fine lines set you centre var back or forward and you pan back or forward by say 0.1 to o.5 of a latitude or longitude viewers will just see a slight jerk back into place when they pan outside your pre de=fine four lines across the map.
Code will like like very basic learner code but it will work.
at least it did for me after some trial and error and the usual debugging typo errors etc.
taking this approach you are in control and not google scripts that may have undocumented code in them that causes the problems your experiencing because google cannot know what your trying to achieve only you know that.
SORRY HAVE NOT GOT THE CODE ANYMORE its not difficult just looks like newbie code and not the code advanced users prefer
it's like making a simple learner program where if you move up or down or diagonally you adjust centre LAT LNG in you var thats store current centre (this is your own variable not a google variable ) if centre (stored in your own variable ) crosses one of your lines stop panning and set Gmap center back forward up or down by a little thats plus or minus a fraction of a LAT or LNG
Thanks, your script crashed my Mozilla :-) It is probably because the zoom_changed event doesn't give you correct center in getCenter() call. It is a known problem that zoom_changed event handler doesn't give correct bounds, so it may apply to the center too. I tried to modify your code to handle only the bounds_changed event (instead zoom_changed and center_changed), and the problem dissapeared! But it is not behaving ideally either.
Maybe better look at this example of range limitation, it works quite nicely.
When you are pretty far zoomed out on a google map, you can drag it enough so that the map ends and becomes a blank gray color. The map seems to repeat seemlessly on the horizontal axis, but not vertically.I'm wondering if there is a way to prevent the map from being dragged when it reaches that gray area. Any ideas?
Just for fun, another approach would be to tell the map to wrap vertically in the same way that it wraps horizontally, by overwriting GMercatorProjection.prototype.tileCheckRange before creating the map.
GMercatorProjection.prototype.tileCheckRange=function(a,b,c){
var d = 1<<b;
if (a.y<0||a.y>=d) {
a.y=a.y%d;
if(a.y<0){
a.y+=d;
}
}
if(a.x<0||a.x>=d){
a.x=a.x%d;
if(a.x<0){
a.x+=d;
}
}
return true
}
The downside is that the API doesn't contain any code for causing the markers and polylines to jump vertically to the copy of the map that's in view, they only jump horizontally. A complete solution would require writing own code to do the vertical jumps, and use unbounded GLatLngs throughout.
This is a good example of how to limit the range of a map. It's a bit of a hack, but it's probably your only real option.