Please help - constrain radius of a circle, ArcGIS API

4718
8
02-06-2015 01:19 AM
OliviaGill
New Contributor

I am using this code to draw a circle:

               $('#circle').click(function () {

                       clearPreviousSearch();

                          map.disableMapNavigation();

                       $('#run').fadeOut();

                       buttonclickvalue = 'circle';

                       drawToolbar.activate(esri.toolbars.Draw.CIRCLE);

                   });

I've been told I need this code to constrain the radius:

var circle = new Circle({
  center
: e.mapPoint,
  geodesic
: domAttr.get(geodesic, "checked"),
  radius
: 100,
  radiusUnit
:units.MILES
});

But where on earth should it go - it's driving me nuts!!

Tags (1)
0 Kudos
8 Replies
RobertScheitlin__GISP
MVP Emeritus

Olivia,

  Basically you would be replacing the users drawn circle with the contained circle that you create above. So in your draw-end function you would get the event geometry and its centroid and replace it with your circle.

Sample:

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta name="viewport" content="width=device-width,user-scalable=no">
    <!--The viewport meta tag is used to improve the presentation and behavior of the samples
      on iOS devices-->
    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
    <title>Maps Toolbar</title>

    <link rel="stylesheet" href="http://js.arcgis.com/3.12/dijit/themes/nihilo/nihilo.css">
    <link rel="stylesheet" href="http://js.arcgis.com/3.12/esri/css/esri.css">
    <style>
      html, body, #mainWindow {
        font-family: sans-serif;
        height: 100%;
        width: 100%;
      }
      html, body {
        margin: 0;
        padding: 0;
      }
      #header {
        height: 80px;
        overflow: auto;
        padding: 0.5em;
      }
    </style>

    <script src="http://js.arcgis.com/3.12/"></script>
    <script>
      var map, toolbar, symbol, geomTask;

      require([
        "esri/map",
        "esri/toolbars/draw",
        "esri/graphic",
        "esri/geometry/Circle",
        "esri/symbols/SimpleMarkerSymbol",
        "esri/symbols/SimpleLineSymbol",
        "esri/symbols/SimpleFillSymbol",
        "esri/units",
        "dojo/parser", "dijit/registry",

        "dijit/layout/BorderContainer", "dijit/layout/ContentPane",
        "dijit/form/Button", "dijit/WidgetSet", "dojo/domReady!"
      ], function(
        Map, Draw, Graphic, Circle,
        SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol,
        units, parser, registry
      ) {
        parser.parse();

        map = new Map("map", {
          basemap: "streets",
          center: [-15.469, 36.428],
          zoom: 3
        });

        map.on("load", createToolbar);
        var tool;
        // loop through all dijits, connect onClick event
        // listeners for buttons to activate drawing tools
        registry.forEach(function(d) {
          // d is a reference to a dijit
          // could be a layout container or a button
          if ( d.declaredClass === "dijit.form.Button" ) {
            d.on("click", activateTool);
          }
        });

        function activateTool() {
          tool = this.label.toUpperCase().replace(/ /g, "_");
          toolbar.activate(Draw[tool]);
          map.hideZoomSlider();
        }

        function createToolbar(themap) {
          toolbar = new Draw(map);
          toolbar.on("draw-end", addToMap);
        }

        function addToMap(evt) {
          var symbol;
          toolbar.deactivate();
          map.showZoomSlider();
          switch (evt.geometry.type) {
            case "point":
            case "multipoint":
              symbol = new SimpleMarkerSymbol();
              break;
            case "polyline":
              symbol = new SimpleLineSymbol();
              break;
            default:
              symbol = new SimpleFillSymbol();
              break;
          }
          if (tool === 'CIRCLE'){
            console.info(evt.geometry);
            var circle = new Circle({
              center: evt.geometry.getCentroid(),
              geodesic: true,
              radius: 100,
              radiusUnit: units.MILES
            });
            map.graphics.add(new Graphic(circle, symbol));
          }else{
            map.graphics.add(new Graphic(evt.geometry, symbol));
          }
        }
      });
    </script>
  </head>
  <body class="nihilo">

  <div id="mainWindow" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'headline'">
    <div id="header" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'top'">
      <span>Draw:<br /></span>
      <button data-dojo-type="dijit/form/Button">Point</button>
      <button data-dojo-type="dijit/form/Button">Multi Point</button>
      <button data-dojo-type="dijit/form/Button">Line</button>
      <button data-dojo-type="dijit/form/Button">Polyline</button>
      <button data-dojo-type="dijit/form/Button">Polygon</button>
      <button data-dojo-type="dijit/form/Button">Freehand Polyline</button>
      <button data-dojo-type="dijit/form/Button">Freehand Polygon</button>
      <!--The Arrow,Triangle,Circle and Ellipse types all draw with the polygon symbol-->
      <button data-dojo-type="dijit/form/Button">Arrow</button>
      <button data-dojo-type="dijit/form/Button">Triangle</button>
      <button data-dojo-type="dijit/form/Button">Circle</button>
      <button data-dojo-type="dijit/form/Button">Ellipse</button>
    </div>
    <div id="map" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'"></div>
  </div>

  </body>
