Select to view content in your preferred language

Combining a drivetime and identify widget.

1441
12
08-01-2011 03:00 PM
SeanCook
Emerging Contributor
Hello everyone. I recently began playing with flex and I am trying to accomplish a task I think should be straight forward but am having some difficulty with. I am trying to create a widget which calculates a drive time, and returns an identify on the objects in the returned drive time.

I can add a button to the identify widget, which when click looks for a map click and calculates a drive time. Now, when a drive time is calculated using the first shown function, is the
variable FeatureSet a geometry variable that I can feed into the second identify features function?

Will that be enough to get this tool working? Any other advice on how it could or should be done?

Sorry about the vague question, but I am getting going and having some trouble with this one.


[PHP]
   private function computeServiceArea(mapPoint:MapPoint):void
   {
   
    myGraphicsLayer.clear();
    var graphic:Graphic = new Graphic(mapPoint, sms_circleAlphaSizeOutline);
    myGraphicsLayer.add(graphic);
    var featureSet:FeatureSet = new FeatureSet([ graphic ]);
    var params:Object =
     {
      "Input_Location": featureSet,
      "Drive_Times": driveTimes
     };
    gp.execute(params, new AsyncResponder(onResult, onFault));
    function onResult(gpResult:ExecuteResult,token:Object = null):void
    {
     var pv:ParameterValue = gpResult.results[0];
     var fs:FeatureSet = pv.value as FeatureSet;
     myGraphicsLayer.graphicProvider = fs.features;
     myGraphicsLayer.renderer=uniqueValueRenderer;
    }
    function onFault(info:Object, token:Object = null):void
    {
     Alert.show(info.toString());
    }
   }
  
[/PHP]

