ArcGIS JavaScript Maps SDK Blog - Page 6

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Latest Activity

(71 Posts)
JuliePowell
Esri Contributor

Support for CORS will be enhanced in 4.9 and will potentially require changes to your code. Read further for the full scoop on this.

The ArcGIS API for JavaScript has long supported CORS. CORS allows web applications to bypass a browser's same origin policy and access resources or services on other servers/domains.

When the web server supports CORS, a proxy is not required to do cross-domain requests. Supporting CORS as opposed to using a proxy is helpful as it can:

  • Provide a performance boost since the web application no longer has to send a CORS detection request back to its server, wait for the server to access the desired resource, and interpret the result before sending it back to the client.
  • Simplify development as it is no longer necessary to maintain a proxy on your server. Avoiding the use of a proxy also ensures that web tier authentication (i.e. Active Directory) can be used when accessing secured resources.

CORS and WebGL

There are multiple scenarios when either CORS or a proxy is needed due to cross-domain requests for a resource. CORS is more important now than ever before when using the ArcGIS API for JavaScript due to the API’s use of WebGL. Thanks to WebGL, the API can render hundreds of thousands of features with fast performance using the GPU. However, WebGL has different requirements than the traditional method of rendering using SVG. When loading images (such as an image used by PictureMarkerSymbol), SVG simply adds an image in the DOM, while drawing on the WebGL canvas requires access to the raw image data. Since the raw image data is required for rendering, the image must meet one of the following requirements: (1) be on the same domain as the app, (2) be hosted on a server that supports CORS, or (3) a proxy must be used.

With WebGL becoming the primary way in which the API renders graphics and its requirement to access raw image data, we’ve optimized the way in which we approach CORS.

Changes to how the API will handle CORS, starting at 4.9

The API will assume web servers support CORS. Here are the details behind how the API handled CORS until 4.8, and how it will change starting at 4.9.

Previously, the API would handle CORS in the following way:

  • Developers could predefine a list of corsEnabledServers to explicitly indicate whether CORS was setup for a given server.
  • If the service was published with ArcGIS Server, the API would automatically send a request to see if CORS was supported (note: this resulted in an extra request to the server before a resource could be requested).
  • If the server didn’t support CORS, a proxy rule could be configured (note: this resulted in the extra hop and performance hit described above).
  • JSONP was used as a workaround when the server wasn't known to support CORS and the request was a GET request for JSON. An example would be using a FeatureLayer from an ArcGIS Server version 10.0 or earlier.

If none of the above criteria could be met (not listed in corsEnabledServers, not an ArcGIS Server service, and no proxy setup), the API didn’t make the request to the resource and generated a console error.

Starting at 4.9, the API will handle CORS in the following way:

If you have configured a proxy rule in your code, the API will continue to use your proxy. Otherwise, requests will always be made with the assumption that CORS is supported.

Assuming CORS support is particularly useful when you don’t know what web servers you might be accessing in advance, for example in some scenarios when loading a web map with a mash-up of services. The first request will be sent assuming CORS is supported, and if the request fails due to the lack of support the API will automatically fallback to the configured proxy (via the proxyUrl property in esri/config.request).

This change also results in a performance gain when working with ArcGIS Server because it is no longer necessary to send a CORS detection request before accessing a resource (in the case when the server isn’t listed in corsEnabledServers).

What do you need to do?

  • If it doesn’t already, configure your web server to support CORS (if possible).
  • Another change at 4.9 is support for JSONP is being removed, which will simplify webpack builds. If your server doesn’t support CORS, setup your proxy so that the app would fallback to using the proxy when the CORS request failed. If you have a specific requirement for using JSONP, you can use the dojo request script module as a workaround.
  • If you previously used any of these APIs, they should be removed as they are no longer needed. Your CORS enabled server should “just work” since the API will make the request assuming CORS support.

esri/config.request

corsDetection

corsDetectionTimeout

corsEnabledServers*

forceProxy

useCors

 

esri/request

allowImageDataAccess option

* If your app is using corsEnabledServers with objects that have withCredentials: true, you should push the domain to esri/config.request.trustedServers instead.

