Lourens Veen ha scritto:
On Tuesday 09 October 2007 14:10:49 Christopher Schmidt wrote:
On Tue, Oct 09, 2007 at 01:24:27PM +0200, Stefano Bonnin wrote:
hi all,

I have to define a popup for every vector feature but I notice that
SelectFeature has some problem when there is more than 1 layer. The
SelectFeature control seems to work only when there is 1 layer
active. This (critical, for me) SelectFeature bug will be pathed
only in the 2.6 release of OpenLayers ... so ...
Actually, it's not expected, as far as I know, to be fixed then
either. (It might be, with some recent work we're doing, but it's not
high on the priority list). This is a limitation of browser event
handling with SVG.

The same limitation causes trouble if you have multiple features on top of each other in the same layer. The browser will render them in some order, and one of them will end up on top. That one can then be selected, but the other ones can't be.

The problem is that the event handler uses the source of the event, as passed by the browser in the Event object, to determine which feature was clicked. The browser chooses one feature to attach the event to, and so only one feature can be selected.

The solution to this is to find out where the user clicked, transform the screen coordinates into LatLon, and then search through the features to find out which features are at that location. It's not very fast, but it works. The problem is that selection isn't precise, because OpenLayers.Geometry.atPoint() uses a bounding box test (and I've got polygons in my WFS layer). That would be quite hard to fix.

Also, you still have no intuitive way of selecting only a small polygon lying completely inside a larger one: you have to select both of them first by clicking inside the small one, and then deselect the large one by clicking somewhere inside it where the small one is not.

Another possibility I'm considering trying is to use the Box handler, and then only select a feature if one (all?) point is within the dragged box.

Lourens

I have written an initial possible solution. The code is very confused but it works. With this solution you can add polygon and lines to the layers and after do the select.
It use a pointinsidepolygon and lineDistance algorithms ...

The code can be useful for people that, like me, have to select features from different layers ...

Red Shaphiro

<!--Red Shaphiro's demo-->
<!--For questions: [EMAIL PROTECTED]>

<html xmlns="http://www.w3.org/1999/xhtml";>
  <head>
    <style type="text/css">
        #map {
            width: 800px;
            height: 350px;
            border: 1px solid gray;
        }
        #controlToggle li {
            list-style: none;
        }
    </style>

    <script src="http://www.openlayers.org/api/OpenLayers.js"; 
