I draw circles and polygons on Google maps using DrawingManager. I tried to remove a circle/polygon by using the below code.
selectedShape.setMap(null);
Here selectedShape is either circle or polygon.
But it just hides the shape from the view. Internally that shape present in DOM.
For example: I have drawn 2 circles and 2 polygons. Now the total of shapes is 4. If I remove a circle or polygon, the count is still 4. It's not removed from DOM. Just hidden.
I want to completely remove a selected shape out of many shapes.
Has you can read from the documentation:
https://developers.google.com/maps/documentation/javascript/shapes#circle_remove
The .setMap(null) does not delete the circle. It simply removes the circle from the map. If instead you wish to delete the circle, you should remove it from the map, and then set the circle itself to null.
Related
I have created polylines with LeafletJS to connect markers on an openstreetmap. However, when I add more than two points to my polyline function an unwanted yellow triangle appears between the points. (Image and code below)
Is this a known issue or is there a bug in my code? I've tried looking at documentation and a couple of examples and they do it the same way.
var firstpolyline = L.polyline([[53.095039, -7.921957],
[51.143901, -1.434145],
[52.915245, 6.869848]], {color: 'red'}).addTo(map);
Turns out you have to specify fill:'false', fillOpacity:'0' where the color is set to remove the yellow triangle (polygon fill). Now there are just the red lines.
The link to the documentation is here: https://leafletjs.com/reference-1.4.0.html#polyline
I have an extjs line chart and my markerconfig is circle but at some point I want to change it with a different marker shape like a line or a cross. How I can change a shape for a single marker dynamically and keep rest marker as they are ? I know that we could change attribute properties of a marker but here I want to change the shape.
I have a plot in D3 where I draw some circles and then some ellipses afterwards to show the median. I have a 1.5 second delay on my median, to try and draw it after the circles have appeared, but I still run into problems.
Here is a screenshot of an example: http://puu.sh/8csEK.png
The circle to the far right are behind it's median, the rest of the circles are all in front. When areas are crowded you cannot see the median anymore.
I have even tried using the following on transitions of my circles, but it's no use:
.each("end", <call function to draw ellipses>)
So my question is, how do i make sure that my ellipses are drawn on top of my circles?
I have a function that draws my ellipses and a function that draws my circles right now.
I'm assuming that you're using SVG to render your elements. In SVG, the display order is the order of drawing/appending to the DOM. That is, the element you append first is drawn at the back, the element you append last at the front. Child elements (e.g. something underneath a g) are drawn when their parent elements are drawn.
To make sure that groups of elements have the right order, it's usually easiest to add them to different SVG groups that are drawn in the right order. In code, this looks something like this.
var circles = svg.append("g");
var ellipses = svg.append("g");
// ...
ellipses.append(...); // this element appears in the front although it is drawn
// earlier because it is appended to the group appended last
circles.append(...); // this element appears behind the one appended to ellipses
Ok, here is my problem, I'll put a picture to illustrate it easier.
I need the user to draw some polygons, representing the coverage area.
The polygon needs to have fixed number of points (vertex) because it goes into a processing algorithm later, and it would be really slow if a polygon can contain a lot of points.
Anyway, in my example lets stick to hexagons (6 points).
The user need to be able to drag the polygon around and modify it, but not change the number of points.
I tried setting the editable: true option for the polygon, it works fine, but it gives me the situation shown on the picture. It creates a handle for every point, and another handle (semi-transparent) in the middle between each points. Now, if the user moves that semi-transparent point, it will add another point (vertex) to the polygon, and add additional two handles in the middle of newly created lines. That gives us a 7 point polygon.
The best option would be to remove those semi-transparent handles, so the user can only drag polygon points, and it that way he can't affect the total number of points.
Can I achieve this using google maps editable option?
Another way to achieve what you want is to forego the built-in edit-ability of the polygon and implement it yourself. This is more powerful and flexible.
First, don't make the polygon editable. Next, make a Marker for each corner of the polygon. Finally, make each marker draggable and an event listener on it's "drag" event to update the polygon.
Making the markers and adding the event listener:
for (var i=0; i<coordinates.length; i++){
marker_options.position = coordinates[i];
var point = new google.maps.Marker(marker_options);
google.maps.event.addListener(point, "drag", update_polygon_closure(polygon, i));
}
Where update_polygon_closure is defined as:
function update_polygon_closure(polygon, i){
return function(event){
polygon.getPath().setAt(i, event.latLng);
}
}
Full code is in a jsfiddle here: https://jsfiddle.net/3L140cg3/16/
Since no one seems to have a better solution, I'm marking my workaround as accepted, in case someone stumbles upon the same problem. Not very pretty, but gets the job done
The only solution I found so far is to hide the handles manually after the polygon has been drawn. The problem here is that the handles don't have any CSS class or id, so I have to hide all divs with opacity 0.5 (opacity of the handles). It works, but it is pretty risky, considering that something else might have the same opacity and doesn't need to be hidden.
// variables
var map, path, color;
polygon = new google.maps.Polygon({
paths: path,
strokeColor: color,
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: color,
fillOpacity: 0.10,
editable: true,
});
polygon.setMap(map);
setTimeout(function(){ map.find('div[style*=opacity: 0.5]').hide(); }, 50);
As a slight improvement to #zolakt's answer, you can both hide the midpoint divs on the polygon and add a mousedown event listener to track when a midpoint is clicked to prevent dragging and changing the polygon:
// hide the midpoints (note that users can still click where the hidden midpoint
// divs are and drag to edit the polygon
$('#multi_markers div[style*="opacity: 0.5"]').hide();
// get the paths for the current polygon
var octopusPaths = HotelLib.octopusPolygon.getPaths();
// track when a polygon midpoint is clicked on
google.maps.event.addListener(HotelLib.octopusPolygon, 'mousedown', function(mdEvent) {
// if a midpoint is clicked on, mdEvent.edge will have an integer value
if(mdEvent.edge || (mdEvent.edge == 0)){
// immediately reset the polygon to its former paths
// effectively disabling the drag to edit functionality
HotelLib.octopusPolygon.setPaths(octopusPaths);
// hide the midpoints again since re-setting the polygon paths
// will show the midpoints
$('#multi_markers div[style*="opacity: 0.5"]').hide();
}
});
I just created an alternative solution to this without having to fiddle around with setTimeout or the polyline creation. This is also a somewhat global solution, so you can basically drop it in any established program that uses Google Maps.
We'll use MutationObserver to observe when those midpoint nodes appear on the DOM and then instantly hide them. They should start appearing when something is set as editable.
Basically just put this anywhere after the map is initialized:
var editMidpointNodeObserver = new MutationObserver(function(list, observer)
{
if($('#mapwrapper div[style*="opacity: 0.5"]').parent('div[style*="cursor: pointer"]').length > 0)
{
$('#mapwrapper div[style*="opacity: 0.5"]').parent('div[style*="cursor: pointer"]').remove();
}
});
editMidpointNodeObserver.observe($('#mapwrapper')[0], { childList: true, subtree: true });
Change the #mapwrapper to whatever the id of your Google Maps wrapper element is. I am using jQuery here, so therefore the $('#mapwrapper')[0] to convert jQuery object to a native DOM object. Should work without jQuery as well, I am assuming you know how to convert this to vanilla js.
We also just straight up remove the nodes, so no need to worry about user being able to click invisible ones by accident or otherwise.
MutationObserver should be supported in all browsers: https://caniuse.com/mutationobserver
I have this map, which I show some red markers over and whenever a location is chosen from a list the current marker is painted blue and the map centers around it.
I achieve this by having 2 layers - one for the red markers which is drawn at the beginning and one which is redrawn whenever a point is chosen from the list.
I would like to define that the red marker layer will always appear above the blue marker layer. Effectively hiding the "current marker" indication. (The reason for this is complicated)
This link is to a page that works the way I don't want. The blue layer is on top of the red layer.
I tried to reverse the order by defining the graphicZIndex property for both the vector and in the layers.addFeature function.
I'm obviously doing something wrong and maybe someone can point me to what it is.
The way I define the z-axis:
currentPointLayer = new OpenLayers.Layer.Vector("Selected Point Layer", {
style : {
externalGraphic : 'marker-blue.png',
graphicHeight : 15,
graphicWidth : 15,
graphicZIndex : 1
},
rendererOptions: { zIndexing: true }
});
Again, I want to hide the blue marker behind the red markers layer.
You can either change the order of your layers as ilia choly stated.
Or, if you want to use zIndexing, you have to put all features into one layer, because zIndexing is only done within a single layer.
Have a look at this simple example about styling, that also uses zIndexing. It randomly creates some points in the map. If you zoom out, chances are good that two circles overlap and if you hoover over one, it will be highlighted and put on top.
So you want highlight a marker with different color whenever a point is selected? Managing it with 2 layers is really an overkill. You should be able to define a vector layer with style like this:
var currentPointLayer = new OpenLayers.Layer.Vector("Selected Point Layer", {
styleMap: new OpenLayers.StyleMap({
externalGraphic : '${markerUrl}',
pointRadius: 20
})});
map.addLayer(currentPointLayer);
Then you have to set attribute 'markerUrl' of every feature(i.e. feature.attributes.markerUrl) to 'marker-red.png' - that would be initial state of all features.
Then whenever feature is selected you change markerUrl attribute of selected feature to 'marker-blue.png' and(important) call
currentPointLayer.redraw();
Obviously you'll also have to set previously selected feature to 'marker-red.png' when new feature is selected.
in your init_map() function you're adding the red marker layer before the blue ones. Try switching them.
preparePointsOnMap(map, points); //red marker
if (!map.getCenter()) {
map_set_center(lon, lat, mZoom); //blue marker
}