The attached patch allows administrators to limit the zoom levels where Views powered vector layers are available. This makes it possible to have different local data shown depending on your zoom level.

One issue with the current patch is that it assumes you'll be using the google projection, I'm not sure the best way to handle that assumption.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

seanr’s picture

After I apply the patch, I end up with this warning on the map page and when saving a preset:

warning: array_values() [function.array-values]: The argument should be an array in /.../openlayers/modules/openlayers_views/includes/layer_types/openlayers_views_vector.inc on line 103.
seanr’s picture

Editing the layer made that go away, but the layer data still shows at all zoom levels even after I limited it from 0 - 5. Here's the layer export:

$items = array();
$openlayers_layers = new stdClass;
$openlayers_layers->disabled = FALSE; /* Edit this to true to make a default openlayers_layers disabled initially */
$openlayers_layers->api_version = 1;
$openlayers_layers->name = 'dped_browser_listing_openlayers_1';
$openlayers_layers->title = 'Applicants';
$openlayers_layers->description = 'Map of all applicants';
$openlayers_layers->data = array(
  'layer_type' => 'openlayers_views_vector',
  'layer_handler' => 'openlayers_views_vector',
  'projection' => array(
    '0' => '4326',
    '1' => '900913',
    '2' => '4269',
  ),
  'views' => array(
    'view' => 'dped_browser_listing',
    'display' => 'openlayers_1',
  ),
  'options' => array(
    'resolutions' => array(
      '156543.0339' => '156543.0339',
      '78271.51695' => '78271.51695',
      '39135.758475' => '39135.758475',
      '19567.8792375' => '19567.8792375',
      '9783.93961875' => '9783.93961875',
      '4891.96980938' => '4891.96980938',
    ),
  ),
);
$items["dped_browser_listing_openlayers_1"] = $openlayers_layers;
return $items;

Here's the preset export:

$items = array();
$openlayers_presets = new stdClass;
$openlayers_presets->disabled = FALSE; /* Edit this to true to make a default openlayers_presets disabled initially */
$openlayers_presets->api_version = 1;
$openlayers_presets->name = 'dped_browser_applications';
$openlayers_presets->title = 'Applicants';
$openlayers_presets->description = 'Applicants';
$openlayers_presets->data = array(
  'width' => 'auto',
  'height' => '400px',
  'image_path' => '/profiles/ngp_deped/openlayers/dark/',
  'css_path' => '',
  'proxy_host' => '',
  'center' => array(
    'initial' => array(
      'centerpoint' => '-114.08203124548, 44.777935894895',
      'zoom' => '2',
    ),
    'restrict' => array(
      'restrictextent' => 1,
      'restrictedExtent' => '-19939668.943016,1242560.331581,-4559315.862341,11613536.327456',
    ),
  ),
  'behaviors' => array(
    'openlayers_behavior_attribution' => array(),
    'openlayers_behavior_popup' => array(),
    'openlayers_behavior_keyboarddefaults' => array(),
    'openlayers_behavior_layerswitcher' => array(),
    'openlayers_behavior_navigation' => array(
      'zoomWheelEnabled' => 1,
    ),
    'openlayers_behavior_panzoombar' => array(),
    'dped_settings_behavior_layerswitcherplus' => array(),
  ),
  'default_layer' => 'dped_browser_world_light',
  'layers' => array(
    'dped_browser_world_light' => 'dped_browser_world_light',
    'congressional_districts' => 'congressional_districts',
    'dped_browser_listing_openlayers_1' => 'dped_browser_listing_openlayers_1',
  ),
  'layer_styles' => array(
    'dped_browser_listing_openlayers_1' => 'dped_red',
  ),
  'layer_activated' => array(
    'dped_browser_listing_openlayers_1' => 'dped_browser_listing_openlayers_1',
  ),
  'layer_switcher' => array(
    'congressional_districts' => 'congressional_districts',
  ),
  'projection' => '900913',
  'displayProjection' => '4326',
  'styles' => array(
    'default' => 'circle-7',
    'select' => 'circle-7',
    'temporary' => 'circle-7',
  ),
  'options' => NULL,
);
$items["dped_browser_applications"] = $openlayers_map_presets;
return $items;
jmiccolis’s picture

Assigned: Unassigned » jmiccolis
Status: Needs review » Needs work
FileSize
3.26 KB

Attached is a patch that fixes the `array_values` issue. I'm still debugging why the new settings for the layer don't take effect, but I'm curious - if you clone the layer and update your preset to use the clone does that work? (That's how I developed initially and had this working)

