[fusion-commits] r2693 - in sandbox/queryfeatures_v2: layers/MapGuide lib

svn_fusion at osgeo.org svn_fusion at osgeo.org
Fri May 3 17:43:15 PDT 2013


Author: jng
Date: 2013-05-03 17:43:15 -0700 (Fri, 03 May 2013)
New Revision: 2693

Modified:
   sandbox/queryfeatures_v2/layers/MapGuide/MapGuide.js
   sandbox/queryfeatures_v2/lib/MGBroker.js
Log:
Support for MapGuide RFC 126:
 - Add a new MGQueryMapFeatures2 class to support our v2.6.0 QUERYMAPFEATURES operation
 - Update Fusion.Layers.MapGuide:
   - Use MGQueryMapFeatures2 if supported by MapGuide (currently hard-coded to always for testing purposes)
   - If using MGQueryMapFeatures2, set up a separate callback code path that bypasses calls to Selection.php and GetSelectionProperties.php, as the content of the v2.6.0 QUERYMAPFEATURES response already contains such information (or can be computed from it.). This cuts down the number of requests per selection from 5 to 3 (could be 2, but we need to modify OpenLayers to accept our inline selection image. As it stands, we need to stick with the existing GETDYNAMICMAPOVERLAYIMAGE for this).

Modified: sandbox/queryfeatures_v2/layers/MapGuide/MapGuide.js
===================================================================
--- sandbox/queryfeatures_v2/layers/MapGuide/MapGuide.js	2013-05-03 22:56:44 UTC (rev 2692)
+++ sandbox/queryfeatures_v2/layers/MapGuide/MapGuide.js	2013-05-04 00:43:15 UTC (rev 2693)
@@ -966,26 +966,28 @@
      *        given, all the elemsnts will be returned.
      */
     getSelection: function(userFunc, layers, startcount) {
-
-      /*for now always go back to server to fetch selection */
-
-      if (userFunc)
-      {
-          //this.aSelectionCallbacks.push(userFunc);
-
-
-          //this.mapWidget._addWorker();
-          // this._bSelectionIsLoading = true;
-          var s = 'layers/' + this.arch + '/' + Fusion.getScriptLanguage() + "/Selection." + Fusion.getScriptLanguage() ;
-          var options = {
-              parameters: {'session': this.getSessionID(),
-                          'mapname': this._sMapname,
-                          'layers': layers,
-                          'startcount': startcount},
-              onSuccess: OpenLayers.Function.bind(this.getSelectionCB, this, userFunc)
-          };
-          Fusion.ajaxRequest(s, options);
-      }
+        /*for now always go back to server to fetch selection */
+        if (userFunc)
+        {
+            if (this.previousAttributes) {
+                userFunc(new Fusion.SelectionObject(this.previousAttributes));
+            } else {
+                //this.aSelectionCallbacks.push(userFunc);
+                //this.mapWidget._addWorker();
+                // this._bSelectionIsLoading = true;
+                var s = 'layers/' + this.arch + '/' + Fusion.getScriptLanguage() + "/Selection." + Fusion.getScriptLanguage() ;
+                var options = {
+                    parameters: {
+                        'session': this.getSessionID(),
+                        'mapname': this._sMapname,
+                        'layers': layers,
+                        'startcount': startcount
+                    },
+                    onSuccess: OpenLayers.Function.bind(this.getSelectionCB, this, userFunc)
+                };
+                Fusion.ajaxRequest(s, options);
+            }
+        }
     },
 
     /**
@@ -1044,6 +1046,14 @@
         this.processSelectedFeatureProperties(r);
     },
 
+    processSelectedFeaturePropertiesNode: function(oNode) {
+        if (oNode.hasSelection) {
+            this.newSelection();
+        } else {
+            this.clearSelection();
+        }
+    },
+
     /**
        Call back function when select functions are called (eg queryRect)
        to handle feature attributes
@@ -1052,13 +1062,7 @@
         this.mapWidget._removeWorker();
         if (r.responseText) {   //TODO: make the equivalent change to MapServer.js
             var oNode = Fusion.parseJSON(r.responseText);
-
-            if (oNode.hasSelection) {
-              this.newSelection();
-            } else {
-              this.clearSelection();
-              return;
-            }
+            this.processSelectedFeaturePropertiesNode(oNode);
         }
     },
 
@@ -1135,7 +1139,13 @@
         {
             options.filter = '';
         }
-        var r = new Fusion.Lib.MGRequest.MGQueryMapFeatures(this.getSessionID(),
+        
+        var bSupportsExtended = true; //If MG server >= 2.6.0
+        if (bSupportsExtended) {
+            var reqData = 1; //attributes
+            //TODO: Can't use inline selection image yet as we'll have to modify OpenLayers to accept an inline selection
+            //over doing a GETDYNAMICMAPOVERLAYIMAGE request
+            var r = new Fusion.Lib.MGRequest.MGQueryMapFeatures2(this.getSessionID(),
                                                                 this._sMapname,
                                                                 options.geometry,
                                                                 maxFeatures,
@@ -1143,9 +1153,25 @@
                                                                 options.selectionType || this.selectionType,
                                                                 options.filter,
                                                                 options.layers,
+                                                                layerAttributeFilter,
+                                                                reqData,
+                                                                this.selectionColor,
+                                                                this.selectionImageFormat);
+            var callback = (options.extendSelection == true) ? OpenLayers.Function.bind(this.processAndMergeExtendedFeatureInfo, this) : OpenLayers.Function.bind(this.processExtendedFeatureInfo, this);
+            Fusion.oBroker.dispatchRequest(r, callback);
+        } else {
+            var r = new Fusion.Lib.MGRequest.MGQueryMapFeatures(this.getSessionID(),
+                                                                this._sMapname,
+                                                                options.geometry,
+                                                                maxFeatures,
+                                                                persist,
+                                                                options.selectionType || this.selectionType,
+                                                                options.filter,
+                                                                options.layers,
                                                                 layerAttributeFilter);
-        var callback = (options.extendSelection == true) ? OpenLayers.Function.bind(this.processAndMergeFeatureInfo, this) : OpenLayers.Function.bind(this.processFeatureInfo, this);
-        Fusion.oBroker.dispatchRequest(r, callback);
+            var callback = (options.extendSelection == true) ? OpenLayers.Function.bind(this.processAndMergeFeatureInfo, this) : OpenLayers.Function.bind(this.processFeatureInfo, this);
+            Fusion.oBroker.dispatchRequest(r, callback);
+        }
     },
 
     showLayer: function( layer, noDraw ) {
@@ -1205,7 +1231,7 @@
         this.drawMap();
     },
 
-  /**
+    /**
      * called when there is a click on the map holding the CTRL key: query features at that postion.
      **/
     mouseUpCRTLClick: function(evt) {
@@ -1403,10 +1429,153 @@
             }
             return url;
         }
