Hi. I know this module is still in development but what it's capable of doing right now is so tempting that I'm going forward with using it.

I've been looking at the documentation for the OpenLayers javascript library, and trying to translate the documentation there. I've got a few things working, including overlaying markers from an external KML file-- I found some examples for that. I have OSM Mapnik layers working with the RC2 version of OpenLayers-2.8.

It's my understanding that OpenLayers itself right now only supports markers and tracks from KML files, and not overlays. That's not a big deal since I have the images and the coordinates of the image's bounding box. However I can't seem to figure out what to put in my map to get that image to display.

Does anybody have a working example of an image overlay layer that I could look at?

Thanks.

CommentFileSizeAuthor
#5 Map display with image layer enabled168.8 KBdmjossel
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

dmjossel’s picture

For instance, this is the map code I'm using. It works and shows OSM Mapnik, the local KML feed, plus an external KML file (at least, the markers portion):

<?php
  $map_def = array(
    'height' => '550px',
    'width' => '625px',

    '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_osm_mapnik',
      'wimax' => array(
        'id' => 'kml_test',
        'type' => 'KML',
        'name' => t('WiMax Base Stations First Phase'),
        'url' => '/test.kml',
      ),
    ),
  );

$map = openlayers_render_map($map_def);

print ($map['themed']);
?>

When I try and guess at what the code should be for an image layer, based on the PHP code examples for the base layers and the KML layer, and some javascript examples of image layers, I got this:

<?php
  $map_def = array(
    'height' => '550px',
    'width' => '625px',

    '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,
      ) // close maxextent
    ), // close options
    
    'controls' => array(
      'LayerSwitcher' => TRUE,
    ), // close controls array
    
    'layers' => array(
      'openlayers_layers_osm_mapnik',

      'wimax' => array(
        'id' => 'kml_test',
        'type' => 'KML',
        'name' => t('WiMax Base Stations First Phase'),
        'url' => '/test.kml',
      ), // close wimax array

      'signal' => array(
        'id' => 'signal',
        'type' => 'Image',
        'name' => t('Signal strength'),
        'url' => '/mxx.png',
        'bounds' => array (
                'left' => 76.8074386678086,
        'bottom' => 43.1026300807703,
        'right' => 77.0937429562739,
        'top' => 43.3711136149743,
), // close bounds array

      ), // close signal  array


    ), // close layers array

  ); // close map_def array

$map = openlayers_render_map($map_def);

print ($map['themed']);
?>

However, this map not only doesn't show the image overlay, it's completely broken-- nothing displays, zoom and pan functions stop working, even the layer selection widget stops displaying anything.

I know this isn't a bug and I'm just doing it wrong... are there any image overlay examples that work specifically with this module's implementation of OpenLayers?

zzolo’s picture

Title: Image overlay example? » Layer Handler Type Should Not Need to Exist
Component: Miscellaneous » Code
Category: support » bug

@dmjossel

Thanks for the comments. For the 1.0 we will have much better documentation.

Basically, we do not have support for an image overlay layer. But we have a hook system that allows for you to make your own.

hook_openalyers_handler_info($map = array()) { }

A good example would be in the openlayers_layers module. Basically it defines the the "types" of layers (seen in your array as "Image"). So, you would define an "Image" type, and the main code for the layer is in a JS file. Basically your JS file will container a function that will return an OpenLayers layers, and you define what options you expect.

If you do this and make it general enough, we could just include it in the openlayers_layers module.

On the notion of your map breaking because you have an undefined type, I would consider that a bug, and it is something we should address. The map should be able to degrade gracefully if that type does not exist or is not defined. I am switching the type of issue this is and the title so that it reflects the bug.

dmjossel’s picture

@zzolo

Thanks for the quick reply. I'm thicker than molasses in January but I'm going to take a crack at this anyway. Feel free to ignore me if my "help" becomes more trouble than it is worth, which seems not only possible but likely.

I've added an entry to the function openlayers_layers_openlayers_layers_handler_info($map = array()), defining "Image" as a type and linking it to a new javascript file:

    'Image' => array(
      'layer_handler' => 'openlayersLayerHandlerImage',
      'js_file' => drupal_get_path('module', 'openlayers_layers') .'/js/openlayers_layers_image.js',

Looking at what was in openlayers_layers_image.js for the other supported layers, I put a single function in my new javascript file:

/**
 * Process Image Layers
 */
function openlayersLayerHandlerImage(layerOptions, mapid) {

  var mapOptions = {
    projection: new OpenLayers.Projection("EPSG:4326"),
    maxExtent: new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34),
     isBaseLayer: false,
    format: OpenLayers.Format.Image,
    formatOptions: {extractStyles: true, extractAttributes: true}
  };
  
  jQuery.extend(mapOptions, layerOptions.options);
  
  var returnImage = new OpenLayers.Layer.Image(
    layerOptions.name, 
    layerOptions.url, 
    mapOptions
  );
  
  return returnImage;
}

The Layer.Image constructor documentation shows one more parameter:

name	{String} A name for the layer.
url	{String} Relative or absolute path to the image
extent	{OpenLayers.Bounds} The extent represented by the image
size	{OpenLayers.Size} The size (in pixels) of the image
options	{Object} Hashtable of extra options to tag onto the layer