</html>
OliviaGill
New Contributor

Hi Robert, thank you for your help.

This is the toolbar initiate code I have - I'm assuming I can make the amendments you suggest here?

          function initToolbars() {

              drawfillsymbol = new esri.symbol.SimpleFillSymbol(esri.symbol.SimpleFillSymbol.STYLE_SOLID,

                      new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID,

                          new dojo.Color([0, 0, 0]), 3.0),

                      new dojo.Color([255, 255, 0, 0.2]));

              drawmarkersymbol = new           esri.symbol.SimpleMarkerSymbol(esri.symbol.SimpleMarkerSymbol.STYLE_CIRCLE, 25,

                      new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID,

                          new dojo.Color([0, 0, 0]), 3.0),

                      new dojo.Color([255, 255, 0, 1.0]));

  

             drawlinesymbol = new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID,

                          new dojo.Color([0, 0, 0]), 3.0);

   

              drawToolbar = new esri.toolbars.Draw(map);

              drawToolbar.setFillSymbol(drawfillsymbol);

              drawToolbar.setMarkerSymbol(drawmarkersymbol);

              drawToolbar.setLineSymbol(drawlinesymbol);

  

              editToolbar = new esri.toolbars.Edit(map);

              dojo.connect(drawToolbar, "onDrawEnd", addSearchGraphic);

              dojo.connect(editToolbar, "onDeactivate", editGraphicEnd);

              graphicClickListener = dojo.connect(searchgraphicsLayer, "onClick", graphicsLayerClicked);

              }

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Olivia,

  The code that you are showing me here has little to do with answering your question.

This line dojo.connect(drawToolbar, "onDrawEnd", addSearchGraphic);

in the addSearchGraphic function is where you need to check if the drawn graphic is a circle (unless that is the only type of geometry that you are using the drawtoolbar to do) and if it is a circle then you replace the drawn circle with your constrained circle:

  1. if (tool === 'CIRCLE'){ 
  2.             console.info(evt.geometry); 
  3.             var circle = new Circle({ 
  4.               center: evt.geometry.getCentroid(), 
  5.               geodesic: true, 
  6.               radius: 100, 
  7.               radiusUnit: units.MILES 
  8.             }); 
  9.             map.graphics.add(new Graphic(circle, symbol)); 
  10.           }else{ 
  11.             map.graphics.add(new Graphic(evt.geometry, symbol)); 
  12.           }
0 Kudos
JoelBennett
MVP Regular Contributor

Robert -

Your code would produce a circle of 100 mile radius even if the user drew a circle with a radius less than that, which I don't think is what's intended.  Perhaps something like the following would be more appropriate:

function addSearchGraphic(evt) {
 var maxCircle = new Circle({    
  center: evt.geometry.getCentroid(),    
  geodesic: true,    
  radius: 100,    
  radiusUnit: units.MILES    
 });
var maxCircleExtent = maxCircle.getExtent();
 var maxCircleArea = maxCircleExtent.getWidth() * maxCircleExtent.getHeight();
var drawnCircleExtent = evt.geometry.getExtent();
 var drawnCircleArea = drawnCircleExtent.getWidth() * drawnCircleExtent.getHeight();
var resultCircle = ((drawnCircleArea > maxCircleArea) ? maxCircle : evt.geometry);
//set the symbol to something meaningful
 var symbol = null;
//assume reference to map is valid
 map.graphics.add(new Graphic(resultCircle, symbol));
}
0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Joel,

   OK, my interpretation of her request was different then.  Olivia did not say constrain to no larger than. But that is good code for the case that it is her intent, to constrain to no larger than.

0 Kudos
OliviaGill
New Contributor

Hi

Sorry I should have been clearer. I am hoping that the user will only be able to draw circles that are a specific radius (10km). So no larger or smaller. Thank you to all for the very helpful replies. I will try and put your suggestions into action today and hopefully I can finally get this very pesky problem pinned down.

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Olivia,

   No matter what the user will be able to draw a circle at what ever size they choose and then that will be replaced by the constrained circle you specify, using the code I posted.

0 Kudos
JoelBennett
MVP Regular Contributor

I agree that the code Robert posted will work for the stated purpose.  My invalid assumption was based on the fact that the user was drawing a circle. I find it strange for a user to draw a circle just so it can be discarded - it seems you're really just after the center point so that you can build a circle of fixed size around it.  Unless your goal is to deceive or confuse the user, it might be better just to have them click the center point instead:

$('#circle').click(function () {
 clearPreviousSearch();
map.disableMapNavigation();
$('#run').fadeOut();
buttonclickvalue = 'circle';
drawToolbar.activate(esri.toolbars.Draw.POINT);
});

function addSearchGraphic(evt) {
 var circle = new Circle({
  center: evt.geometry,
  geodesic: true,
  radius: 10,
  radiusUnit: esri.units.KILOMETERS
 });
//now do whatever with the circle
}