Select to view content in your preferred language

Assistance Building First Widget : Buffer Points?

2890
13
Jump to solution
10-13-2016 08:48 AM
BrianO_keefe
Honored Contributor

Would anyone be willing to help me walk through the steps necessary to develop my first widget?

I believe it would be a simple one. I want to take the following JSAPI functionality and make it into a widget.

Buffer a point | ArcGIS API for JavaScript 3.18 

I'm envisioning a CREATE BUFFER POINTS button. You click it, then click on the map, then I want the user to be able to print the map with the buffers created.

That is all I want... I'm an experienced JS developer, just out of practice and unfamiliar with Dojo. I really just need to know where and what calls and callbacks and function naming conventions to use as well as packaging guidance.

Thanks in advance

Tags (1)
1 Solution

Accepted Solutions
RobertScheitlin__GISP
MVP Emeritus

Brian,

    There is a WAB dijit for drawing on the map called DrawBox, so I switched out your draw stuff to use that. Also disregard that advice about not using "this" you need it for dojo templated widgets. Next I added lang.hitch to all your function calls to keep "this" in scope. See the edits to the attached zip

View solution in original post

13 Replies
RobertScheitlin__GISP
MVP Emeritus

Brain,

   I would start your widget development with using the stemapp/widgets/samplewidgets/CustomWidgetTemplate folder as a base template for your widget (be aware you need to copy the CustomWidgetTemplate folder out of the samplewidgets folder and rename the folder to your widgets name and then update the manifest.json with the new name as well). Next you can look at the SOME details from this like for info:

Create a custom in-panel widget—Web AppBuilder for ArcGIS (Developer Edition) | ArcGIS for Developer... 

But best of all look at other otb and or custom widgets as examples.

If you need more help or get stuck just shout out.

BrianO_keefe
Honored Contributor

Ok... So I'm working on my first widget. Using Robert Scheitlin, GISP‌ -'s recommendations.

Widgets Purpose

This widget needs to have a button, and two input fields. The user enters numbers in the fields, selects distance TYPE (Miles or Feet), presses the button, and clicks on the map to create a buffer set. The widget should generate TWO buffers that are transparent and overlap each other. Those two buffers should be as large as the two numbers in the input fields.

So if the user enters 1000, and 3000 (the most likely buffer range for this widget) and selects FEET from the distance TYPE then clicks on the map the widget should generate two buffers. One that is a 1,000 foot buffer and a 3,000 foot buffer around that initial click point.

Contents

So what I have so far is this:

manifest.json

{
 "name": "cotBuffer",
 "2D": true,
 "3D": false,
 "platform": "HTML",
 "version": "0.1",
 "wabVersion": "2.1",
 "author": "Rev. Brian Scott O'keefe",
 "description": "This is the City of Tulsa's first widget. It serves a single purpose to draw two buffers from one click that are printable.",
 "copyright": "",
 "license": "http://www.apache.org/licenses/LICENSE-2.0",
 "properties": {
 "inPanel":true,
 "hasLocale": true,
 "hasStyle":true,
 "hasConfig":true,
 "hasUIFile":true,
 "hasSettingPage":true,
 "hasSettingUIFile":true,
 "hasSettingLocale":true,
 "hasSettingStyle":true,
 "IsController":false
 }
}

style.css

button{
 margin:2px;
 cursor:pointer;
}

Widget.html

<div>
 <div class="details">Pick a tool and draw on the map. The drawn graphic will be buffered based on the specified parameters.</div>
 <button type="button" class="tool" id="point">Point</button>
 <br/>
 <hr />
 <div><b>Buffer Parameters</b></div>
 First Buffer Distance: <input type="text" id="firstDistance" size="5" value="1000" /><br />
 First Buffer Distance: <input type="text" id="secondDistance" size="5" value="3000" />
 <select id="unit" style="width:100px;">
 <option value="UNIT_STATUTE_MILE">Miles</option>
 <option value="UNIT_FOOT">Feet</option>
 </select><br />
 <button type="button" id="clearGraphics">Clear Graphics</button>
</div>

Widget.js

