Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clustering prevents programatically focus to happen #320

Closed
wixo opened this issue Mar 10, 2014 · 9 comments
Closed

Clustering prevents programatically focus to happen #320

wixo opened this issue Mar 10, 2014 · 9 comments
Labels

Comments

@wixo
Copy link

wixo commented Mar 10, 2014

I have recently added clustering to my leaflet map but the message popup stopped showing up when the marker is inside a cluster.

As a workaround I have been using $timeout( function () { marker.focus = true }, 1000 ); but I was wondering if this is a bug or if is there any other way to make this happen.

Any advice would be appreciated.

@JaumeFigueras
Copy link
Contributor

This problem exists because the directive does not know if the marker is moved by a drag action or by the spiderfy animation of the cluster.
When this happens the marker location is updated and the click event is lost and no popup is shown.
I can't find any feasible solution right now.

@JaumeFigueras JaumeFigueras self-assigned this Mar 15, 2014
@JaumeFigueras
Copy link
Contributor

Created a PR solving this issue. Now the popup appears when the marker is in a MarkerCluster Layer and it is visible, if it is inside a MarkerCluster it can't appear.

tombatossals added a commit that referenced this issue Mar 16, 2014
@lobenichou
Copy link

Any luck on this? Having the same issue. When clustering, the popup stops showing up when programmatically focusing. I also get this: TypeError: Cannot read property 'style' of undefined.

@denjello
Copy link

denjello commented Mar 6, 2015

I have run into this too. I want to move to the spot and zoom in as tight as possible. Then it would be clever to figure out somehow with a native markercluster function if this item is in a cluster, and programatically open the cluster with a fireEvent, but I haven't wrapped my head around it yet...

In the meantime I have changed an option of the L.MarkerClusterGroup in the leaflet.markercluster.js and told it to turn off the clustering at zoom level 18:
disableClusteringAtZoom:18

and this is my function for programatically opening the marker

        $scope.openMarker = function(id) {
                $scope.london = {
                    lat : $scope.markers[id].lat,
                    lng : $scope.markers[id].lng,
                    zoom : 19
                }
               $scope.markers[id].focus = true;
        }

@denjello
Copy link

denjello commented Mar 6, 2015

w00t!

I got something hobbled together. It must have been the Sandman watching over my shoulder helping me improve the QOB (quality of bugs) in exchange for something that just works, without needing to turn off clustering at any specific zoom level!!!

By the way, I am using this version of Leaflet.markercluster from teastman because I am dynamically adding geocoded image assets via socket.io...

Furthermore, this has the additional benefit, that when the ng-click="openMarker( image._id )" is activated a second time, it closes the pop-up.

Problem 1:
On clusters with hundreds of children at maximum zoom, it can take my desktop more than 500ms to render them all, which means that the click comes too late... It should probably be promisified...

This is my leaflet div (in jade):

leaflet#mapContainer(center="london" controls="controls" layers="layers" markers="markers" eventBroadcast="eventBroadcast" height="100%" width="100%" watch-markers="no")

This is my ng-repeat (in a seperate listview div)

    .markerHolder(ng-repeat="image in imageData.latestImages" style="clear:both")
            img(ng-src="{{ image.url }}" width=60 ng-click="openMarker( image._id )")

This is in my controller.js:

