Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

I'm a newbie using OpenLayers with JQuery to display vector data from KML files. I'm creating the layer like this:

newlayer = new OpenLayers.Layer.Vector( layerid, {
    projection: MAPVAR.displayProjection,
    strategies: [new OpenLayers.Strategy.Fixed()],
    protocol: new OpenLayers.Protocol.HTTP({
        url: layerurl,
        format: new OpenLayers.Format.KML({
            extractStyles: true, 
            extractAttributes: true,
            maxDepth: 2
        })
      }) 
    });

I want to avoid using these vector features with the OpenLayers.Control.SelectFeature control. Instead i would like to have each svg feature respond to a click event and pop open their own individual windows with the attributes.

I'm having trouble figuring out how to add the onclick function to ALL the vector features loaded.

For example, I can attache a function to the KML layer's "loadend" event and add the onclick function doing the following:

$('g[id$=vroot] > *').css("cursor", "pointer")
$('g[id$=vroot] > *').click(function(evt){ $w = $.WM_open(); $w.find('.windowcontent').append("SUCKER"); });

But this will only apply the handler to those vector elements in the view extent and not the ones that are waiting to be rendered in the HTML. I'm not sure how to access the unrendered ones -- they are in the DOM.

I've come up with really stupid stupid work around to this problem, but I know there has to be a better way.

Is there some way I can dynamically create the "onclick" handler for each svg feature when they are getting parsed? Would that require me to subclass OpenLayers.Layers.Vector or OpenLayers.Formats.KML? Does anyone have an example? Or recommendation on other ways?

thx mazery


I still have not solved adding the onclick handler to the features. But i was able to override OpenLayers.Format.KML parseData() to add a pointer cursor to the feature styles before the loadend runs on the KML layer (additions demarcated with * EDITS *).

var FormatErmaKml = OpenLayers.Class(OpenLayers.Format.KML, { 
parseData: function (data, b) { 
    typeof data == "string" && (data = OpenLayers.Format.XML.prototype.read.apply(this, [data]));
    for (var c = ["Link", "NetworkLink", "Style", "StyleMap", "Placemark"], d = 0, e = c.length; d < e; ++d) {
        var f = c[d];
        var g = this.getElementsByTagNameNS(data, "*", f);  
        if (g.length != 0) switch (f.toLowerCase()) {
        case "link":
        case "networklink":
            this.parseLinks(g, b);  
            break;
        case "style":
            this.extractStyles && this.parseStyles(g, b);  
            break;
        case "stylemap":
            this.extractStyles && this.parseStyleMaps(g, b);  
            break;
        case "placemark":
            this.parseFeatures(g, b)
        }    

    }    
    **** EDITS BEGIN ****
    for(var count = 0; count < this.features.length; ++count){
            f = this.features[count];
            f.style.cursor = "pointer";
    }
    **** END EDITS ****
    return this.features
},});

Any ideas on adding the onclick handler for each feature are welcomed.

thx mazery

share|improve this question
    
I still have not solved adding the onclick handler to the features. But i was able to override OpenLayers.Format.KML parseData() to add a pointer cursor to the feature styles. –  maztaz Jan 19 '12 at 17:00
    
for a pointer cursor: When you define your layer you can define a stylemap and put cursor: "pointer". –  CaptDragon Jan 19 '12 at 17:39
    
I have tried to do what you are asking with no result. Maybe if you try an SVG framework like rafael or jQuery SVG. The problem i have with SelectFeature is that you can't just bind a click to a feature.. it automatically triggers select, redraw, etc. I'm assuming that is why you don't want to use SelectFeature. So if you do figure it out, please post the answer. –  CaptDragon Jan 19 '12 at 17:50
    
@capdragon -- yes, that's another reason why i would like to not use SelectFeature control –  maztaz Jan 19 '12 at 18:00
    
@maztaz just something to consider, if you haven't before, but IE 8 and lower is VML only, so Canvas-specific functionality won't work. But...of course depends on what browsers you're targeting. –  Vadim Jan 19 '12 at 18:14
add comment

3 Answers

up vote 3 down vote accepted

I believe i found the solution.

SOLUTION DEMONSTRATION

It will:

  1. change the cursor for your feature to cursor:wait using jquery.
  2. It will change the svg fill color of the feature using jquery.
  3. And best of all it's efficient and will NOT trigger anything or disrupt anything else as far as my tests have shown.

Use a regular click Handler (EXAMPLE1, EXAMPLE2) and use the e.target to get the object on the map. If it returns a vector feature great, if not, ignore. It can work for all your layers or you can check the returned feature to see if it belongs to a layer you want it to trigger on.