This guide topic will be updated with the latest information about working with CORS after the 4.9 release.

more
11 1 22.1K
JuliePowell
Esri Contributor

We recently published a series of blogs (with one more to go) aimed at helping JavaScript developers wanting to migrate from Google to ArcGIS come up to speed on the JS API:

Have you gone through the experience of migrating from Google or are you considering starting the process? This GeoNet post serves as a way in which you can provide feedback on the above blogs, as well as share your experience coming up to speed on ArcGIS. How can we help?

more
4 0 1,079
BjornSvensson
Esri Regular Contributor

Today we released versions 4.8 and 3.25 of the ArcGIS API for JavaScript. Read more about it in:

and more details in

more
3 0 1,924
BjornSvensson
Esri Regular Contributor

Today we released versions 4.7 and 3.24 of the ArcGIS API for JavaScript. Read more about it in:

and more details in

more
9 8 3,719
JuliePowell
Esri Contributor

New ArcGIS API for JavaScript releases are just around the corner! Here is a preview of some of the new capabilities coming in early July. 

(Note: These are some of the highlights; a full list of new capabilities and enhancements will be provided in the release notes.)

ArcGIS API 4.4 for JavaScript

New styles for points in city landscapes:

Styling the point data in city scenes can now be done more effectively. Point graphics can be configured to display above buildings with the new relative-to-scene elevation mode. Callout lines can be used to better understand point locations (a callout is essentially extended from the top of the scene).

 

Highlight in 3D:

The ability to highlight features in a 3D scene, with options to configure the color and opacity of the highlight effect.

 

Styling building data:

We added the option to remove building textures to better emphasize thematic mapping of buildings, and also the option to make textures grayscale (one example of when you might want to do this is if you want to draw attention away from the buildings, and highlight a particular set of interest).

 

Smart Mapping

You can now automatically generate renderers for SceneLayers using SmartMapping. Generating type renderers with smart mapping is new to both 2D and 3D views. Note: When we reference smart mapping/generating renderers, we mean that the API creates smart defaults for your map/scene styles on the fly. This capability is typically used in data exploration type apps (as opposed to defining the styling explicitly in code).

 

PointCloudLayer enhancements

Added the ability to add natural lighting conditions to a point cloud layer in order to better distinguish objects.

 

Better web map support

Added support for Map Notes, WMS, and WMTS layers.

 

OGC support

Added support for WMS and WMTS layers.

 

VectorTileLayer printing

This release of the JavaScript API includes a support for vector tile layer printing through client-side image.

 

Arcade support in popups

Arcade expressions can now be applied in the popup’s content. This is useful for situations when you want to display data that isn't present as an attribute value in your FeatureLayer instance. Web maps that have been created in Portal or Online that contain popups with Arcade expressions will be honored in apps built with the JS API, and developers can also write Arcade expressions directly in their code.

 

Widget standardization

In this release, the following widgets have been updated to the widget framework, initially introduced at 4.2: Legend, Popup and Search widgets.

Custom Layers

The SDK will include documentation and samples for creating your own custom layers. 

 

ArcGIS API 3.21 for JavaScript 

Arcade support in popups

As described above.

 

VectorTileLayer printing

As described above.

 

(...plus minor enhancements and bug fixes)

 

more
13 17 14.7K
BjornSvensson
Esri Regular Contributor

When the 4.0 version of the ArcGIS API for JavaScript was released, we also released a Bower compatible minified version of the API for users interested in doing their own custom local builds. This was a big step in our direction to help users integrate the ArcGIS API for JavaScript into their own workflows.

We have since had numerous requests to publish the ArcGIS API for JavaScript to NPM. One of the reasons we have not done this is that Bower provides us with some advantages when it comes to creating custom local builds. Publishing the API to NPM will not automatically make it compatible with build tools like Webpack. It actually adds a couple of steps to the Dojo build needed to compile the ArcGIS API for JavaScript.

With the upcoming release of 4.4 we will publish the ArcGIS API for JavaScript to NPM. We will also be providing some updated resources about how to do a Dojo build with the API.

