dylanfprice / angular-gm

AngularJS Google Maps Directives
MIT License
197 stars 47 forks source link

Lots of maps #22

Closed igler closed 11 years ago

igler commented 11 years ago

Hi, thanx for this great module! I use a lot of maps (around 54) in an accordion. The code that I use is:

<gm-map gm-map-id="location.identifier" gm-center="center" 
        gm-zoom="zoom" gm-map-options="mapOptions.map" gm-bounds="bounds" 
        gm-map-type-id="mapTypeId" class="inner_map">
</gm-map>

Loading in version 0.3.0 is a little bit faster than 0.2.0 which I have noticed this morning. But loading takes its time (15-20sec.) and I wonder if I can accelerate it by maybe one hidden map which is in the background an is referenced and shown in every specific location. This would be sufficient, too.

What I have noticed when I skim through the generated HTML-code is, that the 'gm-map-id' doesn't gets replaced by the corresponding ID. The resulting code is:

<div gm-map-id="location.emonsIdentifier" gm-center="center" ...

Is this desired?

dylanfprice commented 11 years ago

If you look at the inner div, that's where your actual map is going to be. E.g. from one of the plunker examples:

<div gm-map-id="'simpleMap'" gm-center="center" gm-zoom="zoom" class="map">
  <div id="simpleMap" style="width: 100%; height: 100%; position: relative; background-color: rgb(229, 227, 223); overflow: hidden;"> 
  <!-- this is inside the actual google maps dom node -->
  ...
  </div>
  <div ng-transclude=""></div>
</div>

A Google Map lives in the DOM so even in the pure Google Maps API I'm pretty sure there's no way to show the same map in multiple places. If showing the same map is sufficient for you, maybe the static maps API is what you're after? I'm having a hard time envisioning a situation where you need 54 separate maps.

Edit: Ok I think I understand now that what you want is to be able to show a map in 54 different places, but only ever showing one map at a time. You're only allowed one DOM node corresponding to each Google Map at a time, so your strategy here is going to involve injecting the gm-map element where you need it, when you need it. You can accomplish this with a partial and something like ng-include or ng-view. Let me know if that makes sense.

igler commented 11 years ago

Yes, your ng-include or ng-view suggestion would make sense. I could then include the big map showing all locations by some popup-overlay and show this map in every location. As I want to have draggable marker in every location where the user can drag the marker to the correct position I also need to focus the map inside the locations. I will see how I can do so.

Static maps would be a fallback solution if the upper one won't work. Let you know...

igler commented 11 years ago

I have made some progress when using the <div ui-view></div> element from angular-ui-router (https://github.com/angular-ui/ui-router). There you can define nested views. I could manage that the map-loading is much faster and I only show the map when the corresponding accordion-element is opened:

<label class="control-label">{{'MAP' | translate}}
<div class="controls">
    <div ng-show="selectedLocationId === location.id">
        <div ui-view>
</div> </div>

In the background there is a map.html page where the gmap-element is included:

<gm-map gm-map-id="'locationMap_'+location.id" gm-center="center" gm-zoom="zoom" gm-map-options="mapOptions.map" class="inner_location_map"></gm-map>

I had the problem BTW that when I use a constant in gm-map-id the map isn't rendered. I have to make it unique by adding the id of the location to the attribute-string. Don't know why!?

The second problem is, that the map is rendered correct and a moment later a fragment of another part of the map is overlaid on top of the existing map. The fragment is moved upward and left. If I drag the map, then the old map in the background is becoming grey and I only see the fragment from then on. If I try to drag the fragment then it jumps back to its position. Very strange. If I use the the outside the accordion-group, then then there is no fragment. Any ideas how I can debug this to find the culprit? Tried Chrome with its developer-mode but there is no css element which has the size of the fragment.

igler commented 11 years ago

I have made some experiments and noticed, that it only happens when wrapped with ng-show:

<div ng-show="selectedLocationId === location.id">
    <gm-map gm-map-id="'locationMap_'+location.id" gm-center="center" gm-zoom="zoom" gm-map-options="mapOptions.map" class="inner_location_map"></gm-map>
</div>

If I remove the div-tag containing the ng-show attribute, then the map is display correct without any fragments. As I rely on the ng-show for faster loading, how can this issue be solved?

dylanfprice commented 11 years ago

Try making a plunker or jsfiddle that demonstrates your issue and I'll see if I can play around with it a little. I'm not familiar with ui-router and ui-view so it's hard for me to say what's going on.

igler commented 11 years ago

I have created a plunker at http://plnkr.co/edit/34WN7dmCvP3QlksAsLU1?p=preview If the error does not show up, then try to zoom in and out on one of the maps. Then the fragment should be visible.

I have found out that AngularJS in version 1.0.7 (I have uncommented the line) does not have this kind of issue. Version 1.2.0-rc.2 is responsible for it. What do you think, bug report to AngularJS Dev Team?

phil-travelbytes commented 11 years ago

I think this might have something to do with the Google Maps Render Problem expressed here http://stackoverflow.com/questions/1746608/google-maps-not-rendering-completely-on-page

I suspect it has something to do with injecting this in as dynamic. The last comment on this question reports a forced resize of the map may fix the issue.

I am dealing with a similar symptom with the map; as its coming from a directive which chooses a partial to load. If you find a tidy solution please let me know too. I will likewise. thanks

dylanfprice commented 11 years ago

Hey Michael,

I made a fork of your plunker: http://plnkr.co/edit/u2vlITfYHj7QbogfOWMd?p=preview Is that what you wanted?

Dylan

igler commented 11 years ago

Hi Dylan, switching to 'ng-if' solved my issues. Thanx a lot!!!

phil-travelbytes commented 11 years ago

Hi,

ngIf (ng-if) I think creates a new map instance when the ngIf statement is true each time. So if you need to create the map once, and or want to maintain it the state between hide/show - you can't us this technique, and its a bit of a circumvent of the problem.

Here is one possible way of doing it (which I used) in a controller. I used the double timeout because I was doing it in a dynamic directive that chose its own view template at time of instantiation.

        $scope.displayMap = false;
        $scope.first = true;

        $scope.toggleDisplayMap = function(){
            $scope.displayMap = ! $scope.displayMap;
            if( $scope.displayMap ){
                $timeout(function () {
                    $timeout(function () {
                        // This code will run after
                        // templateUrl has been loaded, cloned
                        // and transformed by directives.
                        // and properly rendered by the browser
                        google.maps.event.trigger( LocationMap, 'resize');
                        if( $scope.first ) {
                            $scope.center = new google.maps.LatLng(39.42, -93.96);
                            $scope.first = false;
                        }
                        //LocationMap.setCenter(new google.maps.LatLng(39.42, -93.96));
                    }, 0);
                }, 0);
            }
        }

Hope this helps.

P.S> Thanks for all the posts of everyone else in the community out there that have helped me in the past - much appreciated.

dylanfprice commented 11 years ago
ngIf (ng-if) I think creates a new map instance when the ngIf statement is true each time. 

angular-gm saves the google maps instance when the directive/dom node is destroyed and reuses it on reinstantiation. So only one map instance gets created for each unique gm-map-id. See #3 for more info about this.

But yes the state of the map gets refreshed with gm-map-options every time the directive is reinstantiated, so if you want to save state you will have to do it externally somehow.

igler commented 10 years ago

One minor problem with ng-if: https://github.com/angular-ui/bootstrap/issues/1316