seanr’s picture

Just noticed when going to apply the new patch that the original one failed on one of the hunks. I reverted to the dev version and the new patch applied cleanly. I cloned the layer and changed the preset to use that, but it still shows the points at all zoom levels.

jmiccolis’s picture

FileSize
3.33 KB

Last patch had a small bug where it would over-write the resolutions immediately after writing them. This patches fixes that.

zzolo’s picture

@jmiccolis, thanks for the patch. This looks pretty good except for the 900913 resolution hard-coded thing.

I think openlayers_get_resolutions() and how we manage resolutions could be handled better overall, but that is for another ticket, and @tmcw would probably have better insight on that.

As for a current work around, we could utilize the CTools form API stuff to have dependencies for each projection and only present the relevant resolutions for each.

darksnow’s picture

This is something I've been looking for in my map application.

When I get the time I'd be more than happy to help test this, what are the chances it will make it into the core OpenLayers Module?

The other thing I was planning on having a look at was AJAX capabilities. When the map is zoomed, or panned, the bounds and zoom level are passed to the appropriate views which in turn can load, using AJAX, the correct results using exposed arguments. Any pointers on where I could start looking, and sorry that this last paragraph went off to topic.

Keep up the good work, I'd be very keen to see this working and added.

tmcw’s picture

darksnow:

This feature, abstractly, is a very high priority to get into the module, but not in the current patch-implementation. To be committed, we need to switch to storing limited zoom levels in the view configuration itself, so that there isn't a loose conglomeration of layer-views and view-views lying around as this solution ended up creating. There will also need to be smarter logic for choosing the resolutions array based on projection, because Views layers support any underlying projection

The other thing I was planning on having a look at was AJAX capabilities. When the map is zoomed, or panned, the bounds and zoom level are passed to the appropriate views which in turn can load, using AJAX, the correct results using exposed arguments. Any pointers on where I could start looking, and sorry that this last paragraph went off to topic.

This problem has been in the works for a while. It's very complex - in terms of formats, in terms of performance, as far as handling views parameters and arguments correctly. It's possible to do something halfway by using the KML module, but that's far from optimal. In all, it'll probably take four or five days of work to get that kind of feature done.

darksnow’s picture

Well, that sounds encouraging.

Sorry to push, and I'd be more than happy to help, but what sort of time scale are we looking at for the zoom capabilities? If it's a high priority I assume somebody more qualified than me is already working on it?

As for the AJAX thing, four or five days doesn't sound so bad, I thought it was going to take a long time ;)

I've never written any modules but I have had a look at the code and made some rudimentary changes, so if you have any pointers of where I should start or where I should look, or any work already underway that I can add to, please let me know and I'll see what I can come up with.

Finally, and perhaps most importantly, what are the implications of Drupal 7 to all this work? Is there any point in doing all this if it's going to be obsolete when D7 is released or will features from this work be directly applicable to the D7 version of the OpenLayers module?

tmcw’s picture

It's a high priority task, but there's nobody currently working on it. zzolo's in Italy and I'm currently on a few other projects and just trying to keep bugs down on this one. It'd be awesome if you want to look at it.

The jist is:

zoom levels should be stored in the options array of OpenLayers Data layers, and it'd be best if they're stored as 0-19 (or any specific zoom range) rather than 'resolutions'. A little backstory on resolutions: OpenLayers handles multiple projections (like EPSG:900913 and EPSG:4326, mainly), so it can't think of a pixel as a simple thing, or assume that a tile's pixel coordinates assign it to a certain lat/lon value. So there's a ton of abstraction when it comes to things like zoom levels. Thus resolutions - they're ratios between geographical units, like meters or degrees or minutes, to pixels. As such, they're kind of obscure. But they're the only reliable way to define resolutions in OpenLayers - otherwise the library tries to be 'too clever' and interpolate resolutions between your min and max.

So, the moral of the story is that the openlayers_get_resolutions() function should be used during the render() call of the layer to pull the 0-10 or 0-19 or 5-7 or whatnot zoom range from the Views options and turn it into a resolutions array, and then push that into the layer.

As far as AJAX: possibly that's a low estimate. I was thinking that it would take about 60 hours of a maintainer's time to really iron out the situation. It would be much more difficult to start from scratch with that kind of solution, but we should at least have a ticket about it.

Drupal 7: we're planning on doing a fast, semi-automated port of the module to Drupal 7 when it is released as a stable and starts to pick up adoption. There is very little functionality-wise that will change D6-D7, and porting now and integrating changes would be more difficult than having a stopping point and then push for a D7 port.