(function () {
    'use strict';
    angular.module('project.controllers', [
        'project.services.api'
    ])
      .controller('Mapview', ['$scope', '$timeout', '$location', 'leafletData', '$q', 'apiService', function ($scope,$timeout, $location, leafletData, $q, apiService) {

// ... 
// use apiService to get existing / new images from the server with socket.io
// ...

            // Instantiate the Leaflet
            angular.extend($scope, {
                events: {
                    map: {
                        enable: ['moveend', 'popupopen'],
                        logic: 'emit',
                        maxZoom: 19,
                        animate:true,
                        attributionControl: true,
                        location: "enableHighAccuracy"
                    },
                    marker: {
                        enable: [ 'clusterclick' ],
                        logic: 'emit'
                    }
                }
            });

// ...

            // always center on marker and zoom in on user interaction
            // just a little extra sauce for you. 
            $scope.$on("leafletDirectiveMarkersClick", function(event, args){
                $scope.london = {
                    lat: $scope.markers[args].lat,
                    lng: $scope.markers[args].lng,
                    zoom: $scope.london.zoom
                };
            });


// ... 
            // this is the bit that is interesting and the actual solution
            $scope.openMarker = function(id) {
                leafletData.getMarkers()
                    .then(function(markers) {
                        $scope.london = {
                            lat: $scope.markers[id].lat,
                            lng: $scope.markers[id].lng,
                            zoom: 19
                        };
                        // wishing for a better solution than setting timeout
                        setTimeout(function(){
                            var currentMarker = markers[id];
                            var currentParent = currentMarker.__parent._group;
                            var visibleParent = currentParent.getVisibleParent(markers[id]);
                            currentParent.zoomToShowLayer(markers[id],function(markers) {
                                $scope.london = {
                                    lat: $scope.markers[id].lat,
                                    lng: $scope.markers[id].lng,
                                    zoom: 19
                                };
                            });
                            currentMarker.fire('click');
                            // in case someone needs to get the info about the children...
                            console.log("lengthofchildren",visibleParent.getAllChildMarkers().length);
                            // i null them to help out GC, but prolly doesn't change anything
                            markers=null;
                            currentParent=null;
                            visibleParent=null;
                        },500);
                    })
               };

I'd love feedback if someone has an idea how to improve this, especially because I have the feeling that there are a few things here that aren't necessary...

@denjello
Copy link

denjello commented Mar 6, 2015

w00t v2

So, I fixed up that previous solution with promises instead of the hacky setTimeout, namespaced the variables and passed them from .then to .then and now its not only smoother but has a somewhat lower memory footprint.

            $scope.openMarker = function(id) {
                var _this = [];
                _this.id = id;
                leafletData.getMarkers()
                    .then(function(markers) {
                        $scope.london = {
                            lat: $scope.markers[_this.id].lat,
                            lng: $scope.markers[_this.id].lng,
                            zoom: 19
                        };                  
                        var _markers = [];
                        _markers.currentMarker = markers[_this.id];
                        _markers.currentParent = _markers.currentMarker.__parent._group;
                        _markers.visibleParent = _markers.currentParent.getVisibleParent(markers[id]);
                        _markers.markers = markers;
                        return _markers;
                    }).then(function(_markers){
                        if (_markers.visibleParent !== null) {
                            _markers.visibleParent.fire('clusterclick');
                        } else {
                            _markers.currentMarker.fire('click');
                        }
                        return _markers;
                    }).then(function(_markers){
                         _markers.currentParent.zoomToShowLayer(_markers.markers[ _this.id ], function() {
                            $scope.hamburg = {
                                lat: $scope.markers[_this.id].lat,
                                lng: $scope.markers[_this.id].lng,
                                zoom: 19
                            };
                            if (_markers.currentMarker !== null) {
                                _markers.currentMarker.fire('click');
                            } else {
                                _markers.visibleParent.fire('clusterclick');
                                _markers.currentMarker.fire('click');
                            }
                        });

                    });

            };

@peterver
Copy link

this issue still remains in 0.8.5, any progress on it :] ? i'm using the fix that @denjello created for now :]

@tombatossals
Copy link
Owner

I'm going to rework&redesign angular-leaflet-directive to be compatible with Leaflet v1.0. It will mantain almost all its functionality, and will be compatible with the current features of the directive, but I must start from a fresh point, so I'm going to close this issue. If you think it must be worked with the new version, please reopen it.

@LeeChSien
Copy link

@denjello
thanks a lot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants