I am creating this ticket in order to get conversation between phayes, bdragon, and I out in the open instead of emails. We seems to have a good base of code and good direction, so it would be good to put out in the public now. I am also going to merge/close the other tickets.

Definitely follow the CVS conversation as well: http://drupal.org/project/cvs/177400

Instead of copying all out emails, I will just summarize what we have created so far. At the moment, there are two modules:

OpenLayers API Module
--------------------------------------
This provides the heavy lifting of rendering an OpenLayers map. It is based on creating a descriptive array in PHP for a map, then using that array in Javascript to build the map object. This way, modules can render maps with little to no Javascript, and with very little PHP.

OpenLayers CCK Module
--------------------------------------
The main goal of this module is to create a OpenLayers interface to providing Geo with WKT data (the geospatial data field). This means that it provides a widget that goes over top the regular field.

Some ideas/plans for the future (which are not set in stone):
* Field formatter for Geo field(s)
* Defaults and settings forms
* Views style plugin (probably similar to GMaps)
* WMS administration (See #425930: Abstracting WMS Functionality)

Comments

phayes’s picture

Let's keep the development chat here. The roadmap might be better served as a wiki. I've created one here: http://groups.drupal.org/node/21301

zzolo’s picture

I have been thinking about a Layers hook structure. I was thinking about a hook that describes how to get more information about a layer:

function hook_openlayers_layer_info() {
  return array(
    'modulename_layer_x' = array(
      'name' => t('Layer Name'),
      'file' => 'some_path',
      'callback' => 'openlayers_layers_callback',
    ),
  );
}

Basically, the info hook would be a very simple array that describes the available layers and how to get more info for them. This would mostly be used in the select lists for forms.

function openlayers_layers_callback($layer_id, $layer) {
  if ($layer_id == 'some_layer') {
    return array(
      'modulename_layer_x' = array(
        'id' => 'modulename_layer_x',
        'type' => 'WMS',
        'name' => t('Layer Name'),
        'url' => 'http://labs.metacarta.com/wms/vmap0',
        'params' => array(
          'layers' => 'basic',
        ),
        'options' => array(),
        'events' => array(),
      ),
    );
  }
}

The callback would just do all the processing to get the details of the layer.

This means lots of things:

* Layers would have to be processed a lot more in the render_map() function
* A map array could just provide the layer id, instead of all the information
* The openlayers_layers hook would need to be renamed to something like openlayers_layer_handlers (but we still want this)
* The openlayers API module could provide one simple layer so that the map is working
* We can create a new module openlayers_layers that can provide lots of more exciting layers, and possibly a gui management tool
* Provides an easy way to choose layers in the map_form

What do you think?

phayes’s picture

Let me see if I have this correct:

openlayers_layers defines a whole wack of different layer types. The user would, through an interface (or a module could programatically), define "layer instances": layers with all the parameters filled out. These layer instances gets stored in the database, and then all your maps can call on available layer instances?

zzolo’s picture

Yes, a whole whack. First step would just be programmaticly, with hopes of creating an interface. The interface and management would be on the shoulders of the openlayers_layers module. So, the openlayers_layer module would provide a layers hook that would possibly bring in data from the database, but at first just hard-coded.

It would basically be moving the layer definitions outside the API module and into the hands of other modules. Of course, there will still be the ability to just create a layer when creating a map array.

Does that make any more sense? I am not that good at explaining things, sometimes. It might make a lot more sense when I actually start to code it. I think it will be good. And we can start to put in more fun visual layers.

phayes’s picture

I say go for it. I don't understand all the intricacies of what this will entail, but i get the general gist and think it's a good idea.

One thing i'm not so sure of is pushing this to a separate module. Is there anyone who will ever *not* want to turn on the openlayers_layers.module?

Perhaps just moving it to an outside php file within the main openlayers module. openlayers_layers.inc? This is my recommendation, but I leave this decision up to you.

yarma’s picture

Hi,

at the moment i didn't had enougth time to test the latest changes in the openlayer module, but i can provide some ideas ...

If I good understood what is the proposal of zzolo, we would have a module in 2 parts:
- the openlayer API for displaying the layers
- several little module that are able to touch the data from different type (kml, postgis, cck field, ...) and pass it in a standardized way to the openlayer API

it seems to be very closed to what the Embedded Video Field module (http://drupal.org/project/emfield) is doing: there are 20 .inc files wich give different way of fetching the video from several providers ... it's video and not geographic data but the metod is very similar and i think it can be a good basis for developping a modular openlayer module!

zzolo’s picture

The major point of having a separate module is to keep the render time down for maps. The way I envision it, the rendering of the map will call the hook which means that it could pull in a lot of data. It is similar to what yarma is talking about. It is also a lot like the Views UI. There is need to have the layers rendered or the management tool installed if you are not using it. I also see this module handling some of the layer processing hooks as well.

Though it seems like everyone would want all these layers and functionality, its not inherently true. I think it's important to have the OL API module be very bares bones, but still be able to function by itself; it should provide the interface to put everything together (with sensible defaults).

Anyway, it'll be beautiful when I am done with it; and shouldn't change the way maps are rendered, just how the map array is put together.

zzolo’s picture

Title: Development and Roadmap » Development
phayes’s picture

Awesome. Beautiful sounds good. I look forward to seeing it!

Patrick

zzolo’s picture

I was thinking that we should probably have the rendering process also involve the HTML process. Meaning that instead of the map array, maybe the render_map() should return some themed HTML.

I bring this up because it seems like we should have a class for all maps, in case someone (or we) wants to put a bordder around the maps or something like that.

Another option would be a wrapper function that return themed HTML.

What do you think?

phayes’s picture

I think a really simple wrapper function would be worth while.

Do you want to write up some documentation on your new layer management system? With examples?

I would like to start creating some layers, and I think I understand it, but i'm not to sure.

zzolo’s picture

Basic syntax for the hook_openlayers_layers_info() hook. If you look at the openlayers_layers module, it will be a good example. Please note that I have not tested this yet, just made sure that the defaults page rendered correctly.

The openlayers_layers_layers_info() (say that three times fast) implementation:

/**
 * Implementation of hook_openlayers_layers_info
 */
function openlayers_layers_openlayers_layers_info() {
  $file = drupal_get_path('module', 'openlayers_layers') .'/includes/openlayers_layers.layers.inc';
  $callback = 'openlayers_layers_process_layers';
  $info = array();
  
  // Define info array
  $info['openlayers_layers_jpl_nasa_wms'] = array(
    'name' => t('NASA JPL Global Imagery Service'),
    'file' => $file,
    'callback' => $callback,
  );
  
  return $info;
}

Whats going on here is just defining the basic information about a layer and where to get more. Since I am going to use the same function to get all these layers (that is in a single file), I am using variables for the file and callback. Otherwise, there is an ID (key of array) and a name.

Then, the callback function in includes/openlayers_layers.layers.inc:

/**
 * Process Layers
 *
 * Call back to process layers provided by the
 * openlayers_layers_openlayers_layers_info() function
 *
 * @param $layer
 *   String ID for the layer
 * @return
 *   Array formated for an OpenLayers map layer
 */
function openlayers_layers_process_layers($layer = NULL) {
  $layer_data = array();
  
  // Make sure layer is a string
  if (!is_string($layer)) {
    return FALSE;
  }
  
  // Get info array to reference title
  $layer_info = openlayers_layers_openlayers_layers_info();
  
  // Determine what data to send back
  switch ($layer) {
    case 'openlayers_layers_jpl_nasa_wms':
      $layer_data = array(
        'id' => $layer,
        'type' => $layer_info[$layer]['name'],
        'url' => 'http://wms.jpl.nasa.gov/wms.cgi',
        'params' => array(
          'layers' => 'modis,global_mosaic',
        ),
        'options' => array(),
        'events' => array(),
      );
      break
      
    default
      break;
  }
  
  return $layer_data;
}

So, in this function we are creating the more detailed layer array that would go into a full map array. The $layer argument that is passed is the ID that we defined in the layers_info() hook. So, we are checking what layer ID was passed, and then creating the correct array to return.

This is a simple implementation of the hook. If (and when) we put in a layer management interface, these values would be pulled from a database, but the hook implementation would be the same.

Specially looking at a WMS layer, it actually can hold multiple layers. So, in this instance, I am getting multiple layers with it. I am not sure what would be best practice: do we put each sublayer into its own layer array? Also, I got some positive feedback about getting the WMS administrative features out of nice_maps: #425930: Abstracting WMS Functionality

I am going to work on putting this into the defaults form tonight, and it might make it all even more clear. And, at that point, it might be good to put the ol form into the CCK widget settings.

zzolo’s picture

My work was broken, but through proper testing, it has been fixed. I also added in support fo picking layers in the defaults form. I also changed the example in the ol_layers.module. The same principles still apply:

/**
 * Implementation of hook_openlayers_layers_info
 */
function openlayers_layers_openlayers_layers_info() {
  $file = drupal_get_path('module', 'openlayers_layers') .'/includes/openlayers_layers.layers.inc';
  $callback = 'openlayers_layers_process_layers';
  $info = array();
  
  // Define info array
  $info['openlayers_layers_nasa_global_mosaic'] = array(
    'name' => t('NASA Global Mosaic'),
    'file' => $file,
    'callback' => $callback,
  );
  
  return $info;
}
/**
 * Process Layers
 *
 * Call back to process layers provided by the
 * openlayers_layers_openlayers_layers_info() function
 *
 * @param $layer
 *   String ID for the layer
 * @return
 *   Array formated for an OpenLayers map layer
 */
function openlayers_layers_process_layers($layer = NULL) {
  $layer_data = array();
  
  // Make sure layer is a string
  if (!is_string($layer)) {
    return FALSE;
  }
  
  // Get info array to reference title
  $layer_info = openlayers_layers_openlayers_layers_info();
  
  // Determine what data to send back
  switch ($layer) {
    case 'openlayers_layers_nasa_global_mosaic':
      $layer_data = array(
        'id' => $layer,
        'type' => 'WMS',
        'name' => $layer_info[$layer]['name'],
        'url' => 'http://t1.hypercube.telascience.org/cgi-bin/landsat7',
        'params' => array(
          'layers' => 'landsat7',
        ),
        'options' => array(),
        'events' => array(),
      );
      break;
      
    default:
      break;
  }
  
  return $layer_data;
}
zzolo’s picture

I have also created a field in the default form for the Default Layer, but I have not really thought about how to implement this. I have not looked at how OL actually does this. Any ideas?

phayes’s picture

openlayers_cck should be pretty workable and stable now. It's bug free in my evironment. It needs a code review and some testing before we move onto expanding it's features to include working with the new layer management system.

zzolo’s picture

Awesome! I will take a look, and try to add the open layers settings form to the widget. I haven't looked at the CCK module for a little while.

I think we should revisit what we want to happen in order to release a dev, alpha, beta, and/or 1.0 versions. I think two big features to get going before we release an beta version:

* CCK Formatter for the Geo Field.
* Views Plugin (we can look at GMap and Nice Map for good examples)

I think both of these features will depend on a good system of adding features to a map via the map array. After that, I think its just a matter of finding bugs and cleaning up code.

I think Layer Management GUI should be post 1.0 (there is already good layer management in the code).

phayes’s picture

Thanks for that. One thing we should add for a beta release is support for different projections. Right now we are assuming everyone is storing data in SRID: 4326 (lat and lon).

zzolo’s picture

FYI, I put our module into my API site. This means we can see how our inline documentation is. But, I have to manually update it at the moment, so it'll be good when we are cleaning up documentation and not something we can use easily in our process. Also, you can't really browse the project.

* http://api.zzolo.org/api/file/drupal-6-contrib/openlayers/openlayers.mod...
* http://api.zzolo.org/api/file/drupal-6-contrib/openlayers/modules/openla...
* http://api.zzolo.org/api/file/drupal-6-contrib/openlayers/modules/openla...

zzolo’s picture

As far as providing a theme for the HTML of a map, I added $map['themed'] to the rendering process. It is added after the map is added to the JS settings as it seemed like there was no need to provide it to JS.

phayes’s picture

Layer Terminology?

I'm finding the terminology in our layer management system to be a bit confusing. And i'm familiar with this stuff! What do you think about using the following terminology and updating our hooks / functions to reflect it?

Layer Type: that which is defined by hook_openlayers_layers_handler (perhaps rename to hook_openlayers_define_layer_type ?) This defines a "resuable" layer structure such as WMS, Vector, Marker, KML, etc.

Layer Instance: A specific instance of a Layer Type, with all the information such as url, etc. saved. openlayers_layers_nasa_global_mosaic would be an example of a Layer Instance of the Layer Type: WMS

Question: Should we allow Layer Instances that don't have a Layer Type? For example, Google Sat, Google Street etc. Or perhaps we force modules to define a Layer Type if they want to create a new Layer Instance that doesn't fit into pre-existing Layer Types?

Those are my thoughts. Please let me know what you think!

zzolo’s picture

I agree, it does get a little confusing.

The Layer Type is important, but the hook_openlayers_layers_handler_info() is for defining handlers for the Layer Types. So it may be more appropriate to call it: hook_openlayers_layers_type_handler_info()

I think info is a good suffix because it used in other Drupal places, and usually means that we are just compiling an array of information on what to do when more details is needed.

I like this way of only defining the layer handling, because it allows for lots of flexibility in defining layers and how they get processed. In theory someone could use a layer with type "WMS_extended", then define the handler with the hook, and also add as much information to their layer array and process it accordingly.

Also, I believe that if a Layer Type Handler is not found, then the map renderer does not actually include that data. I may have to double check that.

As far as the other hook, I would describe it more as Available Layers, since they are not automatically included in maps, just available to include. But, as I write this I think Layer Instances is probably a good solution. So maybe the hook could be: hook_openlayers_layers_instance_info()

--
zzolo

zzolo’s picture

Just a note on the blur events of the WKT fields. Currently it is using JQuery but this method does not handle the "Add Field" AHAH event. This needs to be addressed.

On 4/17/09 2:06 PM, Patrick Hayes wrote:
> Thanks for the tweaks to
> openlayers_cck. One thing: I purposefully didn't use jquery for the onblur
> event. When someone does a "add new item" to get another field, Drupal
> reloads all the fields via AHAH / AJAX, and so looses any events attached to
> the fields. You'll note that now if you add a new item, and then edit the
> text in any of the fields, the polygons on the map do not update like they
> were before. The only way I could think of remedying this is to add the
> onblur event in openlayers_cck.module, instead of using jquery. If you have
> any more elegent solutions please let me know!

phayes’s picture

Error checking and collisions:

I'm realizing we need a system for detecting "collisions" or incompatibilities between layers. Spherical Mercador layers such as Google Earth, MS Virtual Earth etc. are very picky about how you define the map projection, maxExtent, and MaxResolution:
http://docs.openlayers.org/library/spherical_mercator.html

So basically we need a way for them to say "Unless anybody else objects, i'm going to set the map projection, maxExtent, and MaxResolution the way I like them".

WMS layers would do something similar. Hopefully our WMS management system will use GetCapabilities to find out what projections are available for our WMS layers. So our WMS will say "Unless anybody else objects i'm going to set map projection to ESPG:4326. If someone does object (for example a google maps layer) I can work with ESPG:900913, ESPG:4043 or ESPG:3785"

Any thoughts?

phayes’s picture

I've implemented Google Maps, Yahoo Maps, and MS Virtual Earth layers.

You can see them in action with:


  $map_def = array(
    'height' => '400px',
    'options' => array(
      'projection' => "EPSG:900913",
      'displayProjection' => "EPSG:4326",
      'maxResolution' => 156543.0339,
      'maxExtent' => array(
        'left' => -20037508.34,
        'bottom' => -20037508.34,
        'right' => 20037508.34,
        'top' => 20037508.34,
      )
    ),
    'controls' => array(
      'LayerSwitcher' => TRUE,
    ),
    'layers' => array(
      'openlayers_layers_google_street',
      'openlayers_layers_google_satellite',
      'openlayers_layers_google_hybrid',
      'openlayers_layers_google_physical',
      'openlayers_layers_yahoo_street',
      'openlayers_layers_yahoo_satellite',
      'openlayers_layers_yahoo_hybrid',
      'openlayers_layers_virtual_earth_street',
      'openlayers_layers_virtual_earth_satellite',
      'openlayers_layers_virtual_earth_hybrid',
      'default_wms' => array(
        'id' => 'default_wms',
        'type' => 'WMS',
        'name' => t('Default Open Layers WMS'),
        'url' => 'http://labs.metacarta.com/wms/vmap0',
        'params' => array(
          'layers' => 'basic',
        ),
        'options' => array(),
        'events' => array(),
      ),
    ),
  );

$map = openlayers_render_map($map_def);

print ($map['themed']);

You'll note that you get a google earth API error - it can be safely ignored. You get it because I haven't yet implemented API key management. But this works for now. You'll also note that i've had to define projection, maxResolution, and MaxExtent. These need to be set like this for these particular layers to work. See my previous post...

One other thing to add to our to do list is implement 'default_wms' as a defined layer instance so we don't need to keep defining it in detail when we want to load it.

One last thing: I've moved the XYZ layer definition to the main openlayers.module. I think we should keep these "general" layer types (along with Marker, KML, GML, WMS and Vector) in the main openlayers.module, since they are likely going to be used a lot and we will want to make them available to other modules even if they don't want to use all the fancy layers we've defined in openlayers_layers. We should keep Google, Yahoo, VirtualEarth, and OSM layer defintions in openlayers_layers since these are "one off" layer types.

phayes’s picture

Did a bunch more work today. I moved our default_wms into a defined layer instance so you can select it in our "map defaults" page. I also updated the default map array to reflect this change.

I added support and definitions for Open Street Map layers. As of right now this requires you to load the dev version of OpenLayers at
http://openlayers.org/dev/OpenLayers.js

But I suspect that the dev version will be released stable very very soon given the state of their outstanding remaining issues: http://trac.openlayers.org/roadmap

phayes’s picture

Whew!

Added some NASA Layers, and also added a KML Layer type. If you install the KML module http://drupal.org/project/kml, you should get the option to use the "Local KML Feed" Layer in your default map. (Don't load any of the google, yahoo, VE, or OSM layers in the default map since the default projection is incompatible with these).

Working with all these many different layers (I think we are getting pretty close to the number we want to offer out of the box!), I'm starting to see the important of some sort of layer projection compatibility checking system.

For example:
All our tile layers (Google, Yahoo, VritualEarth, and OSM) can use projection: 900913 or 3785
Our NASA Layers only work with projection 4326
And our default WMS works with both 4236 and 900913 (but not 3875 strangely enough)

So happily our default layer is compatible with everyone, but Google etc. are incompatible with NASA.

zzolo’s picture

Great work, Patrick. I have not looked at the anything yet, but will in a moment. A few things:

1) Defining layers and implementing the layer_info hook. I am definitely open to discussion, but I think we need to keep those definitions in the ol_layers module and not in the API module, and here is why:

* The OL API module should be just that. A set of functions and methods to bring together definitions and data. It should handle the array, not defining what is in it. The exception here is very simple sensible defaults, with the only goal being that if someone called render_map() (withonly the API module installed) it would actually render a map (with a default layer)
* Every .module file is loaded on a Drupal page. I think its really important to separate out functionality and "data" (definitions) in this case, because there can easily be the case where someone wants to streamline their site and only define a couple custom layers. If we keep basic layers in the API module, then those will always be there.
* Example: CCK comes with FieldGroup. There is pretty much no reason not to install FieldGroup, but it is still separate functionality and thus in its own module, and it would help performance to uninstall it if it was not being used.

2) This ties into the "default_wms" layer and how it is the only exception in my opinion. I think it should be a regular definition like you have done. But it needs to be handled such that if no other layers are present, then the "default_wms" is included. Basically, it is part of the sensible defaults and is an exception.

3) Projections: Does it make sense to define a projection for the map, and have the layers support specific projects? This could ensure that only layers that supported the projection be included in the map. Also, how variable are projections? Is it something we should make a hook of?

--
zzolo

phayes’s picture

Re: API - OK, let's take your lead in terms of where we put things in the API. I won't be able to work on this for the next few days, so feel free to move thing into openlayers_layers if you want. I can also move the code over when i'll have more time for this later this week.

Re projection: Eventually I think some extensive error checking should be implemented - for example checking compatibility between Extent, maxResolution etc. But that's a wack of work and how we will want to implement it will likely become more clear over time. For now I think that layers should optionally define a list of projections that they are compatible with. Example:

      'default_wms' => array(
        'id' => 'default_wms',
        'type' => 'WMS',
        'name' => t('Default Open Layers WMS'),
        'url' => 'http://labs.metacarta.com/wms/vmap0',
        'params' => array(
          'layers' => 'basic',
        ),
        'projections' = array(4326, 900913),
        'options' => array(),
        'events' => array(),
      ),

If a layer does not define 'projections' then we will assume it is compatible with all projections. (Which is true for all vector layers since they can be reprojected on the fly by OpenLayers). Before the map is rendered we could check the list of projections against the map projection and raise a warning if there is an incompatibility.

zzolo’s picture

As far as Projections go.

1) Not sure how you have done it so far, but it would probably be a good idea to keep projections as string: '12345' not 12345. This is because it will be mostly used as a string and PHP handles integers different when they are the key to arrays.

2) The way you have the map error checking is fine, but I was thinking of something different. Since we are already going through the layers in the process method, we can stick the logic in there to check against the map projection. I also think there is no need to set a message. There are three main ways someone will create a map:

1: Sensible Default. We have control over this.
2: Customizing Form. I think we need to put in choosing a projection, and have it update the available layers in the drop down. This would ensure that people can only choose things that are compatible.
3: Programmaticly. Then they should know what they are doing.

So, I don't think there is any reason to display that message. I think it'll confuse the end user if it appears. We can log it, though.

As always, good job.

phayes’s picture

Re: Projections:

1. Good idea, i'll convert those to strings
2. I put the function in the code where it is on purpose thinking that we will likely want to do more error checking of the map when all is said and done - for example checking to make sure the the map's units, maxResolution, projection and maxExtent all make sense vis-a-vis eachother. Hence my comment about adding it as a hook - we may want to allow external modules that are altering the map in various ways to double check everything at the end to make sure there are no inconsistencies. About the drupal_set_message - your right, it's likely to confuse the end user if they ever see it. But most errors will confuse the end user if they ever see it! I know that projections along with all the units, maxResolution etc. can be very confusing, even for a developer who *should* know what they're doing. I like the idea of clearly communicating what is wrong up-front to help those developers who might be good at drupal but are struggling with new ideas around geo-concepts. Once all the bugs are worked out, the end user should never see it (as is the case for most error messages).

Re: Features in map array.

It's done! Check out the following:


$mappy['layers'] = array( 
  'feature_example' => array(
    'id' => 'feature_example',
    'type' => 'Vector',
    'name' => t('Default Vector'),
    'options' => array(),
    'events' => array(),
    'features' => array(
      'feature_1' => array(
        'wkt' => 'POLYGON((10 10,50 10,50 50,10 50,10 10),(20 20, 30 20, 30 30, 20 30,20 20))',
        'attributes' => array(
          'name' => 'A Polygon with a hole in it',
          'date' => 'December 24, 2004',
          'author' => 'Santa Claus',
        ),
        'style' => array(
          'fillColor' => '#aa4400',
          'fillOpacity' => '0.7',
        ),
      ),
      'feature_2' => array(
        'lat' => '40.123',
        'lon' => '-20.123',
        'attributes' => array(
          'name' => 'A point',
          'date' => 'December 24, 2004',
          'author' => 'Rudolf',
        ),
        'style' => array(
          'externalGraphic' => 'http://openlayers.org/dev/img/marker.png',
          'graphicOpacity' => 1,
          'graphicWidth' => 21,
          'graphicHeight' => 25,
          'graphicXOffset' => 10,
          'graphicYOffset' => 10,
        ),
      ),
    ),
  ),
);

$map = openlayers_render_map($mappy);

print ($map['themed']);

You'll note that we can either define a WKT property OR a lat and lon property. I've updated the README.txt with more info about the styles. Is there anything more that you think we need before we start building out a views module?

Re: "Behaviors"

I've put a little more thought into this. The way we currently have events set-up is very much for "end use" modules - which is great. Modules can fill out events and extend the functionality of the map they are displaying. However, this functionality is not reusable by other modules in different maps.

"Behaviors" then would be reusable groups of events, along with associated JS files/handler functions, that can be used across different maps. We actually already have one: draw_features. When draw_features is defined it creates event handlers for featureadded, featuremodified, and featurteremoved. draw_features is basically a group of events and JS event handlers that can be resued by any map array. A tooltip behavior would be handy so that we could define a map like so:

$map = array(
  'id' => 'Testing',
  ...
  'behaviors' => array(
    'tooltip_behavor' => array(
      'type' => 'tooltipper',
      'layer' => 'TheLayerIWantToTooltip',
      'attribute' => 'name',
     ),
     'editing_polygons' => array(
      'type' => 'draw_feature',
      'draw_type' => 'Polygon',
      'layer' => 'TheEditableLayer',
      'featureadded_handler' => array('SomeHandler'),
      )
    ),
    ...
 );


So in this example we are adding both tooltip behavior and draw_feature behavior. To tooltip behavior "tooltipper" would now be called and be responsible for filling out "mouseover" (show a tooltip), and "mouseout" (hide the tooltip) events. It would also add a tooltip div to the DOM. (Just like our draw_features behavior is adding those pan/draw buttons to the DOM).

So anyways. That's my idea for behaviors a little more fleshed out. Let me know what you think.

zzolo’s picture

Great work. I have not looked at the code yet. I like the features a lot. I'll have to think about the Behavoirs thing a little more, but sounds pretty good.

For creating a Views Plugin, there are a few modules that have already done similar things:
* http://drupal.org/project/mapstraction
* http://drupal.org/project/gmap
* http://drupal.org/project/nicemap

I like the idea of having the Views Plugin in another module, but Views actually does a really good job of allowing you to tput your code in a different file, sp I am not sure if it is necessary on the performance side. Any thoughts?

phayes’s picture

I think views in a different modules makes sense. I'm going to do a bit of research into how OpenLayers handles styling, and get my head around how we might want to deal with that in general..

phayes’s picture

Hey great work!

A few comments: I moved openlayers_default_wms out of the default map array since merge_maps simply merges arrays on keys, so it was merging in the default layer even if other layers were present. I think the functionality we want is that the default layer is only loaded if the layers array is non-existent or empty. This actually dove-tails nicely with another bug: We are adding the layer specified by default_layer into the layers array (if it is missing) in the form processing function. This is causing the default layer to be included even if we are overriding the 'default_layer' property in the map array later. We could squash two bugs with one stone if we simply moved this into the beginning of the process_layers function which would include the default layer if it is missing. This would also solve our first problem since our default_layer in our default map array is set to openlayers_default_wms.

Does it make sense to you or do you want some code examples?

I'll check out the openlayers_cck stuff and see if I can find your bug.

zzolo’s picture

I see what you are saying about the default layer. And I think just including it if there are no layers (maybe non-vector layers) is a good way to go. The goal is to make it so that a map works without setting anything up.

zzolo’s picture

Just a note. We are one of the most actively developed modules on Drupal at the moment. Not sure how often the stats update, but cool.

http://drupal.org/cvs (block on the left)

phayes’s picture

Hmm. I need some advice. I'm hoping to make the map form far more user friendly. To do that I would like to put the layers into a table with multiple options (much like the theme selector table we are all so familiar with). So that users could select the layers they want to make available, move them up and down using a handle widget (to order them), select one of them as the default, etc. These pages detail the "normal" way of doing this:

http://www.akchauhan.com/create-drupal-form-using-theme_table-like-modul...
http://drupal.org/node/47582

However, because our openlayers_map_form is actually not a form function it's self, but is used instead to embed map form arrays into other forms, I'm at a loss of how to do this. Any ideas?

Thanks!

phayes’s picture

Great work on the views module!

How do you feel we are doing as far as features go for a primary dev release?

Is there anything else big we want to build? Or do we want to concentrate on bug-squashing and cleaning up what we have?

P

zzolo’s picture

I would say that we could release a dev version right now. This is the time line and major actions I see that need to happen for each step.

* Alpha: After we have fleshed out the views plugin a little.
* Beta: After we have pegged down the API, reviewed logic and functionality of code, and written tests
* RC: After any outstanding bugs have been squashed and we run it through coder
* 1.0: After Full documentation and any bugs are fixed.

Given what we have, I predict the Beta being pretty solid and usable.

phayes’s picture

I'm now happy with the state of the map form. I think there is more work to be done there in terms of limiting options that will result in a broken map when merged with the default. For now, I've added a validator that should stop 95% of broken maps being submitted.

On my end I think we are ready for a dev release.

I was just thinking about the views module and how we might go about styling the features on the map. Eventually it would be cool to have a intuitive system for assigning feature styles. Fow now it might be a good idea to have a php textarea where the user can add code that will return a style array to be attached to each feature. Row data will be made available so the user could style each element based on other data. What do you think?

phayes’s picture

To Do List from Chat between zzolo and phayes:

Map form:
0. Merge in default form values
1. In the field descriptions use "if this value is blank, a default value of blah will be used"
2. after uninstalling and reinstalling I get some errors when going to the defaults page
3. Don't use alerts. Use something nicer.

zzolo’s picture

Patrick. I remember you mentioning how something weren't updating when Drupal did some AJAX things. I am not that well versed in it, but we probably want to change all our document.ready function to Drupal.behaviors function and this might address that sort of issue.

See http://api.drupal.org/api/file/developer/topics/javascript_startup_guide...

phayes’s picture

Good find! I'll set that as my major task to accomplish tomorrow.

The behaviors API is finished, and i've implemented 2 behaviors in openlayers_cck - check 'em out. I still have to translate the feature editing stuff into a behavior that uses the new API.

As always, criticism is *very* appreciated.

phayes’s picture

Version: » 6.x-1.x-dev

I've edited this comment. I've figured out how to extract the geo information without extracting it from added field. Way cleaner, and less computationally intensive. I'll get to work implementing it now!

P

zzolo’s picture

Hey phayes,

I am just starting to go through the code (there's a lot). I was wondering why you made a separate API function: openlayers_prepare_map() ?

phayes’s picture

Because I call it in _openlayers_map_form_validate. When someone submits a map form it goes through the whole process of pretending it is going to display a map, so that when it checks for errors, it can catch all of them properly.

zzolo’s picture

I took out the prepare_map function and just put those steps in the render_map api call. I also added some switch arguments so that you can call it and not go through the JS steps.

I Also changed how the default form was working, both through its check of errors, and how it gets it defaults. I creates new function: convert_map_to_form to create defaults for the form from the system default map. It needs work, but at the moment, there are some defaults in form, so it should make more sense to users.

I am having some problems with some of the values not showing up in the fields. I think this may have to do with some JS. I will look into it more.

zzolo’s picture

JS Namespaces!!!

So, I jsut read Drupal JS and jQuery and its so great! One of the things I picked up in it is namespacing. Not to say I didn't know about it before, but I got to see it used well.

One suggestion in the book is not to use the Drupal settings namespace, but we are a little too entrenched in that approach.

But, I would like to start using the "OL" namespace for functions. this will make things look prettier and we should be able to get out of using the Drupal.settings namespace except for getting data from PHP. I am still thinking about how to do module contributed functions when hooks are used. Any ideas or thoughts?

I am committing my changes to the openlayers.js file so you can start to see how it might work.

zzolo’s picture

Some further uses of a namespace.

* Change all "Drupal.openlayers.activeObjects" to "OL.maps" (this alone will save lots of characters!)
* Change "Drupal.openlayers.mapDefs" to "OL.mapDef"

zzolo’s picture

What I have been doing and am going to commit.

* Went through ol.module and ol_layers module and fixed a lot of formatting and some various logical things. Nothing major.
* The base API module should be mostly solid and ready to go (except for defaults form). It still should be run through Coder and Coder Tough Love, but should be a good example of formatting, documentation, coding practices at this point.
* Totally changed the JS namespaces for the base ol.module
* Changed namespace for layers and layer handlers.

So, now things are like this. Notice the new layer_handler:

function openlayers_layers_openlayers_layers_handler_info($map = array()) {
  // Define Layer Types that won't be used outside of this module 
  // such as Google Maps, Yahoo Maps, and MS Virtual Earth
  $js_file = drupal_get_path('module', 'openlayers_layers') .'/js/openlayers_layers_layers.js';
  return array(
    'KML' => array(
      'layer_handler' => 'KML',
      'js_file' => $js_file,
    ),
    'XYZ' => array(
      'layer_handler' => 'XYZ',
      'js_file' => $js_file,
    ),
    'Google' => array(
      'layer_handler' => 'Google',
      'js_file' => $js_file,
    ),
    'VirtualEarth' => array(
      'layer_handler' => 'VirtualEarth',
      'js_file' => $js_file,
    ),
    'Yahoo' => array(
      'layer_handler' => 'Yahoo',
      'js_file' => $js_file,
    ),
  );
}

And on the JS side:

/**
 * Process Google Layers
 */
OL.Layers.Google = function(layerOptions, mapid) {
  var mapType;
  if (layerOptions.params.type == "street"){
    mapType = G_NORMAL_MAP;
  }
  else if (layerOptions.params.type == "satellite"){
   mapType = G_SATELLITE_MAP;
  }
  // ....
}

Major To-Do's:

* I was not able to address the cck, views, or behavoirs module, so things are broken, given these changes.
* The setting form needs love. Its a good start and is powerful, but
** It seems buggy (I have made it kind of buggy, sorry)
** Does not properly use Drupal's built-in AHAH
** Does not fully support default_values
** The idea of sensible defaults is there, but I think we need to focus on easy changes. I think the biggest thing that most people will want to do is add on cool layers, so we need to ensure that this can be done with ease.

Also, this is probably just an old habit to break but for conditionals, there should be a space between condition and opening bracket, for PHP and JS:

if (condition) {

}
zzolo’s picture

Quick helpful command to see changes in CVS that look like "svn status" output.

cvs status 2>&1 | egrep "(^\? |Status: )" | grep -v Up-to-date
phayes’s picture

Awsome. I will get to work later today fixing behaviors, cck, and views to work with your changes.

Thanks so much for your tireless refactoring!

phayes’s picture

What do you think of having 'only_these_layers' turned on by default. (Or change it to be 'include_default_layers' that is off by default). I think one of the most confusing things is that when users deselect a layer in the settings form, it will still be there from the default - this is not very obvious.

The alternative should be to 'lock' the layer in the settings form, so that a user cannot unselect it. This will also mean marking certain projections as unselectable.

For each projection, we should also provide a link to http://spatialreference.org. (In the format of http://spatialreference.org/ref/epsg/4326/). Annoyingly they don't have 900913 since it isn't 'official'. Ideally, we could make use of their database in real time to fill out MaxResolutions and MaxExtent -- but that's maybe a future version.

phayes’s picture

I've got a good handle on fixing things up from your refactoring.

Some issues:

1. Naming: I think OL.Layers is a bit confusing. Perhaps OL.LayerHandlers? I have added OL.EventHandlers and OL.Behaviors (OL.BehaviorHandlers ?), these should be made consistent at any rate.
2. openlayers_cck.module, line 223. We are adding the themed map div using JS. This is great! However, openlayers can't find it! openlayers build is being triggered before the javascript that inserts the div into the DOM is, so it is failing. Hrm! One option would be to implement a timeout so that openlayers tries X number of times before giving up. Other ideas? I tried having openlayers be built using Drupal.bahaviors - but no dice.
3. openlayers_behaviors.behaviors.js includes helper functions. I didn't namespace these into OL.Behaviors, should I?

zzolo’s picture

"only_these_layers":
I am not entirely sure what this is doing. But what I think it is doing is a way to switch off the default system layer. I think what needs to happen is just a way in the rendering process to not include the default system layer if layers are provided. Basically, the default layer is there if nothing has been changed, but as soon as the user has saved some defaults or is rendering a map from code, then we should ignore our layer. The other settings can be overridden.

"Form Defaults in Description"
I think the key to all this is to make the settings form very descriptive and in those description tell the user what is the system default, so that in theory, they could just use those values to reset it.

"Naming":
I do like OL.LayerHandlers. I think Behavoirs is fine. I think you may have missed the point of namespacing, though, which is to keep things grouped together and shorten code. You did the following:

OL.Behaviors.openlayersBehaviorsDrawFeatures = function(event) { }

You see how it is redundant. What it should be is:

OL.Behaviors.drawFeatures = function(event) { }

"CCK Events"
Drupal.behavoirs to the rescue! Since openlayers rendering happens inside a Drupal behavoirs, all we have to do is call Drupal.attachBehavoirs after we have done our CCK stuff. Pretty awesome.

"$Id$":
Just noticing that seems to be missing from some files. The string "$Id$" needs to be at the top of all files, in a comment. It is used by Drupal's CVS to replace with relevant repo data. Not need to change it once it has been in there.

"My Changes":
I did a lot of work on the CCK and Behavoirs. Lost of formating and docuemntation and renamed functions and stuff. I can get a CCK field without errors but I have no controls, nor can I input anything. I am committing what I have though.

zzolo’s picture

Loading maps need to account for existing maps.

The OL.loadMaps function need to behavior in a more event driven manner. Meaning that it currently just starts over and loads all the maps in Drupal.settings.openlayers. But it should account for possible new maps that might join the page through AJAX or similar JS event. Basically it needs some way or marking maps as rendered and not resetting the OL.maps each time. This will ensure that anytime Drupal attachBehavoirs is called, things are not reset.

I just thought about this as I was looking at the code, then was testing the CCK module which attachBehavoir each time a new field is loaded, and it has some funny results. I think this is the bug you were running into phayes.

zzolo’s picture

Fixed. Pretty simple. I just added a rendered variable to the OL.maps array and just checked for it before rendering.

zzolo’s picture

I am currently working on the settings form. I am trying to make it simpler and use Drupal's AHAH functionality. Should commit something tonight.

zzolo’s picture

Finally committed all my changed for the Settings Form. It took me a while to figure out Drupal's AHAH form stuff, but I got it. (http://drupal.org/node/331941)

So, major changes.

* Overall, more simpler, more elegant
* More logic is pusdhed into PHP side of things
* I put Projections, Layers, and Options at the bottom and collapsed.
* By changing the Projections, it will update the Layers and Options accordingly
* Options now have an Automatic checkbox. This basically fills in the Options if checked.
* On the JS side, the Center Map is working fine now.
* I also moved something into the theme level (and created a new theme file)

Please test. I had to commit each file so that I didn't change any existing changes, but it should be fine.

One thing to note is that the submit handler is called with each AHAH trigger. This means it is saving it as someone is picking things. This could lead to problems.

--
zzolo

zzolo’s picture

So, I was thinking about things running into problems with the Settings Form and defaults, and it occurred to me to switch from an idea of Merging Maps with Defaults, to simply overriding them. This means that we use the system default if no default has been saved in teh defaults form.

I have created a new public API function that just simply checks for the save default map in the variables table, or gets the system default if the variable is not found:

$default_map = openlayers_get_default_map();

I have update the defaults form and CCK to do things in this manner.

zzolo’s picture

I had a pretty great idea in the shower today. I think we should move to using map presets. This would be similar to something like imagecache presets, or basically like gmap macro creation page, but being able to save it. It would require a different interface for the admin, and may be a fair amount of work if we want it in before 1.0 (but the module is still in dev). Here are the wonderful benefits:

* Easier to set a default.
* No need to reuse the complicated Settings Form in different places (like CCK or Views)
* Allows for "exportables" a lot easier
* Could allow for caching easier in the future
* Would allow for inline maps a lot easier that macros, like GMap uses

What do you think?

tmcw’s picture

I think that map presets sound like a really good idea, which would make managing layers a much more possible task for end-users. I'd really like to see the module expose all the various options that layers provide in a good way... that doesn't mean that it'll be user-unfriendly, but rather that stuff like KML layers with Strategy.BBOX() enabled, or any combination of layer, format, and option, wouldn't require hacking (as it has for me). I think something very similar to ImageCache presets would be great, basically saving a serialized layer configuration to the database and returning it as an array. That config should basically be an OpenLayers layer definition so that the javascript does the very bare minimum of modification and make no assumptions about any settings. And, of course, there should be a hook to get all these layer definitions, so that there can be layers dynamically provided by other modules.

At least that's my take on it, what are your thoughts?

zzolo’s picture

@tmcw,

Thanks for the comments. Presets are definitely going to happen. I am currently trying to update the CCK part to work with the new Geo, though it may be futile at the moment, so maybe I will just switch to map presets.

I am a little confused on the things you are referring to here.

that doesn't mean that it'll be user-unfriendly, but rather that stuff like KML layers with Strategy.BBOX() enabled, or any combination of layer, format, and option, wouldn't require hacking (as it has for me).

I am not sure why you would need to hack anything (the goal is not to). If for some reason the hooks for specific things don't work, there is always the final alter that is done, and there are plenty of events to hook into on the JS side. I would love to hear more about specific places you are thinking need to be extensible; I am sure I can't see all the use cases.

Thanks,
zzolo

tmcw’s picture

spoke too soon - I've been able to move a lot of the changes I've made into more standard code that works with the existing module. A few things are still straggling, though, and I'm not sure if I can do them without hacking. For one, I can't figure out how to add custom controls to a map - I have a bit of code that makes nice minimal controls of just zoom in / out, with hovers. I can't find out how events triggered with OL.triggerCustom are actually triggered, where they go - the documentation claims you can just write "function eventName()" and it'll work, but I've had no luck with that method or any of the others I've tried.

zzolo’s picture

@tmcw

I am glad things are looking better. First off, don't trust the documentation at this point; it has not been updated in a while. Second, you should be able to register an event in the following manner:

PHP side:

<?php
  $map = get_map_array();
  // In events key, use the custom triggers, then put in an array of callbacks
  $map['events']['beforeBehaviors'] = array('CCKProcess');
?>

JS side:

OL.EventHandler.CCKProcess = function(event) {
  var mapid = event.mapDef.id;
}

This is what I am doing in the CCK module to create all the extra handling of fields with the map. You should be able to add custom controls at this point. I would like to rename and re-asses or add where custom events are at some point.

Also, I have updated the CCK stuff for Geo-ish changes. It works for a single value, but is broken for multiple values. I started creating the preset interface. Going pretty good, mostly borrowing ideas form image_cache.

tmcw’s picture

Is there any way to do events from a view (where I don't have access to the $map array)? I'm only using OpenLayers via openlayers_views, and can't get default events to work, like

OL.EventHandlers.mapReady = ...
zzolo’s picture

@tmcw

No, at the moment, it has to be registered in the map array first. This makes it easy to put multiple callbacks to a single event. Phayes had implemented this, but I will take a look at it and see if we can't make it a little more flexible.

For now, if you are writing custom JS, you can write a simple custom module that uses the hook_openlayers_map_alter() and add your event registration there.

--
zzolo

zzolo’s picture

Big huge commit: http://drupal.org/cvs?commit=230092 (then plus the stuff I forgot)

Large Commit:
* Added Preset UI module. This allows the user to make map presets.
Presets are now used to manage and display maps
* You set the default Preset in the base OL Admin settings
* Updated Views PLugin to use a Preset
* #485298 by jer: Added support for CloudMade Tiles with the style
option
* Lots of various formatting fixes
* Various small bugs
* CCK And Geo stuff is still broken

So, phayes and I talked in IRC about the main things that need to happen before 1.0. So, I'm gonna go through a small roadmap here:

For ALPHA:
-----------------------
* Styles need reviewing
* Popups
* Smooth out Views Plugin
* Squash bugs

For BETA
-----------------------
* Tests (Should have done first)
* Coder and Coder Tough Love

For RELEASE CANDIDATE
------------------------------
* Squash any existing bugs
* Documentation (Inline and External)
* Demo
* Sweet looking themed controls as default

For 1.0
------------------------------
* Squash any bugs

I have been thinking about possibly making a Geo-independent CCK field. I know this module should not really get into storage but there are two main concerns I have that this would address:

1) When will Geo be stable?
2) How much overhead will Geo have

