<\/HEAD>
Hoy se publicó un gran blog por Paul Barker<\/A> sobre las nuevas funciones FeatureSet: Qué hay de nuevo con Arcade: Un paseo por FeatureSets (Parte 1)<\/A> y también Kelly Gerrow<\/A> compartió un gran documento sobre este tema: https:\/\/community.esri.com\/community\/gis\/web-gis\/arcgisonline\/blog\/2018\/12\/10\/overlapping-features-in-pop-ups-quick-introduction-to-using-featuresets-with-arcade<\/A> . <\/P><\/P>
No quería quedarme atrás, así que pensé en compartir algunos ejemplos usando hidrantes, el historial de mantenimiento y subsectores y sectores hidráulicos para mostrar lo que puedes lograr con las nuevas funciones Arcade lanzadas en ArcGIS Online el 5 de diciembre.<\/P>
<\/P>
Consideremos que tenemos un mapa web con varias capas y una tabla:<\/P>
<\/P>
<\/P>
- Hidrantes<\/EM> es una capa de puntos con hidrantes.<\/LI>Sub Sector<\/EM> es una capa de polígonos con una subdivisión del área de interés.<\/LI>Sector Hidraulico<\/EM> es una capa de polígonos que agrupa subsectores en sectores hidráulicos.<\/LI>Hist Mantenimiento<\/EM> es una tabla con los registros históricos de mantenimiento para cada hidrante.<\/LI><\/UL><\/P>Primero, apliquemos algo de Arcade para visualizar los hidrantes según su antigüedad. Esto ya era posible en la versión anterior, así que no hay novedades aquí todavía. Tenemos la fecha de instalación almacenada en el campo FECHAINSTALACION y podemos usar las funciones DateDiff<\/EM> y Now<\/EM> para determinar la edad en años, lo cual ocurre en las dos primeras líneas. Después clasificamos el valor en rangos significativos:<\/P>
<SPAN class="keyword token">var<\/SPAN> fecha_inst <SPAN class="operator token">=<\/><SPAN class="punctuation token">$feature<\.FECHAINSTALACION<SPAN class="punctuation token">;<\/><SPAN class="keyword token">var<\/> edad <SPAN class="operator token">=<\/><SPAN class="token function">DateDiff<\/><SPAN class="punctuation token">(<\/><SPAN class="token function">Now<\/><SPAN class="punctuation token">(<\/><SPAN class="punctuation token">)<\/><SPAN class="punctuation token">,<\/> fecha_inst<SPAN class="punctuation token">,<\/> <SPAN class="string token">"years"<\/><SPAN class="punctuation token">)<\/><SPAN class="punctuation token">;<\/><SPAN class="keyword token">var<\/> clase_edad <SPAN class="operator token">=<\/> <SPAN class="string token">""<\/><SPAN class="punctuation token">;<\/><SPAN class="keyword token">if<\/> <SPAN class="punctuation token">(<\/>edad <SPAN class="operator token">><\/> <SPAN class="number token">50<\/><SPAN class="punctuation token">)<\/> <SPAN class="punctuation token">{<\/> clase_edad <SPAN class="operator token">=<\/> <SPAN class="string token">"Mayor a 50 aos"<\/><SPAN class="punctuation token">;<\/>} <SPAN class="keyword token">else<\/> <SPAN class="keyword token">if<\/> <SPAN class="punctuation token">(<\/>edad <SPAN class="operator token">><\/> <SPAN class="number token">40<\/><SPAN class="punctuation token">)<\/> { clase_edad <span class='string'>"Entre 40 y 50 aos"</span>; } else if (edad > 30) { clase_edad = "Entre 30 y 40 aos"; } else if (edad > 20) { clase_edad = "Entre 20 y 30 aos"; } else if (edad > 10) { clase_edad = "Entre 10 y 20 aos"; } else if (edad > 5) { clase_edad = "Entre 5 y 10 aos"; } else { clase_edad = "Menor a 5 aos"; } return clase_edad;
El resultado es un texto que describe la edad, para el cual podemos definir símbolos representativos (aquí usando los símbolos Firefly):

