Google Maps JavaScript API V3.
My mapping has me dealing with the idea of polygons, and I'm trying to develop a strategy before I dive into the code.
I'm never going to have more than one polygon on the map at a time, so I'm hoping I can define one polygon and reuse it as you can with markers.
Is my understanding correct that the polygons setPath(); function will move the polygon to represent a new array of points? The documentation says... "Inserting or removing LatLngs from the MVCArray will automatically update the polygon on the map." but it doesn't come right out and say that you can use setPath(); to give it an entirely new array of points.
I'm thinking in psuedocode...
// some event fires
polygon.setPath(latlngArray);
bounds = new google.maps.LatLngBounds();
$.each(latlngArray, function(key, ll){
bounds.extend(ll);
});
polygon.setMap(MyMap);
MyMap.fitBounds(bounds);
//a different event fires
polygon.setMap(null);
// build a new latlngArray
// do it again
Am I correct in thinking that I can reuse the same polygon object in this fasion, or do I need to rethink my strategy?
Thanks.
Skip
EDIT: The answer is yes it can. I'm going to hash out my code better and try to provide a well written answer, that shows the caveats I've come across. Such as, the map must be visible for map.fitBounds(); to give cogent results.
Yes it is quite possible to reuse the same polygon object...
I really don't have any code to offer. The psuedocode I listed in the question basically works.
These are the things I learned or chose in fleshing out my solution...
As stated earlier, the map can't be style="display: none;" for map.fitBounds(); to work as expected.
I already keep a container object that holds my markers. I created a container object for the polygon paths, and add a 'polygon' attribute to markers that are associated with a polygon, so multiple markers can reference the same polygon path.
Even for polygons with a single path, I chose to embed my path array, within another array, then use polygon.setPaths(); This way the code will scale easier if I expand to polygons with multiple paths.
When initially parsing the polygon path build a LatLngBounds object, and then save its bounds.getSouthWest(); & bounds.getNorthEast(); along with the path. This allows for quick and easy map.fitBounds(); at display time, and keeps from recalculating the same bounds multiple times.
Anyhow, yes it is certainly possible, and I think quite efficient to reuse the same polygon object with different paths.
San Francisco & Oakland recycling the same polygon object...
That's all i got!
Skip
UPDATE: I found some polygon data with multiple paths. It plugged right in.
yes, you are both correct in your assumption that redefining the setPaths will redefine the polygon, BUT you must setMap afterwards for the polygon to be redrawn. the polygon may be outside the api window, that is irrelevant. for ease of use, once "repointed", since the polygon may be outside your viewing window, it would be good USABILITY practice to redefine the center of the window using the setCenter method on the map. This code is a chunk that i removed from an application that allows users to draw a polyline and then convert it into a polygon (since user may want to fix perimeter, i allow her to go back and forth between polyline and polygon). i always use the same polygon and simply setPathSSSSSSSSS (there is an S in the end for polygons):
function confirmClosePolyline() {
var pathArrayTemp = areaPerimeterPath.getPath();
var decision = confirm("Change POLYGON?");
if (decision) {
areaMapPolygon.setMap(null); //makes polygon "invisible"/ removes
areaMapPolygon.setPaths(pathArrayTemp);
areaMapPolygon.setMap(map);
}
}
Currently, in 2020 Dec, its sufficiently to use only:
myOldPolygon.setPath(newLatLngs)
to redraw one with new path without resetting map property.
Have tried and this works ok.
Related
I recently set up a non geographical map with leaflet using an image layer. This obviously is a stupid decision working with 'bigger' maps due to high memory usage and the need to load the big image file so I decided to use a tile layer instead.
Working mostly as expected aside from one thing: I can't seem to be able to drag outside of the map, it just jumps back so the map covers the screen. I'm not sure what causes that as I read that this behaviour usually needs to be set manually using maxBounds. Tried setting that to null, doesn't change. The only new thing introduced is Leaflet Rastercoords (https://github.com/commenthol/leaflet-rastercoords) which I'm unsure if that's causing the problems.
Any way to resolve that? Not sure where to look next.Thank you!
I achieved the behaviour you want using the following work around:
map.setMaxBounds(null); //map being the leaflet map.
This need to be called after the initialization of the map and of the raster coords layer.
I have a Bing Maps where i draw some polygons,
I would like to get the best view (zoom / center) to show all the polygons.
I've tried this, and that achieve what i want, but it make a lot of time.
var poly = new Microsoft.Maps.Polygon(allPoints);
var boundaries = Microsoft.Maps.LocationRect.fromLocations(poly.getLocations());
Thanks for help.
If you have a lot of points (tens of thousands) it will take time. Another way to do this is to loop through your array of location objects and get the min and max latitude and longitude values and then use those to create a location rect. However I doubt that would be much faster as that is basically what the fromLocations method does behind the scenes.
Also, rather than using getLocations, just use the allPoints value you have. Might save a bit of processing.
All that said, unless you are working with really large polygons (thousands of points), I can't see this being slow. Panning and zooming may be slow, but would likely be because the browser has to constantly update the position of the points for the polygon as the map moves. The more points your polygon has, the slower the browser will become.
In my JavaScript application I have more than 30+ polygons. They are defined like this:
polygons:[
{name:'xx',bounds:[20,20,60,20,50,40,30,10...],minzoom:0,maxzoom:5},
{name:'yy',bounds:[.....],minzoom:6,maxzoom:8},
........
]
Now given a certain point like [10,10] with zoom 4.
Which is the fast way to check which polygon this point is located inside?
My first thought is iterator the polygons, and to check if the point is inside the polygon.
Then this question came to be a point-in-polygon question which have a lot of answers at stackoverflow.
I just wonder if there is any alternative methods?
Assuming the polygons do not overlap (or that if they do, you're only interested in the top-most polygon), you can employ the "point-in-polygon" solution that involves a canvas:
Create a canvas big enough to hold all your polygons.
Draw each polygon in a different colour, one after the other
Look up what colour the pixel is where the point is located
This will tell you the polygon that's there.
Note that you don't even need them to be human-distinguishable colours, you could literally use #000000, #000001, #000002 and so on, and use the colour's hex code as the index of the polygon.
I have a series of Leaflet FeatureGroups that are made up of a series of GeoJSON layers. The FeatureGroups are conceptually similar but I need them to be separate for certain control reasons. I also need to be able to turn them all on and off at once. Is there a way to do this?
I looked in the documentation and couldn't find an event that fires when the FeatureGroup is switched on and off. There is also no documented way of lumping the FeatureGroups into some kind of superGroup.
For those who want to picture it, here is the workflow:
GeoJSON gets data that is turned into layers in Leaflet. This is of different administration boundaries (e.g. States, Counties, etc...). Each of the layers goes into a different FeatureGroup based on its type (e.g. Arkansas and New York go into the State FeatureGroup, Ford and Lincoln counties go into the County FeatureGroup). This way I have control over opacity and styling for the different FeatureGroups (e.g. when I'm looking at the Counties of a state, I can lower the opacity of all the other states). I also need a way of turning all of this off and back on again. Leaflet provides the ability to do that on a FeatureGroup by FeatureGroup basis, but not a super set of that.
Any ideas on how to achieve this?
New version of question:
What is the event that fires when turning a LayerGroup On and Off? Is there anyway to hook into that?
I ended up having my usual LayerGroups or FeatureGroups, and then a FeatureGroup that contains all the layers on all the groups. So when you add a shape or layer to a FeatureGroup, also add it to the FeatureGroup that you are using to keep track of everything. And of course if you remove don't forget to remove it.
You can add this base FeatureGroup to the map along with the other groups and it should be fine.
I don't think Leaflet currently provides an event when a LayerGroup is turned on or off (you are talking about with the L.Control, right?). I agree that it would be useful. For now, you can just extend the code to do whatever you need to be done. For example:
var customLayerControl = L.Control.Layer.extend({
_onInputClick: function(Layer, name){
// This is just like calling super() if this confuses you!
L.Control.Layers.prototype._onInputClick.call(this,Layer,name);
// Do stuff
}
});
Then instead of using the L.Control.Layers, use your custom layer control:
map.addControl(new customLayerControl({}, {'Custom Layer':customLayer},{}));
I hope this helps.
The closest example of what I'm trying to accomplish is a store locator. I have 6,000+ locations that need to be plotted onto a map of Canada.
My original plan was to use Google maps to place markers on each location, but it doesn't make sense to plot them all every time someone attempts to view the map, or various parts of the map.
How does one only put markers on the locations in view? Do I have to send the geo data of all 6000 locations to the client each time they load the map?
Is this doable with maps? (I'm sure it's got to be) Or is there a better service for this kind of thing?
Definitely do not draw all the locations at the same time if they are not all visible. Consider using MarkerManager (article here) or MarkerLight (code: http://gmaps-samples.googlecode.com/svn/trunk/manymarkers/, demo: http://gmaps-samples.googlecode.com/svn/trunk/manymarkers/randommarkers.html). If your initial map and data is such that all the markers would be visible initially, this is definitely the way to go.
You can also use the GEvent object (docs) to detect a "move" event, then check the current display coordinates, draw any that are in bounds. This is the best route if your initial map is too zoomed or small, and/or your marker set is too large to fit on the map's initial view. Your user will be moving the map around, so you can react to that movement and only draw the relevant markers. Take a look at http://econym.org.uk/gmap/gevent.htm for a list of other GEvent events (couldn't find an official list on the API), you might also want to watch "zoom" events.
The two methods can also be combined.
You can use getBounds() to determine the viewable portion of the map. I'd use this data to request from the server all locations within those bounds. Use the bounds_changed event to monitor changes to the viewport and request additional locations as necessary. You'll probably want to set either a minimum zoom level, or maximum number of results to avoid displaying too many locations than is reasonable. Eg, when the map is zoomed out to display all of Canada in a single view.