[PHP]
  
  
  
   //identify features
   private function identifyFeatures(geom:Geometry):void
   {
    var identifyParams:IdentifyParameters = new IdentifyParameters();
    identifyParams.returnGeometry = returnGeomForZoom;
    identifyParams.tolerance = identifyTolerance;
    identifyParams.geometry = geom;
    identifyParams.width = map.width;
    identifyParams.height = map.height;
    identifyParams.mapExtent = map.extent;
    identifyParams.spatialReference = map.spatialReference;
    if(betaReturnGeometryFix){
     var geomString:String = JSON.encode(geom).replace(',"spatialReference":{"wkid":' + geom.spatialReference.wkid + '}','');
     var idURL:String = "?geometryType=" + geom.type + "&geometry=" + geomString;
     idURL += "&sr=" + map.spatialReference.wkid.toString() + "&layers="
     var idURL2:String = "&tolerance=" + identifyTolerance.toString() + "&mapExtent=" + map.extent.xmin.toString() + "," + map.extent.ymin.toString() + "," +  map.extent.xmax.toString() + "," +  map.extent.ymax.toString();
     idURL2 += "&imageDisplay=" + map.width.toString() + "," + map.height.toString() + ",96" + "&returnGeometry=" + returnGeomForZoom.valueOf().toString() + "&f=json";
    }
    for (var i:Number = map.layerIds.length -1; i >= 0; i--)
    {
     identifyParams.layerOption = identifyLayerOption;
     var layer:Layer = map.getLayer(map.layerIds);
     identifyParams.layerIds = null;
     var url:String = "";
    
     //HAB:Does this layer require a proxy???
     var useProxy:Boolean = false;
    
    
     //HAB:loop thru proxy layer list and determine which layer needs a proxy
     for(var p:int=0; p<configIdentProxyLayers.length; p++)
     {
      //HAB:set the proxy flag if needed
      if (layer.name == configIdentProxyLayers

.name)


      {
       useProxy = true;
      }
     }
    
     if (layer is ArcGISDynamicMapServiceLayer)
     {
      var dynamicLayer:ArcGISDynamicMapServiceLayer = layer as ArcGISDynamicMapServiceLayer;
      url = dynamicLayer.url;
      if(identifyLayerOption == "visible")
      {
       if(dynamicLayer.visible == false){
        url="";
       }else{
        if(dynamicLayer.visibleLayers){
         identifyParams.layerIds = new Array();
         for (var j:Number = 0; j < dynamicLayer.visibleLayers.source.length; j++)
         {
          if (dynamicLayer.layerInfos[dynamicLayer.visibleLayers.source] &&
           !dynamicLayer.layerInfos[dynamicLayer.visibleLayers.source].subLayerIds)
          {
           identifyParams.layerIds.push(dynamicLayer.visibleLayers.source);
          }
         }
         identifyParams.layerOption = "all";
        }
       }
      }
     }
     else if (layer is ArcGISTiledMapServiceLayer)
     {
      var tiledLayer:ArcGISTiledMapServiceLayer = layer as ArcGISTiledMapServiceLayer;
      url = tiledLayer.url;
      if(identifyLayerOption == "visible")
      {
       if(tiledLayer.visible == false)
        url="";
      }
     }
     else if (layer is FeatureLayer)
     {
      var featLayer:FeatureLayer = layer as FeatureLayer;
      url = featLayer.url;
      var layId:int = -1;
      var arcDL:ArcGISDynamicMapServiceLayer;
     
      if( url.indexOf("FeatureServer") > -1)
      {
       var msName:String = url.replace("FeatureServer","MapServer");
       arcDL = new ArcGISDynamicMapServiceLayer(msName.substring(0,msName.lastIndexOf("/")));
       url = arcDL.url;
       layId = parseInt(msName.substring(msName.lastIndexOf("/")+ 1));
      }else{
       arcDL = new ArcGISDynamicMapServiceLayer(url.substring(0,url.lastIndexOf("/")));
       layId = parseInt(url.substring(url.lastIndexOf("/")+ 1));
       url = arcDL.url;
      }
     
      if(identifyLayerOption == "visible")
      {
       if(layId != -1)
        identifyParams.layerIds = [layId];
       if(featLayer.visible == false)
        url="";
      }
     }
    
     if(url)
     {
      if(betaReturnGeometryFix){
       var visString:String = "";
       if(identifyParams.layerIds){
        visString += ":";
        for(var v:int=0; v<identifyParams.layerIds.length; v++)
        {
         if(v>0)
          visString += ","
         visString += identifyParams.layerIds.toString();
        }
       }
       var cIdURL:String = url + "/identify" + idURL + identifyLayerOption + visString + idURL2;
       var iService:HTTPService = new HTTPService();
       iService.url = cIdURL;
       iService.resultFormat = "text";
       iService.addEventListener(ResultEvent.RESULT, buildIdResults);
       iService.addEventListener(FaultEvent.FAULT, onFault);
       iService.send();
      }else{
       var identifyTask:IdentifyTask = new IdentifyTask(url);
       //HAB:apply proxy if needed
       if(useProxy)identifyTask.proxyURL = proxyURL;
       identifyTask.addEventListener(IdentifyEvent.EXECUTE_COMPLETE, onResult);
       identifyTask.addEventListener(FaultEvent.FAULT, onFault);
       identifyTask.execute(identifyParams);
      }      
      showMessage(loadingLabel, true);
      showStateResults();  
     }
    }
   }  
  
   private function buildIdResults(event:ResultEvent):void
   {
    var rawData:String = String(event.result);
    var data:Object = JSON.decode(rawData);
    var retArray:Array = [];
    if(data.error){
     //do nothing;
    }else{
     for each( var idObj:Object in data.results)
     {
      var idResult:IdentifyResult = new IdentifyResult();
      idResult.displayFieldName = idObj.displayFieldName;
      idResult.layerId = idObj.layerId;
      idResult.layerName = idObj.layerName;
      idResult.feature = buildGra(idObj);
      retArray.push(idResult);
     }
    }
    function buildGra(obj:Object):Graphic
    {
     var gra:Graphic;
     switch(obj.geometryType)
     {
      case Geometry.MAPPOINT:
      {
       var mp:MapPoint = new MapPoint(obj.geometry.x, obj.geometry.y, new SpatialReference(obj.geometry.spatialReference.wkid));
       gra = new Graphic(mp);
       gra.attributes = obj.attributes;
       break;
      }
      case Geometry.POLYGON:
      {
       var mPoly:Polygon = new Polygon(null);
       for (var i2:int = obj.geometry.rings.length - 1; i2 >= 0; i2--)
       {
        var ringArray:Array = [];
        for (var j1:int = 0; j1 < obj.geometry.rings[i2].length; j1++)
        {
         var mpStr:String = obj.geometry.rings[i2][j1];
         var xyArr:Array = mpStr.split(",")
         var mp2:MapPoint = new MapPoint(xyArr[0], xyArr[1]);
         mp2.spatialReference = new SpatialReference(obj.geometry.spatialReference.wkid);
         ringArray.push(mp2);
        }
        mPoly.addRing(ringArray);
       }
       mPoly.spatialReference = new SpatialReference(obj.geometry.spatialReference.wkid);
      
       gra = new Graphic(mPoly);
       gra.attributes = obj.attributes;
       break;
      }
      case Geometry.EXTENT:
      {
       var ext:Extent = new Extent(obj.geometry.xmin, obj.geometry.ymin, obj.geometry.xmax, obj.geometry.ymax, new SpatialReference(obj.geometry.spatialReference.wkid));
       gra = new Graphic(ext);
       gra.attributes = obj.attributes;
       break;
      }
      case Geometry.POLYLINE:
      {
       var pLine:Polyline = new Polyline(obj.Geometry.paths, new SpatialReference(obj.geometry.spatialReference.wkid));
       gra = new Graphic(pLine);
       gra.attributes = obj.attributes;
       break;
      }
     }
     return gra;
    }
    onResult(new IdentifyEvent("",retArray));
   }
   [/PHP]