darksnow’s picture

OK, all that's clear. I work in marine navigation so I know a bit about geodetic and reference systems, it is interesting to see that some of the maps available don't use WGS84 as the GPS system and google maps does.

Anyway, my proposal for this is in two parts.

Firstly, I'd like to be able to set a max and min zoom level for each layer added to a given map. That way we could have the terrain map for the high level map of the world, then change to the satellite, or hybrid layers lower down, and have different views based layers for different zoom ranges for whatever reason.

Secondly, and more importantly, I'd like to have the views layers take the zoom level and current bounds as parameters and dynamically, with AJAX, show any markers or polygons that are in the given range. This would require a given node type to include CCK based max and min zoom fields, which would be mapped like the Location module's position fields are currently.

So, for non-AJAX layers, all markers are loaded but can be selectively removed from display in JavaScript, which will provide a performance boost in a lot of cases, but still requires loading all the data into the map at load time. But, for the AJAX maps, it will only load what is needed into the browser based in location and zoom level. Additionally, by combining these two, an AJAX layer which will not display anything at high zoom levels, for example, can be excluded from even being called, given further performance improvements.

So, two changes related to zoom levels, neither sounds trivial, but together could really help the OpenLayers module, especially when dealing with high numbers of markers.

tmcw’s picture

Whatever you can do in this direction would be very useful if it's stable and well-written. Currently I don't have the time to devote to these new features, which really constitute a great deal of investment.

darksnow’s picture

I know I've mention two future enhancements above, but I think I might have a solution to the limited zoom levels.

I've been putting together small JavaScript pages to test the internals of the OpenLayers API before trying to tackle anything Drupal specific and I made a small test page which automatically changes between the Hybrid and Physical Google maps at a certain zoom level.

This is achieved, I think, by limiting which zoom levels each of those Layers, neither as a base layer, are displayed.

There's not much to it but have a look at http://www.darksnow.net/test/map/zoom.html

My idea, through a read of the OpenLayers API, is to allow the resolutions arrays to be created as normal, which already works in the Drupal module, then set the min and max resolutions of the layers to the computed values from the resolutions array.

So, to limit a layer to be only shown between zoom levels 9 and 14, for example, you would set:
layer.minResolution = layer.resolutions[14]
layer.maxResolution = layer.resolutions[9]

It appears that the zoom levels are the wrong way round, max smaller than min, but it's the max and min numbers in the resolutions array, so makes sense.

Anyway, this seems to work and I thought might be a good fit for this patch, and side steps the resolutions issue. Though it does seem too simple to me, so maybe I've missed something.

Work continues so I may add another thread here for the AJAX thing.

Cheers.

zzolo’s picture

"To be committed, we need to switch to storing limited zoom levels in the view configuration itself, so that there isn't a loose conglomeration of layer-views and view-views lying around as this solution ended up creating."

I think I am a little confused on this.

Wouldn't it make the most sense to have zoom level limitation settings in the layer definition itself, as the first patch suggests? A perfect example is the one @darksnow suggests above which are layers that are not Views Data Overlays, let alone logically it seems to make the most sense. The OL Views module could just have this option in the data layer options, and when producing those layers, just set the correct options. Maybe I am missing something?

tmcw’s picture

It makes sense to store zoom levels in the views config, rather than in a layer instantiation, because the management of both views layers and layer objects that refer to views layers becomes horrible quickly. You create a OpenLayers Data view, clone the layer 'of it' in the OpenLayers module, and customize its zoom levels there. Now, when you export, you need to export both? If you rename the view, how does the layer object track it? If it's missing, what does it do? And, in the process, don't we just add to the annoyance involved with switching between the OpenLayers and Views UIs in order to create basic maps?

@darksnow, please open a new thread for the AJAX discussion, it's a much larger topic than this one.

darksnow’s picture

I tend to agree with zzolo on this one.

What if, for a given preset, you only wanted to use the layer for certain zoom levels?

The demo I put together above uses this limited zoom level technique to force that background layer (not really the base layer here) to change between two Google maps layers at a certain zoom level. Since we could have no control over a given layer it makes sense that either the layer configuration, or perhaps more sensibly, the preset that includes that layer, contains the zoom level limits.

As for views layers, where we will have this control. I think it does make sense to have the zoom levels part of the views definition, but I think it is far more important to keep things consistent, which again points to restricting zoom levels in the presets.

The other, AJAX, side of this is that the zoom level gets passed as an argument to views, which can filter their results as they see fit, but, as you say, that is a much bigger discussion for another thread.

