Through the previous three lessons of this course, you've learned how to build useful web maps using the Google Maps JavaScript API. Esri also offers a web mapping API for the JavaScript platform; what you learned earlier in the course has you well positioned to pick up the Esri API without a terrible amount of effort. This lesson covers the similarities and differences between the two APIs and culminates with you creating a mashup using the Esri API.
If you have any questions now or at any point during this week, please feel free to post them to the Lesson 6 Discussion Forum. (That forum can be accessed at any time by clicking on the Discussions tab within Canvas.)
Lesson 6 is two weeks in length. (See the Calendar in Canvas for specific due dates.) To finish this lesson, you must complete the activities listed below. You may find it useful to print this page out first so that you can follow along with the directions.
Step | Activity | Access/Directions |
---|---|---|
1 | Work through Lesson 6. | You are in the Lesson 6 online content now. The Overview page is previous to this page, and you are on the Checklist page right now. |
2 | You will be e-mailed a scenario requiring the development of a map based on Esri's JavaScript API.
|
Follow the directions throughout the lesson and in the scenario sent via e-mail. |
3 | Take Quiz 6 after you read the online content. | Go to the Canvas Homepage and click on the "Lesson 6 Quiz" link to begin the quiz. |
Esri’s ArcGIS API for JavaScript offers web-mapping capability that is quite similar to what you’ve encountered so far in the course with the Google Maps API. But while Google’s API is focused primarily on mapping, Esri’s provides more of the functionality you would expect from a GIS vendor, including geoprocessing, network analysis and data editing. Organizations that have their data in Esri’s formats (shapefiles and geodatabases) should also find it easier to share their maps online as there is less need for massaging data into another format.
We’ll get started by putting together a Hello World map using Esri’s JavaScript API. Take a look at the source code of this Hello World map [1].
Let’s focus first on the elements of the code that are quite similar to what you’ve seen in Google Maps:
Now, let’s get into the differences:
Now that we've seen the Hello World of the Esri JavaScript API and discussed its similarities and differences with the Google API, let's have a look at some resources that developers can consult when putting together an Esri JS page.
Just as the Google Maps API Reference is an important resource for developing custom Google maps, you won't go far in creating maps with the Esri JavaScript API without consulting their resource pages [2]. Each of the three tabs -- Guide, API Reference and Sample Code -- is worth your time checking out.
The Guide tab provides a good starting point for beginners, in particular the topics under the "About the API", "Work with the API" and "Tutorials" headings.
The API Reference tab, as with Google's version of the same, is the place to go for detailed information on the various object classes built into the API including their constructors, properties, methods and events. There is also usually example code on these pages to help clarify usage along with links to samples that use the classes. I encourage you to follow along with the code discussion in the lesson by looking up the various classes utilized in the API Reference. Note that the classes are broken up under a number of headings including esri, geometry, layers, symbols, etc. If you have any trouble finding a class, you can always look it up through the Search box in the upper right of the page.
Finally, the Sample Code tab provides access to a gallery of sample maps that demonstrate a variety of classes and functionality. The samples are categorized on the left side of the page (e.g., Graphics, Query and Select, and Renderers). Clicking on a sample in the gallery pulls up a page that provides links to a live version of the sample and a zipped copy of the source code. The page also lists and discusses the source code. It is also possible to open the sample in "the sandbox," a tool for making modifications to a sample and seeing the resulting changes side by side. As with classes in the API Reference, you can look for samples that make use of a class through the Search box in the upper right of the page.
That last map was pretty boring, so let's spice it up a bit by plotting a point. View the source code of this map [3], copy the code to a text editor and replace the x/y coordinates in the ‘var pt’ statement with the coordinates of your hometown. Save the file and open it in a browser (no need to upload it to a web server) to confirm that you changed the coordinates correctly.
When working with the Google API, we added vector overlays by creating Marker, Polyline and Polygon objects and associating them with the desired Map. In Esri’s API, adding vector overlays involves creating a Graphic object and adding it to the Map’s associated GraphicsLayer. A Graphic has four properties that are typically set: geometry, symbol, attributes and infoTemplate. The bulk of the JS code in this page is concerned with building objects that can be used to set these properties for a new hometown graphic.
The first difference you may notice as compared to the Hello World example is that this page includes several module references and corresponding callback function arguments, in addition to the “Map” reference. As a developer, you probably won’t identify all of the modules you’ll need at the outset. You’re likely to jump back and forth between the body of your code and the module list as you recognize new modules that need to be referenced in the course of your coding.
Moving to the code’s body, an important detail to note is that manipulating the GraphicsLayer can only be done after the Map has finished loading. To ensure that this happens, the graphic adding code is written in a separate function called ShowHome(); that function is triggered by the event handler that is set up on Line 32. Note the use of the “on” syntax to create the event handler.
Getting a graphic to overlay properly on top of the base map requires that the graphic’s coordinates are in the same spatial reference system used by the base map. Esri’s base maps are in the WGS 84 geographic coordinate system. The first line of the ShowHome() function creates a new Point object and defines its spatial reference as 4326, the “Well-Known ID” (WKID) of the WGS 84 coordinate system. (The ID is “Well-Known” because it’s used throughout the geospatial industry.) Complete listings of geographic and projected coordinate systems and their WKIDs can be found at http://resources.arcgis.com/en/help/arcgis-rest-api/02r3/02r3000000qq000000.htm. [4]
The next step in creating the graphic is defining its symbol. If you look under the symbols heading in the API Reference, you're likely to see a number of classes that seem like they might be suitable for depicting a point location. It turns out that the only two choices are actually SimpleMarkerSymbol and PictureMarkerSymbol. The first of these classes is used to depict points using a circle, cross, diamond, square or an x. As its name implies, the other class is used to depict points using an image.
In this script, we use a SimpleMarkerSymbol. Looking at that class in the API Reference, you should note from the Class Constructor section that objects of the class can be created by supplying no arguments (in which case you would follow up the creation of the object with calls to methods like setOutline() and setStyle()), with a list of four arguments separated by commas, or with properties defined in a JSON object. The second option is the one we use in this script.
Before discussing the code further, I want to draw your attention to the Class Hierarchy section near the top of the SimpleMarkerSymbol class. This section shows that SimpleMarkerSymbol is a sub-class of the MarkerSymbol class, which in turn is a sub-class of the Symbol class. What this means is that a SimpleMarkerSymbol inherits the properties and methods defined under the MarkerSymbol class and the Symbol class. So, a SimpleMarkerSymbol has a size property because it inherits it from the MarkerSymbol class and a color property because it inherits it from the Symbol class.
Also, while looking at the MarkerSymbol and Symbol classes, note that their descriptions explain that those classes have no constructor. This means that there are no actual objects of those classes. They simply exist in the abstract as a means of defining properties and methods that are shared in common by sub-classes beneath them in the class hierarchy. You should also note that a similar hierarchy exists for line and polygon symbols.
Returning to our code, the SimpleMarkerSymbol object is constructed using STYLE_CIRCLE for the style parameter (other constants allowed for this parameter are listed on the SimpleMarkerSymbol API Reference page), 8 (pixels) for the size parameter, a SimpleLineSymbol for the outline parameter (which is constructed in a similar way to SimpleMarkerSymbols), and a Color object. The API Reference page for the Color class explains that a Color object can be constructed using either a named color, a hexadecimal value, an array of red/green/blue values or an RGB array plus a transparency value. In this example we use an RGB array.
So far we've discussed the coding of the graphic's geometry and symbology, which leaves the graphic's attributes and info template. In a more typical mashup that displays data stored in a shapefile or geodatabase, the attributes would be retrieved from the dataset's attribute table. Here, since we are building a marker from scratch, we hard-code the attribute information into our script using JSON notation. The InfoTemplate object is then created by supplying a title that will appear in the title bar of all info windows (the first argument to the InfoTemplate constructor) and the text that will appear in the body of the info window (the second argument to the constructor). Pay particular attention to the way values from the feature's attributes are inserted into the string (with the name of the attribute enclosed in braces and preceded by a dollar sign).
With the four necessary components created, we can create the new Graphic using the four components as arguments to the Graphic class constructor. The final line within the ShowHome() function adds the new graphic to the map's graphics layer.
Now that you've been introduced to the use of graphic overlays in Esri's API and gotten some experience digging around in the API Reference, let's continue by discussing a common need for map developers, setting the map's initial extent.
By default, a map will initialize to fit all of its layers. However, you may prefer that it be zoomed in on a particular area instead of opening to the full extent. Example 1 [5] builds on the hometown map by setting the map's extent. It does so by creating a new Extent object from a set of four bounding coordinates. The SpatialReference of the Extent object is set to match that of the base map. The Extent object (stored in the startExtent variable) is then used to set the Map's extent property within its constructor.
Example 2 [6] shows a page containing a world topo map that initializes zoomed in on a Louisville land records layer. (It is adapted from this Esri sample [7].) Refer to the source code to follow along with the discussion below.
The code from this example is a bit complicated as compared to the previous ones. The ultimate goal is to set the Map's extent to match the extent held in the fullExtent property of the Louisville map service layer. However, it is important to wait to read a layer's properties until it's finished loading. Thus, this page includes code that tests whether both layers have successfully loaded before creating the map. Note that the script sets up listeners for the layers' load events, increments a counter variable by 1 when a layer has been loaded, and calls to the createMapAddLayers() function when that counter reaches 2. Unfortunately, the script is further complicated by behavior in Internet Explorer that is documented on Esri's 'Working with Events [8]' page:
In Internet Explorer, due to resource caching, the onLoad event is fired as soon as the layer is constructed. Consequently you should check whether the layer's loaded property is true before registering a listener for the load event..."
This IE behavior is the reason why the lines that increment the counter and call the createMapAddLayers() function are duplicated for each layer.
The createMapAddLayers() function is set up to accept two map service layers as arguments. When the Map is created, note that the Map's extent property is set to the second layer's fullExtent as part of the constructor. Also note that the basemap property is not set as in earlier examples. Instead, the layer in myService1 serves as the basemap after it's added.
Event listeners like those discussed in the example above require memory and unless additional steps are taken that memory will remain tied up unnecessarily when the map is closed. Read on to see how to prevent such memory leaks.
The previous page made reference to a note from Esri's Working with Events page in the API documentation. That page contains another important suggestion:
As a best practice, and to avoid memory leaks, event listeners should be removed when the application is closed. This is done by adding another listener, this time for the map's onUnload event...
var myUnload = map.on("unload", unloadHandler);
In your "unload" handler function, you disconnect the listeners, including any listener you added for the onUnload event:
function unloadHandler(evt){ changeHandler.remove(); myUnload.remove(); }
To see this concept illustrated more fully, please refer to this alternate version of the map from the last page [9]. The differences in this version:
At this point, we've gone over some of the basics of setting up an Esri JavaScript API map. And while there's often good use cases for adding graphic overlays to a map, data are more typically added by consuming services published via ArcGIS Server. So let's explore how to go about doing that.
Now that you've gotten a chance to play around with Esri's JavaScript API, let's pause to discuss the big picture.
Esri's mashup architecture is largely focused on consuming services published through ArcGIS Server. Maps are the most obvious type of service and the type that we will focus on in this lesson. However, there are a number of other ArcGIS web service types that offer a great deal of potential for building rich applications, including geocoding services, geoprocessing services, image services, mobile data services, and network analysis services.
Esri makes it possible to consume their web services through the two primary architectural styles employed by web developers today: SOAP (Simple Object Access Protocol) and REST (REpresentational State Transfer). The SOAP protocol was developed by Microsoft in the 1990s and can be thought of as object-oriented programming in which the objects live on some web server and the programming code that manipulates them lives on some client machine. REST came later and has overtaken SOAP in popularity because of its ease of use. RESTful web services, as they are sometimes called, progressively expose their functionality through URLs that can be invoked almost like properties and methods. They send responses to the client applications in the form of XML or JSON.
Esri's JavaScript API uses the REST framework for working with web services published with ArcGIS Server. One important aspect of using this framework is that information on the various REST web services published through an ArcGIS Server instance can be discovered through a series of pages called the Services Directory. This directory can be viewed in a web browser using a URL of the form <server name>/arcgis/rest/services. For example, earlier in the lesson we consumed map services published through ESRI's server called 'server.arcgisonline.com'.
Let's explore that server's Services Directory.
In this section of the lesson, we saw how to explore the services published on an instance of ArcGIS Server. You might try creating a map that includes an ArcGISDynamicServiceLayer or ArcGISTiledMapServiceLayer from one of the sample servers mentioned above or maybe from a server you have at work using the Louisville land records example map from the previous page as a starting point.
In the next part of the lesson, we'll discuss these layer types in a bit more detail and then focus on another layer type that offers even greater possibilities to developers: the FeatureLayer.
Earlier in the lesson, we saw how a vector feature could be added to a map as a graphic. That method of hard coding coordinates into the script works for a small number of features, but is impractical for large numbers of features. There are a few approaches that can be used in such situations. The approach to use depends on how much the data change and the functionality needed in apps that use the data.
First, you should keep in mind that it is possible to read in and overlay data stored in non-Esri formats (like delimited text) using a methodology similar to the one used in the last lesson with the Google API. You could even store your data in Fusion Tables, though you would not be able to add the features as a layer (i.e., the Esri API has no FusionTablesLayer class). But it is possible.
That said, Esri's API is really geared around consuming services that were published through ArcGIS Server. These services allow for building more sophisticated GIS-like functionality than what is possible with a Google Maps app. Because of time constraints, this lesson focuses on consuming services that have already been published (by someone else). However, if you are interested in building a map using your own services, perhaps for your final project, that is an option you can choose to pursue. Here are the details:
Esri has partnered with Amazon Web Services to provide a "sandbox" for people to experiment with ArcGIS Server. The basic idea is that you request a sandbox, Amazon sets it up for you (a virtual server running ArcGIS Server), you log in to the server remotely and experiment, then Amazon charges you for the time the server was running. If you are interested in trying, please send me an e-mail and I will point you to a tutorial from our Cloud/Server GIS course.
As I said, this lesson only requires you to consume existing services. However, the discussion below goes over some of the considerations a service publisher must take into account when making services available to developers who might use the service in a web map. In other words, whether or not you decide to play with ArcGIS Server, these are issues you need to be aware of.
Datasets that rarely change lend themselves to being served as pre-made (or cached) tiles. The advantage to cached tiles is a faster drawing speed, particularly noticeable as the number and complexity of features increases. The disadvantage is that the tiled layer is a "dumb" picture of your data. Users will not be able to interact with the features depicted in the layer (e.g., to view attribute values in an info window).
For datasets that change more frequently, creating cached tiles is a less desirable option because keeping the service up to date requires frequent re-creation of the tiles. Tile creation involves some manual work to initialize the process (though this can be automated). This may only take a few minutes, but waiting for the software to churn out the tiles may take hours.
For this reason, frequently changing datasets are often published as dynamic services. When a dynamic service layer is requested, the server generates images of the data on the fly and streams them to the client app making the request. This on-the-fly work can take longer than simply serving up pre-made tiles, so dynamic services typically do not draw as quickly as tiled services.
However, what makes dynamic services an attractive option in spite of the performance issue is the ability to allow interaction with the features (e.g., pulling up info windows). Prior to the release of ArcGIS 10, a JavaScript API developer's only choice for consuming this type of service was to use the ArcGISDynamicMapServiceLayer class. This class allows for specifying which layers in the service are visible and also which subset of features are shown by the layer (e.g., show only the Pennsylvania counties from a national counties layer).
With the release of ArcGIS 10, the FeatureLayer class can be used to stream the actual geometries of the features to the client machine and draw them using the web browser. In order to not overwhelm the browser with too much data, the geometries streamed to the machine are filtered based on queries constructed by you, the application developer.
Downloading feature geometries to the client machine's memory opens up more possibilities because it reduces the frequency and size of data transfers needed between the server and client. Among these possibilities are the ability to select features to be used as inputs to geoprocessing tasks, the ability of the user to perform edits on the underlying data, and the ability of the application developer to re-style the features on the fly based on hovering the mouse or clicking a feature or color ramp.
Any app that involves user interaction with the map is especially suited to using a FeatureLayer because of this in-memory geometry factor.
Given our limited time, let's focus on using a FeatureLayer to display a large set of clickable features. A FeatureLayer has a mode property that is used to specify how features are retrieved from the server. Acceptable values for this property are:
In most scenarios, the choice is between the SNAPSHOT and ONDEMAND options. ONDEMAND is especially appropriate when retrieving all features would result in poor drawing performance.
As with the ArcGISTiledMapServiceLayer and ArcGISDynamicMapServiceLayer classes, the FeatureLayer class constructor has a URL parameter and an optional options parameter. The options set most commonly are mode (set to one of the values described above), outFields (set to a comma-delimited list of field names; specify only those fields needed by the app to maximize performance), and infoTemplate (set to an object of the InfoTemplate class, which we saw in the hometown example earlier in the lesson).
Another important property to set for a FeatureLayer is its Renderer. A number of renderer classes exist, with the most commonly used including SimpleRenderer (all features drawn using the same symbol), UniqueValueRenderer (features are drawn using different symbols for different categories; e.g., land use types), and ClassBreaksRenderer (features are drawn using different symbols based on ranges of values in a numerical field; e.g., population density).
Refer to this example [14] adapted from two Esri samples and pay particular attention to the following key aspects:
Now that you've learned a bit about streaming feature geometries to the client machine using FeatureLayers, let's look at how to display associated attribute data alongside the map.
Esri's samples that demonstrate the display of tabular data alongside a map involve the usage of a Dojo class called dgrid. (Samples written for earlier versions of the API used an older Dojo class called datagrid.) See Dojo's website [15] for documentation. Open this example [16] and view the source code to follow along with the discussion below. The example builds on the map of Pennsylvania counties from the previous page. Let's focus on what was added to that example.
Begin by examining the HTML at the bottom of the page. In addition to the usage of the dgrid class, this code also demonstrates how to use Dojo's BorderContainer [17] and ContentPane [18] classes to aid in laying out the page. Note that a div (with id of container) is used as a container for two other divs; one for the map (id of mapDiv) and one for the sidebar (id of sidePane). The sidePane div in turn contains a div with an id of grid. I won't go into great detail on the usage of the BorderContainer and ContentPane classes other than to ask you to note how:
In this example, the ContentPane used to display the sidebar table is positioned to the right and the ContentPane used to display the map is positioned in the center (the setting used to force an element to take up all the space not occupied by the other elements in the container).
Usage of these layout elements requires links to two stylesheets: dojo.css and dgrid.css. Note also that the JavaScript modules associated with BorderContainer, ContentPane, and dgrid must be included in the require list (though variables do not need to be defined for BorderContainer and ContentPane in the callback function's argument list).
Looking at the JavaScript code, the first few lines define several global variables that come into play later in the code. These variables store references to the Map object, an object of the Dojo StandardGrid class, an object of the Dojo Memory class, a string that holds the name of the feature service to be used, an array of field names to be used, and a string that holds a query that will be used to retrieve a subset of features from the service.
Lines 39-64 of the script define references to the modules containing the needed classes, while lines 65-85 define variables that will provide access to those classes. Don't be troubled by the fact that each of these references/variables appears on its own line unlike the examples from earlier in the lesson. Because the order of the variables needs to match the order of the modules, this formatting style may make a lot of sense in situations like this where you have a lot of modules/variables to keep in order.
The first line in the callback function -- parser.parse() -- scans through your HTML looking for specially decorated Dojo elements and converts them to dijits. In this case, it will convert the BorderContainer and ContentPane divs that we discussed moments ago.
Lines 91-97 are concerned with setting up the grid that will appear in the sidebar. First, a new custom class is defined using the Dojo declare() method that combines the Grid and Selection classes. This class is given the name StandardGrid. A new object of this custom class is then created with some properties set as the first argument to the constructor: bufferRows is set to Infinity to render all of the service's rows as opposed to using a value like 10, which would render 10 rows above and 10 rows below the ones currently visible; selectionMode is set to "single" to allow only one row to be selected at a time; sortable is set to true, allowing users to click on a table header to sort by that column. The second argument to the constructor -- which is critical -- is the ID of the DOM element you want to attach the grid to. In this case, our code has a div embedded within the sidePane div with an id of grid. The last statement in this block of code is a call to the startup() method, which completes the programmatic creation of the grid dijit.
The next block of code (Lines 99-117) involve creating a listener for selections made on the grid (i.e., if a user clicks on one of the rows). It will be easier to follow what's happening here after discussing some of the code below, so we'll come back to it later.
Lines 119-125 should look a bit more familiar to you as they are concerned with creating the Map itself.
In Lines 128-131, a listener for the Map's onLoad event is defined. This listener does two things:
Next, we see lines (133-161) that are similar to what we've seen in earlier examples concerned with setting up the info window content, creating the FeatureLayer object that will be used to display the county features, filtering out unwanted counties with a definition expression, creating a fill symbol and applying it through a renderer, and adding the layer to the map. One thing to make particular note of in this code is the setting of the FeatureLayer's id property, which comes in handy later.
Lines 164-169 create listeners for when the user mouses over (turning the cursor into a pointer) and mouses out of (changing it back to a default cursor) the counties layer.
On Line 172, we encounter the populateGrid() function that was called upon earlier. The function starts by creating a QueryTask object and associating the counties map service with it. (As shown in the documentation [19], a QueryTask can be executed in a few ways: to retrieve just the count, extent or IDs of the features meeting the query criteria, or to retrieve the features themselves. In this case, we'll use the "normal" execute method to get back the features.) A Query object is created to go along with the QueryTask. The Query is set to retrieve just PA counties, geometry data is excluded and only certain fields are retrieved.
The FeatureSet returned by the query is available in the callback function through the results variable. The ultimate goal is to get the data into a form that the grid likes, which is what is happening in Lines 178-194. The Dojo array class and its map() method are use to iterate through each item in the results FeatureSet. The map() method takes an array as its input (here results.features, which gets the features in the FeatureSet) and through the callback function "maps" (or converts) each value to something else. In this case, we create an array having keys "ObjectID", "NAME" and "POP2007". We assign values to go along with those keys using the expression feature.attributes[outFields[X]], where X is the appropriate index for the desired field. Recall that outFields was defined as a global variable and held the names of the ObjectID and the 2000 and 2007 population and population density fields. The page is set up to show all of that data in the info window, but here in the sidebar we're only going to show the ObjectID, county name and 2007 population. ObjectID is at position 0 in the outFields array, NAME is at position 1, and POP2007 is at position 3. After this iteration through all of the counties is complete, the resulting array gets stored in the variable called data.
Line 187 sets the columns in the grid by calling upon a function called generateColumns(). That function (defined on Lines 199-213) takes an array of Esri Field objects and converts it to an array of custom JavaScript objects. Each column is assigned a label property (set to the field's alias) and a field property (set to the field's name).
On Line 188, a new Dojo data store [20] is created (specifically, a Memory [21]store). Data stores are used in Dojo to bind data to dijits, in this case data from a map service to a dgrid dijit. The Memory class implements Dojo's object store API, which means it has a data property (used to set the data to be held in the store) and an idProperty property (used to specify a field in the data that uniquely identifies each object in the store). Here we set the data property equal to the data variable that was defined using array.map as described above. idProperty is set to ObjectID (though NAME would work in this instance as well). The object created on this line is stored in the variable memStore.
Unfortunately, there is a slight problem. The records returned by the Esri Query() method are not in a user-friendly order. (The Query class has an orderByFields property, which allows for ordering the results, but that property is not supported for all map services and it appears this is one of those not supported.) So, Lines 190-192 use Dojo's data store API method to query the store in memStore, sort it on the NAME field, and create a new Memory store (called newStore). Finally, the store gets associated with the grid created earlier on Line 193.
Users who click on a county on the map see an info window, but how do we get the info window to appear if the user clicks on a county in the sidebar? That behavior is added by the code we skipped over earlier on Lines 99-117. This code adds a listener for selections on the dgrid we created. (Selections can be made programmatically or by the user clicking on the grid.) The event variable in the callback function provides info on which rows were selected. Because we set the selectionMode to "single", we know that only one row can be selected. Thus, we know that we can ask for rows[0] (i.e., the first and only row). By appending id onto rows[0], we're asking for the ID of that row. This value goes back to the idProperty setting made when we created the grid's data store. We set that to ObjectID, so our rowID variable will end up holding ObjectIDs. If we had set idProperty to NAME, rowID would instead hold NAME values.
Line 101 gets a reference to the counties FeatureLayer using the Map's getLayer() method and stores it in the fl variable. This method works because we assigned the layer an id as part of its creation on Line 142.
Next, we create a Query that retrieves features based on an array of object IDs (in this case, just the one ID associated with the clicked county) and use it along with the FeatureLayer's queryFeatures() method. Inside the callback function associated with that method, the Feature at position 0 in the FeatureSet can be safely retrieved since we know there was only one county object ID supplied to the query.
With the correct county identified, the var screenpoint statement gets the centroid of the selected county polygon and converts it to screen coordinates. The map's InfoWindow is then obtained and its title and content properties set equal to the title and content of the InfoWindow that was created for the selected county. The centroid coordinates are then passed to the InfoWindow's show() method, to ensure that the InfoWindowopens over the correct location.
One thing in this block of code that you may have found confusing was the if expression on Line 106 as you're probably used to seeing expressions that evaluate to True or False. However, it is not uncommon to see developers use an expression that returns a count, as in this line. If the returned value is 0, then the expression will evaluate to False. If it is any other value, it will evaluate to True.
Don't draw the conclusion after completing this course that Google Map sidebar tables must be created through the iterative process outlined in Lesson 4 and Esri sidebar tables must be created as Dojo dgrids. There is nothing preventing you from using a dgrid on a Google Map page and a plain HTML table on an Esri map page. In fact, in Lesson 7, we'll return to the Google API and see how another popular JavaScript framework, jQuery, can be used to improve upon the plain HTML sidebar table we created earlier in the course.
That concludes this lesson on developing maps with Esri's JavaScript API. Move on to the next page to view the graded assignment you're expected to complete as part of the lesson.
Each student in the class will be e-mailed a different scenario requiring the development of a web map based on Esri's JavaScript API. Please alert the instructor if you're ready to begin work on Project 6 but have yet to receive your scenario.
This project is two weeks in length. Please refer to the course Calendar, in Canvas, for the due date.
Links
[1] http://www.personal.psu.edu/jed124/arcgis_js_api/v3/hello_world.html
[2] https://developers.arcgis.com/javascript/3/jsapi/
[3] http://www.personal.psu.edu/jed124/arcgis_js_api/v3/hometown.html
[4] http://resources.arcgis.com/en/help/arcgis-rest-api/02r3/02r3000000qq000000.htm
[5] http://www.personal.psu.edu/jed124/arcgis_js_api/v3/set_map_extent.html
[6] http://www.personal.psu.edu/jed124/arcgis_js_api/v3/set_map_extent_to_layer_extent.html
[7] http://developers.arcgis.com/javascript/samples/map_setextent/
[8] https://developers.arcgis.com/javascript/jshelp/inside_events.html
[9] http://www.personal.psu.edu/jed124/arcgis_js_api/v3/set_map_extent_remove_listeners.html
[10] http://server.arcgisonline.com/ArcGIS/rest/services/
[11] http://resources.arcgis.com/en/help/arcgis-rest-api/#/Using_spatial_references/02r3000000qq000000/
[12] http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/
[13] http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Elevation/ESRI_Elevation_World/GPServer
[14] http://www.personal.psu.edu/jed124/arcgis_js_api/v3/featurelayer_infowindows.html
[15] http://dojofoundation.org/packages/dgrid/
[16] http://www.personal.psu.edu/jed124/arcgis_js_api/v3/featurelayer_infowindows_sidebar.html
[17] http://livedocs.dojotoolkit.org/dijit/layout/BorderContainer
[18] http://livedocs.dojotoolkit.org/dijit/layout/ContentPane
[19] https://developers.arcgis.com/javascript/jsapi/querytask-amd.html
[20] https://dojotoolkit.org/reference-guide/1.10/quickstart/data/usingdatastores.html
[21] http://dojotoolkit.org/reference-guide/1.10/dojo/store/Memory.html