Start using NPM today

However, you could start using NPM today to install the ArcGIS API for JavaScript locally.

Let's start with the sample application provided in the resources repo on github.

Take a look at the bower.json file provided with the ArcGIS API for JavaScript repo.

...
  "dependencies": {
    "dojo": "Esri/dojo#v1.12.1/esri-3.20.0",
    "dojox": "Esri/dojox#v1.12.1/esri-3.20.0",
    "dijit": "Esri/dijit#v1.12.1/esri-3.20.0",
    "util": "Esri/dojo-util#v1.12.1/esri-3.20.0",
    "dgrid": "Esri/dgrid#v1.1.0/esri-3.20.0",
    "dstore": "1.1.1",     "moment": "2.17.1"
  },
...

We can borrow most of this for our package.json of our custom application.

...
  "dependencies": {
    "dgrid": "Esri/dgrid#v1.1.0/esri-3.20.0",
    "dijit": "Esri/dijit#v1.12.1/esri-3.20.0",
    "dojo": "Esri/dojo#v1.12.1/esri-3.20.0",
    "dojo-dstore": "^1.1.1",
    "dojo-util": "^1.12.2",
    "dojox": "Esri/dojox#v1.12.1/esri-3.20.0",
    "arcgis-js-api": "Esri/arcgis-js-api#4.3.1",
    "moment": "2.17.1"
  },
...

You can see this looks very similar. Main difference is that util is now dojo-util and dstore is now dojo-dstore, because these are the names of the published packages on NPM. You may also notice that we can bring in the arcgis-js-api repo using Esri/arcgis-js-api#4.3.1. This tells NPM too look on github at the Esri org and install the arcgis-js-api repo using the 4.3.1 release.

At this point you can delete the bower.json and .bowerrc files from the project since they are not going to be used.

One disadvantage of using NPM instead of Bower is that NPM does not allow you to change the name of the folder the package is installed. Meaning that the JavaScript API will installed to node_modules/arcgis-js-api instead of node_modules/esri which would be ideal as far as how we typically use the Dojo build system.

Hint: If you use Yarn instead of NPM, it can install to custom named directories.

Once you NPM install these packages you will have a folder structure that should look something like this.

node_modules/
  arcgis-js-api/
  dgrid/
  dijit/
  dojo/
  dojo-dstore/
  dojo-util/
  dojox/
src/
  app/
    main.js

Now you need to tell Dojo where to locate the packages. You can do this by supplying a global dojoConfig object.

<!-- index.html -->
    <script>
      // point to node_modules folder
      window.dojoConfig = {
        baseUrl: '../node_modules/',
        packages: [
          'dijit',
          'dojo',
          'dojox',
          'dgrid',
          'moment',
          {
            name: 'app',
            location: '../src/app'
          },
          // alias for dstore package
          {
            name: 'dstore',
            location: 'dojo-dstore'
          },
          // alias for esri package
          {
            name: 'esri',
            location: 'arcgis-js-api'
          }
        ]
      };
    </script>
    <script src="../node_modules/dojo/dojo.js"></script>
    <script>require(["app/main"]);</script>

There is one more thing you will need to do your own code in order for this to work. The ArcGIS API for JavaScript uses Web Workers for Vector Tiles. You will need to let the workers know where the esri package is located in order for them to function. You can do this in the following manner using esri/config and dojo/has.

//app/main.js
if (!has("dojo-built")) {
  esriConfig.workers.loaderConfig = {
    paths: {
      "esri": "../arcgis-js-api"
    }
  };
}

The reason we use dojo/has is that once the application is built, the Dojo build system will install the esri package into an esri folder and not arcgis-js-api. So we only need this configuration during the development process.

Now you can develop your application using the JavaScript API installed in node_modules.

When you do your Dojo build, you will need to do something similar. However, the Dojo build is expecting the build tools to be located in a folder called util, but they are in fact installed in a folder called dojo-util. This requires you to create a dojoConfig for the build system in the root of your project.

