简体   繁体   中英

Google Maps JS API - draw resizable circle with a static center

I have a requirement to draw a circle on google maps from a given static point. I tried to accomplish this by setting the circle setting center as follows, center: new google.maps.LatLng(-34.397, 150.644) after being drawn using the DrawingManager .

But the issue here is the circle starts to draw from the mouse click location and once done the circle snaps into the given lat and lng as demo-ed in the fiddle : http://jsfiddle.net/hjkety80/1/

What I require is, regardless of where I click the circle should start drawing from the static point given. I apologize if the description is vague and would glad to clarify more if required. Any help / reference on this matter is greatly appreciated.

Thanks

EDIT

Even if the circle center binds to a marker is also a good workaround if possible

I have created a working example for you. It's not using DrawingManager because it's not suitable for what you want to achieve, instead I update the radius of the circle programatically.

So in this example, when map is loaded, user is presented with a pointer cursor and when he presses the mouse button, he will start drawing a circle with a center in your static_position and the radius of the new circle is determined based on where he clicked.

The example includes geometry library (notice &libraries=geometry when fetching the Google maps API) and leverages it's google.maps.geometry.spherical.computeDistanceBetween() function to calculate distance in meters between your center and where user just clicked to get radius. If user doesn't immediately release the button and instead moves the mouse around, the circle will automatically adjust it's radius based on user movements with cursor. After the user releases the mouse, he can drag the map around and also circle stays editable for adjustments.

