Delete a vertex of polygon google maps API v3 - javascript

So there are many posts on how to delete the vertex of a google maps polygon. None of them have worked for me - this may be due to the outdated API's they reference. I am trying to limit the number of points a user can create on a polygon. If they create more than a certain number of points I would like to either programmatically trigger the 'undo' functionality built into google maps or have some way of deleting the last vertex created.
When I create the initial polygon for a user to work with I add this event listener in:
google.maps.event.addListener(myPolygon.getPath(), 'insert_at', function(event){
var numPoints = myPolygon.getPath().length;
if(numPoints == 5){
myPolygon.getPath().removeAt(4);
}
});
This ends up removing a point from the polygon (NOT necessarily the last point created). Sometimes it causes the following error:
Uncaught TypeError: Cannot read property 'b' of undefined.
I have attempted using a 'click' listener on the polygon, but the click event does not fire when a user creates a new vertex. It only fires when the actual polygon shaped is clicked.

I guess your are using an path with auto-completition(the first LatLng is not equal to the last LatLng)
There seems to be a bug when you try to remove the last LatLng from an autocompleted path.
This bug doesn't prevent you from removing the point, the error occurs later(I guess when the API updates the UI for the editable polygon).
You may simply use a try/catch-statement to bypass this error.
Related to the position of the removed point: a newly created point will not be inserted at the end of the path, it will be inserted between the points where it's placed.
When you insert a point between point1(index 0) and point2(index 1) the newly created point will have the index 1.
You may use the first argument of the callback to retrieve this index.
Summary:
google.maps.event.addListener(myPolygon.getPath(), 'insert_at', function(index){
if(this.getLength() > 4){
try{
this.removeAt(index);
}catch(e){}
}
});

Related

In Bing Maps v8 can I get a pushpin object from a layer in a loop?

In Bing Maps v7 I was able to add pushpins to an entityCollection and then loop through that collection later in the code to set options or whatever. Now, I am having trouble getting pins from the v8 layers.
Here is what I used to do in v7 after I had already added the pin to the entityCollection:
for (var i = 0; i < entityCollection.getLength() ; i++) {
var pin = entityCollection.get(i);
pin.setOptions({ visible: true });
}
I have changed the object entityCollection to a layer for v8 and I am also looping through the layer while i < entityCollection.data.length
Now, in Bing Maps v8, I'm having trouble getting the pin object from the layer that I have already added it to. The code above throws an error on the setOptions line and I have also tried getting the pin with:
entityCollection.data[i]
instead of
entityCollection.get(i)
But that doesn't work either. I'm afraid my question is too generic, because I can't find anything that actually answers my question. I have a work around, but that causes failures later when I want to hide all the pins with certain attributes. Thanks in advance!
Bing Maps v8 has done away with the entityCollection - though they say it's still sort of supported, you obviously don't want to be using deprecated things any more.
Anywhere you have an entityCollection, replace it with a Layer (Microsoft.Maps.Layer). Layers expose the getPrimitives() method which will provide you with an array of the contents.
var map = new Microsoft.Maps.Map(..., ...);
var layer = new Microsoft.Maps.Layer();
// Add layer data...
layer.add(new Microsoft.Maps.Pushpin(...));
// Add layer to map
map.layers.insert(layer);
// Then you can iterate
var layerItems = layer.getPrimitives();
var len = layerItems.length;
for(var i = 0; i < len; i++){
var pin = layerItems[i];
// Do something with your pin
pin.setOptions({visible: false});
}
Note that if you're doing mass updates to the entire contents of the layer, such as showing or hiding every pin in the layer, you can do that directly on the layer. This will save you (the browser) a chunk of work setting each pin individually.
layer.setVisible(true);
Yes, in V8 layers have a getPrimitives function which returns an array containing all the shapes. You can then loop through these shapes like you would any other array.

Detect when user reaches maxBounds using Leaflet

I am using leaflet to show an interactive map to our users.
We want to let them browse through a limited area, and inform them they have to subscribe in case they want to see something too far away (using a pop up or equivalent).
So far I have seen that Leaflet supports a maxBounds option.
This is a good start that lets me prevent users to see larger areas.
Now I would like to be able to detect a maxBounds 'event' to show the user a pop up.
I have been looking into the Leaflet source code, but couldn't find an obvious way to do it.
so far I have found that the maxBounds option is fed into the setView method.
This method itself uses the _limitCenter method to define the center.
This goes a few levels deeper, down to the _getBoundsOffset method that finally uses the bounds.
_getBoundsOffset: function (pxBounds, maxBounds, zoom) {
var projectedMaxBounds = toBounds(
this.project(maxBounds.getNorthEast(), zoom),
this.project(maxBounds.getSouthWest(), zoom)
),
minOffset = projectedMaxBounds.min.subtract(pxBounds.min),
maxOffset = projectedMaxBounds.max.subtract(pxBounds.max),
dx = this._rebound(minOffset.x, -maxOffset.x),
dy = this._rebound(minOffset.y, -maxOffset.y);
return new Point(dx, dy);
},
The closest I could find so far would be to hook into the moveend event and check whether the center is out of my bounds manually.
However, it seems like this would be redundant with what leaflet is already doing.
Is there a better to leverage leaflet to achieve this?
Thanks
Just check if your defined bounds contain the map bounds. As long as the map bounds are inside the defined bounds, this will do nothing:
var myBounds = L.latLngBounds(...)
map.on('move moveend zoomend', function(){
if (!myBounds.contains(map.getBounds())) {
// Display popup or whatever
}
});
it seems like this would be redundant with what leaflet is already doing.
Don't worry about that. The overhead is negligible for this use case.