tmcw’s picture

What if, for a given preset, you only wanted to use the layer for certain zoom levels?

You'd clone it and create a view with different zoom levels. Just as you'd do for any other kind of layer - you'd clone it. There's no efficiency or architectural win of cloning layers rather than views.

darksnow’s picture

If you clone views for this so you not end up with loads of views that show the same data causing the loose conglomeration you wanted to avoid?

Seems to me that the view should get whatever data is needed, the display of that data is handled by a layer and how that layer is used is handled by presets. For views layers the zoom levels could go anywhere, but it seems most sensible to me to allow users to selectively apply zoom levels to any layer, view or not, depending on what is needed.

In short, it seems most sensible to set limited zoom levels in presets.

tmcw’s picture

I think we may be missing each other here: when you're referring to limited zoom levels in presets, you're talking about limited map zoom levels or layer zoom levels? The map's zoom levels are, of course, managed in presets, but layer zoom levels are managed in layers.

If you clone views for this so you not end up with loads of views that show the same data causing the loose conglomeration you wanted to avoid?

Not quite. If you have views and then 'layer instances' referring to those views, we end up with n + 1 objects, whereas if we have zoom levels in views and duplicates of views displays (note that we're talking about displays - we don't need multiple views here), we end up with n objects.

Seems to me that the view should get whatever data is needed, the display of that data is handled by a layer and how that layer is used is handled by presets. For views layers the zoom levels could go anywhere, but it seems most sensible to me to allow users to selectively apply zoom levels to any layer, view or not, depending on what is needed.

If you're arguing for people to be able to set layer zoom levels on a preset basis, then that's fine and is actually a reasonable feature request - I think that that hits a lot of bases. However, that isn't the system that's in place right now, for OpenLayers Data layers or any other layers, so it's not pertinent.

darksnow’s picture

Perhaps my terminology is off.

What you are saying above makes sense.

What I am arguing for is exactly as you say. We limit the zoom level of any given layer on a preset basis. While this is not how things are working now, it is what I was proposing to add, using the min and max resolution settings I've been looking at and described above. I think this would allow us to easily apply zoom levels, as map zoom levels, not resolutions, to restricting when a given layer appears on the map.

I hope that makes sense and that I've used the right terminology.

If my solution above, using the zoom levels as indexes into a computed resolutions array to get the min and max resolution, is a bit too hacky or just wrong, let me know and we'll see if we can come up with something better.

lucascaro’s picture