No hay símbolos llamativos para las otras dos capas de polígonos para evitar distraer la atención de los hidrantes.
Nos gustaría mostrar en la ventana emergente de cada hidrante la lista de todos los mantenimientos realizados en el hidrante. Tanto la tabla del historial de mantenimiento como la capa de hidrantes contienen el ID del hidrante. La tabla también contiene las fechas y tipo de mantenimiento.
En la configuración del pop-up de los hidrantes podemos agregar una expresión Arcade como esta:
var tbl = FeatureSetByName($datastore,"Hist_Mantenimiento");
var codigo = $feature["COD_HIDRANTE"];
var sql = "COD_HIDRANTE = '" + codigo + "'";
Console(sql);
var mantenimientos = Filter(tbl, sql);
var cnt = Count(mantenimientos);
var historia = "";
if (cnt > 0) {
historia = cnt + " Mantenimiento(s):";
<SPAN class="keyword token">for</SPAN> <SPAN class="punctuation token">(</SPAN><SPAN class="keyword token">var</SPAN> mantenimiento <SPAN class="keyword token">in</SPAN> mantenimientos<SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">{</SPAN>
<SPAN class="keyword token">var</SPAN> txt_fecha <SPAN class="operator token">=</SPAN> <SPAN class="token function">Text</SPAN><SPAN class="punctuation token">(</SPAN>mantenimiento<SPAN class="punctuation token">.</SPAN>Fecha_Mantenimiento<SPAN class="punctuation token">,</SPAN> <SPAN class="string token">' - (Y/MM/DD) '</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="keyword token">var</SPAN> txt_man <SPAN class="operator token">=</SPAN> txt_fecha <SPAN class="operator token">+</SPAN> mantenimiento<SPAN class="punctuation token">.</SPAN>Mantenimiento<SPAN class="punctuation token">;</SPAN>
historia <SPAN class="operator token">+=</SPAN> TextFormatting<SPAN class="punctuation token">.</SPAN>NewLine <SPAN class="operator token">+</SPAN> txt_man<SPAN class="punctuation token">;</SPAN>
<span class="punctuation token">}</span>
<span class="punctuation token">}</span> <span class="keyword token">else</span> <span class="punctuation token">{</span>
historia <span class="operator token">=</span> <span class="string token">"No hay mantenimientos"</span><span class="punctuation token">;</span>
<span class="punctuation token">}</span>
<span class="keyword token">return</span> historia<span class="punctuation token">;</span>
<span class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span>Primero, accedemos a la tabla con el historial de mantenimiento y la asignamos a una variable tbl. Luego leemos el id del hidrante actual para el cual queremos crear el pop-up. Definimos una expresión SQL usando el ID del hidrante que luego se usa para filtrar la tabla de historial. El resultado se almacena en una variable llamada mantenimientos. Podemos hacer un Count para obtener el número de mantenimientos realizados en el hidrante. Si el conteo (cnt) es mayor que 0, comenzamos a leer los detalles y construimos una lista de mantenimientos incluyendo la fecha y tipo de mantenimiento.
El resultado aparecerá así después de configurar un html personalizado simple para mostrar los atributos y resultado de la expresión Arcade en el pop-up:

Ahora continuemos haciendo algo con estas nuevas funciones Arcade para obtener algunos datos de hidrantes a nivel de sub sector. Dado que el número de mantenimientos obviamente depende de la antigüedad del hidrante, sería bueno obtener algunos detalles sobre esto a nivel de sub sector.
En la configuración del pop-up de los sub sectores podemos agregar la siguiente expresión Arcade:
<SPAn class="keyword token">var</SPAn> fs <SPAn class="operator token">=</SPAn> <SPAn class="token function">FeatureSetByName</SPAn>( $datastore , "Hidrantes" ) ;
<SPAn class="keyword token">var</SPAn> hidrantes <SPAn class="operator token">=</SPAn> <SPAn class="token function">Intersects</SPAn>( fs , $feature ) ;
<SPAn class="keyword token">var</SPAn> cnt <SPAn class="operator token">=</SPAn> <SPAn class="token function">Count</SPAn>( hidrantes ) ;
<SPAn class="keyword token">var</SPAn> edad_tot <SPAn class="operator token">=</SPAn> 0 ;
<SPAn class="keyword token">for</SPAn>( <SPAn class="keyword token">var</SPAn> hidrante <SPAn class="keyword token">in</SPAn> hidrantes ) {
<SPAn class="keyword token">var</SPAn> edad <SPAn class="operator token">=</SPAn> <SPAn class="token function">DateDiff</SPAn>( <SPAn class="token function">Now</SPAn>(), hidrante.FECHAINSTALACION, "years" ) ;
edad_tot += edad ;
}
<SPAn class="keyword token">var</SPAn> resultado <SPAn class="operator token">=</SPAn> "" ;
<SPAn class="keyword token">if</SPAn>( cnt > 0 ) {
<SPAn class="keyword token">var</SPAn> edad_media <SPAn class="operator token">=</SPAn> edad_tot / cnt ;
resultado = "Hay " + cnt + " hidrantes en el sub sector" ;
resultado += TextFormatting.NewLine + "La edad media de los hidrantes es de " + <SPAn class="token function">Round</SPAn>( edad_media , 2 ) + " años" ;
} else {
resultado = "No hay hidrantes en el sub sector" ;
}
<span class='keyword'>return </span> resultado;<br/><br/><br/>Esa expresión hará lo siguiente:
- Aceder a la capa Hydrants (Hidrantes)
- Efectuar una intersección con la entidad actual del sub sector (subsector)
- Contar el número de hidrantes en el sub sector (subsector)
- Calcular la edad para cada hidrante y sumar todas las edades (ages)
- Cacular la edad media de los hidrantes y formatear el texto con esta información (mean age)
El resultado aparecerá así:

En este caso hay 93 hidrantes en el sub sector y la edad media es 20.64 años.
Esto es divertido, pero ¿podemos también mostrar los nombres de los sub sectores que están contenidos por un sector hidráulico usando estas nuevas funciones Arcade? La respuesta es sí. Añadamos la siguiente expresión a los sectores hidráulicos:
<span class='keyword'>var </span> fs = FeatureSetByName($datastore, "Sub Sector");
<span class='keyword'>var </span> subsectores = Intersects(fs, $feature);
<span class='keyword'>var </span > cnt = Count(subsectores);
<span cl ass='keyword'>var </ span > resultado = "Listado de los " + cnt + " Subsectores:";
<span class="keyword token">for<\/SPAN> <SPAN class="punctuation token">(<\/SPAN><SPAN class="keyword token">var<\/SPAN> subsector <SPAN class="keyword token">in<\/SPAN> subsectores<SPAN class="punctuation token">)<\/SPAN> <SPAN class="punctuation token">{<\/SPAN>
resultado <SPAN class="operator token">+<\/SPAN><SPAN class="operator token">=<\/SPAN> TextFormatting<SPAN class="punctuation token">.<\/SPAN>NewLine <SPAN class="operator token">+<\/SPAN> subsector<SPAN class="punctuation token">.<\/SPAN>IDSAP<SPAN class="punctuation token">;<\/SPAN>
<SPAN class="punctuation token">}<\/SPAN>
<SPAN class="keyword token">return<\/SPAN> resultado<SPAN class="punctuation token">;<\/SPAN>
<SPAN class="line-numbers-rows"><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><SPAN><\/SPAN><\/SPAN><\/CODE><\/PRE><P><\/P><P>Sólo accede a la capa de subsectores y haz un Intersect con el sector hidráulico actual y voilà, ¿verdad? No, no tan correcto. Cuando usas un Intersect entre dos capas de polígonos, probablemente devolverá demasiadas entidades debido a que cuando dos polígonos tienen un límite coincidente probablemente se incluirán en el resultado, lo que lleva a más subsectores de los que queremos.<\/P><P><\/P><P>Una forma de evitar esto es usar un buffer negativo pequeño en el sector hidráulico y hacer el Intersect con esa geometría bufferizada así:<\/P><PRE class="lia-code-sample line-numbers language-none"><CODE><SPAN class="keyword token">var<\/SPAN> fs <SPAN class="operator token">=<\/SPAN> <SPAN class="token function">FeatureSetByName<\/SPAN><SPAN class="punctuation token">(<\/SPAN>$datastore<SPAN class="punctuation token">,<\/SPAN><SPAN class="string token">"Sub Sector"<\/SPAN><SPAN class="punctuation token">)<\/SPAN><SPAN class="punctuation token">;<\/SPAN>
<SPAN class="keyword token">var<\/SPAN> feature_buf <SPAN class="operator token">=<\/SPAN> <SPAN class="token function">Buffer<\/Span><span class="punctuation token">(<span>$feature<span>,</span> <span>-</span>100<span>,</span> 'meters'<span>)</span></span></span>;<br>
<span class="keyword token">var</span> subsectores <span class="operator token">=</span> <span class="token function">Intersects</span>(fs, feature_buf);<br>
<span class="keyword token">var</span> cnt <span class="operator token">=</span> <span class="token function">Count</span>(subsectores);<br>
<br>
<span class="keyword token">var</span> resultado <span class="operator token">=</span> "Listado de los " + cnt + " Subsectores:";<br>
<span class="keyword token">for</span> (<span class="keyword token">var</span> subsector <span class="keyword token">in</span> subsectores) {<br>
resultado += TextFormatting.NewLine + subsector.IDSAP;<br>
}<br>
<br>
<span class="keyword token">return</span> resultado;<br>
<span class="line-numbers-rows"><span><<EMOJI_10>></span><span><<EMOJI_11>></span><span><<EMOJI_12>></span><span><<EMOJI_13>></span><span><<EMOJI_14>></span><span><<EMOJI_15>></span><span><<EMOJI_16>></span><span><<EMOJI_17>></span><span><<EMOJI_18>></span><span><<EMOJI_19>></span><span><<EMOJI_20>></span></span>
Nótese el Buffer con una distancia negativa que se crea en la línea 2 y se usa en la línea 3 para obtener los polígonos correctos.
El pop-up resultante se mostrará así:

Sinceramente, no me gusta la lista desordenada de subsectores, así que ordenemos esta lista usando OrderBy:
<span class="keyword token">var</span> fs = FeatureSetByName($datastore, "Sub Sector");
<span class="keyword token">var</span> feature_buf = Buffer($feature, -100, 'meters');
<span class="keyword token">var</span> subsectores = OrderBy(Intersects(fs, feature_buf), 'IDSAP ASC');
<span class="keyword token">var</span> cnt = Count(subsectores);
<span class="keyword token">var</span> resultado = "Listado de los " + cnt + " Subsectores:";
<span class="keyword token">for</span>(<span class="keyword token">var</span> subsector in subsectores) {
resultado += TextFormatting.NewLine + subsector.IDSAP;
}
<span class="keyword token">return</span> resultado;
<span class="line-numbers-rows"><span><<EMOJI_21>></span><span><<EMOJI_22>></span><span><<EMOJI_23>></span><span><<EMOJI_24>></span><span><<EMOJI_25>></span><span><<EMOJI_26>></span><span><<EMOJI_27>></span><span><<EMOJI_28>></span><span><<EMOJI_29>></span><span><<EMOJI_30>></span><span><<EMOJI_31>></span></p>
Lo que resultará en una lista ordenada de subsectores:

Espero que estos ejemplos te ayuden a entender lo que es posible usando Arcade con la última actualización en ArcGIS Online, pero antes de que te lances y empieces a crear fabulosas expresiones Arcade quiero citar al Tío Ben (Spider-Man) por un momento:
Con gran poder viene una gran responsabilidad...
Como menciona Paul Barker en su blog, ten cuidado y siempre valida que el rendimiento de tus expresiones produzca un tiempo de respuesta aceptable para tu usuario final.