Basically, this will allow users to store very simple data and have limited functionality with that data. I definitely think that we should push for Geo, but in the meantime for this. It would be fairly easy since most of it is set up for the Geo field. Also, creating a tool to migrate that data to a Geo field should be pretty easy, shoudl we have to support that. Any thoughts?

So, all in all, we are pretty close. I am hoping to tag an ALPHA this weekend. I am very ready to get this module stable and enjoy my summer. Thank you all for the wonderful work.

zzolo’s picture

@phayes

I notticed you changed how the Default map preset was getting put into the database. I did nto have this problem, but it was because I was using the Devel's reinstall functionality, which is awesome, but since the uninstall and install happens on the same request, the functions from the module are still available.

The problem, ultimately was because during the install process, the .module file is not included. So, openlayers_save_preset() is not loaded. I first just dedicded to make a sopy of that function in the .install file, but I believe there is something up with drupal_write_record in the install process as well (not data to back up). So, I just did a manual DB Insert.

Should be working now from the install process.

Maybe further down the line, if the whoel default preset becomes a problem, we can look into hook_requirements.

--
zzolo

zzolo’s picture

Just committed fix for bug that makes the styles actually work, as far as the map preset interface default styles go.

zzolo’s picture

I have changed the 6--1.x version to use the DRUPAL-6--1 branch, instead of HEAD. This will allow for us to make a 7.x version or a 6--2 version in the future.

zzolo’s picture

Released ALPHA2. Main thing is that the WKT Field CCK works for a single value (did not look at multiple values). The formatters should work as well, but need to take into account multiple values. You can also choose which feature types to allow for the widget.

Next main fixes:
* WKT Field for multiples
* Popups

zzolo’s picture

ALPHA3 main changes:

* Grouping in views
* Much better handling of coded presets
* New hook: hook_openlayers_presets
* openlayers_presets provides a layer that uses Drupal's cache
* openlayers_get_presets is still used to get presets, but as a wrapper
* Instead of saving preset in database, the default map is just an implementation of the preset hook
* Coded presets can only be cloned and exported (not edited or deleted)
* I decided to use the default Drupal cache table to store data since this is not a huge amount of data
* Oh, and also, the map UI form now merges the original data with the new data from form, meaning that there was any data that the UI did not account for, it will still be saved.
* Overall, this should make things like integration with Features much easier
* Testing is always appreciated

WKT CCK and Popups, then beta!

zzolo’s picture

Just an update on roadmap and things that need to get done:

For Beta:
------------------------------------------
* CCK stuff (close)
* Fix any existing bugs
* Documentation
** openlayers.api.php (hooks)
** theming, some basic information at least
** Map array
** Changelog.txt
** any other stuff we can fit it

Once Beta, Patrick and I decided we will support any changes to the DB structure, but not to functionality.

For Release Candidate
------------------------------------------
* Fix any bugs that come up
* Tests (should have done first)
* Documentation
** Finish any documentation that belongs in the files
** Provide external documentation
** Provide API inline documentation site (I can put this up at a subdomain)
* Ideally I would like to have a more visually pleasing set of controls, but I am not sure if this will happen.

For 1.0
------------------------------------------
* Fix any bugs
* Provide Demo

Ideally we want to be at at least RC for Paris, Drupalcon. I am not sure if my presentation will be picked, but I put in a proposal for an OpenLayers session. Depending on our time, we should start a 7.x version after Paris.

zzolo’s picture

So, I got the CCK stuff working for the WKT Field. Basics:

* Allows for any combination of feature types
* It now uses a single textarea as the visual input. This is using a GEOMETRyCOLLECTION so that it can be copied and be standardized
* Data is actually stored in a hidden input field. This is done becuase the GEOMETRYCOLLECTION syntax is really hard to parse to get the features out of it.
* The field handles any allowed values. If there are a specified amount of values, any features added will replace the last one added.

Known problems
* Views data needs to be accounted for. Since we using our own handling of multiple values.
* Did not try integrate with Geo

Overall, this seems a little hackish, but it is by far the best solution that we have come up with. CCK does not make it all that friendly to do what we are trying to do: have a single input for multiple values. Testing is encouraged.

ReinoutS’s picture

Hi,

I'm creating a simple site with Drupal where visitors should be able to place markers on a map of the city and others should be able to see them. It looks like OpenLayers is the way to go so I installed it as well as the Views and CCK modules.
Everything seems to be installed correctly, but now my question is: how to proceed? I expected some extra content creation options, but I don't see them. Some hints to get me started would be very much appreciated.
Thanks,
ReinoutS

zzolo’s picture

@ReinoutS

* This module is still in heavy Development
* Make sure you have a firm understanding of Views and CCK first
* You should be able to add an OpenLayers CCK field, as well as use an OpenLayers views plugin
* This is not the correct place to ask this question, please start a new issue.

--
zzolo

zzolo’s picture

http://drupal.org/cvs?commit=247418

Just ran everything through Coder, with Minor warnings on and Internationalization on.

