{"id":257122,"date":"2018-08-06T08:30:15","date_gmt":"2018-08-06T15:30:15","guid":{"rendered":"http:\/\/www.esri.com\/arcgis-blog\/?post_type=blog&#038;p=257122"},"modified":"2018-08-06T08:59:43","modified_gmt":"2018-08-06T15:59:43","slug":"turbo-charge-your-web-apps-with-client-side-queries","status":"publish","type":"blog","link":"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries","title":{"rendered":"Turbo charge your web apps with client-side queries"},"author":6561,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","format":"standard","meta":{"_acf_changed":false,"_searchwp_excluded":""},"categories":[22941],"tags":[30821,99752,30111,27491],"industry":[],"product":[36831,36601],"class_list":["post-257122","blog","type-blog","status-publish","format-standard","hentry","category-mapping","tag-charts","tag-client-side-query","tag-data-visualization","tag-jsapi4","product-js-api-arcgis","product-developers"],"acf":{"short_description":"Enhance the interactivity of data exploration web apps by allowing your users to query features already available on the client.","flexible_content":[{"acf_fc_layout":"content","content":"<p>The <a href=\"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/announcements\/jsapi-4-8\/\">4.8 release<\/a> of the <a href=\"https:\/\/developers.arcgis.com\/javascript\/\">ArcGIS API for JavaScript<\/a> (JS API) completed support for <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-views-layers-LayerView.html\">layer view<\/a> queries in 2D web apps. This means the query capabilities for features available on the client is almost on par with query operations made against a feature server. Now you can execute fast and complex spatial, attribute, and statistical queries for <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-views-layers-FeatureLayerView.html\">FeatureLayerView<\/a> and <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-layers-CSVLayer.html\">CSVLayer<\/a>. Rapid browser-based computation makes data exploration fun, easy, and useful. As demonstrated below, finding data trends is as easy as moving your mouse.<\/p>\n<p>For example, check out the app below, <a href=\"https:\/\/www.washingtonpost.com\/graphics\/2018\/investigations\/unsolved-homicide-database\/\">which explores homicide data<\/a> from 2007-2017 for 50 cities in the U.S. With just the move of a mouse, you can view various statistics related to homicides within one mile of the cursor location. All the queries are fast because they run locally on the client.<\/p>\n"},{"acf_fc_layout":"image","image":{"ID":261512,"id":261512,"title":"client-side-homicides","filename":"client-side-homicides.gif","filesize":2072155,"url":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/client-side-homicides.gif","link":"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries\/client-side-homicides","alt":"","author":"6561","description":"","caption":"Queries to the LayerView execute client-side, allowing you to create interactive data exploration apps.","name":"client-side-homicides","status":"inherit","uploaded_to":257122,"date":"2018-06-30 00:02:52","modified":"2018-06-30 00:04:10","menu_order":0,"mime_type":"image\/gif","type":"image","subtype":"gif","icon":"https:\/\/www.esri.com\/arcgis-blog\/wp-includes\/images\/media\/default.png","width":640,"height":334,"sizes":{"thumbnail":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/client-side-homicides.gif","thumbnail-width":213,"thumbnail-height":111,"medium":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/client-side-homicides.gif","medium-width":464,"medium-height":242,"medium_large":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/client-side-homicides.gif","medium_large-width":640,"medium_large-height":334,"large":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/client-side-homicides.gif","large-width":640,"large-height":334,"1536x1536":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/client-side-homicides.gif","1536x1536-width":640,"1536x1536-height":334,"2048x2048":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/client-side-homicides.gif","2048x2048-width":640,"2048x2048-height":334,"card_image":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/client-side-homicides.gif","card_image-width":640,"card_image-height":334,"wide_image":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/client-side-homicides.gif","wide_image-width":640,"wide_image-height":334}},"image_position":"center","orientation":"horizontal","hyperlink":"https:\/\/developers.arcgis.com\/javascript\/latest\/sample-code\/featurelayerview-query-distance\/index.html"},{"acf_fc_layout":"content","content":"<p>This blog will explore this, and other apps to demonstrate the power of client-side queries.<\/p>\n<h2>A quick review<\/h2>\n<p>Queries are essentially questions you ask your data. In the JS API, these questions are defined in an instance of the <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-tasks-support-Query.html\">Query<\/a> class. You can create a query as a simple JavaScript object, or you can call the <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-layers-FeatureLayer.html#createQuery\">createQuery()<\/a> method directly on the layer. Creating a query object with <code>createQuery()<\/code> is convenient because the resulting object maintains the configuration settings of the layer, such as <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-layers-FeatureLayer.html#definitionExpression\">definitionExpression<\/a> and <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-layers-FeatureLayer.html#outFields\">outfields<\/a>. So I usually call <code>createQuery()<\/code> to get started.<\/p>\n<p>We revamped the <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-tasks-support-Query.html\">Query<\/a> documentation at 4.8 to be more explicit about the following types of queries you can execute against a feature service or layer view.<\/p>\n<ul>\n<li><a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-tasks-support-Query.html#attribute\">Attribute queries<\/a><\/li>\n<li><a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-tasks-support-Query.html#spatial\">Spatial queries<\/a><\/li>\n<li><a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-tasks-support-Query.html#statistic\">Statistic queries<\/a><\/li>\n<\/ul>\n<p>These query types aren\u2019t exclusive of one another. Elements of each can be combined to answer more complex questions related to your data. We encourage you to <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-tasks-support-Query.html\">explore the documentation<\/a> and <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/sample-code\/index.html?search=query\">samples<\/a> to learn more about the query capabilities we support since we can\u2019t cover them all here.<\/p>\n<h2>How it works<\/h2>\n<p>Generally speaking, the concepts mentioned above aren&#8217;t new. The JS API has supported query functionality server-side for years. What is new, is that you can now do all of that client-side, vastly improving the interactivity of your applications. <\/p>\n<p>Querying a lot of features rapidly can be very computation intensive and could easily freeze the web browser. However, you can use the JS API to execute queries rapidly on every pointer move event without much cost to the performance of the application. We accomplish this using two major strategies:<\/p>\n<p><strong>1. Leveraging web platform tooling and advanced features of the web browser, and<br \/>\n2. Developing new technologies in the JS API.<\/strong><\/p>\n<h3>Leveraging web platform tooling and advanced features of the web browser<\/h3>\n<p>Over the last few releases, we have used <strong><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Web_Workers_API\/Using_web_workers\">Web Workers<\/a><\/strong> to offset heavy computational processing to lightweight threads, thus preventing your application&#8217;s user interface from freezing. This allows you to accomplish heavy processing in the browser without negatively affecting the user experience. We developed a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Remote_procedure_call\">RPC framework<\/a> around <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-core-workers.html\">web workers and promises<\/a> to streamline development, allowing us to implement key features such as module loading and falling back code execution to the main thread if the web application runs in a restricted environment (<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/CSP\">CSP<\/a>).<\/p>\n<p>More recently, we have leveraged <a href=\"https:\/\/webassembly.org\/\"><strong>WebAssembly<\/strong><\/a>, which allows us to compile and run C code in the web browser with great performance taking advantage of mature and efficient code Esri already developed through the years for the ArcGIS Pro and Runtime SDKs. WebAssembly is the mechanism that allows us to run the Projection Engine client-side for converting geometries to other spatial references on the fly.<\/p>\n<h3>Developing new technologies in the JS API<\/h3>\n<p>The following pieces of the JS API have also played an integral role in beefing up our support for client side queries.<\/p>\n<p>The <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-geometry-geometryEngine.html\"><strong>Geometry Engine<\/strong><\/a>, which evaluates the spatial relationship between two or more geometries client side, is used to evaluate queries that specify a query <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-tasks-support-Query.html#distance\">distance<\/a> and\/or a <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-tasks-support-Query.html#spatialRelationship\">spatial relationship<\/a>.<\/p>\n<p>We added a <strong>SQL92 parser<\/strong> and runtime, which uses grammar processed with <a href=\"https:\/\/github.com\/pegjs\/pegjs\">PegJS<\/a>, to evaluate <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-tasks-support-Query.html#where\">where<\/a> clauses. It was originally used for the <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-layers-SceneLayer.html#definitionExpression\">definitionExpression<\/a> property of the SceneLayer, but we now use it more broadly to process SQL client-side throughout the API.<\/p>\n<p>Finally, we wrapped up all these technologies in a <strong>query engine<\/strong> that processes the queries, projects (or converts) the geometries on demand, tests feature attributes against the SQL where clause, and evaluates outFields as expressions.<\/p>\n<p>While the query engine powers the query methods in the <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-views-layers-FeatureLayerView.html\">FeatureLayerView<\/a>, it is also used in the <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-layers-CSVLayer.html\">CSVLayer<\/a> to display your data in hundreds of projections and query CSV files transparently. In the upcoming 4.9 release of the JS API, FeatureLayers constructed with client-side features will take advantage of this as well.<\/p>\n<h2>A few examples<\/h2>\n<p>The following are some examples that demonstrate combinations of queries executed on the client rather than a service.<\/p>\n<h3>Mexico Educational attainment<\/h3>\n"},{"acf_fc_layout":"image","image":{"ID":261342,"id":261342,"title":"mexico-predominance","filename":"mexico-predominance.png","filesize":682067,"url":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/mexico-predominance.png","link":"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries\/mexico-predominance","alt":"","author":"6561","description":"","caption":"This app queries data from educational attainment fields each time the user interacts with the view. The chart displays the results of these queries for only features visible in the view.","name":"mexico-predominance","status":"inherit","uploaded_to":257122,"date":"2018-06-29 22:59:24","modified":"2018-06-29 23:01:24","menu_order":0,"mime_type":"image\/png","type":"image","subtype":"png","icon":"https:\/\/www.esri.com\/arcgis-blog\/wp-includes\/images\/media\/default.png","width":2740,"height":1338,"sizes":{"thumbnail":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/mexico-predominance.png","thumbnail-width":213,"thumbnail-height":104,"medium":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/mexico-predominance.png","medium-width":464,"medium-height":227,"medium_large":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/mexico-predominance.png","medium_large-width":768,"medium_large-height":375,"large":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/mexico-predominance.png","large-width":1920,"large-height":938,"1536x1536":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/mexico-predominance.png","1536x1536-width":1536,"1536x1536-height":750,"2048x2048":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/mexico-predominance.png","2048x2048-width":2048,"2048x2048-height":1000,"card_image":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/mexico-predominance.png","card_image-width":826,"card_image-height":403,"wide_image":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/mexico-predominance.png","wide_image-width":1920,"wide_image-height":938}},"image_position":"center","orientation":"horizontal","hyperlink":"https:\/\/developers.arcgis.com\/javascript\/latest\/sample-code\/featurelayerview-query-stats\/index.html"},{"acf_fc_layout":"content","content":"<p>This app visualizes the predominant educational attainment level achieved in each municipality of Mexico. The chart to the right breaks down the proportion of each attained level for all features in the current view. As you pan and zoom to different regions, you\u2019ll see the chart update to reflect the statistics of features within the new extent.<\/p>\n<p>This is accomplished by querying for the sum of each educational attainment field and setting the query geometry to the view&#8217;s extent.<\/p>\n<pre><code\r\n style=\"display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; -webkit-text-size-adjust: none;\">\r\n<span\r\n style=\"color: #998; font-style: italic;\">\/\/ educationFields is an array of field names<\/span>\r\n<span\r\n style=\"color: #998; font-style: italic;\">\/\/ e.g. \"EDUC01_CY\", \"EDUC02_CY\", \"EDUC03_CY\"<\/span>\r\n\r\n<span\r\n style=\"color: #333; font-weight: bold;\">const<\/span> statDefinitions = educationFields.map(<span\r\n><span\r\n style=\"color: #333; font-weight: bold;\">function<\/span>(<span\r\n>fieldName<\/span>)<\/span>{\r\n  <span\r\n style=\"color: #333; font-weight: bold;\">return<\/span> {\r\n    onStatisticField: fieldName,\r\n    outStatisticFieldName: fieldName + <span\r\n style=\"color: #d14;\">\"_TOTAL\"<\/span>,\r\n    statisticType: <span\r\n style=\"color: #d14;\">\"sum\"<\/span>\r\n  };\r\n});\r\n\r\n<span\r\n style=\"color: #998; font-style: italic;\">\/\/ query statistics for features only in view extent<\/span>\r\n<span\r\n style=\"color: #333; font-weight: bold;\">const<\/span> query = layerView.layer.createQuery();\r\nquery.outStatistics = statDefinitions;\r\nquery.geometry = view.extent;\r\n\r\n<span\r\n style=\"color: #333; font-weight: bold;\">return<\/span> layerView.queryFeatures(query)\r\n  .then(<span\r\n><span\r\n style=\"color: #333; font-weight: bold;\">function<\/span>(<span\r\n>response<\/span>)<\/span>{\r\n    <span\r\n style=\"color: #333; font-weight: bold;\">const<\/span> stats = response[<span\r\n style=\"color: #008080;\">0<\/span>].attributes;\r\n    <span\r\n style=\"color: #998; font-style: italic;\">\/\/ send the stats to the function that updates the pie chart<\/span>\r\n  });\r\n<\/code><\/pre>\n<h3>Explore homicides within a distance of a location<\/h3>\n<p>The following application displays various statistics about homicides within a one mile radius of the cursor&#8217;s location. In all, about 30 statistics are queried with each mouse move, allowing the user to dynamically interact with the data in ways that otherwise wouldn&#8217;t be possible if those queries had to be requested from a server.<\/p>\n"},{"acf_fc_layout":"image","image":{"ID":261512,"id":261512,"title":"client-side-homicides","filename":"client-side-homicides.gif","filesize":2072155,"url":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/client-side-homicides.gif","link":"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries\/client-side-homicides","alt":"","author":"6561","description":"","caption":"Queries to the LayerView execute client-side, allowing you to create interactive data exploration apps.","name":"client-side-homicides","status":"inherit","uploaded_to":257122,"date":"2018-06-30 00:02:52","modified":"2018-06-30 00:04:10","menu_order":0,"mime_type":"image\/gif","type":"image","subtype":"gif","icon":"https:\/\/www.esri.com\/arcgis-blog\/wp-includes\/images\/media\/default.png","width":640,"height":334,"sizes":{"thumbnail":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/client-side-homicides.gif","thumbnail-width":213,"thumbnail-height":111,"medium":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/client-side-homicides.gif","medium-width":464,"medium-height":242,"medium_large":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/client-side-homicides.gif","medium_large-width":640,"medium_large-height":334,"large":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/client-side-homicides.gif","large-width":640,"large-height":334,"1536x1536":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/client-side-homicides.gif","1536x1536-width":640,"1536x1536-height":334,"2048x2048":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/client-side-homicides.gif","2048x2048-width":640,"2048x2048-height":334,"card_image":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/client-side-homicides.gif","card_image-width":640,"card_image-height":334,"wide_image":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/client-side-homicides.gif","wide_image-width":640,"wide_image-height":334}},"image_position":"center","orientation":"horizontal","hyperlink":"https:\/\/developers.arcgis.com\/javascript\/latest\/sample-code\/featurelayerview-query-distance\/index.html"},{"acf_fc_layout":"content","content":"<p>There are four relevant fields of interest in this dataset: <code>disposition<\/code>, <code>victim_sex<\/code>, <code>victim_age<\/code>, <code>victim_race<\/code>. Since some of these fields contain string values, we can write a set of SQL expressions to return a count for each unique type. The following snippet demonstrates how the query looks for getting the count of each value of the <code>disposition<\/code> field. Notice the query geometry references the location of the pointer buffered to one mile. Again, this query executes on every <code>pointer-move<\/code> event, something that isn&#8217;t feasible for server-side queries.<\/p>\n<pre><code\r\n style=\"display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; -webkit-text-size-adjust: none;\">\r\nview.on(<span\r\n style=\"color: #d14;\">\"pointer-move\"<\/span>, <span\r\n><span\r\n style=\"color: #333; font-weight: bold;\">function<\/span>(<span\r\n>event<\/span>) <\/span>{\r\n  <span\r\n style=\"color: #333; font-weight: bold;\">const<\/span> query = layerView.layer.createQuery();\r\n  <span\r\n style=\"color: #998; font-style: italic;\">\/\/ converts the screen point to a map point<\/span>\r\n  query.geometry = view.toMap(event);\r\n  <span\r\n style=\"color: #998; font-style: italic;\">\/\/ queries all features within 1 mile of the point<\/span>\r\n  query.distance = <span\r\n style=\"color: #008080;\">1<\/span>;\r\n  query.units = <span\r\n style=\"color: #d14;\">\"miles\"<\/span>;\r\n  <span\r\n style=\"color: #998; font-style: italic;\">\/\/ disposition (aka crime status) is a string field, so we can write a SQL<\/span>\r\n  <span\r\n style=\"color: #998; font-style: italic;\">\/\/ expression to return the total number of each type<\/span>\r\n  query.outStatistics = [\r\n    {\r\n      onStatisticField: <span\r\n style=\"color: #d14;\">\"CASE WHEN disposition = 'Closed by arrest' THEN 1 ELSE 0 END\"<\/span>,\r\n      outStatisticFieldName: <span\r\n style=\"color: #d14;\">\"num_closed_arrest\"<\/span>,\r\n      statisticType: <span\r\n style=\"color: #d14;\">\"sum\"<\/span>\r\n    }, {\r\n      onStatisticField: <span\r\n style=\"color: #d14;\">\"CASE WHEN disposition = 'Open\/No arrest' THEN 1 ELSE 0 END\"<\/span>,\r\n      outStatisticFieldName: <span\r\n style=\"color: #d14;\">\"num_open\"<\/span>,\r\n      statisticType: <span\r\n style=\"color: #d14;\">\"sum\"<\/span>\r\n    }, {\r\n      onStatisticField: <span\r\n style=\"color: #d14;\">\"CASE WHEN disposition = 'Closed without arrest' THEN 1 ELSE 0 END\"<\/span>,\r\n      outStatisticFieldName: <span\r\n style=\"color: #d14;\">\"num_closed_no_arrest\"<\/span>,\r\n      statisticType: <span\r\n style=\"color: #d14;\">\"sum\"<\/span>\r\n    }\r\n  ];\r\n\r\n  layerView.queryFeatures(statsQuery)\r\n  .then(<span\r\n><span\r\n style=\"color: #333; font-weight: bold;\">function<\/span>(<span\r\n>response<\/span>)<\/span>{\r\n    <span\r\n style=\"color: #333; font-weight: bold;\">const<\/span> stats = response.features[<span\r\n style=\"color: #008080;\">0<\/span>].attributes;\r\n    <span\r\n style=\"color: #998; font-style: italic;\">\/\/ send the stats to the function that updates the charts<\/span>\r\n    <span\r\n style=\"color: #998; font-style: italic;\">\/\/ stats.num_closed_arrest<\/span>\r\n    <span\r\n style=\"color: #998; font-style: italic;\">\/\/ stats.num_closed_no_arrest<\/span>\r\n    <span\r\n style=\"color: #998; font-style: italic;\">\/\/ stats.num_open<\/span>\r\n  });\r\n\r\n});\r\n<\/code><\/pre>\n<h2>A note on precision<\/h2>\n<p>Spatial queries are only as good as the precision of the data. Since the LayerView generalizes geometries for optimized performance in a browser, each spatial relationship, such as <em>touches<\/em>, may yield unexpected results. Smaller features may also be completely dropped from the client, since they can&#8217;t be appropriately visualized anyway, thus yielding incomplete query results for certain cases. In the app below, for example, as the user moves the cursor over a municipality, a spatial query is executed for all features that <code>touch<\/code> the feature intersecting the pointer. The value of a variable from the selected feature is then compared to the average value of the same variable from the neighboring, or touching, features. <\/p>\n<p>As you zoom away from the data, the polygons become more generalized, causing the touches query to return imprecise results even though the full resolution geometries from the service follow strict topological rules. As you zoom closer to the data, the geometries are loaded at a higher resolution, allowing the queries to return expected results.<\/p>\n"},{"acf_fc_layout":"image","image":{"ID":261352,"id":261352,"title":"imprecise","filename":"imprecise.png","filesize":444110,"url":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/imprecise.png","link":"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries\/imprecise","alt":"","author":"6561","description":"","caption":"As you zoom to smaller scales, geometries become more generalized, so some spatial relationships like \"touches\" will yield results that appear incorrect.","name":"imprecise","status":"inherit","uploaded_to":257122,"date":"2018-06-29 23:05:07","modified":"2018-06-30 20:10:44","menu_order":0,"mime_type":"image\/png","type":"image","subtype":"png","icon":"https:\/\/www.esri.com\/arcgis-blog\/wp-includes\/images\/media\/default.png","width":2484,"height":1252,"sizes":{"thumbnail":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/imprecise.png","thumbnail-width":213,"thumbnail-height":107,"medium":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/imprecise.png","medium-width":464,"medium-height":234,"medium_large":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/imprecise.png","medium_large-width":768,"medium_large-height":387,"large":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/imprecise.png","large-width":1920,"large-height":968,"1536x1536":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/imprecise.png","1536x1536-width":1536,"1536x1536-height":774,"2048x2048":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/imprecise.png","2048x2048-width":2048,"2048x2048-height":1032,"card_image":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/imprecise.png","card_image-width":826,"card_image-height":416,"wide_image":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/imprecise.png","wide_image-width":1920,"wide_image-height":968}},"image_position":"center","orientation":"horizontal","hyperlink":"https:\/\/ekenes.github.io\/esri-ts-samples\/query\/neighbor-comparison\/touches.html"},{"acf_fc_layout":"image","image":{"ID":261362,"id":261362,"title":"precise","filename":"precise.png","filesize":381249,"url":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/precise.png","link":"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries\/precise","alt":"","author":"6561","description":"","caption":"However, as you zoom to larger scales, the geometry will have a higher resolution, so spatial relationships are more accurately maintained, yielding more precise results.","name":"precise","status":"inherit","uploaded_to":257122,"date":"2018-06-29 23:09:07","modified":"2018-06-30 20:11:33","menu_order":0,"mime_type":"image\/png","type":"image","subtype":"png","icon":"https:\/\/www.esri.com\/arcgis-blog\/wp-includes\/images\/media\/default.png","width":2500,"height":1252,"sizes":{"thumbnail":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/precise.png","thumbnail-width":213,"thumbnail-height":107,"medium":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/precise.png","medium-width":464,"medium-height":232,"medium_large":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/precise.png","medium_large-width":768,"medium_large-height":385,"large":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/precise.png","large-width":1920,"large-height":962,"1536x1536":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/precise.png","1536x1536-width":1536,"1536x1536-height":769,"2048x2048":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/precise.png","2048x2048-width":2048,"2048x2048-height":1026,"card_image":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/precise.png","card_image-width":826,"card_image-height":414,"wide_image":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/precise.png","wide_image-width":1920,"wide_image-height":962}},"image_position":"center","orientation":"horizontal","hyperlink":"https:\/\/ekenes.github.io\/esri-ts-samples\/query\/neighbor-comparison\/touches.html"},{"acf_fc_layout":"content","content":"<p>To keep the user from seeing imprecise results, you can set a scale constraint on the view to prohibit them from zooming out to scales where low resolutions are inevitable, or you can compromise and alter the query in the following manner.<\/p>\n<pre><code\r\n style=\"display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; -webkit-text-size-adjust: none;\">\r\n<span\r\n style=\"color: #333; font-weight: bold;\">const<\/span> layerView = params.layerView;\r\n<span\r\n style=\"color: #333; font-weight: bold;\">const<\/span> geometry = params.centerFeature.geometry;\r\n<span\r\n style=\"color: #333; font-weight: bold;\">const<\/span> layer = layerView.layer;\r\n\r\n<span\r\n style=\"color: #333; font-weight: bold;\">const<\/span> queryParams = layer.createQuery();\r\n<span\r\n style=\"color: #998; font-style: italic;\">\/\/ geometry of feature returned from a hitTest() of the cursor location<\/span>\r\nqueryParams.geometry = geometry;\r\n<span\r\n style=\"color: #998; font-style: italic;\">\/\/ use \"intersects\" instead of \"touches\"<\/span>\r\nqueryParams.spatialRelationship = <span\r\n style=\"color: #d14;\">\"intersects\"<\/span>;\r\nqueryParams.returnGeometry = <span\r\n style=\"color: #333; font-weight: 500;\">false<\/span>;\r\n<span\r\n style=\"color: #998; font-style: italic;\">\/\/ exclude the query geometry<\/span>\r\nqueryParams.where = <span\r\n style=\"color: #d14;\">`OBJECTID &lt;&gt; <span\r\n style=\"color: #333; font-weight: normal;\">${params.centerFeature.attributes.OBJECTID}<\/span>`<\/span>;\r\n\r\n<span\r\n style=\"color: #998; font-style: italic;\">\/\/ query for the ids of the features that touch the<\/span>\r\n<span\r\n style=\"color: #998; font-style: italic;\">\/\/ input feature, then highlight them<\/span>\r\n<span\r\n style=\"color: #998; font-style: italic;\">\/\/ this code executes in an async function allowing us to take advantage<\/span>\r\n<span\r\n style=\"color: #998; font-style: italic;\">\/\/ of await to make the code more readable<\/span>\r\n<span\r\n style=\"color: #333; font-weight: bold;\">const<\/span> ids = <span\r\n style=\"color: #333; font-weight: bold;\">await<\/span> layerView.queryObjectIds(queryParams);\r\nhighlightFeatures(layerView, ids);\r\n<\/code><\/pre>\n<p>This query is for intersecting features that don&#8217;t match the input geometry, yielding better results at smaller scales.<\/p>\n<p>If precision is more important than fast performance, then you need to query the service for the full resolution geometries. <\/p>\n"},{"acf_fc_layout":"content","content":"<h2>Summary<\/h2>\n<p>LayerView queries can be a powerful way to add interactivity to your application. However, they come at the expense of precision. So if geometry precision matters more than fast interactivity in your app, then stick with executing server-based queries against the feature service. However, if interactivity wins, then give LayerView queries a shot. Your users will find your apps more engaging and may be prompted to ask additional questions resulting in them gaining more insight into the data.<\/p>\n"}],"authors":[{"ID":6561,"user_firstname":"Kristian","user_lastname":"Ekenes","nickname":"Kristian Ekenes","user_nicename":"kekenes","display_name":"Kristian Ekenes","user_email":"KEkenes@esri.com","user_url":"https:\/\/github.com\/ekenes","user_registered":"2018-03-02 00:18:32","user_description":"Kristian Ekenes is a Principal Product Engineer at Esri specializing in data visualization on the web. He works on the ArcGIS Maps SDK for JavaScript, ArcGIS Arcade, and Map Viewer in ArcGIS Online. Kristian's work focuses on researching and developing new and innovative data visualization capabilities of geospatial data in web maps, Arcade integration in web maps, and applications of generative AI assistants in web maps. Prior to joining Esri, he worked as a GIS Specialist for an environmental consulting company. Kristian has degrees from Brigham Young University and Arizona State University.","user_avatar":"<img data-del=\"avatar\" src='https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2021\/10\/ekenes-zurich-213x200.png' class='avatar pp-user-avatar avatar-96 photo ' height='96' width='96'\/>"},{"ID":7791,"user_firstname":"Yann","user_lastname":"Cabon","nickname":"YCabon","user_nicename":"ycabon","display_name":"Yann Cabon","user_email":"YCabon@esri.com","user_url":"","user_registered":"2018-04-12 18:23:30","user_description":"Lead Developer on the ArcGIS API for JavaScript 4.x","user_avatar":"<img alt='' src='https:\/\/secure.gravatar.com\/avatar\/3b3c9e03675f6e6a0e122dd21d383e6097c894a955c446de912e7b9c3b11221f?s=96&#038;d=blank&#038;r=g' srcset='https:\/\/secure.gravatar.com\/avatar\/3b3c9e03675f6e6a0e122dd21d383e6097c894a955c446de912e7b9c3b11221f?s=192&#038;d=blank&#038;r=g 2x' class='avatar avatar-96 photo' height='96' width='96' loading='lazy' decoding='async'\/>"}],"related_articles":"","card_image":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/homicide-card-2.png","wide_image":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/touches-banner.png"},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.9 (Yoast SEO v25.9) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Turbo charge your web apps with client-side queries<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Turbo charge your web apps with client-side queries\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries\" \/>\n<meta property=\"og:site_name\" content=\"ArcGIS Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/esrigis\/\" \/>\n<meta property=\"article:modified_time\" content=\"2018-08-06T15:59:43+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:site\" content=\"@ESRI\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":[\"Article\",\"BlogPosting\"],\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries\"},\"author\":{\"name\":\"Kristian Ekenes\",\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/#\/schema\/person\/5469f723fbfb78138efbb1da56e6aa9b\"},\"headline\":\"Turbo charge your web apps with client-side queries\",\"datePublished\":\"2018-08-06T15:30:15+00:00\",\"dateModified\":\"2018-08-06T15:59:43+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries\"},\"wordCount\":8,\"publisher\":{\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/#organization\"},\"keywords\":[\"charts\",\"client-side query\",\"data visualization\",\"jsapi4\"],\"articleSection\":[\"Mapping\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries\",\"url\":\"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries\",\"name\":\"Turbo charge your web apps with client-side queries\",\"isPartOf\":{\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/#website\"},\"datePublished\":\"2018-08-06T15:30:15+00:00\",\"dateModified\":\"2018-08-06T15:59:43+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.esri.com\/arcgis-blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Turbo charge your web apps with client-side queries\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/#website\",\"url\":\"https:\/\/www.esri.com\/arcgis-blog\/\",\"name\":\"ArcGIS Blog\",\"description\":\"Get insider info from Esri product teams\",\"publisher\":{\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.esri.com\/arcgis-blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/#organization\",\"name\":\"Esri\",\"url\":\"https:\/\/www.esri.com\/arcgis-blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/04\/Esri.png\",\"contentUrl\":\"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/04\/Esri.png\",\"width\":400,\"height\":400,\"caption\":\"Esri\"},\"image\":{\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/esrigis\/\",\"https:\/\/x.com\/ESRI\",\"https:\/\/www.linkedin.com\/company\/5311\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/#\/schema\/person\/5469f723fbfb78138efbb1da56e6aa9b\",\"name\":\"Kristian Ekenes\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2021\/10\/ekenes-zurich-213x200.png\",\"contentUrl\":\"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2021\/10\/ekenes-zurich-213x200.png\",\"caption\":\"Kristian Ekenes\"},\"description\":\"Kristian Ekenes is a Principal Product Engineer at Esri specializing in data visualization on the web. He works on the ArcGIS Maps SDK for JavaScript, ArcGIS Arcade, and Map Viewer in ArcGIS Online. Kristian's work focuses on researching and developing new and innovative data visualization capabilities of geospatial data in web maps, Arcade integration in web maps, and applications of generative AI assistants in web maps. Prior to joining Esri, he worked as a GIS Specialist for an environmental consulting company. Kristian has degrees from Brigham Young University and Arizona State University.\",\"sameAs\":[\"https:\/\/github.com\/ekenes\",\"https:\/\/www.linkedin.com\/in\/kristian-ekenes\/\",\"https:\/\/x.com\/kekenes\"],\"gender\":\"male\",\"jobTitle\":\"Principal Product Engineer\",\"worksFor\":\"Esri\",\"url\":\"https:\/\/www.esri.com\/arcgis-blog\/author\/kekenes\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Turbo charge your web apps with client-side queries","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries","og_locale":"en_US","og_type":"article","og_title":"Turbo charge your web apps with client-side queries","og_url":"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries","og_site_name":"ArcGIS Blog","article_publisher":"https:\/\/www.facebook.com\/esrigis\/","article_modified_time":"2018-08-06T15:59:43+00:00","twitter_card":"summary_large_image","twitter_site":"@ESRI","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":["Article","BlogPosting"],"@id":"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries#article","isPartOf":{"@id":"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries"},"author":{"name":"Kristian Ekenes","@id":"https:\/\/www.esri.com\/arcgis-blog\/#\/schema\/person\/5469f723fbfb78138efbb1da56e6aa9b"},"headline":"Turbo charge your web apps with client-side queries","datePublished":"2018-08-06T15:30:15+00:00","dateModified":"2018-08-06T15:59:43+00:00","mainEntityOfPage":{"@id":"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries"},"wordCount":8,"publisher":{"@id":"https:\/\/www.esri.com\/arcgis-blog\/#organization"},"keywords":["charts","client-side query","data visualization","jsapi4"],"articleSection":["Mapping"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries","url":"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries","name":"Turbo charge your web apps with client-side queries","isPartOf":{"@id":"https:\/\/www.esri.com\/arcgis-blog\/#website"},"datePublished":"2018-08-06T15:30:15+00:00","dateModified":"2018-08-06T15:59:43+00:00","breadcrumb":{"@id":"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.esri.com\/arcgis-blog\/"},{"@type":"ListItem","position":2,"name":"Turbo charge your web apps with client-side queries"}]},{"@type":"WebSite","@id":"https:\/\/www.esri.com\/arcgis-blog\/#website","url":"https:\/\/www.esri.com\/arcgis-blog\/","name":"ArcGIS Blog","description":"Get insider info from Esri product teams","publisher":{"@id":"https:\/\/www.esri.com\/arcgis-blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.esri.com\/arcgis-blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.esri.com\/arcgis-blog\/#organization","name":"Esri","url":"https:\/\/www.esri.com\/arcgis-blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.esri.com\/arcgis-blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/04\/Esri.png","contentUrl":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/04\/Esri.png","width":400,"height":400,"caption":"Esri"},"image":{"@id":"https:\/\/www.esri.com\/arcgis-blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/esrigis\/","https:\/\/x.com\/ESRI","https:\/\/www.linkedin.com\/company\/5311\/"]},{"@type":"Person","@id":"https:\/\/www.esri.com\/arcgis-blog\/#\/schema\/person\/5469f723fbfb78138efbb1da56e6aa9b","name":"Kristian Ekenes","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.esri.com\/arcgis-blog\/#\/schema\/person\/image\/","url":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2021\/10\/ekenes-zurich-213x200.png","contentUrl":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2021\/10\/ekenes-zurich-213x200.png","caption":"Kristian Ekenes"},"description":"Kristian Ekenes is a Principal Product Engineer at Esri specializing in data visualization on the web. He works on the ArcGIS Maps SDK for JavaScript, ArcGIS Arcade, and Map Viewer in ArcGIS Online. Kristian's work focuses on researching and developing new and innovative data visualization capabilities of geospatial data in web maps, Arcade integration in web maps, and applications of generative AI assistants in web maps. Prior to joining Esri, he worked as a GIS Specialist for an environmental consulting company. Kristian has degrees from Brigham Young University and Arizona State University.","sameAs":["https:\/\/github.com\/ekenes","https:\/\/www.linkedin.com\/in\/kristian-ekenes\/","https:\/\/x.com\/kekenes"],"gender":"male","jobTitle":"Principal Product Engineer","worksFor":"Esri","url":"https:\/\/www.esri.com\/arcgis-blog\/author\/kekenes"}]}},"text_date":"August 6, 2018","author_name":"Multiple Authors","author_page":"https:\/\/www.esri.com\/arcgis-blog\/products\/js-api-arcgis\/mapping\/turbo-charge-your-web-apps-with-client-side-queries","custom_image":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/07\/touches-banner.png","primary_product":"ArcGIS Maps SDK for JavaScript","tag_data":[{"term_id":30821,"name":"charts","slug":"charts","term_group":0,"term_taxonomy_id":30821,"taxonomy":"post_tag","description":"","parent":0,"count":46,"filter":"raw"},{"term_id":99752,"name":"client-side query","slug":"client-side-query","term_group":0,"term_taxonomy_id":99752,"taxonomy":"post_tag","description":"","parent":0,"count":1,"filter":"raw"},{"term_id":30111,"name":"data visualization","slug":"data-visualization","term_group":0,"term_taxonomy_id":30111,"taxonomy":"post_tag","description":"","parent":0,"count":97,"filter":"raw"},{"term_id":27491,"name":"jsapi4","slug":"jsapi4","term_group":0,"term_taxonomy_id":27491,"taxonomy":"post_tag","description":"","parent":0,"count":111,"filter":"raw"}],"category_data":[{"term_id":22941,"name":"Mapping","slug":"mapping","term_group":0,"term_taxonomy_id":22941,"taxonomy":"category","description":"","parent":0,"count":2696,"filter":"raw"}],"product_data":[{"term_id":36831,"name":"ArcGIS Maps SDK for JavaScript","slug":"js-api-arcgis","term_group":0,"term_taxonomy_id":36831,"taxonomy":"product","description":"","parent":36601,"count":363,"filter":"raw"},{"term_id":36601,"name":"Developers","slug":"developers","term_group":0,"term_taxonomy_id":36601,"taxonomy":"product","description":"","parent":0,"count":765,"filter":"raw"}],"primary_product_link":"https:\/\/www.esri.com\/arcgis-blog\/?s=#&products=js-api-arcgis","_links":{"self":[{"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/blog\/257122","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/blog"}],"about":[{"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/types\/blog"}],"author":[{"embeddable":true,"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/users\/6561"}],"replies":[{"embeddable":true,"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/comments?post=257122"}],"version-history":[{"count":0,"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/blog\/257122\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/media?parent=257122"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/categories?post=257122"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/tags?post=257122"},{"taxonomy":"industry","embeddable":true,"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/industry?post=257122"},{"taxonomy":"product","embeddable":true,"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/product?post=257122"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}