Draw graphics + Query

3546
16
Jump to solution
12-08-2014 08:24 AM
jaykapalczynski
Frequent Contributor

I am using the below code to draw graphics in the map.  Everything works great....

But I want to use those geometries to do spatial queries.  I need to call a specific Feature to get the geometry for the query making the Graphic far to general.   I am trying to select all the features from X Feature that are within the Geometry Drawn.  Noting that there might be other graphics in the map so thats why I am thinking I need to separate them and get them into a Feature that I can reference by itself.

I think I need to push the graphics drawn to a Feature?  Not sure how to do this.  Once I have the feature I can use its geometry for the query. 

Not sure if I am on the right path here...AND unsure how to convert the graphic to a feature so that its geometry can be used in a query....hope someone can help.

    // markerSymbol is used for point and multipoint, see http://raphaeljs.com/icons/#talkq for more examples

    var DrawmarkerSymbol = new SimpleMarkerSymbol();

        DrawmarkerSymbol.setPath("M16,4.938c-7.732,0-14,4.701-14,10.5c0,1.981,0.741,3.833,2.016,5.414L2,25.272l5.613-1.44c2.339,1.316,5.237,2.106,8.387,2.106c7.732,0,14-4.701,14-10.5S23.732,4.938,16,4.938zM16.868,21.375h-1.969v-1.889h1.969V21.375zM16.772,18.094h-1.777l-0.176-8.083h2.113L16.772,18.094z");

        DrawmarkerSymbol.setColor(new Color("#00FFFF"));

  // http://blogs.esri.com/esri/arcgis/2012/02/03/esri-picture-marker-symbol-generator-for-javascript-dev...

  var DrawPicturemarkerSymbol = new esri.symbol.PictureMarkerSymbol({

  "angle": 0,

  "xoffset": 0,

  "yoffset": 12,

  "type": "esriPMS",

  "url": "http://static.arcgis.com/images/Symbols/Basic/RedStickpin.png",

  "contentType": "image/png",

  "width": 24,

  "height": 24

  });

        // lineSymbol used for freehand polyline, polyline and line.

        var DrawlineSymbol = new CartographicLineSymbol(

          CartographicLineSymbol.STYLE_SOLID,

          new Color([255,0,0]), 2,

          CartographicLineSymbol.CAP_ROUND,

          CartographicLineSymbol.JOIN_MITER, 5

        );

        var DrawfillSymbol = new SimpleFillSymbol(

           "solid",

           new SimpleLineSymbol("solid", new Color([255,0,0]), 2),

           new Color([0,128,255,0.25])

         );

        function initToolbar() {

          tb = new Draw(app.map);

          tb.on("draw-end", addGraphic);

              // event delegation so a click handler is not

              // needed for each individual button

          on(dom.byId("infoShapefileCreate"), "click", function(evt) {

            if ( evt.target.id === "info" ) {

              return;

            }

            var tool = evt.target.id.toLowerCase();

            app.map.disableMapNavigation();

            tb.activate(tool);

          });

        }

  function addGraphic(evt) {

          //deactivate the toolbar and clear existing graphics

          tb.deactivate();

          app.map.enableMapNavigation();

          // figure out which symbol to use

          var symbol;

          if ( evt.geometry.type === "point" || evt.geometry.type === "multipoint") {

            symbol = DrawPicturemarkerSymbol;

          } else if ( evt.geometry.type === "line" || evt.geometry.type === "polyline") {

            symbol = DrawlineSymbol;

          }

          else {

            symbol = DrawfillSymbol;

          }

          app.map.graphics.add(new Graphic(evt.geometry, symbol));

    }

0 Kudos
1 Solution

Accepted Solutions
OwenEarley
Occasional Contributor III

Hi Jay,

Steve and Robert have been pointing you in the right direction. You need to create your GraphicsLayer once and then add user polygon graphics to it. Then before you run the spatial query, use a geometry service to union the geometries for all of the graphics in the GraphicsLayer.

A working example is available here - User Input Graphics Layer

The key parts of the code are:

        // Create your custom graphics layer and add it to the map
        drawnGL = new GraphicsLayer({id:'user-input'});
        map.addLayer(drawnGL);

        function addGraphic(evt) {
          ...         
          // Add  your user created graphic to your graphics layer:
          drawnGL.add(new Graphic(evt.geometry, fillSymbol));
          ...
        }

        function unionGraphics(){
            ...
            // get geometries from your graphics layer
            var geoms = [];
            for (var i=0; i<drawnGL.graphics.length;i++){
              geoms.push(drawnGL.graphics.geometry)
            }
            // union geometries
            geomSvc.union(geoms, function(result){
              runAnalysis(new Graphic(result));
            }, function(){             
              alert("Geometry service error");
            });
            ...
        }

There are also a few console.log statements in the sample so you can open developer tools and see the results.

View solution in original post