type="text/javascript"></script>

    <script type="text/javascript">
        var map, drawControls, select;
        var layers = Array();

        //compute the point-line distance
        function lineDist(wktline, _p) {

            var p1x = Array();
            var p1y = Array();
            var p2x = Array();
            var p2y = Array();

            var _tmp = wktline.substring(11,wktline.length-1).split(","); 
//point list
            var p = map.getPixelFromLonLat(_p);

            for (var k = 0; k < _tmp.length - 1; k++) {
                var p1xy = _tmp[k].split(" ");
                var p2xy = _tmp[k+1].split(" ");

                var _point1 = new OpenLayers.LonLat(p1xy[0],p1xy[1]);
                var _point2 = new OpenLayers.LonLat(p2xy[0],p2xy[1]);

                var p1 = map.getPixelFromLonLat(_point1);
                var p2 = map.getPixelFromLonLat(_point2);

                p1x.push(p1.x);p1y.push(p1.y);
                p2x.push(p2.x);p2y.push(p2.y);
            }

            var dist = -1;
            for (var k = 0; k < p1x.length; k++) {
                var area = Math.abs(.5 * (p1x[k] * p2y[k] + p2x[k] * p.y + p.x 
* p1y[k] - p2x[k] * p1y[k] - p.x * p2y[k] - p1x[k] * p.y));
                var bottom = Math.sqrt(Math.pow(p1x[k] - p2x[k], 2) + 
Math.pow(p1y[k] - p2y[k], 2));

                if (dist == -1) 
                        dist = (area / bottom * 2);
                else
                        dist = Math.min((area / bottom * 2),dist);
            }

            return dist;
        }


        //point inside polygon algorithm
        function pointInPolygon(wktpoly,ll) {

          var x = ll.lon;
          var y = ll.lat;

          var _tmp = wktpoly.substring(9,wktpoly.length-2).split(","); //point 
list
          var polySides = _tmp.length-1;

          var polyX = Array();
          var polyY = Array();

          for (var k = 0; k < polySides; k++) {
                var xy = _tmp[k].split(" ");
                polyX.push(parseFloat(xy[0]));
                polyY.push(parseFloat(xy[1]));
          }

          var      i,j;
          var      oddNodes=false   ;

          for (i=0,j=polySides-1; i<polySides; j=i++) {
            val = polyX[i]+(y-polyY[i])/(polyY[j]-polyY[i])*(polyX[j]-polyX[i]);
            if (polyY[i]<y && polyY[j]>=y || polyY[j]<y && polyY[i]>=y) {
              if 
(polyX[i]+(y-polyY[i])/(polyY[j]-polyY[i])*(polyX[j]-polyX[i])<x) {
                oddNodes=!oddNodes; 
              }
            }
          }
        
          return oddNodes; 
        }


        //popup on select
        function onFeatureSelect(feature) {
            popup = new OpenLayers.Popup.Anchored("chicken", 
                                     
feature.geometry.getBounds().getCenterLonLat(),
                                     new OpenLayers.Size(250,75),
                                     "<div style='font-size:.8em'>Feature: " + 
feature.id +"<br />Area: " + feature.geometry.getArea()+"</div>",
                                     null, true);
            feature.popup = popup;
            map.addPopup(popup);
        }

        //unselect
        function onFeatureUnselect(feature) {
            map.removePopup(feature.popup);
            feature.popup.destroy();
            feature.popup = null;
        }    

        //object selection function
        //when the user click on the map the function returns the selected 
