angular-ui / angular-google-maps

AngularJS directives for the Google Maps Javascript API
http://angular-ui.github.io/angular-google-maps
2.52k stars 1.07k forks source link

Set map bounds to circle bounds? (polyline, polygon, marker, circle) #449

Open ollietreend opened 10 years ago

ollietreend commented 10 years ago

Hi,

Intro I am currently building a search tool which will plot search results on a map, similar to your typical store locator. The user chooses a location (lat/lon) to search from and a radius. A database is queried for records which are within the specified radius of the user's location. These results are returned back to the browser to be plotted on a Google Map with angular-google-maps.

I am using <markers> directive to display the results on the map. I am also using a <circle> directive to show the search radius, setting the "center" property to be the user's chosen location, and the "radius" property to be the search radius.

The Problem I would like to have the map fit to the bounds of the circle. I understand that I can set the "bounds" property on the <google-map> directive. However I'm not sure how I can retrieve the bounds of the circle.

Potential Solution The google.maps.Circle class has the method getBounds() which returns a LatLngBounds object. However I'm not sure if I'm able to access the Circle object of the <circle> directive in order to retrieve its bounds.

Even if I am able to retrieve the bounds of the <circle>, I'm not sure how I would store that in a scope model in order to assign it to the <google-map>.

Do you know how I could achieve the above using angular-google-maps?

Also Tried I have also tried setting "fit" to true on the <markers> directive. This works as expected, however because it fits the map based on the returned results, it doesn't center the map based on the initial search location, nor does it fit to the radius circle.

I want to show the search location in the center, even if the results only exist within the southern region of the radius circle. Therefore this approach doesn't achieve what I'm looking for.

Thanks

nmccready commented 10 years ago

I'll get back to you.

nmccready commented 10 years ago

I could easily add in a control object to the Circle and for that matter many objects so you could get the reference directly. Lastly if there is an events attribute you can listen on the events for the circle and the circle's reference is passed as the first argument.

Also see here for fit on a circle. http://stackoverflow.com/questions/9768439/how-to-google-map-circles-fit-the-map

(HACK) Lastly if that is not to you liking you can just do a fit on for mock markers that are all the same radius at 0, 90, 180, 270 degrees from the circle and that should produce a fit result.

nmccready commented 10 years ago

Well crap none of these options ( events, options, or control) exist on Circle.

https://github.com/nlaplante/angular-google-maps/blob/1.1.0/src/coffee/directives/circle.coffee

This would need to be an improvement, which should not take long. I can do it or if you would like to do it let me know as it would save me time to do other bugs.

nmccready commented 10 years ago

Please responds as I will not move on this until I hear back.

ollietreend commented 10 years ago

Thanks for looking into this @nmccready.

I'm afraid pretty new to the world of GitHub & open source, and have yet to learn CoffeeScript (I'm primarily a PHP guy, but am starting to explore AngularJS).

If you could find the time to implement this feature, it would be much appreciated. I'll be sure to pick apart your changes to try and learn from them too.

Jerome2606 commented 9 years ago

So, is there any enhancements for this feature?

nmccready commented 9 years ago

No but I just added it to the milestone list. Feel free to have at it.

ollietreend commented 9 years ago

OP here. The original project is long gone now (as of about 1 year), and I'm trying to remember how I worked around this (in case it's of any help to @Jerome2606). IIRC I did something along the lines of – centre the map based on the initial search lat/lon, and then 'guesstimated' the appropriate zoom level based on the user's chosen search radius.

The map in question needed to be responsive down to mobile devices, so unfortunately that added another variable into the mix. I think I played around with changing the zoom level based on screen width (window.matchMedia came in handy here), but that made things rather complicated so I gave up on that and stuck with 1 zoom level per radius.

YMMV, but that's the solution I went with. (Again, IIRC.)

Of course a proper solution to this would be ideal, but this doesn't seem to be a highly requested feature.

Jerome2606 commented 9 years ago

I found a way to get Circle:

Use control attribute to circle directive and it's populate an object with function getCircle:

<ui-gmap-circle events="map.circle.events" control="map.circle.gObject"></ui-gmap-circle>

After you can simply do:

$scope.map.circle = {
    ...
    gObject: {},
                    events:{
                        radius_changed: function(){

                            $scope.map.control.getGMap().fitBounds($scope.map.circle.gObject.getCircle().getBounds());
                        }
                    }
};
ollietreend commented 9 years ago

@Jerome2606 perfect! It looks like the control object on the circle directive is new – that wasn't possible when I opened this ticket.

A 'fit' attribute on the circle directive would be the ideal solution, but the use of the control object is a nice workaround.

nmccready commented 9 years ago

Yeah I'll add fit since im in the midst of adding it to polyline, polygon, and marker.

dmackerman commented 8 years ago

I'm running into a similar issue, but what I'm trying to do is use fitBounds method on my map (or the bounds config) to fit the map bounds to an array of Circles that are being drawn with the ui-gmap-circle directive.

Is there anyway to access the raw, underlying google.maps.Circle object for each of these after they are drawn on the map? I can figure out the bounding logic quite easily if I had access to the getBounds() methods on the Circle's themselves.

Pretty standard layout here:

                  <ui-gmap-google-map
                      center="detail.map.center"
                      options="detail.mapOptions"
                      zoom="detail.map.zoom"
                      events="detail.mapEvents">
                      <ui-gmap-circle
                          id="zone.id"
                          ng-repeat="zone in detail.profile.zones"
                          center='zone.center'
                          radius='zone.radius'
                          fill='zone.fill'
                          stroke='zone.stroke'
                          name="zone.name"
                          clickable='true'
                          draggable='true'
                          editable='true'
                          visible='true'
                          events='detail.zoneEvents'
                          >
                      </ui-gmap-circle>
                  </ui-gmap-google-map>

I've tried inspecting the map instance itself and it doesn't appear that anything is being added in terms of seeing which shapes are present on the map.

Any ideas on how I can access the raw Circle instances? I'm not sure the control solution that @Jerome2606 suggested will work in this case for repeated elements.

Additionally, is there some hook or event I can listen for to see when the circles have actually been added to the map? I've tried using the addFeature event on map, but that doesn't seem to fire.

Thanks!

blaues0cke commented 8 years ago

After a lot of sturggle, I came up with a modified version of the solution from @Jerome2606, maybe it will help someone to workaround this:

<ui-gmap-circle
    ...
    events="mapObjects.circle.events"
>
</ui-gmap-circle>

+

events:{
    dragend: function(circle, eventName, scope) {
        circle.getMap().fitBounds(circle.getBounds());
    },
    radius_changed: function(circle, eventName, scope) {
        circle.getMap().fitBounds(circle.getBounds());
    }
}

This will automatically zoom to the cricles bounds.

For polygons, this should work for dragging:

<ui-gmap-polygon
    ...
    events="mapObjects.polygon.events"
>
</ui-gmap-polygon>

+

events:{
    dragend: function(polygon, eventName, scope) {
        var bounds = new google.maps.LatLngBounds();
        var paths = polygon.getPaths();
        var path;
        for (var i = 0; i < paths.getLength(); i++) {
            path = paths.getAt(i);
            for (var ii = 0; ii < path.getLength(); ii++) {
                bounds.extend(path.getAt(ii));
            }
        }

        polygon.getMap().fitBounds(bounds);
    }
}
ROJAHEMA commented 6 years ago

Hi,

Is there any feature for drawing curved /Arc polyline between two latitude and longitude. If so can you please give me some info...?