// dojoconfig.js
dojoConfig = {
  baseUrl: './node_modules/',
  packages: [
    {
      name: 'dojo',
      location: 'dojo'
    },
    {
      name: 'build',
      location: 'dojo-util/build'
    }
  ]
};
require('./node_modules/dojo/dojo.js');

Then to run your Dojo build from the command line you can use node dojoconfig.js load=build --profile build.profile.js --releaseDir ../dist.

This will now tell Dojo where to find the build tools needed.

You will also need to update the build.profile.js to reflect the new locations of the packages.

// build.profile.js
  packages: [
    // "app" is a sample path for your application
    // set this accordingly
    "app",
     {
       name: 'dijit',
       location: '../node_modules/dijit',
       trees: [
           // don"t bother with .hidden, tests, min, src, and templates
          [".", ".", /(\/\.)|(~$)|(test|node_modules)/]
       ]
     },
     {
       name: 'dojo',
       location: '../node_modules/dojo',
       trees: [
           // don"t bother with .hidden, tests, min, src, and templates
          [".", ".", /(\/\.)|(~$)|(test|node_modules)/]
       ]
     },
     {
       name: 'dojox',
       location: '../node_modules/dojox'
     },
     {
       name: 'dstore',
       location: '../node_modules/dojo-dstore',
       trees: [
           // don"t bother with .hidden, tests, min, src, and templates
          [".", ".", /(\/\.)|(~$)|(test|txt|src|min|templates|node_modules)/]
       ]
     },
     {
       name: 'dgrid',
       location: '../node_modules/dgrid',
       trees: [
           // don"t bother with .hidden, tests, min, src, and templates
          [".", ".", /(\/\.)|(~$)|(test|node_modules)/]
       ]
     },
     {
       name: 'esri',
       location: '../node_modules/arcgis-js-api'
    },
     {
       name: "moment",
       location: "../node_modules/moment",
       main: "moment",
       trees: [
           // don"t bother with .hidden, tests, min, src, and templates
          [".", ".", /(\/\.)|(~$)|(test|txt|src|min|templates)/]       ],
       resourceTags: {
         amd: function(filename, mid){
           return /\.js$/.test(filename);
         }
       }
     }
   ],

Notice the addition of the trees array for each package. This lets the Dojo compiler know which files and folders to ignore so it doesn't try to include tests and documentation in the build process.

Summary

So if you are interested in using NPM to install the ArcGIS API for JavaScript locally today, these are the steps you would need to take. All this is still valid once we publish the JavaScript API to NPM, except you will only need to install the arcgis-js-api package by name and not need to install the other dependencies yourself. Bower does provide us with a distinct advantage when it comes naming the folders and locations that packages are installed, but NPM allows to keep all dependency code in a single location.

Please note, that if you want to use RequireJS and the RequireJS Optimizer to build the ArcGIS API for JavaScript, you should continue to use Bower as some of the required build tools cannot be installed via NPM.

Even once the API is published to NPM, we will continue to provide the Bower release for as long as it's sustainable since it's all the same codebase.

Contributed by Rene Rubalcava !

more
6 16 11.3K
JamesMilner1
Deactivated User

Esri Polymer

This is a quick post to talk a little bit about Esri Polymer! It's a project I've been working on for a little while (very intermittently) but never put on GeoNet, so thought I would make this post!

Before I begin to start talking about the project I would like to point out what Polymer is. Polymer is a library from Google for building web components. It allows developers to create custom compartmentalised HTML elements. In a way you can think of a web component similar to a 'widget'. Some contrived examples might be a an image carousel, a YouTube video, or a PayPal checkout, or rather a <image-carousel> , a <youtube-video> and a <paypal-checkout>

Polymer provides a light wrapper around some native/polyfilled web standards that make up web components, namely:

  • Custom Elements - for defining a unique custom element
  • HTML Imports - for importing HTML
  • Shadow Dom - for encapsulating sub trees of DOM
  • HTML Template - for reusable inert pieces of DOM

The necessary polyfills come curtsy of webcomponents.js​ which allow web components to run on all modern evergreen browsers.

Great stuff James, but why would I ever want to use web components?