0 Kudos
16 Replies
SteveCole
Frequent Contributor

I think the answer depends on how you want things to work. Do you want the query to happen as soon as the user finishes drawing a graphic? If so, your current code is fine and you just need to create a new function for the actual query (using queryTask) and call that function from inside your addGraphic function.

Assuming that what I have suggested is what you want, it would go something like this:

  function addGraphic(evt) {
          //deactivate the toolbar and clear existing graphics
          tb.deactivate();
          app.map.enableMapNavigation();

          // figure out which symbol to use
          var symbol;
          if ( evt.geometry.type === "point" || evt.geometry.type === "multipoint") {
            symbol = DrawPicturemarkerSymbol;
          } else if ( evt.geometry.type === "line" || evt.geometry.type === "polyline") {
            symbol = DrawlineSymbol;
          }
          else {
            symbol = DrawfillSymbol;
          }
          app.map.graphics.add(new Graphic(evt.geometry, symbol));
          getIntersectingFeatures(evt.geometry);
    }

function getIntersectingFeatures(theGeometry) {
        var query = new esri.tasks.Query();
        query.outFields = ["*"];
        query.returnGeometry = true;
        query.geometry = theGeometry;

        var theQuery = new esri.tasks.QueryTask(<feature service URL>);
        theQuery.execute(query);
      ....etc....
}

Sorry I used legacy code instead of AMD but it's what I had handy.

0 Kudos
jaykapalczynski
Frequent Contributor

I was hoping that I can fire that query off separately.....the user might create a couple polygons....these polygons will then be used for the query.  I think can work?

0 Kudos
SteveCole
Frequent Contributor

You absolutely can do that. In fact, In my application, the user draws their feature, and then initiates the query by clicking a button after they've completed their sketch. I have only worked with a single feature geometry so someone else will have to chime in about how you query based on multiple features. The API doesn't indicate if you can specify an array of features so my take away is that you can only specify a single feature geometry. If that's a case, maybe you need to union the various individual geometries together before specifying it to the Query?...

CC:

Kelly Hutchins

RobertScheitlin__GISP
MVP Emeritus

Jay,

   Steve is right you will have to union the drawn geometries either using the Geometry Service or some client side code. I do this in my eSearch widget for WAB you can look at the code there go get some ideas.

Enhanced Search Widget Beta 3.3.2

jaykapalczynski
Frequent Contributor

I think I need to start with the thought of trying to determine how many objects there are drawn in the map.

Say I have the user and they draw 4 different polygons via the code I pasted in the first post above.

1. How would I test to determine if there are more than one feature?

... if thats the case then I run a Union. if not I go right to the query

2. What do I run the Union against....its just a graphic....

3. How to I specify the specific graphics in the Union (what if there are other graphics in the map, I dont want those to be in the union)

4. Can I assign the graphics being added via this draw tool to a specific ID  or feature that I can reference in the Union and the eventual Query?

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Jay,

  I Would start by assigning a unique GraphicsLayer that the drawn features will be added to istead of the maps graphics layer.  If you do that then you would not have to worry about if there are other graphics in the maps graphics layer.

You run the union on the graphics geometry. you can use esri/graphicsUtils and the getGeometries method.

jaykapalczynski
Frequent Contributor

Just getting the straight....I would run the Union on the New GraphicsLayer I created instead of the map graphics I am doing currently?

0 Kudos
jaykapalczynski
Frequent Contributor

PART 1:  Add the graphics to my Graphic Layer Like this????

O am attempting to comment out eixting code that draws pushed the graphics to the graphics map layer

and replace with code that creates a GraphicsLayer and adds the graphics to it...

That seem correct:

  function addGraphic(evt) {

          //deactivate the toolbar and clear existing graphics

          tb.deactivate();

          app.map.enableMapNavigation();

          // figure out which symbol to use

          var symbol;

          if ( evt.geometry.type === "point" || evt.geometry.type === "multipoint") {

            symbol = DrawPicturemarkerSymbol;

          } else if ( evt.geometry.type === "line" || evt.geometry.type === "polyline") {

            symbol = DrawlineSymbol;

          }

          else {

            symbol = DrawfillSymbol;

          }

// REMOVE FROM EXISTING

      app.map.graphics.add(new Graphic(evt.geometry, symbol));

  // ADD THIS TO ADD GRAPHICS TO GraphicLayer

  var DrawnGraphics = new esri.layers.GraphicsLayer();

  app.map.DrawnGraphics.add(evt.geometry, symbol);

    }

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Jay,

   As long as you are not adding a GraphicsLayer every time the addGraphic function is called. I would create the GraphicsLayer in one of your apps init functions and also add it to the map at that point and using a global var to this new GraphicsLayer. The way your code looks now you are creating a local var called DrawnGraphics and then attempting to use a global var called app.map.DrawnGraphics when you are adding the actual graphic...

0 Kudos