kaoscify
kaoscify

Reputation: 1763

Custom Zoom Control Results In Maximum Call Stack Size Exceeded Error

I'm trying to change the zoom increment when using Google Maps JavaScript API on iOS. For example, instead of going from zoom 14 to zoom 15, I would like for it to go straight to zoom 16 and then zoom 18, and so on... when a user uses the pinch to zoom gesture.

I know I can achieve this with buttons, but I can't seem to find a solution for pinch to zoom gesture. I realize that the zoom_changed event needs to be tracked.

I get an error of Maximum call stack size exceeded with map.setZoom(zoom + 2); and map.setZoom(zoom - 2); when added on line 17 and 19, respectively.

Check out this JSFiddle: http://jsfiddle.net/2zmn9173/4/. This is the part I need help with:

if (useragent.indexOf('iPhone') != -1) {
    google.maps.event.addListener(map, 'zoom_changed', function () {
        if (map.getZoom() > zoom) {
            alert("ZOOMED IN from Level " + zoom);
        } else if (map.getZoom() < zoom) {
            alert("ZOOMED OUT from Level " + zoom);
        }
        zoom = map.getZoom();
    });
}

The buttons on top demonstrate the functionality I am trying to achieve, but with pinch to zoom gesture.

Upvotes: 0

Views: 482

Answers (2)

Dr.Molle
Dr.Molle

Reputation: 117354

Simple approach:

only set a new zoom when the current zoom is not a even number(this should stop the infinite loop)

    google.maps.event.addListener(map,'zoom_changed',function(){
      var z=this.getZoom();
      if(z%2){//when zoom is a odd number
        var fx=((!isNaN(this.get('z'))&&this.get('z')<z))?2:0;
        this.setZoom(Math.floor(z/2)*2+fx);
      }else{
        this.set('z',z);
      }
    });

Demo:

function initialize() {
  var ctrl = document.getElementById('zoom');
  map = new google.maps.Map(document.getElementById('map_canvas'), {
      zoom: 14,
      center: new google.maps.LatLng(52.549,
        13.425),
      noClear: true
    }),


    map.controls[google.maps.ControlPosition.TOP_CENTER].push(ctrl);

  google.maps.event.addListener(map, 'zoom_changed', function() {
    var z = this.getZoom();
    if (z % 2) { //when zoom is a odd number
      var fx = ((!isNaN(this.get('z')) && this.get('z') < z)) ? 2 : 0;
      this.setZoom(Math.floor(z / 2) * 2 + fx);
    } else {
      this.set('z', z);
    }
    ctrl.innerHTML = this.getZoom();
  });
  google.maps.event.trigger(map, 'zoom_changed');
}


google.maps.event.addDomListener(window, 'load', initialize);
html,
body,
#map_canvas {
  height: 100%;
  margin: 0;
  padding: 0
}
#zoom {
  font: bold 2em Monospace;
  background: tomato;
  width: 30px;
  text-align: center;
}
<script src="https://maps.googleapis.com/maps/api/js?v=3"></script>
<div id="map_canvas">
  <div id="zoom"></div>
</div>

Upvotes: 1

taxicala
taxicala

Reputation: 21779

If you add those lines where you are pointing in your question, You will be firing the event zoom_changed inside the event zoom_changed, this will create a stackoverflow because it will never end firing the events.

if (useragent.indexOf('iPhone') != -1) {
    google.maps.event.addListener(map, 'zoom_changed', function () {
        if (map.getZoom() > zoom) {
            map.setZoom(zoom + 2); //This will trigger "zoom_changed" again
        } else if (map.getZoom() < zoom) {
            map.setZoom(zoom - 2); //This will trigger "zoom_changed" again
        }
        zoom = map.getZoom();
    });
}

And zoom = map.getZoom(); will change the zoom afterwards, but the other events will be already executed, my suggestion, is set a value, and call setZoom afterwards:

if (useragent.indexOf('iPhone') != -1) {
    google.maps.event.addListener(map, 'zoom_changed', function () {
        var newZoom = map.getZoom(), oldZoom = zoom;
        if (newZoom > oldZoom) {
            oldZoom + 2;
        } else if (newZoom < oldZoom) {
            oldZoom - 2;
        }
        zoom = oldZoom;
        map.setZoom(oldZoom);
    });
}

Upvotes: 1

Related Questions