I beg you guys to try to run this before committing any new code. It will save me form ahving to spend 3 more hours getting rid of white space and change "){" to ") {" (I'm looking at you Phayes :)).

I am gonna work on some documentation now.

zzolo’s picture

http://drupal.org/cvs?commit=247430

I made some major changes to the documentation in the docs/ directory.

API.txt
* Points readers to other files
* Lists out the major public functions found in openlayers.module. Note that this just gives a very brief description. There is no need to duplicate the inline commenting

HOOKS.txt
This is just a directional sign, since most people may not think to look at openlayers.api.php

openlayers.api.php
This is the doxygen formatted inline documentation for the available hooks for openlayers. This can get parsed by the drupal api module.

THEMING.txt
Like the api.txt this provides a very brief overview of the available theming functions. Again, no need to duplicate inline commenting that should be adequate.

MAP_ARRAY.txt
This still needs lots of work. I am not sure the best way to go about this one. There is a lot of needed information, but I don't want to necessarily put it all in a text file like this.
* Maybe we can put it in douxygen format and make sure drupal api will read it
* Put it in Advanced Help format
* Keep it in plain text
* Any ideas?

I have updated my API site (api.zzolo.org). You can browse the hook code here:
http://api.zzolo.org/api/file/drupal-6-contrib/openlayers/docs/openlayer...

brynbellomy’s picture

I've implemented the Cluster strategy as a subset of Behaviors. The views style plugin interface has been updated with a clustering toggle, inputs for threshold and distance parameters, a 'popups allowed on clusters?' toggle, and a place to input the name of a custom JS callback (written by the user) returning the contents of cluster popups (this last bit has to happen this way because the contents of clusters are unpredictable before runtime, that is, long after Drupal/PHP has its way with things). This JS callback takes one parameter: 'feature'. It should look something like this:

function my_cluster_popup_contents(feature) {
    var to_return = feature.cluster.length + ' ' + feature.cluster[0].attributes.node_type_rendered + ' points here:<br>';
    for(f in feature.cluster) {
        to_return += '<img src="images/mapicon-' + feature.cluster[f].attributes.node_type + '.png" height=18 width=18>';
        to_return += feature.cluster[f].attributes['node_title_rendered'] + "<br>\n";
    }
    
    return to_return;
}

As you can see, it simply returns the HTML to be used as the popup's contents. feature.cluster is an array containing the Feature objects clustered together in a given cluster feature. Any views field that you include in your view is available in feature.cluster[x].attributes (as explained in more detail below).

Theming cluster features dynamically (based on the stuff they contain) is tricky for the same reason that it's tricky to know what to put in their popups. That is, we don't know what'll be clustered together until runtime. For this reason, I've provided a place in the views style plugin interface to input the name of a second JS callback. This callback is for defining OpenLayers Style Contexts. Because drupal_add_js() cannot pass functions to Drupal.settings, we need another way of getting those functions attached to our styles if we want those styles to be dynamic. Style contexts are just the ticket (see example below).

For what its worth, style contexts work just as well with non-clustered features and with non-dynamic styles, so if you feel like it, you can do all of your theming through this mechanism and forgo the theme_vector_styles, map_alter, and the Feature Styles box in the Views interface (though I don't really recommend it). But clustering is by far the best application of this technique, because clustering is the only time you have zero information about a feature until runtime, and so it's the only time you need Javascript to figure out how to theme features.

BRIEF INTERLUDE -- IMPORTANT FUNCTIONALITY W/STYLES THAT I DON'T KNOW IF PEOPLE ARE USING YET
When defining a style array for a layer or feature or whatever, OpenLayers allows you to use the following notation:
'pointRadius': '${radius}'
The OpenLayers JS code then searches first in feature.attributes and then in layer.styleMap.style.context for either a variable or a function called 'radius' to provide the value for pointRadius. This is how we achieve dynamic theming of features. (Warning: if you have a style context set up, OpenLayers will NOT look in feature.attributes).
END INTERLUDE.

Now, the way the OL Drupal module is set up, if you add some fields in Views to an OL map view, those fields are automatically added to feature.attributes. That means that, all of this style context business aside, any field you add in a view can be used to dynamically theme a feature. For example, if you add the Node Type field to your view, you might choose to define a style array somewhere that looks like this:
'externalImage': 'images/${node_type}.png'
Assuming you don't use the style context feature, OpenLayers will look for feature.attributes.node_type in determining the externalImage parameter.

On the other hand, if you DO enable style contexts in the OL module, OpenLayers will no longer look in feature.attributes for values (this is just how OL works). That means the fields you add to your view will still be in feature.attributes, but OpenLayers won't find them automatically. The tradeoff, however, is that now you can style features with JS functions at runtime.

Time for an example. Let's say you write the following JS callback:

function my_style_contexts(mapid, layerid, render_intent) {
    
    var style_context = {
        radius: function(feature) {
            if(feature.cluster)
                return 10 + feature.cluster.length * 3;
            else return 10;
        },
    };
    
    return style_context;
}

...and then specify "my_style_contexts" in the OL module Views interface. Now, when I define a style array somewhere, I can use ${radius}, which is automatically passed the feature variable, instead of simply assigning pointRadius a static value. But what about my feature's icon? Can we still use

    'externalImage': 'images/mapicon-${node_type}.png'

...? No, as I mentioned before, once you specify a style context, OpenLayers stops looking in feature.attributes where Views fields like node_type are stored. So what you have to do is simply add a kind of pass-through function that digs the value out of feature.attributes manually:

function my_style_contexts(mapid, layerid, render_intent) {
    
    var style_context = {
        radius: function(feature) {
            if(feature.cluster)
                return 10 + feature.cluster.length * 3;
            else return 10;
        },
        icon: function(feature) {
            if(feature.cluster) return 'images/mapicon-cluster.png';
            else {
                return 'images/mapicon-' + feature.attributes.node_type + '.png';
            }
        }
    };
    
    return style_context;
}

Now in your style array, you can set 'externalGraphic': '${icon}' and your features' icons will magically be based on their node types again.

Anyway, to reiterate, style contexts are most useful for clustering, but you can use them for all sorts of things if you're creative.

As far as implementation, I implemented Clustering as a subset of Behaviors, and it'll be really easy to add the other OpenLayers Strategy classes as Behaviors as well. The mapDefs object now has an array called 'strategies' (added by openlayers_behaviors_process_cluster() in openlayers_behaviors.behaviors.inc), which is then parsed in OL.Layers.Vector right before the Layer object is instantiated. Strategies have to be activated WHEN THE LAYER IS INSTANTIATED. They can't be attached later. Hence the slight changes to the flow of code in the Layer constructor.

Here's the commit: http://drupal.org/cvs?commit=252156

phayes’s picture

Holy cow brynbellomy!

To be honest my understanding of what overrides what in terms of styling is a little hazy. If you think you have it clear in your head could you possibly make some contributions to the documentation?

It also sounds to me like your experience with this suggests that some styling API changes might be in order to make things a little more consistent / easy to understand. Could you make any suggestions? This might be a good post 1.0 change. Or pre 1.0 if it seems important or small enough.

Thanks!

Patrick

zzolo’s picture

Pushed first Beta through (even though there were still some bugs out there). I also wrote up a big post on my blog to help get some buzz going: http://zzolo.org/thoughts/drupal-and-openlayers

These are things that I feel need to get done for a 1.0 (as well as just time to allow for bugs to be found)

* Squashing any bugs
* Testing
o We need people to start using the module and see how it works for them
o I also want to have at least a few SimpleTests done before a stable release
* Documentation
o Text-based documentation in the module needs to be finished up
o It would probably be better to push documentation to Advanced Help
o Any further documentation like handbook pages or screencasts would be wonderful
* Stylish Controls
o My personal goal is to get some stylish controls for the module to have by default. OpenLayers default controls are alright, but they won't win any hearts, and design goes a long way.
o Any designers out there want to help? (I have little to no design skills)

Thanks for all your hard work, everyone!

zzolo’s picture

I put in integration with the Module Builder module. See #406538: Module Builder Hook

Though this module is still in heavy development, I was the one who suggested the hook, so I figure I sort of had to be the one to start using it. I think its a good ideas, but could use a little work; I think the Module Builder module could really be something great. Either way, its a very minimal implementation and does not add any code to the .module file.

zzolo’s picture

Title: Development » Development for 6-1.x

Changing name to reflect new issue for other branches.

zzolo’s picture

I was going through some bugs and noticed some things about the context styles and clustering that I believe Bryn worked on.

1) Using eval() which is really bad.
2) Spacing and indenting is off.
3) If..else structures needs to be complete with curly brackets, even if they are not technically needed.

JS coding standards:
http://drupal.org/node/172169
http://www.stellapower.net/content/drupal-js-coding-standards-final-version

I will admit my meticulousness about all this, but we have come this far with doing a pretty good job of sticking to standards, so it would be awesome if it could get cleaned up.

zzolo’s picture

I am just noticing that a new drupal_alter was added to the render_map process and am confused by this. I believe phayes did this.

1) What is the use case for this? A drupal alter is pretty expensive, and anything that needs to be altered can still be altered after processing the layers, styles, and behaviors.
2) It seems that the later drupal_alter was renamed, which will probably break anyone's code that is currently using it. If this pre alter is needed, it should be the one that is named differently.
3) The drupal_alter for the map should be viewed as a last resort. Again drupal_alter is expensive, and if everyone seems to be using the map alter, then we are doing something wrong.

Personally, I would like to see this removed, but would like to hear what your goal with this is, phayes, and anyone else who has opinion.

phayes’s picture

Sorry for not putting this into a patch first for review - I didn't know it would be controversial, so apologies.

1. This whole issue came to my attention helping shiraz with his project, and noticing that hook_map_alter where it was wasn't working for him. The problem being that with hook_map_alter after the processing of layers, behaviors it was impossible to add preset layers or behaviors. Layers it is possible to add manually by building out the array, but I still think it is useful to be able to add them using just a string. Behaviors, however proved to be a bit of a show stopper. Behaviors often reference layers, and because layers names are often built programatically, it is not possible to add a behavior in a preset to target specific layers in some cases (or add behaviors based on things that are added to the map by other modules). I added the openlayers_map_final_alter to take care of cases where we *do* definitely want to alter the map after processing.

2. I thought about this. I think that it makes more sense to place the main map_alter before processing, so that people can use pre-defined layers and behaviors. As for existing implementation of hook_map_alter, most people should not be affected, as any changes made to the map will survive the rendering process just fine. There are some cases where people might use properties created by rendering to decide HOW to alter the map - this change will break their logic. With only 100 installations (as reported by usage, so there are likely a few more), I thought this was an acceptable risk. I should have posted a note on the issue cue or something I guesse.

3. This is true - but I still like the idea of giving people the choice.

phayes’s picture

P.S Let's resolve this before posting the next beta.

zzolo’s picture

I screwed up... twice.