+    },
+    
+    typeNameToValue: function(name) {
+        switch(name) { //Values from MgPropertyType
+            case "byte":
+                return 2;
+            case "boolean":
+                return 1;
+            case "blob":
+                return 10;
+            case "clob":
+                return 11;
+            case "datetime":
+                return 3;
+            case "double":
+                return 5;
+            case "int16":
+                return 6;
+            case "int32":
+                return 7;
+            case "int64":
+                return 8;
+            case "single":
+                return 4;
+            case "string":
+                return 9;
+        }
+        return -1;
+    },
+    
+    convertExtendedFeatureInfo: function(efi) {
+        var bHasSelection = false;
+        var result = {};
+        var layerNames = [];
+        //First pass: Collect and group by layers
+        var featuresByLayer = {};
+        var bp = efi.FeatureInformation.Attributes[0].BatchPropertyCollection[0].PropertyCollection;
+        for (var i = 0; i < bp.length; i++) {
+            bHasSelection = true;
+            var props = bp[i];
+            
+            var feat = { attributes: {} };
+            
+            for (var j = 0; j < props.Property.length; j++) {
+                var name = props.Property[j].Name[0];
+                var typeName = props.Property[j].Type[0];
+                var value = props.Property[j].Value == null ? null : props.Property[j].Value[0];
+                
+                if (name == "_MgLayerName") {
+                    if (!featuresByLayer[value]) {
+                        featuresByLayer[value] = [];
+                        layerNames.push(value);
+                    }
+                    featuresByLayer[value].push(feat);
+                } else if (name == "_MgFeatureBoundingBox") {
+                    var b = value.split(" ");
+                    feat.bounds = { minx: parseFloat(b[0]), miny: parseFloat(b[1]), maxx: parseFloat(b[2]), maxy: parseFloat(b[3]) };
+                } else {
+                    feat.attributes[name] = { type: typeName, value: value };
+                }
+            }
+        }
+        
+        //Second pass: Convert intermediate form to final result
+        var box = new OpenLayers.Bounds();
+        for (var layerName in featuresByLayer) {
+            var bSetProperties = false;
+            if (!result[layerName]) {
+                result[layerName] = {
+                    metadata: [],      //TODO: What do we put here?
+                    metadatanames: [], //TODO: What do we put here?
+                    numelements: featuresByLayer[layerName].length,
+                    propertynames: [], //TODO: QUERYMAPFEATURES 2.6.0 does not yet return system property names, this will always be empty for now
+                    propertytypes: [],
+                    propertyvalues: [],
+                    values: []
+                };
+            }
+            for (var i = 0; i < featuresByLayer[layerName].length; i++) {
+                var feat = featuresByLayer[layerName][i];
+                var featVals = [];
+                if (!bSetProperties) {
+                    for (var attrName in featuresByLayer[layerName][i].attributes) {
+                        var attrInfo = featuresByLayer[layerName][i].attributes[attrName];
+                        result[layerName].propertyvalues.push(attrName);
+                        result[layerName].propertytypes.push(this.typeNameToValue(attrInfo.type));
+                        featVals.push(attrInfo.value);
+                    }
+                    bSetProperties = true;
+                } else {
+                    for (var attrName in featuresByLayer[layerName][i].attributes) {
+                        var attrInfo = featuresByLayer[layerName][i].attributes[attrName];
+                        featVals.push(attrInfo.value);
+                    }
+                }
+                result[layerName].values.push(featVals);
+                box.extend(new OpenLayers.LonLat(feat.bounds.minx, feat.bounds.miny));
+                box.extend(new OpenLayers.LonLat(feat.bounds.maxx, feat.bounds.maxy));
+            }
+        }
+        
+        return OpenLayers.Util.extend(result, {
+            hasSelection: bHasSelection,
+            extents: {
+                minx: box.left,
+                miny: box.bottom,
+                maxx: box.right,
+                maxy: box.top
+            },
+            layers: layerNames
+        });
+    },
 
+    processAndMergeExtendedFeatureInfo: function(r) {
+        this.processSelectedExtendedFeatureInfo(r, true);
+        //this.processSelectedFeatureInfo(r, true);
     },
-
-
+    
+    processExtendedFeatureInfo: function(r) {
+        this.processSelectedExtendedFeatureInfo(r, false);
+        //this.processSelectedFeatureInfo(r, false);
+    },
+    
+    processSelectedExtendedFeatureInfo: function(r, mergeSelection) {
+        var o = Fusion.parseJSON(r.responseText);
+        var sel = new Fusion.SimpleSelectionObject(o);
+        var attributes = this.convertExtendedFeatureInfo(o);
+        var selText = sel.getSelectionXml();
+        if (mergeSelection == true)
+        {
+            sel.merge(this.previousSelection);
+        }
+        this.previousSelection = sel;
+        //Because the QUERYMAPFEATURES 2.6.0 response contains mostly everything we need, we cut down
+        //on lots of async request ping-pong. So we can just update the selection image and notify any
+        //interested parties of the new selection attributes
+        if (selText != "" && selText != null) {
+            this.previousAttributes = attributes;
+            this.updateMapSelection(selText, false);
+            this.processSelectedFeaturePropertiesNode(attributes);
+        } else {
+            this.previousAttributes = null;
+            this.clearSelection();
+        }
+        this.mapWidget._removeWorker();
+    },
+    
     processAndMergeFeatureInfo: function (r) {
         this.processSelectedFeatureInfo(r, true);
     },

Modified: sandbox/queryfeatures_v2/lib/MGBroker.js
===================================================================
--- sandbox/queryfeatures_v2/lib/MGBroker.js	2013-05-03 22:56:44 UTC (rev 2692)
+++ sandbox/queryfeatures_v2/lib/MGBroker.js	2013-05-04 00:43:15 UTC (rev 2693)
@@ -641,6 +641,59 @@
 });
 
 /****************************************************************************
+ * Class: Fusion.Lib.MGRequest.MGQueryMapFeatures2
+ *
+ * encapsulate a request to the server to query map features on 
+ * selectable layers
+ * 
+ * Inherits from:
+ *  - <Fusion.Lib.MGRequest>
+ */
+Fusion.Lib.MGRequest.MGQueryMapFeatures2 = OpenLayers.Class(Fusion.Lib.MGRequest, {
+    /**
+     * Constructor: Fusion.Lib.MGRequest.MGQueryMapFeatures2
+     * 
+     * initialize a new instance of Fusion.Lib.MGRequest.MGQueryMapFeatures2
+     *
+     * Parameters:
+     * sessionId - {String} the id of the session to restore
+     * mapName - {String} the id of the session to restore
+     * geometry (sting wkt} gemetry to use for selection.  Example : POLYGON(x1 y1, x2,y2)
+     * maxFeatures - {integer} number of maximum results (-1 to indicate no maximum)
+     * selectionPersist - {boolean} save the selection (valid values are 0 and 1) 
+     * selectionVariant - {String} indicates the spatial operation. Valid values are 'INTERSECTS', ...
+     * featureFilter - {String} filter crieteria to be applied for selection.
+     * layerNames - {String} comma separated list of layer names to include in the query
+     * layerAttributeFilter - {integer} bitmask determining layer selection behaviour (1=visible layers,
+     *          2=selectable layers, 4=layers with tooltips)
+     * requestData - {integer} a bitmask of the desired information to return (Attributes = 1 InlineSelection? = 2 Tooltip = 4 Hyperlink = 8)
+     * selectionColor - {String} the html color for the inline selection image (if requested)
+     * selectionFormat - {String} the format of the inline selection image (if requested)
+     */
+    initialize : function( sessionId, mapName, geometry, maxFeatures, persist, selectionVariant, featureFilter, layerNames, layerAttributeFilter, requestData, selectionColor, selectionFormat) 
+    {
+        this.initializeRequest();
+        this.setParams( {
+            operation : 'QUERYMAPFEATURES',
+            format: "application/json",
+            version: "2.6.0",
+            session: sessionId,
+            mapname: mapName,
+            geometry: geometry,
+            maxFeatures: maxFeatures,
+            persist: persist,
+            selectionVariant: selectionVariant,
+            featureFilter: featureFilter,
+            layerNames: layerNames,
+            layerAttributeFilter: layerAttributeFilter,
+            requestData: requestData,
+            selectionColor: selectionColor,
+            selectionFormat: selectionFormat
+        } );
+    }
+});
+
+/****************************************************************************
  * Class: Fusion.Lib.MGRequest.MGGetFeatureSetEnvelope
  *
  * encapsulate a request to the server to query map features on 



More information about the fusion-commits mailing list