The example (Just press left mouse button on the map to start drawing. For better experience run in full page mode):

 var map = null; function initialize(){ var static_position = new google.maps.LatLng(-34.397, 150.644); var the_circle = null; map = new google.maps.Map(document.getElementById('map-canvas'), { center: static_position, zoom: 8, draggable: false, draggableCursor:'pointer' }); var mousemove_handler; google.maps.event.addListener(map, 'mouseup', function(e) { if(mousemove_handler) google.maps.event.removeListener(mousemove_handler); map.setOptions({draggable:true, draggableCursor:''}); //allow map dragging after the circle was already created the_circle.setOptions({clickable:true}); }); google.maps.event.addListenerOnce(map, 'mousedown', function (mousedown_event) { var radius = google.maps.geometry.spherical.computeDistanceBetween(static_position, mousedown_event.latLng); //get distance in meters between our static position and clicked position, which is the radius of the circle the_circle = createCircle(static_position, radius); //create circle with center in our static position and our radius mousemove_handler = google.maps.event.addListener(map, 'mousemove', function(mousemove_event) { //if after mousedown user starts dragging mouse, let's update the radius of the new circle var new_radius = google.maps.geometry.spherical.computeDistanceBetween(static_position, mousemove_event.latLng); console.log(new_radius); the_circle.setOptions({radius:new_radius}); }); }); } google.maps.event.addDomListener(window, 'load', initialize); function createCircle(center, radius) { var circle = new google.maps.Circle({ fillColor: '#ffffff', fillOpacity: .6, strokeWeight: 1, strokeColor: '#ff0000', draggable: false, editable: true, map: map, center: center, radius: radius, clickable:false }); google.maps.event.addListener(circle, 'radius_changed', function (event) { console.log('circle radius changed'); }); google.maps.event.addListener(circle, 'center_changed', function (event) { if(circle.getCenter().toString() !== center.toString()) circle.setCenter(center); }); return circle; } 
 <script src="//maps.google.com/maps/api/js?sensor=false&libraries=geometry&dummy=.js"></script> <body style="margin:0px; padding:0px;"> <div id="map-canvas" style="height:400px; width:500px;"></div> </body> 

One option (from my answer to this question: How to style editable circle controls in Google Maps ). DistanceWidget with a fixed center marker.

related questions:

code snippet:

 function init() { var mapDiv = document.getElementById('map-canvas'); var map = new google.maps.Map(mapDiv, { center: new google.maps.LatLng(-34.397, 150.644), zoom: 8, mapTypeId: google.maps.MapTypeId.ROADMAP }); var distanceWidget = new DistanceWidget(map); google.maps.event.addListener(distanceWidget, 'distance_changed', function() { displayInfo(distanceWidget); }); google.maps.event.addListener(distanceWidget, 'position_changed', function() { displayInfo(distanceWidget); }); } google.maps.event.addDomListener(window, 'load', init); /** * A distance widget that will display a circle that can be resized and will * provide the radius in km. * * @param {google.maps.Map} map The map on which to attach the distance widget. * * @constructor */ function DistanceWidget(map) { this.set('map', map); this.set('position', map.getCenter()); var marker = new google.maps.Marker({ draggable: false, icon: { url: "https://maps.gstatic.com/intl/en_us/mapfiles/markers2/measle_blue.png", size: new google.maps.Size(7, 7), anchor: new google.maps.Point(4, 4) }, title: 'Move me!' }); // Bind the marker map property to the DistanceWidget map property marker.bindTo('map', this); // Bind the marker position property to the DistanceWidget position // property marker.bindTo('position', this); // Create a new radius widget var radiusWidget = new RadiusWidget(); // Bind the radiusWidget map to the DistanceWidget map radiusWidget.bindTo('map', this); // Bind the radiusWidget center to the DistanceWidget position radiusWidget.bindTo('center', this, 'position'); // Bind to the radiusWidgets' distance property this.bindTo('distance', radiusWidget); // Bind to the radiusWidgets' bounds property this.bindTo('bounds', radiusWidget); } DistanceWidget.prototype = new google.maps.MVCObject(); /** * A radius widget that add a circle to a map and centers on a marker. * * @constructor */ function RadiusWidget() { var circle = new google.maps.Circle({ strokeWeight: 2 }); // Set the distance property value, default to 50km. this.set('distance', 50); // Bind the RadiusWidget bounds property to the circle bounds property. this.bindTo('bounds', circle); // Bind the circle center to the RadiusWidget center property circle.bindTo('center', this); // Bind the circle map to the RadiusWidget map circle.bindTo('map', this); // Bind the circle radius property to the RadiusWidget radius property circle.bindTo('radius', this); this.addSizer_(); } RadiusWidget.prototype = new google.maps.MVCObject(); /** * Update the radius when the distance has changed. */ RadiusWidget.prototype.distance_changed = function() { this.set('radius', this.get('distance') * 1000); }; /** * Add the sizer marker to the map. * * @private */ RadiusWidget.prototype.addSizer_ = function() { var sizer = new google.maps.Marker({ draggable: true, icon: { url: "https://maps.gstatic.com/intl/en_us/mapfiles/markers2/measle_blue.png", size: new google.maps.Size(7, 7), anchor: new google.maps.Point(4, 4) }, title: 'Drag me!' }); sizer.bindTo('map', this); sizer.bindTo('position', this, 'sizer_position'); var me = this; google.maps.event.addListener(sizer, 'drag', function() { // Set the circle distance (radius) me.setDistance(); }); }; /** * Update the center of the circle and position the sizer back on the line. * * Position is bound to the DistanceWidget so this is expected to change when * the position of the distance widget is changed. */ RadiusWidget.prototype.center_changed = function() { var bounds = this.get('bounds'); // Bounds might not always be set so check that it exists first. if (bounds) { var lng = bounds.getNorthEast().lng(); // Put the sizer at center, right on the circle. var position = new google.maps.LatLng(this.get('center').lat(), lng); this.set('sizer_position', position); } }; /** * Calculates the distance between two latlng locations in km. * @see http://www.movable-type.co.uk/scripts/latlong.html * * @param {google.maps.LatLng} p1 The first lat lng point. * @param {google.maps.LatLng} p2 The second lat lng point. * @return {number} The distance between the two points in km. * @private */ RadiusWidget.prototype.distanceBetweenPoints_ = function(p1, p2) { if (!p1 || !p2) { return 0; } var R = 6371; // Radius of the Earth in km 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; }; /** * Set the distance of the circle based on the position of the sizer. */ RadiusWidget.prototype.setDistance = function() { // As the sizer is being dragged, its position changes. Because the // RadiusWidget's sizer_position is bound to the sizer's position, it will // change as well. var pos = this.get('sizer_position'); var center = this.get('center'); var distance = this.distanceBetweenPoints_(center, pos); // Set the distance property for any objects that are bound to it this.set('distance', distance); }; function displayInfo(widget) { var info = document.getElementById('info'); info.innerHTML = 'Position: ' + widget.get('position').toUrlValue(3) + ', distance: ' + widget.get('distance').toFixed(3); } 
 html, body, #map-canvas { height: 100%; margin: 0px; padding: 0px } 
 <script src="https://maps.googleapis.com/maps/api/js?v=3&libraries=geometry"></script> <div id="info"></div> <div id="map-canvas"></div> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM