Provide a Legend behavior.

Comments

tmcw’s picture

Er, unclear.

openlayers_plus hacks in a legend behavior, and hacks in legend data, which is then hacked into layer objects because, after all, it's javascript. Unless this can be written in a way that can be accepted into OpenLayers proper, I don't think that this belongs in the OpenLayers module.

strk’s picture

StatusFileSize
new7.24 KB

I did take a look at OL+, but it didn't help WMS in any way.
Similar to the query behavior this one would aim at abstracting legend for all layers.

The attached patch provides implementation for the WMS part.

You're probably right the functionality might be in a separate module.
Just haven't found a good name yet for my own hacks (ol++ might be one :)

tmcw’s picture

Uh, I don't really get why this patch is this way. The openlayers_plus legend implementation handles legends from any layer type, provided that that layer type provides the legend as an attribute on the layer object. Why not build this as WMS support for the openlayers_plus legend functionality, rather than ending up having two legend behaviors that do basically the same thing in slightly different ways with completely different code?

strk’s picture

Yeah, you're right I should have worked on improving the ol+ behavior.
So, how would this be done ? Implementing a map_hook to fill up the 'legend' option for the layers I want to support ?
There's no UI provided by ol+ itself, right ?

strk’s picture

After some discussion on IRC I realized the ol+ behavior only takes care about putting legends in the page, but in no way attempts to create the legends, which is left to layer_type classes.
This approach requires to write more code to get the actual legend, so is pretty useless on itself.

My approach instead tries to enable legends automatically for WMS layers.
Not sure how the same could be done for other layer types, but surely such approach
needs to add layer-specific knowledge into the behavior. I'm not against that, also the
Query behavior (my other proposal) does that.

strk’s picture

Ok, summary after a second talk on IRC. We agreed on the following:

- Each layer should provide it's own legend, if any
- Core should contain legend provider for WMS layers
- Core should contain legend behavior (the part showing the legends)

As for implementation, the idea is that the OL layers created by DOL
layer factories would be optionally equipped with a method to be used
by the legend behavior to enable the layer's legend.
Such method would be passed a div object, so that the layer can also
decide to register map event callbacks to update the legend based on
scale.
The behavior itself will take care about making the layer legend visible or
not based on layer visibility.

strk’s picture

About passing a div object to the layer's legend manager I think that's not enough flexible.

Consider the case in which you may or may not want to add the layer name to the legend.
That'd be a behavior configuration, not a layer configuration.

So here's another architecture:

Layer objects (OL) would expose these methods:
  - enableLegend(legendHandler) // calls legendHandler(layer, text), optionally registers events to re-call it
  - disableLegend() // optionally de-register events

With the above model a layer_type willing to update the legend based on scale will register
its own events on 'enableLegend' call and possibly de-register it on 'disableLegend'.

The behavior will take care of putting the text to final destination so can decide to add
the layer name or not, and where to put the things as it will provide a legendHandler itself.

The behavior may call 'disableLegend' when hiding a layer's legend due to visibility state
and call 'enableLegend' again when it comes back visible.

How do you like it ?

strk’s picture

StatusFileSize
new8.7 KB

The attached patch implements the idea in previous commit, basically adding enableLegend/disableLegend to WMS layer_type
and tweaking my previous legend behavior to use that information.

Should work fine with user-defined layer_types as long as they provide enableLegend/disableLegend too.
Only additional thing might be tweaking the interface to select which layers to handle legend for, which currently
only allows WMS layers.

tmcw’s picture

Huh? I think we might have been talking past each other at some point, or all points... This code still has nothing in common with the openlayers_plus code, and it still includes coupling with the WMS layer.

The justification for this approach is still evading me. Have I not shown that all of this is possible with the stock ol+ control and a few lines of straightforward code?

Consider the case in which you may or may not want to add the layer name to the legend.
That'd be a behavior configuration, not a layer configuration.

If you read the openlayers_plus control, that's incredibly straightforward to implement within it, and it's by no means a limitation of its design.

About passing a div object to the layer's legend manager I think that's not enough flexible.

How? I don't understand how the code that I've demonstrated can be exactly as functional as what you've just posted, but less complexity on the concept level and a more straightforward implementation of the 'normal case' in which Drupal is writing the legends.

Sorry, I must be missing something here, or we must be talking past each other, but the approach that this is taking really doesn't seem optimal, given that it misses out on a lot of the code cleanliness of the ol+ approach, it introduces a whole lot more javascript, the javascript is much more complex while doing the same thing.

If there's a one-off solution that needs to be built for your project, go for it, I just don't understand the rationale of this approach.

strk’s picture

This code still has nothing in common with the openlayers_plus code

I didn't feel like touching openlayers_plus code at this stage, particularly didn't feel
like refactoring it to prepare for DOL-core (renames...).

The patch I sent is just for concept proving for the bahvior part, and proposal for
the WMS layer_type impelementation of the legend concept (enableLegend/disableLegend)

I still belive OL+legend is the one which should end up in core, appropriately modified
to make use of the enableLegend/disableLegend methods of layers, when available.

it still includes coupling with the WMS layer.

Not really. The behavior only checks for existance of 'enableLegend' and 'disableLegend' methods
in the OL layer object. Nothing more.

The patch does additionally contain a patch for layer_type_wms, but that's not part of the behavior.