The major reason is that it allows us to write markup and code an abstracted level. You can import a web component into your page and mark it up in your HTML page just like you would a div or a span, or any other element without having to worry about the underlying implementation.

This works great with things like basemaps, web maps, feature layers, and markers. Each one of those becomes its own element, and we can have feature layers as child elements of a map add them to it.

For example:

<esri-map basemap="dark-gray" centerLng="-0.122" centerLat="51.514" zoom="7">

  <esri-featurelayer

          featurelayer="http://services.arcgis.com/Qo2anKIAMzIEkIJB/arcgis/rest/services/TubeMap/FeatureServer/2">

  </esri-featurelayer>

  <esri-marker lng="-0.5" lat="51.3">

  <esri-marker-title>Hello World</esri-marker-title>

  <esri-marker-content>Some Content</esri-marker-content>

  </esri-marker>

  </esri-map>

will produce the following once rendered:

Caveats

  • Web components are only supported with polyfills on modern browsers
  • Polymer is a relatively early stage project
  • Some argue that you shouldn't use web components in production

If you can live with these things than they are great fun to experiment with!

GitHub

You can find the project here: JamesMilnerUK/esri-polymer · GitHub

The Latest Version

I've just updated the project, hopefully with some certain niceties:

  • Polymer 1.1.5
  • ArcGIS JS 3.14
  • Cleaner code
  • Less hacky hacks for element lifecycles and interacting with parent and child elements

more
0 0 1,894
JamesMilner1
Deactivated User

It's been a while since I've posted anything to GeoNet, but I thought I'd share some samples that I was working on this weekend at Hackference to show case how to do some basic functions In ArcGIS. The repo has examples of how to do the first steps with the API, with code samples such as:

  • Creating a map
  • Creating a map from a Web Map ID
  • Adding markers (AKA Graphics, Points) to the map
  • Adding a Feature Layer to a map
  • Adding a CSV file to a map
  • Adding a KML file to a map
  • Creating a basic heatmap

These samples are meant to compliment some of the samples available from the JavaScript samples page​. There focus is on simplicity, commenting and on the bare minimum amount of code to do a requirement ('add a point to a map'). This is mostly useful for things such as teaching, hackathons and coding sessions with people completely new to the ArcGIS JavaScript API.

You can see the repo on GitHub here:

               JamesMilnerUK/ArcGISHelloWorld · GitHub   

               The Zip File

Got some simple,  commented, single function examples to add? Why not make a pull request!

more
0 0 1,354
AndyGup
Esri Regular Contributor

If you haven't had a chance to read up on what's coming in the next major release of the ArcGIS API for JavaScript v4, then it's time to get your game on and brush up on some of the exciting changes that can be explored today in v4 beta1. For those of you who haven't heard of this API or ArcGIS, we provide a large selection of APIs, SDKs, services, content and applications for building commercial mapping/geo-spatial applications. You'll want to check out the following:

  • The 4.0 API is currently in beta, so give v4beta1 a spin. This version of the API is a rewrite and it is fundamentally based on using JavaScript Promises. With these promise-based coding patterns you will be adopting a new and powerful architectural change in how you do JS app development.
  • Get a quick overview of Working with Promises (and the ArcGIS API for JavaScript).
  • Read about promises as guarantees in ArcGIS JavaScript Promises.
  • And, here's a great intro article from HTML5 Rocks simply called JavaScript Promises.

I promise to...?

Promises bring a whole new level of application life-cycle control to building web applications for use on mobile devices. In particular, there are two aspects of promises that will change how you do mobile development, forever: the ability to look back in time to see if some process has completed, and the ability to easily manage multiple, asynchronous requests.

In part 1 of this series we'll chat about how promises will allow you to verify after-the-fact and in a stateful way if an asynchronous action has completed successfully or failed. This is such an important concept that I'll illustrate it in a variety of ways to help push home the basics. All the examples are written for the ArcGIS API for JavaScript v4.x.

