3

I'm stuck with the performance issue loading 2000 markers on google map. This question is overview can be found in many places, but still, can't figure out the problem for me.

So, the problem in short: google map initialization hanging the browser for 10-20 seconds.

Setting:

  • The markers data from back-end received in a single get request. loaded in 0.3 sec
  • Marker Clusterer (https://googlemaps.github.io/js-marker-clusterer/docs/examples.html) library is used. However, with or without it the browser still hanging the same time.
  • The markers are rich. with custom pics, infowindows and events.
  • InfoWindows is setting up as the AngularJS directive

Markers setup code:

function showMarkers(scope,data) {
    var locations = data;
    console.log("Starting markers setup: ", new Date());
    for(var i = 0; i < locations.length; i++) {

        var MarkerImage = '/img/reasestate.png';
        markers[i] = new google.maps.Marker({
            position: {lat:locations[i].latitude, lng:locations[i].longtitude},
            map: map,
            id: locations[i].id,
            icon: MarkerImage
        });


        var infowindow = new google.maps.InfoWindow();
        var contentString = '<infowindow></infowindow>';
        var compiled = $compile(contentString)(scope);

        google.maps.event.addListener(markers[i], 'click', (function(i, scope) {
            return function(){
                scope.placeInfo = null;

                //for search around
                scope.condo_LatLng = new google.maps.LatLng(locations[i].latitude,locations[i].longtitude);

                //update scope
                scope.$apply();

                //////////////////
                ///INFOWINDOW SETUP
                ///////////////////
                //you can change url to your url . '/maps/api/getcondo?CondoID='+scope.place.id'
                $http.get('/maps/api/condo/items?CondoID='+locations[i].id).then(function(success) {
                    //a bit of additional received data processing, not important.
                }, function(error) {
                }).finally(function() {})
            };
        })(i, scope, locations[i]));
    }
    setClustering(markers);
    console.log("Finished markers setup: ", new Date());

    /////////////
    ///context menu
    ////////////
    var menuStyle = {
        menu: 'context_menu'
        //menuSeparator: 'context_menu_separator',
        //menuItem: 'context_menu_item'
    };

    var contextMenuOptions  = {
        classNames: menuStyle,
        menuItems: [
            { label:'Add your condo...', id:'menu_option1',
                className: 'menu_item', eventName:'option1_clicked' },
            { label:'Exit', id:'menu_option2',
                className: 'menu_item', eventName:'option2_clicked' }
        ],
        pixelOffset: new google.maps.Point(10, -5),
        zIndex: 5
    };

    var contextMenu = new ContextMenu(map, contextMenuOptions);
    google.maps.event.addListener(contextMenu, 'menu_item_selected',
        function(latLng, eventName, source){
            switch(eventName){
                case 'option1_clicked':
                    createDraggableMarker(latLng);
                    break;
                case 'option2_clicked':
                    // do something else
                    break;
                default: break;
            }
        });

    google.maps.event.addListener(map, 'rightclick', function(mouseEvent) {
        contextMenu.show(mouseEvent.latLng, map);
    });
}

function setClustering(markers){
    var mcOptions = {gridSize: 150};
    mc = new MarkerClusterer(map,markers, mcOptions);
}

Getting this on console.out:

Starting markers setup:  Sun Jun 19 2016 16:43:57 
jsAllMain.js:240 Finished markers setup:  Sun Jun 19 2016 16:43:57
jsAllMain.js:256 Show markers method done at:  Sun Jun 19 2016 16:43:57
jsAllMain.js:256 Initialize searchmap done at:  Sun Jun 19 2016 16:43:57

but after i get this in console.out, the browser is hanging like 10-20 seconds more until it show the map with markers.

UPDATE: The problem is with AngularJS bindings processing (infowindow directive). Any idea how to deal with it?

user1935987
  • 3,136
  • 9
  • 56
  • 108
  • I think this is one of angular's performance issues. i am assuming 2000 markers means more than 2000 bindings, and this will cause angular to have performance impacts. have you tried with 100 markers, does it still take time? – gaurav5430 Jun 20 '16 at 05:25
  • with 100 markers it's ok – user1935987 Jun 20 '16 at 05:52
  • 2
    then most certainly it is angular performance issue for these many bindings, if you want to check you can keep checkpoints in your code (in chrome debugger) and see how long is the angular code executing for, because 2000 bindings mean, it would have to check for 2000 watches in every digest loop – gaurav5430 Jun 20 '16 at 05:54
  • right, i just checked, it is because of infowindow angular directory most probably. Any idea how to deal with it? the infowindow is must be there :( – user1935987 Jun 20 '16 at 05:55
  • i would suggest to load less data (less bindings) at once. may be you can load more data as the user zooms in and less data as he zooms out, or vice versa, whatever suits you – gaurav5430 Jun 20 '16 at 05:56
  • i was thinking about it... but can't figure out the algorithm i should use for that. Maybe any pattern solution for this kind of problem? – user1935987 Jun 20 '16 at 06:02
  • seems like i found the solution. Really thanks for pointing me on Angular! – user1935987 Jun 20 '16 at 06:04
  • great (y). please post the solution that you found for future users – gaurav5430 Jun 20 '16 at 06:04

2 Answers2

1

Solution: Put the AngularJS directive initialization inside of the click event listener.

    google.maps.event.addListener(markers[i], 'click', (function(i, scope) {
        return function(){
            var infowindow = new google.maps.InfoWindow();
            var contentString = '<infowindow></infowindow>';
            var compiled = $compile(contentString)(scope);

            scope.placeInfo = null;

            //for search around
            scope.condo_LatLng = new google.maps.LatLng(locations[i].latitude,locations[i].longtitude);

            //update scope
            scope.$apply();

            //////////////////
            ///INFOWINDOW SETUP
            ///////////////////
            //you can change url to your url . '/maps/api/getcondo?CondoID='+scope.place.id'
            $http.get('/maps/api/condo/items?CondoID='+locations[i].id).then(function(success) {


                //setup infowindow
                infowindow.close();
                infowindow = new google.maps.InfoWindow({
                    id: markers[i].id,
                    content:compiled[0],
                    position:new google.maps.LatLng(locations[i][1],locations[i][2])
                });

                //infowindow.setContent(compiled[0]);
                infowindow.open(map, markers[i]);

            }, function(error) {
            }).finally(function() {})
        };
    })(i, scope, locations[i]));
user1935987
  • 3,136
  • 9
  • 56
  • 108
1

I do not use Angular yet so I can not help you with that. But as a general rule I suggest to invest some of your time in do the clustering in the server side, then avoid at all costs to load all the rich environment you mentioned, make the most of them you can, available only at user request. It would need some work, but if your application has plans to grow its marker population, will be appreciate it later. In the case of the clustering algorithm I found this StackOverflow reference hope it could help you.
Server-side clustering for google maps api v3

Community
  • 1
  • 1