strk’s picture

.. hopefully with better format ..

This code still has nothing in common with the openlayers_plus code

I didn't feel like touching openlayers_plus code at this stage, particularly didn't feel
like refactoring it to prepare for DOL-core (renames...).

The patch I sent is just for concept proving for the bahvior part, and proposal for
the WMS layer_type impelementation of the legend concept (enableLegend/disableLegend)

I still belive OL+legend is the one which should end up in core, appropriately modified
to make use of the enableLegend/disableLegend methods of layers, when available.

it still includes coupling with the WMS layer.

Not really. The behavior only checks for existance of 'enableLegend' and 'disableLegend' methods
in the OL layer object. Nothing more.

The patch does additionally contain a patch for layer_type_wms, but that's not part of the behavior.

tmcw’s picture

Not really. The behavior only checks for existance of 'enableLegend' and 'disableLegend' methods
in the OL layer object. Nothing more.

The code within the legend behavior currently only lets users enable legends on WMS layers, and there's no construct for any other layer to have a legend (or indicate that it can provide one)

The problem is that this code is a whole lot different from the openlayers_plus approach - the way that HTML is written here and how it's generated in openlayers_plus is entirely different, and the way that they keep track of layer visibility and bind events (this method actually re-binds events every time visibility is changed), is entirely different.

And, as far as the disableLegend behavior, I just don't get it. What's the advantage of this approach over a legend simply managing its own legend and checking whether it is visible before doing anything?

strk’s picture

The code within the legend behavior currently only lets users enable legends on WMS layers, and there's no construct for any other layer to have a legend (or indicate that it can provide one)

Right, this is a limitation which should be removed. Prompting for all layers which _can_provide_a_legend_ would be much better.
In order to do this we'll need an additional per-layer configuration (much like the current 'isBaseLayer' kind of thing).
I can work on adding that, still core, still useful for 'legend supports in core'.

The problem is that this code is a whole lot different from the openlayers_plus approach

I might try to fork from OL+legend if that'd make you less anxious, but again, take the code just as a proof of concept,
not as a proposal to put in core.

More on the points:

the disableLegend behavior, I just don't get it. What's the advantage of this approach over a legend simply managing its own legend and checking whether it is visible before doing anything?

The advantage of the 'handler' approach is that the legend behavior can decide whether or not to enable a layer legend
and what to do with the legend text whenever the layer decides to update it.

What's your idea of a layer "simply managing its own legend" ? The layer (JS) would need to:
- create the legend
- optionally update it based on map events

tmcw’s picture

The advantage of the 'handler' approach is that the legend behavior can decide whether or not to enable a layer legend
and what to do with the legend text whenever the layer decides to update it.

On a per-layer level? Possibly there's some use case in which a layer can provide a legend but you don't want to see it (but want to see other layers's legends), but this just doesn't follow the pattern of, for instance, the built-in OpenLayer attribution control.

Yes, in order to not update the legend when the layer is inactive, you'd need... something like if(this.visibility){, and that's all...

strk’s picture

StatusFileSize
new7.68 KB

Another version adding an .updateLegend() method in case a behavior would want to trigger the call to the handler again for any reason.

strk’s picture

StatusFileSize
new1.65 KB

New version of wms.js adds scale-dependent legend support.
I've tested it, and works (with mapserver).

The way it works is you add a SCALE parameter to the GetLegendGraphic URL.
It's an optional parameter, so not guaranteed to work with all servers.

strk’s picture

StatusFileSize
new9.29 KB

New version of full patch.

Now you can specify, for each LAYER object wheter or not it supports legends (in layer_type PHP side).
Then, the PHP side of legend behavior will only prompt you to select the layers actually SUPPORTing a legend,
and allow you to select NO layers to enable it for all supported ones.

zzolo’s picture

Some insignificant comments:

* Coding standards
* Variable names are inconsistent. Underscore in PHP, lowerCamelCase in JS, and the former for variables that pass form PHP to JS. (please note that the last one is not the standard)
* Too many comments about TODO or debugging

Overall, this seems to make sense, but I haven't actually put much thought into it. I do think a Drupal block implementation is better than an OL control, because 1) its not an interactive control like draw features, and 2) it could take up a lot of map real estate, and 3) a Drupal block can be put over top a map if needed.

tmcw’s picture

Considering killing this ala #860444: Add WMSGetFeatureInfo behavior, and supporting openlayers_plus instead...

strk’s picture

Status: Active » Postponed

Yeah, let's kill.
My vector legend is much worst than teh GeoExt one, btw :)

tmcw’s picture

Status: Postponed » Closed (works as designed)

Closing - works as designed. Won't comment on the less-than-beautiful GeoExt panel :)

AgentJay’s picture

Version: 6.x-2.x-dev » 7.x-3.x-dev
Component: Behaviors » OL API
Issue summary: View changes
Status: Closed (works as designed) » Active

I believe it might be worth re-visiting this issue. Mainly as the Openlayers plus only supports point legends based on the styles defined in Drupal Openlayers, where this was intended to display WMS layer legends based on styles defined on the server that is storing the map.

I have re-opened the ticket and changed it to version 7.x-3.x. I am currently trying to figure out how to get this feature working with the newest version of Drupal Openlayers based on the old patch, but I would greatly appreciate some help.