Absolutely yes these ideas work just fine on desktop apps. But desktop apps, in general, are significantly less susceptible to life-cycle issues as compared to mobile apps. Desktop web apps are tapped into dedicated internet connections with fairly reliable up times and connection speeds. In comparison, mobile web apps oftentimes easily suffer from small connectivity interruptions, hiccups and slowdowns. This can play havoc on your app while it's in the process of downloading and parsing HTML, CSS, JS and images as well as going through the initialization process. Promises can go a long way to smoothing out these potential speed bumps and towards helping you build consistent and stable applications without bending, breaking or stretching the basic rules of JavaScript best practices and sensibilities.

Promises, promises: the .then() pattern

All this magic works because promises have a built-in .then() mechanism that is your ticket to getting access to an asynchronous processes' state at any time whether it is still pending, if its completed or even if it failed. Simple in concept, powerful in execution. So, let's dig in.

We mention this several times in the ArcGIS API for JavaScript v4 documentation, the basic structure and concept of a promise looks like this:

someAsyncFunction.then(callback, errback);

A related side note, until the ECMAScript 2015 Promise standard is fully adopted and integrated by the various browser vendors, some third party libraries may provide slightly different syntax than what is shown in this post, but the concepts should all generally lead to the same result.

Below is a slightly exaggerated code snippet of how the concept works, and for a fully working version check out this jsbin. In this sample, a timer forces the code to wait for 5 seconds before calling view.then(). If you run the jsbin with the developer console window open you'll see the map has already loaded and should be visible by the time "View is ready? true" gets written to the console. The point here is that the SceneView's promise did, in fact, let us query its state well after the map and view were initialized.

     map = new Map({
          basemap: "streets"
     });

     view = new SceneView({
          container: "viewDiv",
          map: map,
          scale: 240000000
     });
            
      // Let's wait for 5 seconds
      setTimeout(function() {
           view.then(function(viewEvt){
                console.log("View is ready? " + viewEvt.ready);
           });
      }, 5000);        

Huh, how does this benefit me? I still don't get it.

Hang in there, we have a few more examples to look at. The above example demonstrates that the promises pattern truly lets you de-couple the timing on when you execute various aspects of your code. It means you can access the state of an asynchronous process at any time and anywhere in your application, even after the process has long been completed. It gives you another excellent tool in your coding toolkit for going several steps beyond what's possible with using only event listeners and callbacks.

The most important benefit of this pattern for mobile development, or really for any JavaScript development, is you can delay asking for a promise if you need to wait for other asynchronous or synchronous processes to complete first. You can't delay an event listener and it's bad, bad practice to place timers in callbacks. Promises give you a scalpel for exerting significantly greater control over application logic flow than was ever possible before with simply using event listeners and stand-alone callbacks by themselves.

Okay, so how's this different than events and event listeners?

The promise-based .then() pattern offers a significant advantage over the tried-and-true, events-based coding pattern. JavaScript event messages are similar to bullets; once they are fired they are gone forever and you can't bring them back. Once an event has fired you can't get it back, and it only hangs around for a very short period of time as it bubbles its way up through various layers of JavaScript and then it's gone. Poof.

What this means is if you initialize an event listener in your app after an event has already occurred then the event listener will never fire. Period. It will simply wait faithfully for eternity and pretty much do nothing.

Here's a snippet to demonstrate the concept of an event listener created after-the-fact and will never fire. You can also check it out live in a jsbin version.


            map = new Map({
                basemap: "streets"
            });

            view = new SceneView({
                container: "viewDiv",
                map: map,
                scale: 240000000
            });            


            view.then(function(viewEvt){

                console.log("View is ready? " + viewEvt.ready);

                //Event listener is initialized after the event has occurred!
                map.on("load", function(){
                    // This will never fire!
                    console.log("Map loaded via event listener!");
                });

                console.log("The map already loaded? " + map.loaded);

            });           

Yes, this snippet is an oversimplification to help clarify how event listeners can easily cause life-cycle issues, and I'm definitely not implying that all event listeners are bad. The point is that it's very easy in large JavaScript applications to initialize an event listener too late in the life-cycle for it to ever fire properly. What's happens next is you troubleshoot and wonder for hours why your code isn't working properly, or why it may only work intermittently.

