I have recently integrated drawing functions in a website. But I want to be able to clear the map without having to recharge the whole page.
I followed this great example about Custom Controls in order to add a well-integrated button that react on click.
Also, I read the DrawingManager documentation, there is several options you can play with, but nothing about clearing a map.
Based on the Custom Controls example, I would like to do something like that:
controlUI.addEventListener('click', function() {
clearMap();
});
But I don't know how to get an array of drawn objects in order to erase them.
If you can't find an array of drawn objects, you can at least create one.
At the bottom of the link that you provided, there is something helpful about Drawing Events.
So if you want to clear the map with a custom control, the idea is to hold a list of these objects since they are created. For example, with circles and rectangles:
First hold a global array of desired objects (here, circles and rectangles):
var circles = [];
var rectangles = [];
Then initialize your map (it needs to be done BEFORE adding the drawing API):
function initMap(){
// Your initializations
initDrawings();
}
Then, init your DrawingManager as desire and add event listeners. Don't forget to add the control button:
function initDrawings(){
drawingManager = new google.maps.drawing.DrawingManager({
drawingMode: null,
drawingControl: true,
drawingControlOptions: {
position: google.maps.ControlPosition.BOTTOM_CENTER,
drawingModes: ['circle', 'rectangle']
},
markerOptions: {icon: '/path/to/icon.png'},
circleOptions: {
fillColor: '#ffff00',
fillOpacity: 0.25,
strokeWeight: 3,
zIndex: 1
}
});
google.maps.event.addListener(drawingManager, 'circlecomplete', updateDrawings);
google.maps.event.addListener(drawingManager, 'rectanglecomplete', updateDrawings);
drawingManager.setMap(map);
var eraseControlDiv = document.createElement('div');
var eraseControl = new EraseButton(eraseControlDiv,map);
eraseControlDiv.index = 1;
map.controls[google.maps.ControlPosition.TOP_CENTER].push(eraseControlDiv);
}
function EraseButton(controlDiv, map) {
var controlUI = document.createElement('div');
controlUI.style.backgroundColor = '#fff';
controlUI.style.border = '2px solid #fff';
controlUI.style.borderRadius = '3px';
controlUI.style.boxShadow = '0 2px 6px rgba(0,0,0,.3)';
controlUI.style.cursor = 'pointer';
controlUI.style.marginBottom = '20px';
controlUI.style.textAlign = 'center';
controlUI.title = 'Click to clear map';
controlDiv.appendChild(controlUI);
var controlText = document.createElement('div');
controlText.style.color = 'rgb(25,25,25)';
controlText.style.fontFamily = 'Roboto,Arial,sans-serif';
controlText.style.fontSize = '12px';
controlText.style.lineHeight = '38px';
controlText.style.paddingLeft = '5px';
controlText.style.paddingRight = '5px';
controlText.innerHTML = 'Empty Map';
controlUI.appendChild(controlText);
controlUI.addEventListener('click', emptyMap);
}
Here is the function that check the shape of the object that triggered a shapecomplete event. It just adds an element in the corresponding array.
function updateDrawings(shape){
if(shape == null) return;
if(shape instanceof google.maps.Circle){
circles.push(shape);
}
else if (shape instanceof google.maps.Rectangle) {
rectangles.push(shape);
}
}
And here, we set these elements out of the map, and we clear each list.
function emptyMap(){
circles.forEach(function(e){
e.setMap(null);
});
rectangles.forEach(function(e){
e.setMap(null);
});
circles = [];
rectangles = [];
}
Related
In my rails application I have implemented a google maps using the polygon drawing tool. I have been able to add coordinates and save these to my database successfully.
The problem i'm having is when a user wants to edit and save any changes made to the polygon shape. How do i implement this function? My best guess is to use a conditional to see if the database has any saved coordinates, if so, load them in a listener?
HTML
<div style='width: 100%;'>
<%= hidden_field_tag(:map_coords, value = nil, html_options = {id: 'propertyCoordinates'}) %>
Javascript
function initMap() {
var map = new google.maps.Map(document.getElementById("map"), {
center: { lat: -40.6892, lng: 74.0445 },
zoom: 8,
mapTypeId: google.maps.MapTypeId.HYBRID,
});
var polyOptions = {
strokeWeight: 0,
fillOpacity: 0.45,
strokeColor: "#FF0000",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#FF0000",
fillOpacity: 0.35
};
// loads databased saved coordinates
var propertyCoords = [<%= #property.coordinates %>];
var points = [];
for (var i = 0; i < propertyCoords.length; i++) {
points.push({
lat: propertyCoords[i][0],
lng: propertyCoords[i][1]
});
}
var drawingManager = new google.maps.drawing.DrawingManager({
drawingMode: google.maps.drawing.OverlayType.POLYGON,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_CENTER,
drawingModes: ["polygon"]
},
polylineOptions: {
editable: true,
draggable: true
},
rectangleOptions: polyOptions,
circleOptions: polyOptions,
polygonOptions: polyOptions,
map: map
});
if (typeof points !== 'undefined') {
// My guess is to use a conditional statement to check if the map has any coordinates saved?
} else {
google.maps.event.addListener(drawingManager, 'overlaycomplete', function (e) {
if (e.type !== google.maps.drawing.OverlayType.MARKER) {
// Switch back to non-drawing mode after drawing a shape.
drawingManager.setDrawingMode(null);
// Add an event listener that selects the newly-drawn shape when the user
// mouses down on it.
var newShape = e.overlay;
newShape.type = e.type;
google.maps.event.addListener(newShape, 'click', function (e) {
if (e.vertex !== undefined) {
if (newShape.type === google.maps.drawing.OverlayType.POLYGON) {
var path = newShape.getPaths().getAt(e.path);
path.removeAt(e.vertex);
if (path.length < 3) {
newShape.setMap(null);
}
}
}
setSelection(newShape);
});
}
var coords = e.overlay.getPath().getArray();
document.getElementById("propertyCoordinates").value = coords;
});
}
} // END function initMap()
If I understand correctly, what you're looking for is the polygon editing functionality. My stackblitz example goes something like this:
Draw a polygon if you already have user-saved coordinates. Then fit the map bounds to the poly's bounds. For this you'll probably need a getBounds polyfill.
Make the polygon editable so you can listen to its points' changes. Check the function enableCoordinatesChangedEvent.
Listen to the changes & extract the new polygon points. Look for function extractPolygonPoints.
Then proceed with your business logic.
FYI you'll need to put your own API key at the bottom of the stackblitz index.html. Look for YOUR_KEY.
This question already has answers here:
How to get point coordinates of a modified drawingManager shape? GoogleMaps API v3
(2 answers)
Closed 9 years ago.
I have an example how to write polygon on google map:
http://jsbin.com/quzed/1/edit
So here is the code:
var drawingManager;
var selectedShape;
var colors = ['#1E90FF', '#FF1493', '#32CD32', '#FF8C00', '#4B0082'];
var selectedColor;
var colorButtons = {};
function clearSelection() {
if (selectedShape) {
selectedShape.setEditable(false);
selectedShape = null;
}
}
function setSelection(shape) {
clearSelection();
selectedShape = shape;
shape.setEditable(true);
selectColor(shape.get('fillColor') || shape.get('strokeColor'));
}
function deleteSelectedShape() {
if (selectedShape) {
selectedShape.setMap(null);
}
}
function selectColor(color) {
selectedColor = color;
for (var i = 0; i < colors.length; ++i) {
var currColor = colors[i];
colorButtons[currColor].style.border = currColor == color ? '2px solid #789' : '2px solid #fff';
}
// Retrieves the current options from the drawing manager and replaces the
// stroke or fill color as appropriate.
var polylineOptions = drawingManager.get('polylineOptions');
polylineOptions.strokeColor = color;
drawingManager.set('polylineOptions', polylineOptions);
var rectangleOptions = drawingManager.get('rectangleOptions');
rectangleOptions.fillColor = color;
drawingManager.set('rectangleOptions', rectangleOptions);
var circleOptions = drawingManager.get('circleOptions');
circleOptions.fillColor = color;
drawingManager.set('circleOptions', circleOptions);
var polygonOptions = drawingManager.get('polygonOptions');
polygonOptions.fillColor = color;
drawingManager.set('polygonOptions', polygonOptions);
}
function setSelectedShapeColor(color) {
if (selectedShape) {
if (selectedShape.type == google.maps.drawing.OverlayType.POLYLINE) {
selectedShape.set('strokeColor', color);
} else {
selectedShape.set('fillColor', color);
}
}
}
function makeColorButton(color) {
var button = document.createElement('span');
button.className = 'color-button';
button.style.backgroundColor = color;
google.maps.event.addDomListener(button, 'click', function() {
selectColor(color);
setSelectedShapeColor(color);
});
return button;
}
function buildColorPalette() {
var colorPalette = document.getElementById('color-palette');
for (var i = 0; i < colors.length; ++i) {
var currColor = colors[i];
var colorButton = makeColorButton(currColor);
colorPalette.appendChild(colorButton);
colorButtons[currColor] = colorButton;
}
selectColor(colors[0]);
}
function initialize() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 10,
center: new google.maps.LatLng(22.344, 114.048),
mapTypeId: google.maps.MapTypeId.ROADMAP,
disableDefaultUI: true,
zoomControl: true
});
var polyOptions = {
strokeWeight: 0,
fillOpacity: 0.45,
editable: true
};
// Creates a drawing manager attached to the map that allows the user to draw
// markers, lines, and shapes.
drawingManager = new google.maps.drawing.DrawingManager({
drawingMode: google.maps.drawing.OverlayType.POLYGON,
markerOptions: {
draggable: true
},
polylineOptions: {
editable: true
},
rectangleOptions: polyOptions,
circleOptions: polyOptions,
polygonOptions: polyOptions,
map: map
});
google.maps.event.addListener(drawingManager, 'overlaycomplete', function(e) {
if (e.type != google.maps.drawing.OverlayType.MARKER) {
// Switch back to non-drawing mode after drawing a shape.
drawingManager.setDrawingMode(null);
// Add an event listener that selects the newly-drawn shape when the user
// mouses down on it.
var newShape = e.overlay;
newShape.type = e.type;
google.maps.event.addListener(newShape, 'click', function() {
setSelection(newShape);
});
setSelection(newShape);
}
});
// Clear the current selection when the drawing mode is changed, or when the
// map is clicked.
google.maps.event.addListener(drawingManager, 'drawingmode_changed', clearSelection);
google.maps.event.addListener(map, 'click', clearSelection);
google.maps.event.addDomListener(document.getElementById('delete-button'), 'click', deleteSelectedShape);
buildColorPalette();
}
google.maps.event.addDomListener(window, 'load', initialize);
How i can see what are coordinates from drawen polygon, and how to save it (etc. mysql) also how to write polygon if you know coordinates ?
Can sombody help me? I lose in this code? Where is coordinates from user action (user drawing polygon)?
ETC. if I have 3 coordinates (44.5, 55.6) (45.7, 56.87) (46.7, 46.8) how I can draw it here?
And if I draw some polygon on example, how I can see coordinates for polygon?
Look at the example on google's site.
Given you already have that polygon, you can get it's path coordinates with the getPath method.
console.log(bermudaTriangle.getPath() );
There's also a setPath method which would accept an array of coordinates (or an MVCArray for that matter).
Polygons can also have interior rings (as in a donut), but you should get accustomed to simple convex polygons before trying that.
Regarding the question as to "how to save a drawn polygon", Google Maps API provides static functions to encode polygon and polyline paths so you can persist the objects as text.
There are other libraries such as Wicket that can take a Google Maps Object and encode it with a standard WKT format, that is natively understood by geometrical enabled databases.
I have a map I exported from tilemill, made a mapbox map and threw some points on it. The view starts off looking at the US, with a marker somewhere in the middle. If I pan left until the next time I see the US, the markers are gone. Here's the code minus the geoJson data.
var map = L.mapbox.map('map', 'natecraft1.xdan61or').setView([-102, 39], 4);
map.markerLayer.on('layeradd', function(e) {
var marker = e.layer;
var feature = marker.feature;
var image = feature.properties.images
// var img = images
// Create custom popup content
var popupContent = '<img class="pics" src="' + image + '" />'
marker.bindPopup(popupContent,{
closeButton: false,
minWidth: 320,
offset: [180, 20]
});
});
map.markerLayer.setGeoJSON(geoJson);
map.markerLayer.on('click', function(e) {
e.layer.openPopup();
var lat = e.layer.getLatLng().lat;
var lng = e.layer.getLatLng().lng;
map.panTo([lat+5, lng+5], 2);
});
map.markerLayer.on('', function(e) {
e.layer.closePopup();
});
Your tilelayer is wrapping around the globe for coordinates outside of the (-180, 180) range. Best option is to set the maxBounds option so users don't pan outside of that map and just get bounced back.
var map = L.mapbox.map('map', 'examples.map-9ijuk24y').setView([0,0], 2);
var layer = L.mapbox.tileLayer('examples.map-9ijuk24y', {
noWrap: true,
minZoom: 3
}).addTo(map);
map.options.maxBounds = map.getBounds();
Here's a live demo of what that would look like
I have seen an impressive mapping example on http://jerusalem.com/map#!/tour/the_way_of_the_cross/location/abu_jaafar, Does anybody how a similar animation on the drawn path of the points can done using openlayers?
The following fiddle shows the linestrings http://jsfiddle.net/pwuVz/58/ but I need is to be able to animate the line string itself so that the string is not directly drawn.
var map = new OpenLayers.Map( 'map', {theme:null,
controls:[new OpenLayers.Control.Navigation()]} );
layer = new OpenLayers.Layer.WMS( "OpenLayers WMS",
"http://vmap0.tiles.osgeo.org/wms/vmap0",
{layers: 'basic'} );
map.addLayer(layer);
map.setCenter([3, 49], 5);
var startPt=new OpenLayers.Geometry.Point( 2, 45);
var endPt=new OpenLayers.Geometry.Point(7,55);
//make the line:
var line=new OpenLayers.Geometry.LineString([startPt, endPt]);
//style
var style={strokeColor:"#0500bd", strokeWidth:15, strokeOpacity: 0.5, strokeColor: '#0000ff'};
//make vector
var fea=new OpenLayers.Feature.Vector(line, {}, style);
//make vectorLayer
var vec= new OpenLayers.Layer.Vector();
//add the feature
vec.addFeatures([fea]);
//add to map
map.addLayer(vec);
setTimeout(function() {
var startPt=new OpenLayers.Geometry.Point( 7, 55);
var endPt=new OpenLayers.Geometry.Point(13,52);
//make the line:
var line=new OpenLayers.Geometry.LineString([startPt, endPt]);
//style
var style={strokeColor:"#0500bd", strokeWidth:15, strokeOpacity: 0.5, strokeColor: '#0000ff'};
//make vector
var fea=new OpenLayers.Feature.Vector(line, {}, style);
//make vectorLayer
var vec= new OpenLayers.Layer.Vector();
//add the feature
vec.addFeatures([fea]);
//add to map
map.addLayer(vec);
}, 2000);
You can animate it by drawing only one part of the line at a time. Here is one way you could do it:
function drawAnimatedLine(startPt, endPt, style, steps, time, fn) {
var directionX = (endPt.x - startPt.x) / steps;
var directionY = (endPt.y - startPt.y) / steps;
var i = 0;
var prevLayer;
var ivlDraw = setInterval(function () {
if (i > steps) {
clearInterval(ivlDraw);
if (fn) fn();
return;
}
var newEndPt = new OpenLayers.Geometry.Point(startPt.x + i * directionX, startPt.y + i * directionY);
var line = new OpenLayers.Geometry.LineString([startPt, newEndPt]);
var fea = new OpenLayers.Feature.Vector(line, {}, style);
var vec = new OpenLayers.Layer.Vector();
vec.addFeatures([fea]);
map.addLayer(vec);
if(prevLayer) map.removeLayer(prevLayer);
prevLayer = vec;
i++;
}, time / steps);
}
The time argument specifies how long you want the animation to last (in milliseconds), and the steps specifies how many steps you want to divide the animation into. fn is a callback that will be executed when the animation is complete.
Here is a jsFiddle demo that demonstrates this.
I'd like to draw an animated (geodesic) polyline in google maps, a bit like this: http://planefinder.net/route/SFO/
I found many tutorials on how to animate a symbol along a polyline, but nothing about animating the polyline itself from the source to the destination.
Any hints ? Where should I start ?
Any help is really appreciated.
I've had some success with the following:
var departure = new google.maps.LatLng(dept_lat, dept_lng); //Set to whatever lat/lng you need for your departure location
var arrival = new google.maps.LatLng(arr_lat, arr_lng); //Set to whatever lat/lng you need for your arrival location
var line = new google.maps.Polyline({
path: [departure, departure],
strokeColor: "#FF0000",
strokeOpacity: 1,
strokeWeight: 1,
geodesic: true, //set to false if you want straight line instead of arc
map: map,
});
var step = 0;
var numSteps = 250; //Change this to set animation resolution
var timePerStep = 5; //Change this to alter animation speed
var interval = setInterval(function() {
step += 1;
if (step > numSteps) {
clearInterval(interval);
} else {
var are_we_there_yet = google.maps.geometry.spherical.interpolate(departure,arrival,step/numSteps);
line.setPath([departure, are_we_there_yet]);
}
}, timePerStep);
This is basically using an interval to redraw the path. At each step, the visible, animated path makes up a larger percentage of the total path from departure to arrival until finally the arrival location is reached.