Tags (2)
0 Kudos
12 Replies
RobertScheitlin__GISP
MVP Emeritus
Sean,

   Once the drive time result is received the featureset is just a special group of graphics so you can use a line like this:

identifyFeatures(fs.features[0])


As the drivetime widget returns a 3 ring polygon normally and the identifyWidget only want one geometry you would have to send an individual drive time polygon to the IdentifyWidget.
0 Kudos
SeanCook
Emerging Contributor
Thank you so much...another problem I am having that is driving me up the wall. I often make changes, that entirely fail to materialize when I run my code...after clearing my cache, etc.

This seems to happen a lot, so I assume I am missing something obvious.  Should the widgets listed in the flex modules recompile/get updated whenever I hit the green run button? Or is there another way to trigger a recompile on an mxml module?

Edit: I was assuming it would compile if it has an error. Does an error in the code stop a module from compiling entirely?
0 Kudos
RobertScheitlin__GISP
MVP Emeritus
Sean,

  In Flash Builder do you have the Build Automatically option selected under the project menu?
0 Kudos
SeanCook
Emerging Contributor
Sean,

  In Flash Builder do you have the Build Automatically option selected under the project menu?


Yes, I just had a number of errors. I have it compiling properly. I am still having a lot of trouble so if you could take a look at what I am trying to do, maybe you could point out my more obvious errors. Essentially, what I want to know is if my first piece of code should trigger my second piece of code. I also could use a sentence decribing the difference between click and name. Click should activate whenever the button is clicked, correct? And how exactly does 'name' function....not the function it calls, but the actual purpose of the name property.

  <mx:Image id="iDrawPnt" width="30" height="30" 
    buttonMode="true"
    click="driveTime_openHandler(event)" 
    name="{DrawTool.MAPPOINT}"
    rollOut="iconRollOutHandler(event)" 
    rollOver="iconRollOverHandler(event)"
    source="assets/images/i_servicearea.png" 
                                toolTip="{driveLabel}"
    useHandCursor="true"


 protected function driveTime_openHandler(event:Event):void
   {
         map.addEventListener(MapMouseEvent.MAP_CLICK,mapClickHandler)    
   }
   

