openlayers / ol2

OpenLayers v2 - deprecated!
Other
1.48k stars 772 forks source link

OpenLayers.Map.getSize returns (sometimes) null when map.div width or height is percentage while adding vector-Layers #669

Closed fastrde closed 11 years ago

fastrde commented 11 years ago

the error looks like a timing issue. I try to explain it on a simple example...

<html>
<head>
<style>
  div#map{ width 100%; height: 100%; } //div#map width and height are percentage
</style>
</head>
<body>
<div id="map"></div>
<script>

  var map = new OpenLayers.map("map");
  var v1    = new OpenLayers.Layer.Vector("v1");
  var v2    = new OpenLayers.Layer.Vector("v2");
  var v3    = new OpenLayers.Layer.Vector("v3");

  var dump = clone(map); //function to clone(!) an object
  console.log(dump); //cloned map doesn't have a size object
  console.log(map); //TRAP: map has a size object in chrome devtools because the devtools shows the last state of the object.
  map.addLayers([v1,v2,v3]); //here getSize is called internally and the error occured sometimes
  map.setCenter(greatLocationToCenter);
</script>
</body>
</html>

I cloned the map Object before map.addLayers is called and it doesn't have a map.size object when the error happens. Looks like the Browser (Chrome in my case) is not ready with calculating the pixel height and width at this moment. When you give static pixel values in css the error doesn't happen. I can't reproduce the error with firefox on the same machine. Maybe firefox ist faster in calculating the height/width or the internal handling is different.

Here are the Points where the error occured

Uncaught TypeError: Cannot read property 'w' of null in OpenLayers/Layer/Vector.js:400

 391     setMap: function(map) {
 392         OpenLayers.Layer.prototype.setMap.apply(this, arguments);
 393 
 394         if (!this.renderer) {
 395             this.map.removeLayer(this);
 396         } else {
 397             this.renderer.map = this.map;
 398 
 399             var newSize = this.map.getSize(); // here getSize returns null because map.size is not initialized
 400             newSize.w = newSize.w * this.ratio; //here happens the TypeError
 401             newSize.h = newSize.h * this.ratio;
 402             this.renderer.setSize(newSize);
 403         }
 404     },

Uncaught TypeError: Cannot read property 'w' of null im OpenLayers/Map.js:1787

1785     adjustZoom: function(zoom) {
1786         var resolution, resolutions = this.baseLayer.resolutions,
1787             maxResolution = this.getMaxExtent().getWidth() / this.size.w; //here this.size is null
1788         if (this.getResolutionForZoom(zoom) > maxResolution) {
1789             for (var i=zoom|0, ii=resolutions.length; i<ii; ++i) {
1790                 if (resolutions[i] <= maxResolution) {
1791                     zoom = i;
1792                     break;
1793                 }
1794             }
1795         }
1796         return zoom;
1797     },
ahocevar commented 11 years ago

You should use a html doctype, and your CSS looks a bit suspicious. Try the following instead:

<!DOCTYPE html>
<html>
<head>
<style>
  html, body, #map { width 100%; height: 100%; }
</style>
</head>
<body>
  <div id="map"></div>
</body>
</html>
fastrde commented 11 years ago

sorry, the code above is a quick and dirty example... In my project I've set a doctype and html, body, #map to width and height 100% via CSS.

But i think i found a workaround because of your post. Directly formatting is ugly but it looks like the error is gone.

<div id="map" style="width: 100%; height: 100%"></div>

Do you think there is a chance to init the map or add the layers not until the div size is calculated by the browser (or this.size != null) or sounds it more like a chrome issue to you?

ahocevar commented 11 years ago

I am not sure if div#map is a valid CSS selector. So in your