I used Example #1 and replaced the latlon alert for this:

    if (e.target._featureId) {
        var feature = vectorLayer.getFeatureById(e.target._featureId);
        $(e.target).css('fill', '#000000');
        $(e.target).css('cursor', 'wait');
        $("div#info").append("<span>You just clicked on " + feature.id + "<span><br />");
    }
share|improve this answer
    
is the hero of the hour, i owe you beer –  maztaz Jan 21 '12 at 0:39
add comment

This is not an answer to your original question but show you how to define a cursor on all the features on a layer:

newlayer = new OpenLayers.Layer.Vector(layerid, {
    projection: MAPVAR.displayProjection,
    styleMap: new OpenLayers.StyleMap({
        "default": new OpenLayers.Style({
            strokeColor: '#000000',
            strokeOpacity: .3,
            strokeWidth: 2,
            fillColor: '#000000',
            fillOpacity: 0,
            cursor: "pointer"
        })
    }),
    strategies: [new OpenLayers.Strategy.Fixed()],
    protocol: new OpenLayers.Protocol.HTTP({
        url: layerurl,
        format: new OpenLayers.Format.KML({
            extractStyles: true,
            extractAttributes: true,
            maxDepth: 2
        })
    })
});

Here's an EXAMPLE

share|improve this answer
    
wow, that's easy. Thanks for showing me. –  maztaz Jan 19 '12 at 17:47
    
that didn't seem to work...debugging it now but "default" is overwritten with new style after loadend...hmmm –  maztaz Jan 19 '12 at 19:00
    
Sure it does... check my simple example i uploaded. It has the "waiting" cursor on the features. Make sure you are not overwriting the style on loadend. –  CaptDragon Jan 19 '12 at 19:14
    
thx....i'll have to debug mine more to figure out what's wrong –  maztaz Jan 19 '12 at 20:28
add comment

-- edited 1/19 9:45am per @capdragon's comment

Why add on-click to each feature? That is far too expensive. Why not add it to the layer?

Then the 2nd question is, how to add same handler to multiple layers.

  1. Create one click handler
  2. Keep an in-memory array of layers that you pass to this handler
  3. Update click handler whenever a new layer is added or removed
  4. Create all your handler functions, and inside the on-click you can find out easily what feature was clicked on

1)

var hoverAndClickControl = new OpenLayers.Control.SelectFeature(
                mylayers // this is the array of layers you're keeping in memory
                ,{
                    callbacks:
                    {
                          click: onFeatureSelect
                        , clickout: onFeatureUnselect
                        , over:  onFeatureHover
                        , out: onFeatureUnhover
                    }
                }
            );

3)

function addLayerToHandler(p_layer)
{
   // add layer to array
   // e.g. mylayers.push(p_layer);

   // update click handler
   // handler.setLayers(mylayers);  // since OL 2.9

}

4)

function onFeatureSelect(p_feature)
{
  // hey, feature you want is the parameter.  do whatever you need to do 

  // create a pop-up balloon, or send data to server, alert user, write out data, etc
}
share|improve this answer
1  
OpenLayers.Control.SelectFeature DOES support multiple layers out of the box. You just add layers with myselfeatureControl.setLayers([layer1,layer2]); (+1) for trying to convince to use 1 handler instead of one for each feature. –  CaptDragon Jan 19 '12 at 17:32
    
@capdragon I stand corrected on the lack of setLayers() function. Just checked the trunk source, looks very similar to all the other rigamarole I was doing to deactivate handler, remove layers, re-add the layers and re-activate. One of my products is still on 2.8 and there's no such function in 2.8. Looks like it was introduce in 2.9.1. –  Vadim Jan 19 '12 at 17:41
    
@Vadim -- all that advice looks great...but I really want to avoid using OpenLayers.Control.SelectFeature control as I said in the original post even if other options are expensive. Is there another way? –  maztaz Jan 19 '12 at 17:45
    
@Vadim Ahh, yes you're right. –  CaptDragon Jan 19 '12 at 17:46
    
@maztaz I'm not sure why you don't want 1 handler? In the handler you can easily create an individual pop-up for each feature. It's not like one popup kills the other. You can certainly manage state (when one opens, kill all others) or you can let user manage it by clicking the "x" in popup. What we also do is keep track, if feature has popup and user clicks on feature again, we kill the popup. So it's a toggle on/off. You can do a lot in just the single handler and you're going to have a memory problem by attaching to each feature. –  Vadim Jan 19 '12 at 17:48
show 3 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.