wicketstuff / core

Wicketstuff-core projects are bundled user contributions for use with Apache Wicket (https://wicket.apache.org/). They are released in step with Wicket releases to make them easy to use.
342 stars 298 forks source link

[Openlayers3] How to do a GetFeatureInfo request #514

Open abiuan opened 8 years ago

abiuan commented 8 years ago

Hello, at first glance I have a simple task: do a GetFeatureInfo request inside a handleClick method of a ClickHandler behaviour. This behaviour is added to a map containing a TileWms layer.

Building the url I have some mandatory parameters like bbox, width, height, i, j for which I'm unable to find a value.

Any suggest?

I looked Openlayers3 examples and they use the method getGetFeatureInfoUrl() that is not available in wicketstuff-openlayers3. Could be added?

Regards

Alberto

martin-g commented 8 years ago

@cmiles74 Ping!

cmiles74 commented 8 years ago

My current approach to implementing features has been to wait until I need one, then go ahead and implement it. So far, I haven't needed to use a WMS layer; that's why the method your interested in hasn't been implemented yet.

Looking at the OpenLayers 3 documentation, it looks like you use this method to construct a URL, then you can read the feature information from the URL. If the WMS layer doesn't support this function, you'll get a null return value and if there's not a feature at the coordinate, I guess you get a not found or something from the URL's endpoint.

Right now we do have a ClickFeatureHandler that you can add to your layer, you can take a look at our example code to see how that works. You add it to your layer and when it gets called, it has the feature ID, the coordinates and any properties that are attached to the feature. This does not do what you want, but I am wondering how much of this information you'll be getting from the WMS layer. Some of the data you want may be there already, but at the minimum we'll have the coordinate.

In my opinion, implementing this feature will be pretty straightforward. Is this something you might be interested in contributing? I do my best to keep the current code up-to-date as the OpenLayers 3 library changes, but it's something that I do as time allows. Having another contributor would be a huge help. :-)

abiuan commented 8 years ago

Unfortunately ClickFeatureHandler works only on WFS layers and, obviously, is quite different from ClickHandler, because features are already on the client. In case of WMS layer there is only an image hence you have to call GetFeatureInfo to obtain features data. I have to use a WMS layer because I have a big amount of features (~ 400k) and a WFS layer is unusable in that case. Finally, I think ClickHandler is the right behaviour to use. The only thing is missing is how to build the url to call the WMS service. I would be happy to contribute but i'm not a big expert of Openlayers and I'm not a good friend of javascript. Anyway I will give it a try. Do you have some suggest?

abiuan commented 8 years ago

I tool a look to the sources and I didn't found a good sample to follow. All methods are simple getters or setters. In this case the problem is different because it has to call the javascript method that returns something and the wrapper has to to the same. Is there something similar that I can follow?

I'm also reasoning about the main problem: wrapping a javascript library. Are there a common pattern? Is it conceivable a "wrapper generator" to produce java code from javascript sources?

cmiles74 commented 8 years ago

Yep, you are right; most of the work is done in Javascript. Really what this library does is provide a kind of bridge between the Java and Javascript code. The developer describes what they want in Java and then we emit the proper Javascript to the browser. It's both kind of cool and kind of yucky all at the same time. ;-)

Take a look at ClickHandler.java and it's matching Javascript class, ClickHandler.js...

These two files provide a Wicket "behavior", they let you decorate a component with some Javascript that does something. In this case, we always use the ClickHandler to decorate the map on the Wicket side.

Anyway, the ClickHandler Java class is pretty simple. We provide a default projection and let the developer override this if they want. The developer needs to implement the "handleClick" method and when they do, they'll get the latitude and longitude that was clicked on.

The "respond" method gets called by our Javascript code that lives in the ClickHandler.js file. When "respond" is called, we get the AjaxRequestTarget and, although you can't see it here, some parameters are passed in by the Javascript code. In the "respond" method you can see us pulling this data out through the RequestCycle and then parsing them into coordinates. Lastly, the respond method calls the developer's "handleClick" method with those parsed out coordinates.

The "renderHead" method sets everything up for the code in the Javascript file, ClickHandler.js. It creates a map of parameters and passes the following data:

Then the ClickHandler.js file is loaded and, as you can see, it's a template. The parameters in the map will be written into the template when it's written to the browser. If you take a look at the ClickHandler.js file, you can see that we use the "${variable}" notation to fill that data in.

At the top of ClickHandler.js, you can see the click handling function that will get called when something is clicked. All it does is post some data back to the server and that data is then available to the "respond" method in the Java class. In this function we return a little JSON data with the coordinate that was clicked.

Next we actually (finally) setup our Javascript click handler on the OpenLayers map. We register to handle single clicks and provide a function that gets the click event. The function gets the coordinate from the event and if we've set the projection, it transforms the coordinate. Lastly it calls the click handler with the coordinate and that click handler will post back to the Wicket server and then Wicket will call the "respond" method in our Java class.

Whew! The process is a little complicated but the code, I think, is pretty simple. Or at least there isn't too much of it.

I'm a little torn on the smartest way to implement this. My thinking is that we should create a new type of click handler, maybe call it ClickWMSFeatureHandler. It will differ from the regular click feature handler in that it won't be asking the map for the feature data (via forEachFeatureAtPixel), instead the Javascript code will use the getFeatureInfoUrl OpenLayers function and return that data instead. If the WMS layer provides feature data, we can call the developer's handleClick method otherwise we can call handleClickMiss.

Once implemented, we can take another look at it and see if there's a better way. All of these click handlers are pretty specialized, this might just be the most practical way to go.

Let me know if this doesn't make any sense. It sounds reasonable to me, but I've been doing this stuff for a while. ;-)

Thank you!

martin-g commented 8 years ago

Let me know if this doesn't make any sense. It sounds reasonable to me, but I've been doing this stuff for a while. ;-)

Sounds reasonable to me too! :-) Very good explanation how Wicket Ajax behaviors work! Thanks, @cmiles74 !