geometry objects
        //for polygons I use pointInPolygon
        //for path I use lineDist
        //for points ... nothing but it's simple to add
        function objectSelection(evt) {

                if (!document.getElementById('selectToggle').checked) return;

                var fout = Array();
                var lonlat = map.getLonLatFromViewPortPx(evt.xy);

                for (var l = 0; l < layers.length; l++) {

                        var features = layers[l].features;
                        for (var f = 0; f < features.length; f++) {
                                var the_geom = features[f].geometry.toString();

                                if (the_geom.indexOf('POLYGON') != -1) {
                                        if (pointInPolygon(the_geom,lonlat)) 
fout.push(features[f]);
                                }
                                else {
                                        if (lineDist(the_geom,lonlat) <= 10) 
fout.push(features[f]);
                                }
                        }
                }

                for (k = 0; k < fout.length; k++) {
                        var feature = fout[k];
                        var layer = feature.layer;

                        if(OpenLayers.Util.indexOf(layer.selectedFeatures, 
feature) > -1) {
                                if(feature.originalStyle != null) {
                                    feature.style = feature.originalStyle;
                                }

                                layer.drawFeature(feature);
                                
OpenLayers.Util.removeItem(layer.selectedFeatures, feature);
                                onFeatureUnselect(feature);
                        } else {
                                if(feature.originalStyle == null) {
                                        feature.originalStyle = feature.style;
                                }
                                feature.layer.selectedFeatures.push(feature);
                                feature.style = 
OpenLayers.Feature.Vector.style['select'];
                                feature.layer.drawFeature(feature);
                                onFeatureSelect(feature);
                        }
                }
        }

        function init(){
            map = new OpenLayers.Map('map');

            var wmsLayer = new OpenLayers.Layer.WMS( "OpenLayers WMS", 
                "http://labs.metacarta.com/wms/vmap0?";, {layers: 'basic'}); 

            layers[0] = new OpenLayers.Layer.Vector("Polygon Layer 1");
            layers[1] = new OpenLayers.Layer.Vector("Polygon Layer 2");
            layers[2] = new OpenLayers.Layer.Vector("Polygon Layer 3");
            layers[3] = new OpenLayers.Layer.Vector("Polygon Layer 4");
            layers[4] = new OpenLayers.Layer.Vector("Line layer 1");

            map.addLayers([wmsLayer, layers[0], layers[1], layers[2], 
layers[3], layers[4]]);

            map.addControl(new OpenLayers.Control.LayerSwitcher());
            map.addControl(new OpenLayers.Control.MousePosition());
            
            drawControls = {
                polygon: new OpenLayers.Control.DrawFeature(layers[0],
                            OpenLayers.Handler.Polygon),

                polygon2: new OpenLayers.Control.DrawFeature(layers[1],
                            OpenLayers.Handler.Polygon),

                polygon3: new OpenLayers.Control.DrawFeature(layers[2],
                            OpenLayers.Handler.Polygon),

                polygon4: new OpenLayers.Control.DrawFeature(layers[3],
                            OpenLayers.Handler.Polygon),

                line: new OpenLayers.Control.DrawFeature(layers[4],
                            OpenLayers.Handler.Path)

            };
            
            for(var key in drawControls) {
                map.addControl(drawControls[key]);
            }
            
            map.setCenter(new OpenLayers.LonLat(0, 0), 3);

            map.events.register("click", map, objectSelection);

        }

        function toggleControlSelect(element) {
                document.getElementById('polygonToggle').checked = true;
                var ele = {"value":"line","checked":true};
                
                if (element.value < 5)
                        ele = {"value":"polygon","checked":true};


                toggleControl(ele);
        }

        function toggleControl(element) {
            for(key in drawControls) {
                var control = drawControls[key];
                var layer = document.getElementById('layer').value;

                if((key.indexOf(element.value)!=-1) && element.checked) {

                        if      (key == 'polygon'  && layer == '1') 
control.activate();
                        else if (key == 'polygon2' && layer == '2') 
control.activate();
                        else if (key == 'polygon3' && layer == '3') 
control.activate();
                        else if (key == 'polygon4' && layer == '4') 
control.activate();
                        else if (key == 'line' && layer == '5') 
control.activate();
                        else if (key.indexOf('polygon')==-1) {
                                control.activate();
                                //alert(key+' control activated!');
                        }
                        else {
                                //alert(key+ ' control deactivated!');
                                control.deactivate();
                        }
                } else {
                    control.deactivate();
                }
            }
        }
    </script>
  </head>
  <body onload="init()">
    <h1>OpenLayers Feature Selection Example</h1>

    <div id="map"></div>
    <ul id="controlToggle">
        <li>
            <input type="radio" name="type" value="none" id="noneToggle"
                   onclick="toggleControl(this);" checked="checked" />
            <label for="noneToggle">navigate</label>
        </li>
        <li>
            <table><tr><td><input type="radio" name="type" value="polygon" 
id="polygonToggle"
                   onclick="toggleControl(this);" /></td>
            <td> draw polygon on <select id="layer"' 
onchange='toggleControlSelect(this)'><option value='1'>Layer poligon<option 
value='2'>Layer polygon 2<option value='3'>Layer poligon 3<option 
value='4'>Layer poligon 4<option value='5'>Line layer</select></td></tr></table>

        </li>
        <li>
            <input type="radio" name="type" value="select" id="selectToggle"
                   onclick="toggleControl(this);" />
            <label for="selectToggle">select polygon on click</label>
        </li>
    </ul>       
    <p>It is possible to use the onSelect/onUnselect hooks on the SelectFeature
       to do fun things -- like open a popup.
    </p>   
  </body>

</html>
_______________________________________________
Users mailing list
[email protected]
http://openlayers.org/mailman/listinfo/users

Reply via email to