define([
 'dojo/_base/declare',
 'jimu/BaseWidget',
"dojo/dom",
"dojo/_base/array",
 "dojo/parser",
 "dojo/query",
 "dojo/on",
"esri/Color",
 "esri/config",
 "esri/map",
 "esri/graphic",
"esri/geometry/normalizeUtils",
 "esri/tasks/GeometryService",
 "esri/tasks/BufferParameters",
"esri/toolbars/draw",
"esri/symbols/SimpleMarkerSymbol",
 "esri/symbols/SimpleLineSymbol",
 "esri/symbols/SimpleFillSymbol",
"dijit/layout/BorderContainer",
 "dijit/layout/ContentPane",
 "dijit/form/Button",
 "dojo/domReady!"
],
 function(
 declare,
 BaseWidget,
 dom,
 array,
 parser,
 query,
 on,
 Color,
 esriConfig,
 Map,
 Graphic,
 normalizeUtils,
 GeometryService,
 BufferParameters,
 Draw,
 SimpleMarkerSymbol,
 SimpleLineSymbol,
 SimpleFillSymbol
) {
 //To create a widget, you need to derive from BaseWidget.
 return declare(
 [BaseWidget],
 {
 // Custom widget code goes here
baseClass: 'jimu-widget-customwidget',
//this property is set by the framework when widget is loaded.
 name: 'cotBuffer',
tb: '',
//methods to communication with app container:
// postCreate: function() {
 // this.inherited(arguments);
 // console.log('postCreate');
 // },
startup: function() {
 this.inherited(arguments);
//Setup button click handlers
 on(dom.byId("clearGraphics"), "click", function()
 {
 if(this.map){
 this.map.graphics.clear();
 }
 });
//click handler for the draw tool buttons
 query(".tool").on("click", function(evt)
 {
 if(this.tb)
 {
 this.tb.activate(evt.target.id);
 }
 });
this.initToolbar();
console.log('startup');
 },
initToolbar: function (evtObj) {
 this.tb = new Draw(evtObj.map);
 this.tb.on("draw-end", createCOTBuffers);
 },
createCOTBuffers: function(evtObj) {
 this.tb.deactivate();
 var geometry = evtObj.geometry, symbol;
 symbol = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_SQUARE, 10, new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([255,0,0]), 1), new Color([0,255,0,0.25]));
var graphic = new Graphic(geometry, symbol);
 this.map.graphics.add(graphic);
//setup the buffer parameters
 var params = new BufferParameters();
 params.distances = [ dom.byId("firstDistance").value, dom.byId("secondDistance").value ];
 params.outSpatialReference = this.map.spatialReference;
 params.unit = GeometryService[dom.byId("unit").value];
//normalize the geometry
 normalizeUtils.normalizeCentralMeridian([geometry]).then(function(normalizedGeometries)
 {
 var normalizedGeometry = normalizedGeometries[0];
 params.geometries = [normalizedGeometry];
 esriConfig.defaults.geometryService.buffer(params, showCOTBuffers);
 });
 },
showCOTBuffers: function (bufferedGeometries) {
 var symbol = new SimpleFillSymbol(
 SimpleFillSymbol.STYLE_SOLID,
 new SimpleLineSymbol
 (
 SimpleLineSymbol.STYLE_SOLID,
 new Color([255,0,0,0.65]), 2
 ),
 new Color([255,0,0,0.35])
 );
array.forEach(bufferedGeometries, function(geometry)
 {
 var graphic = new Graphic(geometry, symbol);
 this.map.graphics.add(graphic);
 });
}

 // onOpen: function(){
 // console.log('onOpen');
 // },
// onClose: function(){
 // console.log('onClose');
 // },
// onMinimize: function(){
 // console.log('onMinimize');
 // },
// onMaximize: function(){
 // console.log('onMaximize');
 // },
// onSignIn: function(credential){
 // /* jshint unused:false*/
 // console.log('onSignIn');
 // },
// onSignOut: function(){
 // console.log('onSignOut');
 // }
// onPositionChange: function(){
 // console.log('onPositionChange');
 // },
// resize: function(){
 // console.log('resize');
 // }
//methods to communication between widgets:
});
 });

I was at the Dev Summit and I remember the KeyNote speaker saying, "Don't use THIS in your Javascript." I'm definitely rusty on my Javascript  but I tried to leave out this and suddenly I can't reference the map object...

But I'm having more issues than that...

I'm basing this Widget off of a JSAPI reference.

Geometry Service - Buffer | ArcGIS API for JavaScript 3.18 

Any help would be appreciated.

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Brian,

    There is a WAB dijit for drawing on the map called DrawBox, so I switched out your draw stuff to use that. Also disregard that advice about not using "this" you need it for dojo templated widgets. Next I added lang.hitch to all your function calls to keep "this" in scope. See the edits to the attached zip

BrianO_keefe
Honored Contributor

The draw box is INFINITELY better than what I was using. Thank you for that...

I'm running into an Access-Control-Allow-Origin header issue now.

Can you think of what would do this?

This isn't from my proxy, is it?

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

do you have tasks.arcgisonline.com in your proxy.config? Better yet why are you not using your own geometry service in the apps main config.json?

BrianO_keefe
Honored Contributor

As this was the demo: /webappviewer/?config=sample-configs/config-demo.json

I hadn't even looked at it. I have added in our Geometry service and voila! Issue resolved.

As usual, thank you sir.

It's incredibly amazing that you help out like this.

Widget #1... done.

Now I can see that I need to start wrapping my head around libraries like the DrawBox...

Any recommendations for what should be looked through?

Dojo seems to complicate things unnecessarily with their data-dojo-attach-point and data-dojo-type, etc.

Trying to figure out where and what needs to be added where and when is a little overwhelming.

But it's past time...

But thank you again.

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Brian,

   I actually find dojo template'd widgets to be easier. instead of having to use dojo.byId("blahblah") I just use this.blahblah.

You can get the basics by studying dojo template'd widget docs like this:

Creating Template-based Widgets - Archived Tutorial - Dojo Toolkit 

0 Kudos
BrianO_keefe
Honored Contributor

Any idea why I would get THIS...?

I'm trying to add the widget to an application...

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

When you change the widgets name you need to change it in multiple locations.

  1. The widgets main folder name
  2. The manifest.json
  3. The Widget.js
  4. The nls/strings.js