1) I tried to change some eval statements and did not test. (http://drupal.org/node/432642#comment-2034806)
2) I changed the hover behavior on popups thinking it would just affect the feature hover, but it messed up the popup behavior all together. Again did not test.

My apologies. I will fix these soon. It was very bad development practices.

zzolo’s picture

Just an update on the the impending 1.0 release. This is what I am thinking is left to do to finally get this out the door, and just support bug fixes, and focus mostly on 2.x:

Status or changes:
* I am conceding the #555992: 2.x: Stylish Controls or A Theme System?
* Things are up to date according to Coder. Closing #583562: Coder for 1.x
** Please continue (or start) to run Coder through your commits first.
* #447686: 2.x: SimpleTests! Tests are still important!

To do:

* Features-Task-ish:
** #528952: Do not show empty map when views result is empty
** #555978: Handbook Page Documentation for 1.0 - I think we just need to add a little bit here. I think the handbook pages are a good place for recipies or more advanced tips, and that the internal Advanced Help should have all the basics of the module.
*** #564432: Import KML
** #555976: Advanced Help Documentation for 1.0
*** #587392: Guide users to custom builds for deployment.
** #583556: Clean up JS for 1.x
** #567898: 2.x: Temporary styles for hover events - I would argue that this could just be pushed back to 2.x, or added in a later 1.x version.
** #570236: 2.x Port: Support Domain Access module for Layers Keys and Main Settings
** #570292: 1.x: New Behavior: Click to zoom - This doesn't seem all that important. Can be moved to 2.x

* Bugs
** #519492: maps won't display in collapsible fieldgroup or other hidden div
** #586944: zoom_to_layer does not work for closed linestrings
** #592816: Cluster behavior does not work with two layers
** #592808: Views arguments break custom styles
** #566452: Openlayers causes php warning when adding a new item for a different multi-value cck field
** #566456: hook_features_api is broken

It looks like a lot, but it all seems like small discrete tasks. But It think we can move to release candidates once we get the bugs worked out. So close! Thanks for the great work, everyone.

tmcw’s picture

It seems like we're getting very close on 1.x. Thoughts?

It looks like we've got

  1. #528952: Do not show empty map when views result is empty
  2. #592816: Cluster behavior does not work with two layers
  3. #566452: Openlayers causes php warning when adding a new item for a different multi-value cck field

Anything else that's blocking the release?

phayes’s picture

I think those are the only bugs we need to squash before releasing an RC. Then we should wait two weeks and if no more bugs go for a 1.x. Do we have any features / tasks that are blocking a 1.x release?

I've still got to port my recent bug fixes on 1.x to 2.x - I think i'll get to that tomorrow.

zzolo’s picture

I would definitely say that we can go to a release candidate. The main thing, IMO, that is holding up the final release (besides fixing bugs) is documentation. It seems like a lot of the problems people are having are similar, and we can do a lot up front by creating good documentation. I think the best documentation we can do right now is to create map preset examples, and how to add/override layers/behaviors that are not available in the preset interface. I would also like to see #598206: Localize happen, not that it is much work.

Open 6.x-1.x issues:
* http://drupal.org/project/issues/search/openlayers?text=&assigned=&submi...

Most of these are support requests. The only bugs are the ones that tmcw listed above.

(Sorry for being MIA for the past while, I am moving out of the country in a couple weeks and it has gotten me pretty busy. I should be back in the full swing of things in the next few weeks.)

zzolo’s picture

Just an FYI (http://drupal.org/node/592816#comment-2332700), I updated the clustering code pretty significantly and it will probably break whatever someone is currently using.

zzolo’s picture

Released another beta: http://drupal.org/node/668378

Lots of good bug fixes in there. Great work, all. I chose another beta because we still have bugs in the queue.

It looks like there are a couple bugs that are holding us up:
* CCK and multiple values (a few issues here)
* Browser compatibility (a few issues here)

Both of these issues kind of suck. I am definitely getting tired of the 1.x branch and would much rather be working on the 2.x, but I still want to get a 1.0 out. I 'm gonna try and put a lot more time towards it both versions this week, and hopefully get at least an rc1 out for 1.x.

zzolo’s picture

OK! So, there are no bugs for 1.x and only a couple feature requests and support. I am sure some of this is caused by the fact that 2.x is getting much better and more widely talked about.

Anyway, let's do the 1.0. Here are my thoughts on what should happen beforehand:

* A coder run.
* A JSLint run
* Clean up Advanced_Help documentation. No need ot complete it, just make sure what is there is accruate.
* Release it! (and then suggest that people start using 2.x :)

Thoughts/Concerns?

phayes’s picture

I've run through everything with IE7 and it seems to be working relatively well - I had to do a bunch of JS changes to the preset UI to make IE happy. If anyone wants to pressure-test the preset UI in other browsers / OS's I think that would be a good idea.

I would recommend doing a coder, JSLint, and documentation cleanup, and then going for a release.

phayes’s picture

Also, not sure how much of this needs to be done before a 1.0 release...

grep -Rn "TODO" *
help/openlayers-map-array-layers.html:103:<strong>TODO: Add docs for the specific options for each layer that OL modules provide.</strong>
help/openlayers-map-array-styles.html:28:<strong>TODO</strong>
js/openlayers.js:156:  // @@TODO: Do this in the map options -- As is,
js/openlayers.js:245:    // @@TODO: This should be a little more dynamic
modules/openlayers_behaviors/includes/openlayers_behaviors.behaviors.inc:195:    // @@TODO: Add Events to layer (features added + removed)
modules/openlayers_behaviors/js/openlayers_behaviors.behaviors.js:835:  //@@TODO: Fix the use of direction instead of using math.random
modules/openlayers_cck/openlayers_cck.module:84:      // TODO: ,'content_icon' => '',
modules/openlayers_cck/openlayers_cck.module:150:        // @@TODO: validate WKT
modules/openlayers_cck/openlayers_cck.module:790:      // @@TODO: Allow default values using a map
modules/openlayers_cck/js/openlayers_cck.js:86:        // TODO: Notification a little less harsh
modules/openlayers_filters/openlayers_filters.module:100:        // @@TODO: Make better description for long text
modules/openlayers_layers/js/openlayers_layers.layers.js:186:  // @@TODO: Check for CloudMade definition since it is in another file
modules/openlayers_presets_ui/js/openlayers_presets_ui.ui.js:32:  //TODO: process above function on page load for the currently selected item
modules/openlayers_presets_ui/js/openlayers_presets_ui.ui.js:62:  // @@TODO: Reproject lat/lon values of center map. On the first load
modules/openlayers_views/views/openlayers_views_style_map.inc:346:      // @@TODO: In theory, there could be multiple features per row., allow for multiple features per row
modules/openlayers_views/views/openlayers_views_style_map.inc:353:            // @@TODO: These fields are provided only if the fields are chosen in the interface.
modules/openlayers_views/views/openlayers_views_style_map.inc:362:            //@@TODO: Make it work on grouped multi-value fields geo. First http://drupal.org/node/446754 must be fixed.
modules/openlayers_views/views/openlayers_views_style_map.inc:408:                // @@TODO: Allow different projections
modules/openlayers_views/views/openlayers_views_style_map.inc:511:      // @@TODO: Reduce and sort duplicates
modules/openlayers_views/views/openlayers_views_style_map.inc:597:      // @@TODO: Put checkboxes in the style plugin interface to choose layers to use popups with?
openlayers.module:630:  // @TODO: Instead of manually specifying projections, we should do a lookup on the projections in a big table to get variables that it should be checked against.
openlayers.module:631:  // @TODO: For next release, make hook
zzolo’s picture

That's a good catch on the TODO's, but personally I would rather just push it under the rug. :) Awesome, it seems like 1.0 is near ready!

zzolo’s picture

So, ran through coder, and everything is fine.

Still running through JSLint, and have found this:
* #730778: Use of eval() in Context Styles

zzolo’s picture

Ok, I went through it all to the best of my ability and things are better. Most of the stuff that JSLint catches is not that big of a deal.

So, if we could get someone else to take a look and sign off, I say, let's do the 1.0 (and finally close this ticket)!

Also, I made a few more test maps, which should make testing a lot easier.

zzolo’s picture

I'm gonna try to push out a 1.0 tonight (or at least an rc2) and then I think we should stop support for 1.x, though still excepting patches of course. This means updating the project page to make it all more obvious about using 2.x. If I don't hear any objections in the next week, I will go ahead with this.

zzolo’s picture

Status: Active » Closed (fixed)

OK, so, I pushed out a RC2. There are a few minor issues in the queue. As disappointed as I am to not actually push out a 1.0, I think its best to just leave in current state and maybe someone will come along with time to dedicate to addressing these issues.

I have also updated the project page to better reflect the shift to promoting 2.x fully.

Closing.... *sniff*