...which in this case is size. I don't know how to implement that (I'm a writer, Jim, not a programmer) but I'm also unsure if it's necessary/desirable for what I'm attempting to do, which is display a scalable image overlay-- one that will scale as the map zooms so that its size in relation to map features remains constant. Putting in a size in pixels would seem to indicate that this would not work (or perhaps it means the size in pixels at the default zoom level?)

Anyway fantastic work with the module so far, it has let me do quite a lot without requiring any real code writing (which is what's dangerous about it I suppose) but the results look great and for that I thank you.

phayes’s picture

I see a few problems with your implementation. You are almost there!

Referring http://dev.openlayers.org/releases/OpenLayers-2.7/doc/apidocs/files/Open... we can see that an Image layer requires:

name {String} A name for the layer.
url {String} Relative or absolute path to the image
extent {OpenLayers.Bounds} The extent represented by the image
size {OpenLayers.Size} The size (in pixels) of the image
options {Object} Hashtable of extra options to tag onto the layer

The first step would be to get it working without all that mapOption stuff (as the mapOption array is what goes into the options parameter for building your layer, and is not required).

So we want to do something like this:

  var returnImage = new OpenLayers.Layer.Image(
    layerOptions.name, 
    layerOptions.url, 
    extent,
    size
  );

You'll not that for extent and size I didn't just reference the layerOptions, that is because these need to be returned in the form of a extent object, and a size object, which have documentation here:

http://dev.openlayers.org/releases/OpenLayers-2.7/doc/apidocs/files/Open...
http://dev.openlayers.org/releases/OpenLayers-2.7/doc/apidocs/files/Open...

dmjossel’s picture

Thanks very much for your help!

I think I didn't understand the difference there between the options object and the other objects needed to render a layer, thanks for that.

On your advice I temporarily removed the mapoptions var, so openlayers_layers_image.js looks like this:

/**
 * Process Image Layers
 */
function openlayersLayerHandlerImage(layerOptions, mapid) {

  jQuery.extend(mapOptions, layerOptions.options);
  
 var returnImage = new OpenLayers.Layer.Image(
    layerOptions.name, 
    layerOptions.url, 
    extent,
    size
  );

  return returnImage;
}

In keeping with the documentation on bounds and size, I changed the map definition to this:

<?php
  $map_def = array(
    'height' => '550px',
    'width' => '625px',

    '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,
      ) // close maxextent
    ), // close options
    
    'controls' => array(
      'LayerSwitcher' => TRUE,
    ), // close controls array
    
    'layers' => array(
      'openlayers_layers_osm_mapnik',

      'wimax' => array(
        'id' => 'kml_test',
        'type' => 'KML',
        'name' => t('WiMax Base Stations First Phase'),
        'url' => '/test.kml',
      ), // close wimax array

      'signal' => array(
        'id' => 'signal',
        'type' => 'Image',
        'name' => t('Signal strength'),
        'url' => '/mxx.png',
'size' => array (
'w' => 625,
 'h' => 550,
), // close size
      'bounds' => array(
        'left' => 77.0937429562739,
        'bottom' => 43.1026300807703,
        'right' => 76.8074386678086,
        'top' => 43.3711136149743,
      ) // close bounds
      ), // close signal  array


    ), // close layers array

  ); // close map_def array

$map = openlayers_render_map($map_def);

print ($map['themed']);
?>

Bounds is apparently supposed to be in the form top, bottom, left, right, but takes lat/long values, so I took the bounds from the KML file that has this embedded image and used those values.

Size I just made the same as the map size itself to start with. I'm still not really sure OL supports scaling this the way I want since I've never seen an example that does this, but I figure I should be able to get SOMETHING to show and then go to some other option (polygons?) if I can't make it work at all.

I think I still must be missing some element, though, as the result I get is the attached. Now the widgets render, but they don't function, and the map still does not display. If I remove the image layer definition, it renders.

dmjossel’s picture

Looks like this might be fixed now... my image layers still don't work, but they don't seem to break the map anymore.

zzolo’s picture

Status: Active » Fixed

This has bee fixed:

/**
 * Process Layers
 *
 * Process the layers part of the map definition into OpenLayers layer objects
 * 
 * @param layers
 *   The layers section of the map definition array.
 * @param mapid
 *   The id of the map to which we will eventually add these layers.
 */
OL.processLayers = function(layers, mapid) {
  OL.maps[mapid].layers = [];
  
  // Go through layers
  if (layers) {
    for (var layer in layers) {
      // Process layer, check for function
      if (OL.isSet(OL.Layers) && typeof(OL.Layers[layers[layer].layer_handler]) == 'function') {
        var newLayer = OL.Layers[layers[layer].layer_handler](layers[layer], mapid);
        OL.maps[mapid].layers[layer] = newLayer;
  
        // Add our Drupal data to the layer
        newLayer.drupalId = layer;
        newLayer.drupalData = layers[layer];
        
        // Add events
        for (var evtype in layers[layer].events){
          for (var ev in layers[layer].events[evtype]) { 
            newLayer.events.register(evtype, newLayer, OL.EventHandlers[layers[layer].events[evtype][ev]]);
          }
        }
      }
    }
  }
}

Status: Fixed » Closed (fixed)

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