How to save custom property to LatLng in Google Map Javascript API

I would like to show some specific data when user mouseover the polyline in google map. I get LatLng object in in mouseover event. I would like to save custom field (index to another array with data to show) to the LatLng object, so I don't need to scan another collection.
I am not expert on Javascript. Can I add a custom property to LatLng or can I inherit/extend myLatLng object? What is the best approach?
google.maps.event.addListener(polyline, 'mouseover', function (event) {
var indexOfPointInPolyline = SomeFunc(event);//I don't know how to do this properly
});
Basically a LatLng is an object, you can assign any property you want to via:
obj.myProperty='myValue'
for the given code it would be like:
event.latLng.someProperty='someValue';
But: this will not work because:
the mouseover-event will always pass a new LatLng-instance
it's also useless to implement other solutions based on the coordinates. When you log the returned values you'll see that they are always different(the accuracy will be up to centimeters or even millimeters ), it's nearly impossible for a user to touch a polyline repeatedly at the exact same point.

Openlayers 2. z-axis and select control

I've got a couple vector layers one has polygons, one has lines. We have a need to add lines to the line layer that attach to the polygons (database procedure requires the polygons IDs, which are stored in attributes on the polygons)
So I have a drawFeature control on the lineLayer, and a selectFeature (which stores off the ID on hover rather than just selecting) on the polygonLayer. It actually works just fine except the z axis of the linelayer while added is lower, so it shows the new line being drawn under the polygon. Would rather have the line show over the polygon. I know it's because when the selectFeature control is active it's setting the z-index of the polygon layer higher than the lineLayer.
I manually set the z-index of the linelayer higher than the polygon layer using lineLayer.setZIndex(800) or whatever, and that certainly makes the new line draw over the polygons, but then the selectFeature events don't trigger.
I've considered several solutions including adding the drawFeature to my polygon layer and then moving the feature to the line layer when done, but it's still rendering under the polygons, I even played with the graphicZIndex on the "temporary" style for my stylemap on the polygon layer. to no avail (i did set the renderOptions zindexing to true on the polygon layer)
I may be approaching this from the wrong angle, so I'm open to suggestions. If there was a function available on the vector layer something like getFeatureByPosition(position), I could grab the position on sketchStarted, and sketchEnded events and query that, but so far I've been unable to find anything like that.
I'm not on my dev box at the moment in case anyone is wondering why no code. Wanted to post this from work, but the base network is having issues displaying the logon page (due to ssl I think)
So my solution required a few things. First I needed to upgrade from OL 2.10 to the latest 2.13.1. Mostly this was due to needing a new event that was added to 2.11 (I think or maybe 2.12) the event is "featureover" which can be caught at the map level and therefore will trigger on all layers, so I'm not fighting with Z-Index of the select. I removed the select control from the polygon layer as it was not needed.
var featureOverHandler = function(event){
if (event.feature.layer.id == polygonLayer.id) {
selectedPolygonId = event.feature.attributes.POLYGON_ID;
console.log("Selected Polygon Id: " + selectedPolygonId);
map.events.unregister('featureover',map,featureOverHandler);
map.events.register('featureout',map,featureOutHandler);
}
};
var featureOutHandler = function (event) {
if (event.feature.layer.id == polygonLayer.id) {
selectedPolygonId = 0;
console.log("Cleared Selected Polygon ID ");
map.events.unregister('featureout', map, featureOutHandler);
map.events.register('featureover', map, featureOverHandler);
}
};
These will catch the polygon that is currently hovered over. But then I add events to catch where the line starts and ends. Since as of 2.11, they changed the way the "sketchstarted" event works, you can non longer use that to capture which polygon the pointer was over when the first point was added. I used the point callback on the vector layer.
var vDrawOptions = {
callbacks: {
"point": function (p) {
if (p.parent.components.length == 2) {
console.log("First Point added");
startingPolygonId = selectedPolygonId;
}
}
}
}
vectorAddControl = new OpenLayers.Control.DrawFeature(vectorLayer, OpenLayers.Handler.Path,vDrawOptions);
however, the "skecthcomplete" can still be used to capture the ending point (and thus polygon)
function vSketchComplete(evt) {
endingPolygonId = selectedPolygonId;
};
vectorLayer.events.register('sketchcomplete', vectorLayer, vSketchComplete);
Hopefully this will help someone else, in a similar situation.

Polygon with multiple paths -- how to connect?

I am creating a polygon with multiple event handlers -- I can click-drag to draw freehand, hold shift and click to snap to roads, and do a normal click as well. Originally, I had one array that I pushed each of these points to. However, since the event handlers are unique, debugging an array that I pass everywhere and modify everywhere seems like bad form.
I've made it so that the polygon paths is an array of arrays of points. When I shift-click, it makes an array of points, when I click-drag, it makes an array of points, and then I push these to the array of arrays.
However, how do I connect these together? I am currently not able to connect the endpoints of one array to the start of the next. Because I'm trying to modularize my code, I don't want to have to pass the last point of an array to the event listener that makes the next array, because that defeats the purpose of having separate arrays.
The documentation is pretty thin on multiple paths for a polygon.
Here's what I have so far.
http://jsfiddle.net/skitterm/fn4g5/1/
Pseudocode:
array C = new Array();
addEventListener for click {
populate array A
C.push(A);
}
addEventListener for shift-click {
populate array B
C.push(B);
}
addEventListener for right-click {
create polygon {
paths: C
}
}
I can create a polygon by just shift-clicking, or by clicking, or clicking and dragging, but I can't make a polygon where one side is done by shift-clicking and the rest by normal clicks.
Any ideas?

Categories

Resources