What I have :
As per Google suggestion we have used MVC object and the events DistanceWidget
& RadiusWidget
to display the radius while re-sizing the circle which is working fine for existing circle (circle drawn by DistanceWidget).
Fiddle Demo
What I need :
I need to show the radius of the circle while drawing a new circle. The event DistanceWidget
& RadiusWidget
are used only for existing circle (circle drawn by DistanceWidget
) not for new circle (user drawn circle by using DrawingManager tool).
Is it possible to show DistanceWidget for creating new circle?
Fiddle
What I have :
As per Google suggestion we have used MVC object and the events DistanceWidget
& RadiusWidget
to display the radius while re-sizing the circle which is working fine for existing circle (circle drawn by DistanceWidget).
Fiddle Demo
What I need :
I need to show the radius of the circle while drawing a new circle. The event DistanceWidget
& RadiusWidget
are used only for existing circle (circle drawn by DistanceWidget
) not for new circle (user drawn circle by using DrawingManager tool).
Is it possible to show DistanceWidget for creating new circle?
Fiddle
Share Improve this question edited Dec 15, 2017 at 16:50 halfer 20.4k19 gold badges108 silver badges201 bronze badges asked May 21, 2015 at 8:20 Vignesh Kumar AVignesh Kumar A 28.4k14 gold badges66 silver badges119 bronze badges 2-
4
There cannot be any Distance Widget or Radius Widget, there needs to be an area selected. The Drawing Manager only creates graphic images until the
circleplete
event, at which point a selectedArea (circle) object is instantiated. At that point you can analyze it's Radius / Distance even while they change with listeners. – Dave Alperovich Commented May 25, 2015 at 23:00 - The [circle] tag is deprecated (see its tag wiki). Please do not use. – user12205 Commented May 30, 2015 at 17:02
1 Answer
Reset to default 18 +50a nice challenge indeed. As @DaveAlperovich has mented, you can't use the DrawingManager
to retrieve this piece of information; While drawing, you don't have any access to the circle; You have to wait for the DrawingManager
to trigger the circleplete
event to get a reference to this circle.
Nevertheless, if you can't have a real manager, just fake it. See the snippet and the description right below.
var FakeDrawer = function(controlDiv, map) {
var self = this;
/* Initialization, some styling ... */
self._map = map;
self.initControls(controlDiv);
/* Setup the click event listener: drawingmode for the circle control */
google.maps.event.addDomListener(self._controls.circle, 'click', function() {
/* Ensure consistency */
self.reset();
/* Bind the drawing mode */
self._map.setOptions({
draggableCursor: "crosshair"
});
self._drawListener = self._map.addListener('mousedown', self.drawingMode(self));
});
/* Just reset things for the stop controls */
google.maps.event.addDomListener(self._controls.stop, 'click', function() {
self.reset();
});
};
FakeDrawer.prototype.drawingMode = function(self) {
return function(center) {
/* Let's freeze the map during drawing */
self._map.setOptions({
draggable: false
});
/* Create a new circle which will be manually scaled */
var circle = new google.maps.Circle({
fillColor: '#000',
fillOpacity: 0.3,
strokeWeight: 2,
clickable: false,
editable: false,
map: self._map,
radius: 1,
center: center.latLng,
zIndex: 1
});
/* Update the radius on each mouse move */
var onMouseMove = self._map.addListener('mousemove', function(border) {
var radius = 1000 * self.distanceBetweenPoints(center.latLng, border.latLng);
circle.setRadius(radius);
/* Here is the feature, know the radius while drawing */
google.maps.event.trigger(self, 'drawing_radius_changed', circle);
});
/* The user has finished its drawing */
google.maps.event.addListenerOnce(self._map, 'mouseup', function() {
/* Remove all listeners as they are no more required */
google.maps.event.removeListener(onMouseMove);
circle.setEditable(true);
/* Restore some options to keep a consistent behavior */
self.reset();
/* Notify listener with the final circle */
google.maps.event.trigger(self, 'circleplete', circle);
});
};
};
FakeDrawer.prototype.reset = function() {
var self = this;
self._map.setOptions({
draggableCursor: "",
draggable: "true"
});
/* Remove any applied listener */
if (self._drawListener) {
google.maps.event.removeListener(self._drawListener);
}
};
/* Create views and associated css */
FakeDrawer.prototype.initControls = function(controlDiv) {
var self = this;
function createControlUI(title, image) {
var controlUI = document.createElement('div');
controlUI.style.backgroundColor = '#fff';
controlUI.style.border = '1px solid rgba(0, 0, 0, .15)';
controlUI.style.boxShadow = '1 4px -1px rgba(0, 0, 0, .3)';
controlUI.style.marginTop = '10px';
controlUI.style.textAlign = 'center';
controlUI.style.width = '25px';
controlUI.style.height = '25px';
controlUI.style.display = 'inline-block';
controlUI.title = title;
if (image == "circle") {
controlUI.style.borderLeft = "none";
}
var controlImgWrapper = document.createElement('div');
controlImgWrapper.style.width = '16px';
controlImgWrapper.style.height = '16px';
controlImgWrapper.style.overflow = 'hidden';
controlImgWrapper.style.display = 'inline-block';
controlImgWrapper.style.marginTop = '4px';
controlUI.appendChild(controlImgWrapper);
var imageOffset = {
"circle": 0,
"openhand": -9 * 16
}[image];
var controlImg = document.createElement('img');
controlImg.src = 'https://maps.gstatic./mapfiles/drawing.png';
controlImg.style.marginTop = imageOffset + "px";
controlImgWrapper.appendChild(controlImg);
var focusBackground = function() {
controlUI.style.backgroundColor = '#eee';
};
var unfocusBackground = function() {
controlUI.style.backgroundColor = "#fff";
};
controlImg.addEventListener('mouseenter', focusBackground);
controlImg.addEventListener('mouseout', unfocusBackground);
controlUI.addEventListener('mouseenter', focusBackground);
controlUI.addEventListener('mouseout', unfocusBackground);
return controlUI;
}
self._controls = {
circle: createControlUI("Draw a circle", "circle"),
stop: createControlUI("Stop drawing", "openhand"),
};
controlDiv.appendChild(self._controls.stop);
controlDiv.appendChild(self._controls.circle);
};
FakeDrawer.prototype.distanceBetweenPoints = function(p1, p2) {
if (!p1 || !p2) {
return 0;
}
var R = 6371;
var dLat = (p2.lat() - p1.lat()) * Math.PI / 180;
var dLon = (p2.lng() - p1.lng()) * Math.PI / 180;
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(p1.lat() * Math.PI / 180) * Math.cos(p2.lat() * Math.PI / 180) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
return d;
};
function InitializeMap() {
var latlng = new google.maps.LatLng(29.760193, -95.36939);
var myOptions = {
zoom: 12,
center: latlng,
zoomControl: true,
mapTypeId: google.maps.MapTypeId.ROADMAP,
disableDefaultUI: true
};
var map = new google.maps.Map(document.getElementById("map"), myOptions);
/* Add a custom control */
var fakeDrawerDiv = document.createElement('div');
var fakeDrawer = new FakeDrawer(fakeDrawerDiv, map);
fakeDrawerDiv.index = 1;
map.controls[google.maps.ControlPosition.TOP_CENTER].push(fakeDrawerDiv);
var updateInfo = function(circle) {
document.getElementById("info").innerHTML = "Radius: " + circle.getRadius();
};
google.maps.event.addListener(fakeDrawer, 'drawing_radius_changed', updateInfo);
google.maps.event.addListener(fakeDrawer, 'circleplete', function(circle) {
google.maps.event.addListener(circle, 'radius_changed', function() {
updateInfo(circle);
});
});
}
google.maps.event.addDomListener(window, 'load', InitializeMap);
html,
body {
height: 100%;
margin: 0px;
padding: 0px
}
#map {
height: 80%;
width: 100%;
}
<script src="https://maps.googleapis./maps/api/js?v=3&libraries=drawing&ext=.js"></script>
<div id="map"></div>
<div id="info"></div>
Step 1: Create a custom control
Somewhere in the file or as an external library:
var FakeDrawer = function (controlDiv, map) {
var self = this;
/* Initialization, some styling ... */
self._map = map;
self.initControls(controlDiv);
};
FakeDrawer.prototype.initControls(controlDiv) {
var self = this;
function createControlUI (title, image) {
var controlUI = document.createElement('div');
/* ... See the snippet for details .. just some styling */
return controlUI;
}
self._controls = {
circle: createControlUI("Draw a circle", "circle"),
stop: createControlUI("Stop drawing", "openhand"),
};
controlDiv.appendChild(self._controls.stop);
controlDiv.appendChild(self._controls.circle);
};
Step 2: Add some sugars
This are functions that we may use; Highly inspired from your JsFiddle :)
A reset method to recover a consistent state when needed:
FakeDrawer.prototype.reset = function () {
var self = this;
self._map.setOptions({
draggableCursor: "",
draggable: "true"
});
/* Remove any applied listener */
if (self._drawListener) { google.maps.event.removeListener(self._drawListener) ; }
};
And, a distance puter:
FakeDrawer.prototype.distanceBetweenPoints = function (p1, p2) {
if (!p1 || !p2) {
return 0;
}
var R = 6371;
var dLat = (p2.lat() - p1.lat()) * Math.PI / 180;
var dLon = (p2.lng() - p1.lng()) * Math.PI / 180;
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(p1.lat() * Math.PI / 180) * Math.cos(p2.lat() * Math.PI / 180) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
return d;
};
Step 3: Create your own drawing mode
Now that we have some controls, we have to define their behavior. The stop
control is straightforward; Let's have a look to the circle
control.
FakeDrawer.prototype.drawingMode = function (self) {
return function (center) {
/* Let's freeze the map during drawing */
self._map.setOptions({draggable: false});
/* Create a new circle which will be manually scaled */
var circle = new google.maps.Circle({
fillColor: '#000',
fillOpacity: 0.3,
strokeWeight: 2,
clickable: false,
editable: false,
map: self._map,
radius: 1,
center: center.latLng,
zIndex: 1
});
/* Update the radius on each mouse move */
var onMouseMove = self._map.addListener('mousemove', function (border) {
var radius = 1000 * self.distanceBetweenPoints(center.latLng, border.latLng);
circle.setRadius(radius);
/* Here is the feature, know the radius while drawing */
google.maps.event.trigger(self, 'drawing_radius_changed', circle);
});
/* The user has finished its drawing */
google.maps.event.addListenerOnce(self._map, 'mouseup', function () {
/* Remove all listeners as they are no more required */
google.maps.event.removeListener(onMouseMove);
circle.setEditable(true);
/* Restore some options to keep a consistent behavior */
self.reset();
/* Notify listener with the final circle */
google.maps.event.trigger(self, 'circleplete', circle);
});
};
};
Step 4: Bind controls
Now that everything is okay, let's add some listeners to the initial version of the constructor so that each control has a corresponding action when clicked.
var FakeDrawer = function (controlDiv, map) {
var self = this;
/* Initialization, some styling ... */
self._map = map;
self.initControls(controlDiv);
/* Setup the click event listeners: drawingmode */
google.maps.event.addDomListener(self._controls.circle, 'click', function() {
/* Ensure consistency */
self.reset();
/* Only drawingmode */
self._map.setOptions({draggableCursor: "crosshair"});
self._drawListener = self._map.addListener('mousedown', self.drawingMode(self));
});
google.maps.event.addDomListener(self._controls.stop, 'click', function () {
self.reset();
});
};
Step 5: Use it!
Assuming that your map has been initialized correctly.
Inside your map init function:
var fakeDrawerDiv = document.createElement('div');
var fakeDrawer = new FakeDrawer(fakeDrawerDiv, map);
fakeDrawerDiv.index = 1;
map.controls[google.maps.ControlPosition.TOP_CENTER].push(fakeDrawerDiv);
var updateInfo = function (circle) {
document.getElementById("info").innerHTML = "Radius: " + circle.getRadius();
};
google.maps.event.addListener(fakeDrawer, 'drawing_radius_changed', updateInfo);
google.maps.event.addListener(fakeDrawer, 'circleplete', function (circle) {
google.maps.event.addListener(circle, 'radius_changed', function () {
updateInfo(circle);
});
});
Enjoy, hope it will help.