In mobile web applications, this simple concept is perhaps one of the most common reasons for intermittent failures!

What happens if you swap an event listener for a promise?

This next sample demonstrates swapping out the failed event listener pattern from the previous example with a promise-based pattern. Here's the jsbin for this sample. As you migrate existing applications, you'll be going through similar steps.

There is also an important twist in this sample that steps away from simply checking if the map.loaded boolean is true or false and then continuing with code execution. With the promises-based pattern we can inspect the promises' callback object and verify, among other things, if the process completed successful or if it failed and why.

We always have access to the promise associated with map, and we can access it at any time and anywhere in our application.


            map = new Map({
                basemap: "streets"
            });

            view = new SceneView({
                container: "viewDiv",
                map: map,
                scale: 240000000
            });

            view.then(function(viewEvt){
                console.log("View is ready? " + viewEvt.ready);

                   map.then(function(mapEvt) {
                        console.log("The map already loaded? " + mapEvt.loaded);
                    }, function(mapErr){
                        console.log("Was there any map load errors? " + mapErr);
                    });

                console.log("The map already loaded? " + map.loaded);
            });           

So, let's take this one step further and ask for the map.then() promise after a 5 second timer run. This is similar to what we did with the event listener above, and the purpose is to simulate asking for the promise at some point signfiicantly later in the application life-cycle than the process occurred. The big difference is this pattern will, in fact, be successful because the promise maintains state! Try modifying the above sample in jsbin and try it out yourself.


            map = new Map({
                basemap: "streets"
            });

            view = new SceneView({
                container: "viewDiv",
                map: map,
                scale: 240000000
            });

            view.then(function(viewEvt){
                console.log("View is ready? " + viewEvt.ready);

                setTimeout(function() {
                    map.then(function(mapEvt) {
                        console.log("The map already loaded? " + mapEvt.loaded);
                    }, function(mapErr){
                        console.log("Was there any map load errors? " + mapErr);
                    });
                }, 5000);

                console.log("The map already loaded? " + map.loaded);
            });           

Closing thoughts

There is a learning curve associated with promises, and they aren't perfect. However, hopefully this post has helped you understand just a little bit more about the value that promises can provide. As you consider the possibilities, you might start to rethink how you architect applications and that is a good start to continuously improve what we create!

Promises, callbacks and event listeners all still have important roles play depending on the unique requirements for the applications we build on a daily basis. In fact, many people overlook or ignore the fact that a promise does indeed include its very own callbacks to indicate if the process completed successfully or if it failed.

As you start to migrate existing applications to the promises pattern you may find yourself mixing-and-matching promises, callbacks and event listeners as you go through the process of reinventing your architecture. This is all part of the normal progression as new architectures gradually take over the old. And, as you build new applications from scratch you'll get to try your hand at a fresh approach.

Try these samples out, check out the ArcGIS API for JavaScript v4 samples and hopefully have fun learning the latest and greatest that is available in JavaScript!

[Minor edit - Aug 10, 2015 to read as 'any' async request!]

more
6 4 4,453
JamesMilner1
Deactivated User

Recently I came across an article that had used the GitHub API to scrape information regarding the number of users in major cities in the US. The article gave me the idea to take this a little further and see if we could map out the number of users in each city, or perhaps more importantly the percentage of people in that city with a GitHub accounts. Before we begin let met point out the obvious flaws with the methodology of this application:

  • Populations are estimations (plus the UK census is now 4 years old)
  • Populations for cities can be difficult to define (city, urban, metro area)
  • GitHub accounts can be owned by companies as well as people
  • Not everyone gives their location on their GitHub accounts, or people may lie/not update

Having said this, it's still interesting to explore the available data and try to see or explain any patterns. Plus it's fun!

Data Scraping

Firstly to get the data into a format that could be mapped, it was necessary to instantiate a list of cities that I was interested in, and assign these their populations (I used Wikipedia).

Then using Python and the GitHub API I scraped the number accounts that matched the town name. Here it was necessary to try multiple different matches to get an accurate data. For example, with London it was necessary to try "London, England", "London, Great Britain", "London, United Kingdom" and "London, UK" as these are all valid locations representing the same place. You will need a GitHub account and a token to avoid rate limiting.

