ArcGIS Blog

Mapping

ArcGIS Maps SDK for JavaScript

Functions aren't fields; use Arcade instead

By Kristian Ekenes

As of version 4.9 of the ArcGIS API for JavaScript (JS API), we removed support for rendering feature layers based on the result of a JavaScript function. In lieu of JavaScript functions we added support for Arcade expressions in renderers.

Background

Prior to 4.9, the JS API allowed developers to pass a JavaScript function to the field property of a renderer and any visual variable. This provided the developer with the flexibility to calculate new values client-side and render the layer based on those values. This was great for the following reasons:

  • It allowed you to calculate new values based on existing field values in your layer. For example, it made sense where service fields couldn’t be modified, or you didn’t own the layer, but wanted to calculate new data values based on values already present in the layer.
  • It allowed you to use values provided by end users via UI elements (e.g. input elements, select elements, HTML range sliders, etc.). One example of this is updating an above-and-below visualization based on the value of an HTML range slider moved by the user.
  • It allowed you to perform calculations for data not present in your layer. For example, you can query features from other layers and perform geometry operations on them within the renderer’s field function to visualize the results of any spatial operation. This workflow isn’t currently supported in Arcade, but will be soon.

Check out the following app, which visualizes a FeatureLayer representing political boundaries in mainland China using a function set on the field property of the layer’s renderer. This is an above-and-below visualization, which categorizes each feature based on whether the percentage of the population without education is above or below the value of the feature selected by the user.

While powerful, renderers that use JavaScript functions as fields cannot be persisted and used for visualizations across the ArcGIS platform. There are a couple of reasons for this:

  • Attempting to save a renderer with a JavaScript function for reuse in other web apps would introduce security vulnerabilities in the apps loading the layer. It would open the door for malicious code to be executed within the renderer function.
  • The JS API is designed for consumption in web browsers. Other clients in the ArcGIS platform, such as ArcGIS Pro and the ArcGIS Runtime SDKs cannot display renderers that depend on JavaScript to return values for a data-driven visualization because JavaScript doesn’t execute in those environments.

For these reasons, you were limited to using JavaScript functions as fields in renderers and visual variables in standalone web apps.

Arcade: A better approach

In December 2016, Esri introduced Arcade – an expression language for returning new data values client-side. Arcade can be used to calculate and return values for labels, popups, and renderers based on logic defined in an expression.

Several people have already written on various ways Arcade is and has been used for visualization in the JS API. Check out the following blogs to learn more about this.

Arcade provides many benefits that the JavaScript functions could not guarantee, including the following:

  • Security. It does not have the same security vulnerabilities as JavaScript because it can only be executed in intended profiles specifically designed for parsing and running Arcade syntax.
  • Persistence throughout the ArcGIS platform. This means you can author and save an Arcade expression for a layer’s renderer within a web app or ArcGIS Online, and the same syntax will be understood and executed properly in other web apps, mobile apps created with the Runtime SDKs, and ArcGIS Pro.

Because Arcade expressions allow you to create the same visualizations as those created using JavaScript functions, we are confident in removing support for JavaScript functions as fields in renderers.

Migrating JavaScript functions to Arcade expressions

If you’ve already created renderers with JavaScript functions, then you were likely familiar with the limitations.

So why take away this support? What about the benefits mentioned above? What if I want to create a visualization based on user input? What about access to outside features, or geometry operations?

The short answer to these questions is that Arcade allows you to create these visualizations.

Let’s check out the example above to learn how to migrate a renderer from using a JavaScript function as a field to using an Arcade expression. This example uses a JavaScript function in the field property of a UniqueValueRenderer.

valueFunction is the name of a function that takes an esri/Graphic instance as a parameter. This function executes for each feature at the time of rendering. For that reason, it is important to keep the code in this function light. Adding heavier code will come with a performance cost to the application.

Each time the user clicks a feature, the app updates the value of the value variable to the value of the clicked feature, causing the renderer to change.

I used the 4.9 version of the JS API to create the exact same app. But this time I pass an Arcade expression to the valueExpression property of the renderer.

The createArcade function returns an Arcade expression that determines whether the feature’s value is similar, above, or below the input value. Note how I use template literals to access the value of the selected feature and insert it to the Arcade expression. This same technique can be used to get user input from other DOM elements.

Since the clicked, or selected value, is a constant in the Arcade expression, the expression must be re-created with the new value and reset on the renderer. Once you update the renderer on the layer, the layer’s layer view will automatically refresh and update the visualization appropriately.

Now the final app looks like the following.

Keep in mind that while this version of the app doesn’t expose any functional differences from the previous version, it does redraw features more slowly than the 4.8 version of the app. We will improve performance in this regard at a future release.

Coming soon

In past conferences, such as the 2018 Esri User Conference, I’ve demonstrated other use cases that required using a JavaScript function as a field in a renderer. One such case is the app below, which visualizes restricted air space in the Gulf of Mexico based on their risk for encroachment by proposed oil rig locations. As you change the height of the proposed projects, you will see the renderer update accordingly. Read this blog post to learn more about how a similar app was created.

The JavaScript function referenced in this layer’s renderer uses the height obtained from a CSVLayer or as determined by the user along with the geometry engine to see if the features intersect buffers of the project areas.

We will add support for all Arcade geometry functions soon, making it possible to use Arcade for this use case with the 4.x JS API. Note that version 3.26 of the JS API already supports Arcade’s geometry functions, so you can use that API if your visualizations require them now.

Share this article