I thought once the button was clicked, the map would be looking for a click on the map and would compute a drive time as the drive time widget normally does after being open from the top bar, but it doesn't work.

Oh, follow up....does the order of the function in the code matter? Does init have to be first?

Sorry for bombarding you. I feel like once I get the hang of this I'll run away with it, but it's a rough week starting out!
0 Kudos
RobertScheitlin__GISP
MVP Emeritus
Sean,

   It is not recommended at ALL that you add or manage your own mapclick functions when using the viewer.

The DriveTime is expecting a MapPoint and you can get that by using the activateIdentifyTool function that the rest of the IdentifyWidget uses as this sends the setMapAction and uses the DrawTool. If you look in the activateIdentifyTool function the name that you are asking about is what type of geometry the DrawTool will draw on the map. Once the DrawTool is done the drawEnd function is fired and there is where you can use the selectedDrawingIcon.name to determine if the button clicked is yours or not (of course you will have to set it to something unique and then add the unique name to the switch statement in the activateIdentifyTool function), and finally fire off your drive time analysis using the MapPoint.
0 Kudos
SeanCook
Emerging Contributor
Sean,

   It is not recommended at ALL that you add or manage your own mapclick functions when using the viewer.

The DriveTime is expecting a MapPoint and you can get that by using the activateIdentifyTool function that the rest of the IdentifyWidget uses as this sends the setMapAction and uses the DrawTool. If you look in the activateIdentifyTool function the name that you are asking about is what type of geometry the DrawTool will draw on the map. Once the DrawTool is done the drawEnd function is fired and there is where you can use the selectedDrawingIcon.name to determine if the button clicked is yours or not (of course you will have to set it to something unique and then add the unique name to the switch statement in the activateIdentifyTool function), and finally fire off your drive time analysis using the MapPoint.



That is an amazingly helpful post. I'll play with that for a while. Thank you!

Is there some equivalent to an easy print function for debugging here? For instance, making a popup window that returns a value I specify?
0 Kudos
SeanCook
Emerging Contributor
Still haven't gotten it to work. To make sure I am on the right track, this is a stripped down version of my fundamental changes to the endDraw function:

 private function drawEnd(event:DrawEvent):void
   {
    var point:MapPoint;
    var geometry:Geometry = event.graphic.geometry;
    point = geometry as MapPoint;
    computeServiceArea(point);
   }


That does not initiate the computeServiceAreas function and I am unsure why. I would expect it to as long as I am using the point tool, and do nothing otherwise.

Second, what would you use for the  selectedDrawingIcon.name to check if it's the correct button...I'm not sure what it is or how to find out. I am guessing something like:

if (selectedDrawingIcon.name == "assets/images/i_draw_point.png")?

Third and last, I mentioned this earlier....is their a way to give myself the equivalent of a print statement in python for checking my code? How could I easily see what selectedDrawingIcon.name actually is, for example?