I like this idea (#13)! When using this method, in my case, i had to set layer.alwaysInRange to false to make it work.

zzolo’s picture

Version: 6.x-2.x-dev » 7.x-2.x-dev
Priority: Normal » Minor

I think this is still a valid feature request. Moving to D7. This will not have high priority until we can push out a 2.0 (eventually :). Also, this issue will probably be related: #818302: Abstract out layer types

zzolo’s picture

Title: Limit zoom levels of Views vector layers » Limit zoom levels for layers and maps

Changing this into a general issue about zoom level restrictions. In theory, regardless of technological issues, we should be able to have both preset/map level zoom restrictions and layer level zoom restrictions.

Here is a duplicate issue: #887904: Provide a map (preset) level zoom restriction option

Also, check out this OL page for some background: http://trac.osgeo.org/openlayers/wiki/SettingZoomLevels

Summit’s picture

Subscribing, greetings, Martijn

dawnlight’s picture

Status: Needs work » Needs review

openlayers_vector_zoom_level_range.patch queued for re-testing.

// ======

It seems not to work for me when I overwrote the default OpenLayers_Views (I can't reach the zone limit option without overwriting it).
Any hint?

Thanks.

// ======

I found that it works for the views layer, but not for the map. Herhaps it's the problem of wrong setting with the PanZoomBar (behavior, herhaps the navigate mouse scroll too).

It can also be changed by directly adding "minZoomLevel" to options_init() function in includes/layer_types/xxx.inc. But adding a value input option in backoffice and load it when initialization is better.

Sorry for having reported a wrong message yesterday.

The last submitted patch, 805796_20100524.patch, failed testing.

omasal’s picture

katbailey’s picture

Hey All,
I'm pretty new to OpenLayers but I do need this functionality for a client site I'm working on. In my case, I need to be able to prevent a particular views-based vector layer from rendering until a certain zoom level is reached. The solution I've come up with so far is to add a new behavior plugin that allows this. I'll most likely just add this behavior plugin in a custom module, but thought I'd just attach it as a patch to the openlayers module here to get feedback from others who've been thinking about this issue. It is by no means perfect but it seems to work for my purposes. Here's a screenshot of how you configure it in the behaviors section of your map: https://skitch.com/katbailey/g55ji/openlayers-zoom-levels-per-layer

Katherine

katbailey’s picture

Meh, there's no actual performance gain with this approach, which is what I'm really looking for. Going to look into ajax-loading the layers.

zzolo’s picture

Version: 7.x-2.x-dev » 7.x-3.x-dev
Status: Needs review » Active

HEy @katbailey. What were your findings here?

katbailey’s picture

Well, the fact that the data was still being loaded to the page even though it wasn't being rendered at the higher zoom levels meant it was still really slow with large amounts of data.
So I wrote a sandbox project called OpenLayers BBox: http://drupal.org/sandbox/katbailey/1445310
Here's the description from the sandbox project page:
Provides a GeoJSON BBox layer type plugin for the OpenLayers module, which uses the BBox layer strategy provided by the OpenLayers js library for loading only the features of the layer that lie within the current bounding box. It also provides a behavior plugin which permits the activation of the strategy based on zoom level.

Countzero’s picture

I find it difficult to understand the status of this. I came here searching for a solution to limit the maximum zoom level for all maps on the site, and I see you people are talking about much more complex issues like performance and clustering et al.

Also, this thread is now 7.x-3.x oriented.

Is there a solution somewhere, even a stupid and ugly one, to limit the max zoom level of a map in 7.x-2.x using gmap type layers ? Sorry if I'm in the wrong place to ask.

EDIT :

Kind of found it : As per this, I overrode the value returned by getNumZoomLevels in OpenLayers.js from numZoomLevels to a plain 12 at line 505 (V 2.11). Ugly but works if you want a sitewide max zoom level.

japo32’s picture

FileSize
2.54 KB

Hi, I'm trying to make this patch into a module. It's enabled and I can see the interface in the Behaviors tab.
Then I set the zoom levels and check the "Enable dymamic zoom levels for this layer" box.
When I save nothing happens to the map. Did I miss something?

attached is the module.

I think this would be an awesome addition to the openlayers behaviors collection.

japo32’s picture

FileSize
2.55 KB

UPDATE:

I managed to make it work. I'll attach the module for the next guy like me who needs this feature.

Pol’s picture

Status: Active » Needs work

I think this could go in a patch and included in OpenLayers!

japo32’s picture

I recently installed the dev version for D7 and found that it's already part of the code. :p

Pol’s picture

Status: Needs work » Fixed

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

treckstar’s picture

FileSize
2.25 KB

Hi everyone, ran into a situation where I needed to use the module linked in #35 by japo32. The module works great, thanks dude!

In the version of OpenLayers I was using (7.x-2.0-beta3), ran into this little bug.
http://drupal.org/node/1876702

After several patches not applying to fix this bug, I opted to use the OpenLayers (7.x-2.x-dev) release. Everything was good until I ran into this message with the japo32's module.
"There's a problem in the definition of the behavior !behavior. The behavior will be disabled."

This is because some fields are mandatory for behaviors.
http://drupalcode.org/project/openlayers.git/blob/91523146d6a31b11b8daa2...

I made the changes to the module japo32 wrote to comply with this definition check. The attached file works with the dev release.

Hope this helps anyone who ended up in the same situation as me.

Pol’s picture

I like a lot :-)

I'll include it in the next dev version !

Many thanks !

Pol’s picture

Version: 7.x-3.x-dev » 7.x-2.x-dev
Assigned: jmiccolis » Pol
Status: Closed (fixed) » Needs work

Hello @Treckstar,

I've tried the script on my local install and I do not find a way to get it working, could you explain a working use case so I can test it myself ?

thanks !

Pol’s picture

Title: Limit zoom levels for layers and maps » Limit the display of features per zoom levels.
Status: Needs work » Fixed

Ok I got it working.

This is not about limiting zoom level for layers and maps, it's about limiting the display of features only.

Committed in 7.x-2.x: http://drupalcode.org/project/openlayers.git/commit/7709de5

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

basvredeling’s picture

Issue summary: View changes

FYI, for views_geojson I've created a custom views argument handler which allows you to return no results if the zoom argument doesn't meet certain criteria (for instance: zoom > 5). The current solution for this issue doesn't display layers for specific zoom ranges, but it does load the data. To minimise the data on requests of hidden layers, use the aforementioned argument handler as inspiration: #2813059: Zoom argument handler