The Results

    

CityGitHub AccountsCity PopulationRate
Cambridge, England13131285151.022
Brighton, England5881630000.361
Oxford, England5511713800.322
Bath, England231888590.260
Reading, England2911608250.181
Durham, England68480690.141
Bristol, England8376170000.136
York, England2602044390.127
Norwich, England1651404520.117
Edinburgh, Scotland8017820000.102
London, England929197874260.095
Glasgow, Scotland5585899000.095
Dundee, Scotland1331539900.086
Exeter, England981218000.080
Belfast, Northern-Ireland2162767050.078
Bangor, Wales11163580.067
Aberdeen, Scotland1251891200.066
Cardiff, Wales2834472870.063
Bournemouth, England1161834910.063
Sheffield, England3626407200.056
Nottingham, England3897299770.053
Liverpool, England2364664150.051
Manchester, England129125533790.051
Plymouth, England1222566000.048
Swansea, Wales1012390230.042
Newcastle, England3518799960.040
Southampton, England3128555690.036
Inverness, Scotland21579600.036
Leicester, England1435090000.028
Leeds, England49617779340.028
Gloucester, England291256490.023
Warwick, England291393960.021
Birmingham, England50324409860.021
Newport, Wales261457000.018
Derry, Northern-Ireland6836520.007
Aylesbury, England131845600.007
Lisburn, Northern-Ireland4714030.006

We can see highest on the list is Cambridge with over 1 % of the population having a GitHub account. Lowest on the list was Lisburn with 0.006 closely followed by Aylesbury (where I live ) and Derry with 0.007%. To put this into perspective the original Hirily analysis found 3% of San Francisco's population had a GitHub account!

Making the Map

The script outputs a CSV which was then uploaded into ArcGIS Online content pane using a developer account. When uploading the CSV we can set the city column to be geocoded. This allows us to take the address of the city and turn it into a latitude and longitude, in turn allowing us to map the data.

githubcsv.png

The process asks if you want to review (probably worth while as some points can end up astray). Once this was done, I gained a Feature Service of the data (a REST end point we can get our data from). From here I took this into a Esri Leaflet map (one of Esri's GitHub projects!). The main bulk of the mapping is outlined in the JavaScript code below:

    var map = L.map('map').setView([ 54.514, -2.122], 6);

    L.esri.basemapLayer("Gray").addTo(map);
    L.esri.basemapLayer("GrayLabels").addTo(map);


    var ukGitHub =
    "http://services1.arcgis.com/Q6SkXeZHDxVxhXA4/arcgis/rest/services/GitHub_Data/FeatureServer/0";
    var gh = L.esri.featureLayer(ukGitHub, {
        pointToLayer: function (geojson, latlng) {
            console.log(geojson);
            var rate = geojson.properties.Rate;
            var size;


            if (rate >= 0.361 && rate < 1.2 ) {
                size = [65, 63];
            }
            else if (rate >= 0.181 && rate < 0.361 ) {
                size = [55, 53];
            }
            else if  (rate >= 0.095 && rate < 0.181 ) {
                size = [45, 43];
            }
            else if  (rate >= 0.046 && rate < 0.095 ) {
                size = [35, 33];
            }
            else if  (rate >= 0 && rate < 0.046 )  {
                size = [25, 23];
            }


            return L.marker(latlng, {
                icon: L.icon({
                    iconUrl: 'imgs/github4.png',
                    iconSize: size,
                    iconAnchor: [size[0] / 2, size[1] / 2],
                    popupAnchor: [0, -11]
                })
            });
        }
    }).addTo(map);

Screenshot and Live Demo

A screenshot of the map can be seen below, a live demo can be seen here.

githubmap.png

Where's the code?

You can find the code on my GitHub account: JamesMilnerUK/github-mapping · GitHub 

set the city column to be geocoded. This allows us to take the address of the city and turn it into a latitude and longitude, in turn allowing us to map the data.

more
0 3 5,780
240 Subscribers