Thanks for all your help. I am learning a lot here and really appreciate it.
0 Kudos
RobertScheitlin__GISP
MVP Emeritus
Sean,


  This is more of what I was talking about, (easier for me to show you than explain).

                <mx:Image id="iDTPnt"
                          name="DriveTime"
                          width="40" height="40"
                          buttonMode="true"
                          click="{activateIdentifyTool(event)}"
                          rollOut="iconRollOutHandler(event)"
                          rollOver="iconRollOverHandler(event)"
                          source="assets/images/i_servicearea.png"
                          toolTip="Calculate Drive Times"
                          useHandCursor="true"/>

            private function activateIdentifyTool(event:MouseEvent, lTool:String = ""):void
            {
                addSharedData("Deactivate_DrawTool", null); // to be able to deactivate drawTool on other widgets
                
                // apply glow
                if(event){
                    selectedDrawingIcon = Image(event.currentTarget);
                }else{
                    switch(lTool){
                        case "DriveTime" :
                        {
                            selectedDrawingIcon = iDTPnt;
                            break;
                        }
                        case DrawTool.EXTENT :
                        {
                            selectedDrawingIcon = iDrawExt;
                            break;
                        }
                        case DrawTool.POLYGON :
                        {
                            selectedDrawingIcon = iDrawPoly;
                            break;
                        }
                        case DrawTool.MAPPOINT :
                        {
                            selectedDrawingIcon = iDrawPnt;
                            break;
                        }
                        case DrawTool.POLYLINE :
                        {
                            selectedDrawingIcon = iDrawLine;
                            break;
                        }
                        default:
                        {
                            selectedDrawingIcon = iDrawPnt;
                        }
                    }
                    
                }
                clearSelectionFilter();
                selectedDrawingIcon.filters = [ glowFilter ];
                
                var status:String;
                var value:String = selectedDrawingIcon.name;
                
                if(!drawTool)
                    drawTool = new DrawTool();
                drawTool.showDrawTips = false;
                
                lastTool = selectedDrawingIcon.name;
                setMapNavigation("none", "");
                map.panEnabled = false;
                switch (value)
                {
                    case "DriveTime":
                    {
                        status = pointLabel;
                        drawTool.markerSymbol = identMarkerSymbol;
                        drawTool.activate(DrawTool.MAPPOINT);
                        break;
                    }
                    case DrawTool.MAPPOINT:
                    {
                        status = pointLabel;
                        drawTool.markerSymbol = identMarkerSymbol;
                        drawTool.activate(DrawTool.MAPPOINT);
                        break;
                    }
                    case DrawTool.POLYLINE:
                    {
                        status = lineLabel;
                        drawTool.lineSymbol = identLineSymbol;
                        drawTool.activate(DrawTool.POLYLINE);
                        break;
                    }
                    case DrawTool.EXTENT:
                    {
                        status = rectLabel;
                        drawTool.fillSymbol = identFillSymbol;
                        drawTool.activate(DrawTool.EXTENT);
                        break;
                    }
                    case DrawTool.POLYGON:
                    {
                        status = polyLabel;
                        drawTool.fillSymbol = identFillSymbol;
                        drawTool.activate(DrawTool.POLYGON);
                        break;
                    }
                }
            }
            
            private function drawEnd(event:DrawEvent):void
            {
                clear();
                if(keepActive){
                    activateIdentifyTool(null, lastTool);
                }else{
                    event.target.deactivate();
                    map.panEnabled = true;
                    if (selectedDrawingIcon)
                    {
                        selectedDrawingIcon.filters = [];
                        selectedDrawingIcon = null;
                    }
                }
                if(lastTool == "DriveTime"){
                    computeServiceArea(event.graphic.geometry as MapPoint);
                }else{
                    identifyFeatures(event.graphic.geometry);
                }
            }


To print to the console you use
trace("hello world");
0 Kudos
SeanCook
Emerging Contributor
Thanks for the help.

I can get into the computeServiceArea function fine now....my problem has become a bit more esoteric.

Basically, when I use the drivetime widget

var params:Object =
     {
      "Input_Location": featureSet,
      "Drive_Times": driveTimes
     };
    trace (params.Input_Location);

returns

FeatureSet[index0.ApplicationSkin2._ApplicationSkin_Group1.contentGroup.viewerContainer.mapManager.MapManagerSkin8.managerView.map.UIComponent11.LayerContainer12.GraphicsLayer466.Graphic469]


However, when I close and open the widget, or when I use my new Drivetime + Identify widget,  the same code returns:

FeatureSet[GraphicsLayer466.Graphic484]


and fails. Any thoughts on what the difference is? In both cases I am feeding in a map point which trace shows has the full range of attributes, both before going into and after being in the computeServiceArea function.

On another note, do you have an email I could contact you with regarding a more business related matter? Feel free to drop me a line at seangcook {at} gmail [dot] com
0 Kudos