Navigation überspringen
All Places > GeoDev Germany > Blog
1 2 3 Zurück Weiter

GeoDev Germany

251 Einträge

Die ArcGIS API for Python ist das perfekte Werkzeug für das Automatisieren, Administrieren und Nutzen von ArcGIS Online und ArcGIS Enterprise. Vor kurzem wurde die ArcGIS API for Python v1.5.1 mit vielen Neuerungen veröffentlicht, nun wurde die Version 1.5.2 nachgeschoben. Der Schwerpunkt liegt auf der Unterstützung von User Types, die im ArcGIS Online Dezember Release eingeführt wurden (und Anfang 2019 in die nächste ArcGIS Enterprise Version  eingeführt werden).

 

Einige Neuerungen in v1.5.2 sind:

 

  • Unterstützung des neuen User Type Lizenzmodells
  • Möglichkeit für Batch-Sharing im ContentManager
  • History-Funktion zum Überprüfen von LogIns in AGOL oder ArcGIS Enterprise
  • Screenshot-Funktion für das Map Widget im Jupyter Notebook
  • Diverse Bug Fixes

 

Ausführliche Informationen zu allen Neuerungen der ArcGIS API for Python 1.5.2 findet Ihr in der ArcGIS API for Python GeoNet Gruppe und in den Release Notes im ArcGIS Developer Portal.

 

Happy scripting!

Die ArcGIS API for Python ist das perfekte Werkzeug für das Automatisieren, Administrieren und Nutzen von ArcGIS Online und ArcGIS Enterprise. Mit den coolen Jupyter Notebooks kann Python im Browser geskripted und zudem Ergebnisse anschaulich mit Widgets basierend auf der ArcGIS API for JavaScript (z.B. interaktive Maps und 3D Szenen) visualisiert werden. Mit dem neuen Release 1.5.1 bekommen wir wieder neben diversen Bug-Fixes, Verbesserungen der Performance und der Dokumentation eine Reihe spannender neuer Funktionen und Updates.

 

Highlights:

  • Es kann nun eine Legende im Map Widget in Jupyter Notebooks angezeigt werden

 

 

  • Die Ergebnisse einer Query auf einem FeatureLayer kann nun sowohl als FeatureSet als auch direkt als Pandas DataFrame mit dem Parameter as_df ausgegeben werden

 

 

  • Es lassen sich nun auch Workflows für Survey123 automatisieren, z.B. Surveys suchen, abrufen, die Umfragedaten herunterladen und Berichte daraus generieren
  • uvm.

 

 

Ausführliche Informationen zu allen Neuerungen der ArcGIS API for Python 1.5.1 findet Ihr in diesem News Blog von Esri Inc. und in den Release Notes auf dem ArcGIS Developer Portal.

 

Happy scripting!

Seit Mitte Oktober 2018 steht das neue ArcGIS Runtime Major Release Version 100.4 zur Verfügung. ArcGIS Runtime ist eine Familie aus mehreren SDKs zum Entwickeln nativer Geo-Apps für alle relevanten Plattformen. Neben den üblichen Bug-Fixes und Performance Verbesserungen beinhaltet es folgende Highlights:

 

  • Viele Verbesserungen für das Handling von Offline Maps
  • Unterstützung des MrSID Raster Formats
  • KML kann nun in 2D Maps und 3D Scenes genutzt werden und es werden mehr KML 2.2 Features unterstützt
  • Plattformspezifische Änderungen

 

KML Placemarks in einer 3D WebScene

 

Ausführliche Informationen zu allen Neuerungen in ArcGIS Runtime 100.4 findet Ihr in diesem News Blog von Esri Inc. und in den Release Notes, jeweils unter Guide -> Reference der verschiedenen SDKs auf dem ArcGIS for Developers Portal.

Mit Web AppBuilder for ArcGIS können Anwender ohne Programmierkenntnisse fokussierte 2D und 3D Web-Apps mithilfe von vielen konfigurierbaren, ready-to-use Widgets und Designs erstellen. Sollte die Funktionalität nicht ausreichen, können Entwickler mit der Developer Edition bestehende Widgets und Designs erweitern oder vollständig eigene erstellen.

 

Neue CoordinateControl class für das Parsen von Koordinaten

 

Die neue Version 2.10 hat nun den gleichen funktionalen Stand wie der eingebettete Web AppBuilder in ArcGIS  vom September 2018 Update. Neu ist ein Pocket Design für Web-Apps, das optimiert ist für das Einbetten in andere Apps, z.B. in StoryMaps. Neben dem wurden über 10 bestehende Widgets verbessert und/oder funktional erweitert. Das SDK wurde ebenfalls funktional erweitert und die Dokumentation wurde verbessert.

 

Vollständige Auflistung der Neuigkeiten stehen im Esri Blog oder im What's New auf dem ArcGIS Developer Portal.

Ab sofort stehen allen Entwicklern die neuen Versionen der ArcGIS API for JavaScript zur Verfügung. In den Updates der Version 4.9 sowie 3.26 wurden wieder viele Verbesserungen vorgenommen und einige neue Features hinzugefügt.

 

Alle Neuerungen werden in diesem Blog-Post detailliert vorgestellt:

ArcGIS API 4.9 for  What’s new (September 2018) 

 

Mehr dazu zeigen auch die neusten Beispielcodes:

3.26 Latest Samples

4.9 Latest Samples

 

und die Release Notes:

3.26 Release Notes

4.9 Release Notes

 

Zu den Unterschieden zwischen den beiden Versionen 3.26 und 4.9 und dazu, welche Version in welchem Anwendungsfall zu bevorzugen ist, gibt die aktualisierte FAQ einige gute Hinweise: 
Choose between version 3.26 and 4.9

 

Happy coding!

Since 2006, the Esri DevSummit Europe has been the largest, longest-running conference for developers building next-generation apps with advanced GIS technology.

 

Yet it's more than just a conference--it's a productivity event. After all, you are building apps that help millions of users successfully better our world, in so many different ways.

  

Berlin is where the brightest minds in geodevelopment gather to take users inside the future of app-building with location intelligence. This starts with hands-on training on the latest tools and advanced technology, enabling the user community to continue doing great things.

 

The growth of ArcGIS, and what it can do, is growing at a break-neck pace. Given that It will have been six months since the Developer Summit event in Palm Springs, California—and six months until the next one—there is so much that you will be seeing for the first time in Berlin.

 

Your attendance is critical to ensure you are aligned with Esri, as we move forward. There’s no other event to learn and get hands-on with the latest capabilities and functionality of ArcGIS, directly from the lead developers who are building the technology.

 

Esri Developer Summit Europe 

 

AppStudio for ArcGIS ist eine innovative Anwendung zur Erstellung mobiler Karten-Apps für Android, iOS, Mac, Linux und Windows. Apps werden einmal erstellt und sind dann plattformübergreifend und auf jedem Gerät sofort verwendbar. Mit der Standard-Version lassen sich die mit den konfigurierbaren Esri Vorlagen erstellten Apps weiter ausbauen. Entwickler-Werkzeuge und Codebeispiele ermöglichen die effiziente Erstellung benutzerdefinierter Apps, powered by ArcGIS Runtime. Fertige Apps können innerhalb des Unternehmens oder in öffentlichen App-Stores bereitgestellt werden. Nun ist die Version 3.1 verfügbar:

 

Einige Highlights sind:

  • Verbesserungen der UI des AppStudio Desktop
  • Änderungen/Verbesserungen der Esri Templates
  • ArcGIS Runtime wurde zur Version 100.3 hochgezogen
  • Qt Framework wurde zur Version 5.11.1 hochgezogen
  • AppStudio Player hat ein grüßeres UI- und UX-Update erhalten
  • Einige Bugfixes

 

AppStudio Desktop Settings Tool Dialog

 

Ausführliche Informationen zu den Neuerungen von AppStudio for ArcGIS Version 3.1 findet Ihr in diesem News Blog von Esri Inc., im Whats New der Hilfeseiten und in der AppStudio GeoNet Gruppe.

There are multiple ways how you might use OpenStreetMap. The most commonly used might be the OSM dataset as a basemap. Some others might already used the ArcGIS Editor for OSM. But I haven't found a soultion to query OSM directly from within ArcGIS. The question to answer was: "Where are bakeries in Northumberland?" The Overpass API offers a great  query tool to define queries and get the result on a map. I wanted to have a comparable but easy to use tool in ArcGIS so I created OSMQuery. You can use OSMQuery for free.

The Inputs of OSMQuery

OSMQuery takes only a simple set of inputs at the moment:

- a tag like "building", "shop" or "amenity"

- a key like "farm", "bakery" or "place_of_worship"

- an area which will be used as a "related" feature

- or a bounding box / spatial extent

The tool uses the name of the region and gets an area ID from the Nominatim Geocoder. This area ID or the bounding box of the spatial extent will be used to create a query for the Overpass API.

OSMQuery in ArcMAP 10.6

(the above image is already outdated after one day. See the end of this post!)

The query is send to the Overpass API which responds with a JSON object. The JSON object contains elements like nodes, ways and relations.

The Logic of OSMQuery

The processing logic is splitted in two parts. First I needed to determine whether points, line and/or polygon feature classes will be needed to store the features. This is a bit tricky as polygons are also "ways" in terms of OpenStreetMap logic. The response of a way not only contains the tags of a way but also the id's of nodes defining the way geometry. A polygon can be created if the first nodeID in the list of nodes is also the last nodeID for the way:

As you can see, the result way has 71 nodes and the response looks like this:

{
  "version": 0.6,
  "generator": "Overpass API 0.7.55.4 3079d8ea",
  "osm3s": {
    "timestamp_osm_base": "2018-08-29T08:10:02Z",
    "copyright": "The data included in this document is from www.openstreetmap.org. The data is made available under ODbL."
  },
  "elements": [

{
  "type": "node",
  "id": 2496059820,
  "lat": 51.0703208,
  "lon": 4.9863343
},
{
  "type": "node",
  "id": 2496059823,
  "lat": 51.0703401,
  "lon": 4.9865653
},
...
{
  "type": "node",
  "id": 2496059818,
  "lat": 51.0702779,
  "lon": 4.9863413
},
{
  "type": "way",
  "id": 242035363,
  "nodes": [
    2496059820,
    2496059823,
...
    2496059818,
    2496059820
  ],
  "tags": {
    "OnroerendErfgoed:criteria": "M",
    "addr:city": "Veerle",
    "amenity": "place_of_worship",
    "building": "house",
    "denomination": "roman_catholic",
    "description": "Parochiekerk",
    "heritage": "4",
    "heritage:operator": "OnroerendErfgoed",
    "heritage:website": "https://inventaris.onroerenderfgoed.be/dibe/relict/41142",
    "image": "https://commons.wikimedia.org/wiki/File:Veerle_-_Onze-Lieve-Vrouw-in-de-Wijngaardkerk.jpg",
    "name": "Onze-Lieve-Vrouw-in-de-Wijngaardkerk",
    "ref:OnroerendErfgoed": "41142",
    "religion": "christian",
    "source": "AGIV",
    "wikimedia_commons": "Category:OLV in de Wijngaardkerk (Veerle)"
  }
}
  ]
}

Furthermore the result has not a defined datamodel. Each node may come with a very different set of tags and keys. So I needed to create a union of tags for each feature class type. The adding fields algorithm is the slowest part in my toolbox as the number of tgas can be as high as 40...

After I created the feature classes and added the fields accrodiung the list of attributes/tags I can add the features from the Overpass repsonse.

This is quite easy in the end but it is a pain for the polylines and polygons as I needed to read the lat/lon attributes for each node recursively.

But in the end: There are 33 bakeries in Northumberland, UK according to the OpenStreetMap dataset:

result for bakeries in Northumberland

Here is the compared dataset in the Overpass API:

result for bakeries in Northumberland using the Overpass API

If you want to test/download/develop the toolbo, go ahead and use the OSMQuery repo at GitHub.

Here is a short video about the usage:

Thanks to the support of GitHub user rastrau OSMQuery also supports multiple queries now:

Sometimes you see this great tile layer in a web map and you want to use it in your ArcGIS online project or ArcGIS Pro. That was the feeling I had, seeing this nice little BVG basemap. The usage of this kind-of-twisted basemap was a bit tricky as the logic for latitude-longitude to tile numbers was a bit twisted. In products like ArcGIS Online/ ArcGIS Enterprise there is no way to alter the logic of this. So if you want to use a tile layer like this in AGOL you need to intervene somewhere else.

Interrupt the Tile Acquisition

The tiles are fetched from a server any time you pan or zoom the map. The approach I used to get the tiles uses a simple php proxy.

So instead of collecting the tiles from the webserver via a direct pull, we use the php script which gets our request, calculates the somewhat twisted tile number for the row and requests the correct tile and forwards it to your AGOL project.

But let us start with a simple trick which serves as the basis: kitten watermarks.

PlaceKitten serves placeholder images in a very common format: http://placekitten.com/256/256?image=5 where the first "256" is the width, the second one the height and the last one the image you would like to see (image number 5). The images are served as PNGs.

placeholder kittenAs said, we will use a php script to fetch the data and send every image back to AGOL as we receive it. This makes no sense at all from a geo perspective. So you will need a php-enabled server. I was using a Windows virtual machine with IIS and installed PHP by using the Web Platform Installer.

So we need a way to fetch images from the web using php. I stumbled upon the cURL method you might already know from the command line world of Linux based systems.

All we need to do is to mimic our script to look like a real computer trying to get an image from this server:

<?php
header ('Content-Type: image/png'); #content returns as an image
$url = 'https://placekitten.com/256/256?image='; #this is the base url
$ynew = rand(1,16); #we can collect one out of 16 images
$url .= $ynew;
$ch = curl_init(); #Initialize a cURL session
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); #don't verify the peer's SSL certificate
curl_setopt($ch, CURLOPT_FRESH_CONNECT, TRUE); #don't use any cache
curl_setopt($ch,CURLOPT_URL, $url); #provide the URL to use in the request
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1); #return the transfer as a string of the return value of curl_exec() instead of outputting it directly.     
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.A.B.C Safari/525.13"); #set HTTP user-agent header
$data = curl_exec($ch); #perform the cURL session
curl_close($ch); #Close the cURL session
echo $data; #return the date (image)
?>

Now you can already use the real URL of your server (don't even try localhost my friend ;-) ) and embed the placeholder cats in your AGOL project.

Open up a new web map and add a new web based layer:

add web layerI am using here the proposed "{level}/{col}/{row}.png" connotation as we would like to create new calls for every image to get a true random pattern:

Look, all those cute kitties...

Running real Cartography

At the very moment we do have an idea on how to forward images from the web into AGOL as a web layer. Now let's move on and fill these placeholder with "real cartography".

As we have seen in this last post, the naming schema for the BVG map is a bit crooked. But first, our script needs to know, which images it should pull. So we need to send the script some parameters. We will do this in a similar way like the real TMS servers: Send the ZXY parameters via the URL, read the in our script and append the URL with them:

<?php
header ('Content-Type: image/png');
$y = $_GET['y']; #the parameter y is stored as a string in the variable y
$x = $_GET['x']; #the parameter x is stor...
$z = $_GET['z']; #you get it, right?
$ynew =( -1*intval($y))+pow(2,intval($z))-1; #recalculate the y coordinate using the found formula.
$url = 'https://fahrinfo.bvg.de/tiles/base/'.$z.'/'.$x.'/'.$ynew.'.png'; #creating the url
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, TRUE);
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.A.B.C Safari/525.13");
$data = curl_exec($ch);
curl_close($ch);
echo $data;
?>

The parameters are send to the PHP-enabled server using the following schema:

http://your-server-URL.com/name-of-your-script.php?z={level}&x={col}&y={row}

Using this script you will get a nice BVG basemap in your ArcGIS Online editor Map Viewer:

Once you saved the web map you can even open it in ArcGIS Pro and use it for your purposes by adding the map from Portal:

Multiple Servers

If you want to handle multiple servers with the same script you can add a fourth parameter which handles the tileserver and adding some switches:

<?php
header ('Content-Type: image/png');
$tileservice=null; #
if (isset($_GET['t'])){
     $tileservice = $_GET['t'];
}
if(!$tileservice){
     $tileservice = 'bvg'; #if no tileserver parameter was handled
}
$y = $_GET['y'];
$x = $_GET['x'];
$z = $_GET['z'];
$server = array();
switch ($tileservice){
     case 'cat':
          $url = 'https://placekitten.com/256/256?image=';
          $ynew = rand(1,16);
          $url .= $ynew;
          #echo $url;
          break;
     case 'bvg':
     default:
          $ynew =( -1*intval($y))+pow(2,intval($z))-1;
          $url = 'https://fahrinfo.bvg.de/tiles/base/'.$z.'/'.$x.'/'.$ynew.'.png';
          break;
};    
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, TRUE);
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.A.B.C Safari/525.13");
$data = curl_exec($ch);
curl_close($ch);
echo $data;
?>

Now your proxy URL should look like this to get a cat tile:

http://your-server-URL.com/name-of-your-script.php??t=cat&z=15&x=16371&y=10936 

Sometimes you also want to have a fallback server if no tiles were fetched. Therefore we will check response of the cURL call and will use a black-white layer as a fallback layer:

<?php
header ('Content-Type: image/png');
error_reporting(E_ALL);
ini_set('display_errors', '1');
$tileservice=null;
if (isset($_GET['t'])){
     $tileservice = $_GET['t'];
}
if(!$tileservice){
     $tileservice = 'bvg';
}
$y = $_GET['y'];
$x = $_GET['x'];
$z = $_GET['z'];
$server = array();
switch ($tileservice){
     case 'cat':
          #$server[] = 'https://placekitten.com/256/256';
          $url = 'https://placekitten.com/256/256?image=';
          $ynew = rand(1,16);
          $url .= $ynew;
          #echo $url;
          break;
     case 'bvg':
     default:
          $ynew =( -1*intval($y))+pow(2,intval($z))-1;
          $url = 'https://fahrinfo.bvg.de/tiles/base/'.$z.'/'.$x.'/'.$ynew.'.png';
          break;
};    
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, TRUE);
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.A.B.C Safari/525.13");
$data = curl_exec($ch);
if (curl_getinfo( $ch, CURLINFO_HTTP_CODE ) != 200) {
     curl_close($ch);
     $server = array();
     $server[] = 'http://a.tiles.wmflabs.org/bw-mapnik/';
     $server[] = 'http://b.tiles.wmflabs.org/bw-mapnik/';
     $server[] = 'http://c.tiles.wmflabs.org/bw-mapnik/';
     $url = $server[array_rand($server)];
     $url .= $z."/".$x."/".$y.".png";
     #echo $url;
     $ch = curl_init();
     curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
     curl_setopt($ch, CURLOPT_FRESH_CONNECT, TRUE);
     curl_setopt($ch,CURLOPT_URL, $url);
     curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
     curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.A.B.C Safari/525.13");
     $data = curl_exec($ch);
}
curl_close($ch);
echo $data;
?>

The map shows now both tiles:

If you want to add some "annoying annotation" you might also add a nice watermark on those slippy tiles:

<?php
header ('Content-Type: image/png');
error_reporting(E_ALL);
ini_set('display_errors', '1');
$tileservice=null;
if (isset($_GET['t'])){
     $tileservice = $_GET['t'];
}
if(!$tileservice){
     $tileservice = 'bvg';
}
$y = $_GET['y'];
$x = $_GET['x'];
$z = $_GET['z'];
$server = array();
switch ($tileservice){
     case 'cat':
          #$server[] = 'https://placekitten.com/256/256';
          $url = 'https://placekitten.com/256/256?image=';
          $ynew = rand(1,16);
          $url .= $ynew;
          #echo $url;
          break;
     case 'bvg':
     default:
          $ynew =( -1*intval($y))+pow(2,intval($z))-1;
          $url = 'https://fahrinfo.bvg.de/tiles/base/'.$z.'/'.$x.'/'.$ynew.'.png';
          break;
};    
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, TRUE);
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.A.B.C Safari/525.13");
$data = curl_exec($ch);
$size = curl_getinfo($ch, CURLINFO_SIZE_DOWNLOAD );
if (curl_getinfo( $ch, CURLINFO_HTTP_CODE ) != 200) {
     curl_close($ch);
     $server = array();
     $server[] = 'http://a.tiles.wmflabs.org/bw-mapnik/';
     $server[] = 'http://b.tiles.wmflabs.org/bw-mapnik/';
     $server[] = 'http://c.tiles.wmflabs.org/bw-mapnik/';
     $url = $server[array_rand($server)];
     $url .= $z."/".$x."/".$y.".png";
     #echo $url;
     $ch = curl_init();
     curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
     curl_setopt($ch, CURLOPT_FRESH_CONNECT, TRUE);
     curl_setopt($ch,CURLOPT_URL, $url);
     curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
     curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.A.B.C Safari/525.13");
     $data = curl_exec($ch);
}
curl_close($ch);
$im = imagecreatefromstring($data);
$stamp = imagecreatetruecolor(100, 30);
imagestring($stamp, 10, 10, 5, 'watermark', 0xff0000);
// set borders and get sizes
$marge_right = 100;
$marge_bottom = 100;
$sx = imagesx($stamp);
$sy = imagesy($stamp);
// copy the watermark with transparency of 50 into the original image
imagecopymerge($im, $stamp, imagesx($im) - $sx - $marge_right, imagesy($im) - $sy - $marge_bottom, 0, 0, imagesx($stamp), imagesy($stamp), 50);
header('Content-Type: image/png');
imagepng($im);
imagedestroy($im);
?>

But this will create some load on the server... so you might want to rethink this ;-)

Final remarks

Running PHP with a "bad" script can produce a very slow response of your proxied tile server. So you should try to cache tiles on your server. But this is a total different story.

Introduction

Publishing one feature layer in ArcGIS Online or ArcGIS Enterprise in one feature service is a simple procedure, there is a native function for uploading data inside a Spatial Dataframe to one hosted feature layer inside a feature service available in ArcGIS API for Python.

However, publishing multiple layers with different geometries inside one feature service requires more effort. To make this process less complex and more convenient for all users we created a 10 step workflow. We attached a Jupyter Notebook to the end of this blog, which can be simply uploaded to Esri Jupyter Hub to test the workflow.

 

To simplify the written language of this article, we describe the workflow mentioning ArcGIS Online only. All steps performed within this article are also applicable to ArcGIS Enterprise.

 

The Data

Data is available from multiple sources on the web in various geospatial formats. The ArcGIS Spatial Dataframe is a pythonic data structure, that allows to import and include several other geospatial formats on the fly. The table like structure is merely based on a Pandas DataFrame, but incorporates several extensions for geodata elements.

We use the ArcGIS Spatial Dataframe object to store tabular and geometric data. Pandas DataFrames are also used, to store tabular data.

 

Step 1: Import of the needed modules and login to ArcGIS Online with your subscription

We will have to load a few modules to setup the publishing process, the getpass module allows us to interactively enter our password. Using this module we have a secure way to do the login process, as we do not need to type our password as plaintext. The second argument to the GIS function should be changed from "username" to your username for ArcGIS Online. We suggest the installation of the needed python modules including the python environment and the Jupyter Notebooks by using Anaconda Distribution. It features python environments, which are separated from the system wide python installations and therefore reduces complexity and enhances compatibility.

from arcgis import GIS
from arcgis import geometry
from arcgis import features as fs
from getpass import getpass as pwd
import pandas as pd
pwd = pwd()
gis = GIS("https://www.arcgis.com/home/index.html", "username", pwd)

Step 2: Create the features and setup two geometry types

To demonstrate this workflow, we will now create some hard coded sample features with basic point and polyline geometries. To define the two features, we will also create some field values to visualize how field creation and setting attributes to features works in ArcGIS Online.

2.1 Creation of sample field values for features

We create two dictionaries for each geometry and two lists to contain the dictionaries. The list of dictionaries of each geometric element is then added to a Pandas DataFrame. If we had to create attributes for multiple features of one geometry, we would have to add as many dictionaries to the list of dictionaries as geometric features are available.

dictPointAttr = {}
dictPointAttrList = []
dictPointAttr["someint1"] = 123456789101112
dictPointAttr["sometext1"] = "Text"
dictPointAttr["somefloat1"] = 1.25
dictPointAttrList.append(dictPointAttr)
dfpnt = pd.DataFrame.from_dict(dictPointAttrList)

dictPolyLineAttr = {}
dictPolyLineAttrList = []
dictPolyLineAttr["someint2"] = 121110987654321
dictPolyLineAttr["sometext2"] = "Txet"
dictPolyLineAttr["somefloat2"] = 5.21
dictPolyLineAttrList.append(dictPolyLineAttr)
dfpll = pd.DataFrame.from_dict(dictPolyLineAttrList)

2.2 Creation of a simple point geometry

To setup a simple point geometry we will need to create a dictionary containing the two point coordinates “x” and “y” as keys, as well as a sub dictionary with “spatialReference” as key, containing the spatial reference defined by EPSG codes. The dictionary object is then converted to an ArcGIS point geometry and appended to a list of geometries. To store the feature data, an ArcGIS Spatial Dataframe is used. It is capable of storing lists of geometries as well as Pandas DataFrames containing the attribute data for every feature.

listGeometryPoint = []
pnt = {"x": 11.0419520737521,"y": 48.4391156813199, "spatialReference" : {"wkid" : 4326,"latestWkid" : 4326}}
point = geometry.Point(pnt)
listGeometryPoint.append(point)
spatialDataFramePoint = fs.SpatialDataFrame(data=dfpnt, geometry=listGeometryPoint)

2.3 Creation of a simple polyline geometry

The workflow of creating a simple polyline geometry is more or less the same as the creation of a simple point geometry, it differs in requirement of another syntax to define the vertices of the line.

listGeometryPolyLine = []
plyln = { "paths": [[[11.0419520737521,48.4391156813199],[11.0416097302404,48.4390815262157], [11.0414886646127,48.4392674452629]]], "spatialReference" : {"wkid" : 4326, "latestWkid" : 4326}}
polyline = geometry.Polyline(plyln)
listGeometryPolyLine.append(polyline)
spatialDataFramePolyLine = fs.SpatialDataFrame(data=dfpll, geometry=listGeometryPolyLine)

Step 3: Creation of the feature service and a feature layer collection

In this step we will setup a feature service and create a feature layer collection from a new (empty) service. The feature layer collection is used to store the definition of the feature service as well as the layer objects, which will be created in the following steps. To create the service we call the function “gis.content.create_service” from ArcGIS API for Python.

Feature services must have a unique name. If you like to repeat this workflow, please ensure to rename your feature service.

 

Provided function parameters are:

 

  • A name for the resulting feature service via name=
  • The spatial reference via wkid=
  • The spatial extent via item_properties=

 

The extent setting is necessary to ensure, that layers inside the feature service are displayed correctly in maps on ArcGIS Online. Without the extent setting, the wrong initial area might be displayed and users need to zoom to the appropriate part of the map by using “zoom to layer”. In this example we use the extent of the whole world. The items inside the dictUpdate dictionary can be set to user defined values. We recommend setting the "objectIdField" key to a custom value. Therefore, we ensure:

 

  • Every new feature object is provided with a new feature ID
  • No conflicts with the default setting of "objectIdField" occur (default setting is "objectId")

 

The key "capabilities" is needed to define what users with access to the feature service item can do with the service. Information on capabilities is provided in the ArcGIS REST API documentation.

newService = gis.content.create_service(name="featureservice", wkid=4326, item_properties={"extent":[-180.0,-90.0,180.0,90.0]})

newFtLC = fs.FeatureLayerCollection.fromitem(newService)

dictUpdate = {"copyrightText": "copyrightText",
              "objectIdField" : "FID",
              "globalIdField" : "GlobalID",
              "maxRecordCount": 25000,
              "serviceDescription": "description",
              "capabilities": 'Editing,Query,Update,Uploads,Delete,Sync,Extract',
              "spatialReference": {"wkid": 4326,"latestWkid": 4326},
              "initialExtent":{
                   "xmax": 180.0,"ymin": -90.0,"xmin": -180.0,"ymax": 90.0,
                   "spatialReference": {"wkid" : 4326, "latestWkid" : 4326}
                  },
              "fullExtent":{
                   "xmax": 180.0,"ymin": -90.0,"xmin": -180.0,"ymax": 90.0,
                  "spatialReference": {"wkid" : 4326, "latestWkid" : 4326}
                  }
    }
newFtLC.manager.update_definition(dictUpdate)

Step 4: Setup of required and optional fields inside the feature layers

The fields required to describe a valid feature layer are the "objectIdField" and the "globalIdField", which we already defined by their name in the previous step. All fields can be provided with an alias if the field name is too short to provide a meaningful description of its content. The length attribute should be set to appropriate values to add the needed count of features to the layers. The field attributes ["nullable"] and ["editable"] should be set to False for both fields "objectIdField" and "globalIdField".

# General Fields
dictFieldOBJECTID = {}
dictFieldOBJECTID["alias"] = "FID"
dictFieldOBJECTID["name"] = "FID"
dictFieldOBJECTID["type"] = "esriFieldTypeOID"
dictFieldOBJECTID["sqlType"] = "sqlTypeOther"
dictFieldOBJECTID["length"] = 10
dictFieldOBJECTID["nullable"] = False
dictFieldOBJECTID["editable"] = False
dictFieldOBJECTID["domain"] = None
dictFieldOBJECTID["defaultValue"] = None

dictFieldGlobalID = {}
dictFieldGlobalID["alias"] = "GlobalID"
dictFieldGlobalID["name"] = "GlobalID"
dictFieldGlobalID["type"] = "esriFieldTypeGlobalID"
dictFieldGlobalID["sqlType"] = "sqlTypeOther"
dictFieldGlobalID["length"] = 38
dictFieldGlobalID["nullable"] = False
dictFieldGlobalID["editable"] = False
dictFieldGlobalID["domain"] = None
dictFieldGlobalID["defaultValue"] = None

The optional fields are defined to ensure all values we defined in step 2.1 are transferred to the appropriate fields in the layer.

For integer fields we need to pay attention to the required field lengths. If we have 64 bit numbers, we need to define a data type for the key ["sqlType"] named "sqlTypeBigInt" and set the key ["type"] to "esriFieldTypeInteger". By ignoring this fact we may cause data corruption in our layers in ArcGIS Online, the values which do not fit into a standard integer field are sometimes written on into the next field, overwriting values in the next field.

 

FYI: If you use the Spatial Dataframe workflow as mentioned in the introduction, you are not able to use 64 bit numbers in integer fields, they are automatically converted into string fields / strings or stored as 32 bit integers causing data corruption in the hosted feature layer.

Fields containing float values can be defined by setting the key ["type"] to "esriFieldTypeDouble" and the key ["sqlType"] to "sqlTypeOther".

Fields containing strings can be defined by setting the key ["sqlType"] to "sqlTypeOther", the key ["type"] to "esriFieldTypeString" and defining a field length by setting the key ["length"] to a numeric integer value like the number 10.

# Fields for point layer
dictFieldInt1 = {}
dictFieldInt1["alias"] = "someint1"
dictFieldInt1["name"] = "someint1"
dictFieldInt1["sqlType"] = "sqlTypeBigInt"
dictFieldInt1["type"] = "esriFieldTypeInteger"
dictFieldInt1["nullable"] = "yes"
dictFieldInt1["editable"] = "yes"
dictFieldInt1["visible"] = "yes"

dictFieldString1 = {}
dictFieldString1["alias"] = "sometext1"
dictFieldString1["name"] = "sometext1"
dictFieldString1["sqlType"] = "sqlTypeOther"
dictFieldString1["type"] = "esriFieldTypeString"
dictFieldString1["length"] = 10

dictFieldFloat1 = {}
dictFieldFloat1["alias"] = "somefloat1"
dictFieldFloat1["name"] = "somefloat1"
dictFieldFloat1["sqlType"] = "sqlTypeOther"
dictFieldFloat1["type"] = "esriFieldTypeDouble"

 

# Fields for polyline layer
dictFieldInt2 = {}
dictFieldInt2["alias"] = "someint2"
dictFieldInt2["name"] = "someint2"
dictFieldInt2["sqlType"] = "sqlTypeBigInt"
dictFieldInt2["type"] = "esriFieldTypeInteger"
dictFieldInt2["nullable"] = "yes"
dictFieldInt2["editable"] = "yes"
dictFieldInt2["visible"] = "yes"

dictFieldString2 = {}
dictFieldString2["alias"] = "sometext2"
dictFieldString2["name"] = "sometext2"
dictFieldString2["sqlType"] = "sqlTypeOther"
dictFieldString2["type"] = "esriFieldTypeString"
dictFieldString2["length"] = 10

dictFieldFloat2 = {}
dictFieldFloat2["alias"] = "somefloat2"
dictFieldFloat2["name"] = "somefloat2"
dictFieldFloat2["sqlType"] = "sqlTypeOther"
dictFieldFloat2["type"] = "esriFieldTypeDouble"

 

Step 5: Create list of fields for each layer element and append field definitions

To store our field definitions in the following layer definitions, we create two lists, which store the dictionaries for every field. We need two lists to store the fields because we are not allowed to put the two different geometric objects, point and polyline, into the same layer.

The python list.append operation is applied for every field dictionary.

 

# Lists containing the fields
listFieldsPoint = []
listFieldsPolyLine = []

# Append fields to list of fields for points
listFieldsPoint.append(dictFieldOBJECTID)
listFieldsPoint.append(dictFieldGlobalID)
listFieldsPoint.append(dictFieldInt1)
listFieldsPoint.append(dictFieldString1)
listFieldsPoint.append(dictFieldFloat1)

# Append fields to list of fields for polylines
listFieldsPolyLine.append(dictFieldOBJECTID)
listFieldsPolyLine.append(dictFieldGlobalID)
listFieldsPolyLine.append(dictFieldInt2)
listFieldsPolyLine.append(dictFieldString2)
listFieldsPolyLine.append(dictFieldFloat2)

Step 6: Create layer definitions for two layers

We need to define the layer definitions to provide information on what type of features we would like to add to the feature service and how the layers are named inside the service. As we defined fields via dictionary elements, we need to define the layer definition using dictionaries as well. The key ["geometryType"] defines the geometries, one layer contains. The layer definition also contains information, we already set in step 3, the definition of the ["objectIdField"] and the ["globalIdField"]. For every layer a separate extent, which matches the extent of all features in the layer and a separate name can be defined. Fields are defined by setting the key ["fields"] to the corresponding list of fields for the layer.

dictPolyLineLayer = {}
dictPolyLineLayer["geometryType"] = 'esriGeometryPolyline'
dictPolyLineLayer["globalIdField"] = 'GlobalID'
dictPolyLineLayer["objectIdField"] = 'FID'
dictPolyLineLayer["extent"] = {
         "xmax": 180.0,"ymin": -90.0,"xmin": -180.0,"ymax": 90.0,
        "spatialReference": {"wkid": 4326, "latestWkid": 4326}
        }
dictPolyLineLayer["name"] = 'PolyLineLayer'
dictPolyLineLayer["fields"] = listFieldsPolyLine
dictPointLayer = {}
dictPointLayer["geometryType"] = 'esriGeometryPoint'
dictPointLayer["globalIdField"] = 'GlobalID'
dictPointLayer["objectIdField"] = 'FID'
dictPointLayer["extent"] = {
         "xmax": 180.0,"ymin": -90.0,"xmin": -180.0,"ymax": 90.0,
        "spatialReference": {"wkid": 4326, "latestWkid": 4326}
        }
dictPointLayer["name"] = 'PointLayer'
dictPointLayer["fields"] = listFieldsPoint

Step 7: Create a layer list, append layer definitions and update feature layer collection

This step will update the feature layer collection, by adding the layer definitions. They are added to a list and this list is then added to a dictionary as value for the key "layers". The feature layer collection is then updated by the dictionary.

layersList = []
layersList.append(dictPointLayer)
layersList.append(dictPolyLineLayer)
dictUpdate = {"layers": layersList }
newFtLC.manager.add_to_definition(dictUpdate)

Step 8: Create FeatureSets from Spatial Dataframes and append FeatureSets to list

The Spatial Dataframes are converted to FeatureSet elements and then added to a list. The list is used to store the values for the next step, the creation of features using a feature layer collection.

dflist = []
featureSetPoint = spatialDataFramePoint.to_featureset()
featureSetPolyLine = spatialDataFramePolyLine.to_featureset()
dflist.append(featureSetPoint)
dflist.append(featureSetPolyLine)

Step 9: Create features and add them to feature layer collection

The actual feature creation is performed in this step. We need to loop through our feature layer collection using a counter to add new features.

To improve readability and structure we create the function add_features, which performs the additions of features for each layer. The input values for the function are the current layer object and the current set of features. We define a variable result, which we set to the output of the edit function layer.edit_features of the given layer. As argument for the function layer.edit_features, we set (adds = featlist). The variable featlist matches our current set of features. We then return the result of our editing. The function add_features is called inside the for loop

for i in range(len(newFtLC.layers)):


were we loop through the feature layer collection by counter. The output of the function call is set to the variable status, which is then printed to the console.

The console output shows us, if our layer operation was successful. If this is the case, we will see two times an output containing: 'success': True.

def add_features(layer, featlist):
     result = layer.edit_features(adds = featlist)
     return result

for i in range(len(newFtLC.layers)):
     status = add_features(newFtLC.layers[i],
     dflist[i])
     print (status)

Step 10: Inspect results on ArcGIS Online

We created a sample feature service containing two different layers with two different layer types. To check if everything was created and all of the items work, we open another web browser window or tab and go to our portal. There should be an item in the list of items named “featureservice” if we click on the “content”  tab. We can now click on the item and inspect it, there should be values in the attribute table and one point in the point layer as well as one polyline in the polyline layer when regarding the features inside the layers. When we add the feature service to a map we should see a result like this:

The results

Conclusion

Setting up a feature service with multiple layers can be performed fast and efficiently using ArcGIS API for Python. There is no need to publish services from ArcGIS for Desktop, datasets can be easily published to ArcGIS Enterprise or ArcGIS Online using a few lines of python code. Though it is cool to publish a feature service with multiple layers in ten steps, it would be great if there was a function available, which makes the effort to publish multiple layers in one single feature service smaller and allows setting up a service and the creating layers and features within only a few steps. If you have any questions or comments please feel free to contact me or leave a comment in the comment section below.

 

Happy coding, Lukas

I like to explore the city via public transport and as I am a big map fan, I fell in love with the map of our Berlin based public transport service provider BVG. The map is a great product and has so many levels of information. It has a well know style established in Berlin so I wanted to use it in my own web mapping application.

As I scanned the website of the BVG I noticed the leaflet map on their page:

So I asked the question: "Where does the tiles came from". A short look in the network developer pane in firefox revealed the address https://fahrinfo.bvg.de/tiles/base/15/17605/22019.png  (example)

The Tiles can be easily added inside a ArcGIS Javascript API based webmap:

var tiledLayer = new WebTileLayer({
     urlTemplate: "https://fahrinfo.bvg.de/tiles/base/{level}/{col}/{row}.png",
     title: "BVG Basemap",
     copyright:            
          "Map Data by <a href='https://Bvg.de'>BVG</a>, " +
          "Imagery by <a href='https://Bvg.de/'>BVG</a>"
});

But as soon you embed this, you will notice: There are only 404s send back from the BVG server. So I examined the URL-schema and found out, that the Y id is somewhat different compared to mapbox or OSM Y ids for the same tile:

y-tile: BVGy-tile: MapboxzoomLevel
220201074715
220151075215
220131075415
11007537614
440252151016
440262150916

So the tile indices are somehow shifted compared to the normal schema... So let us reverse engineer the conversion. First approach: plot the IDs on a chart and try some regression:

But as you can see: the line looks straight but the equation is just ****. Let's zoom in a bit:

This is of course a bit different: the regression line flipped and we do have no residuals. The summand looks very common as it is near a power of 2. to be exact: 2^15-1

So there is a direct equation to transform the original tile row into a BVG tile row:

var rownew = -1*row+Math.pow(2,level)-1;

So now we need to import this logic into the method ArcGIS uses to get the tiles. And BAMM: here are the tiles:

var tiledLayer = new WebTileLayer({
     urlTemplate: "https://fahrinfo.bvg.de/tiles/base/{level}/{col}/{row}.png",
     title: "BVG Basemap",
     getTileUrl: function (level, row, col) {
          var rownew = -1*row+Math.pow(2,level)-1;
          return this.urlTemplate.replace("{level}", level).replace("{col}", col).replace("{row}", rownew);
     },
     copyright:            
          "Map Data by <a href='https://Bvg.de'>BVG</a>, " +
          "Imagery by <a href='https://Bvg.de/'>BVG</a>"
});

Explore the webmap on CodePen, or download it below.

And last but not least: You can even rotate it:

In the end: If you know the math, you can change the world ;-)

Introduction

Esri Deutschland developed a python tool based on ArcGIS API for Python to manage licenses and Named User in ArcGIS  and ArcGIS Enterprise. The tool is named ArcGIS Python package for user administration (ArcGIS admin toolbox). Information on this tool can be found in a blog on GIS IQ (in german language). While optimizing, several pitfalls and common reasons for major errors in user administration tasks and license assignment could be identified. Problems occur, when programmers do not notice, that some items do not exist at a certain point or for certain users or some items are assigned to users, which then prevents functions from completion. The most common identified pitfalls in administration tasks and license assignment are presented below.

 

1. Deleting User

 

Deleting Named User fails if a user has one or more licenses assigned, to ensure deleting works without any problem, programmers are reminded to always revoke licenses before deleting users. Exceptions should always be handled correctly, exceptions invisible to the user may also prevent scripts from working correctly. Sometimes missing attributes like biography-description-texts can lead to malfunctioning of scripts, it is always suggested to use if-else-queries to prevent accessing attributes, which are missing.

Missing biography-description-text causes delete to fail

 

Deleting Named User from ArcGIS  can be safely performed if the user:

 

  • Has no licenses assigned
  • Missing properties (e.g. biography-description-text) for users are properly handled
  • Unimportant exceptions are properly handled

 

2. Assigning Licenses

 

Assigning licenses to Named User fails if users are not entitled to use the requested license. If licenses are not available in the user’s organization, but are hard-coded and therefore required for every user, a exception may be raised if licenses are not available in some organizations. Invalid licenses as well as a missing count of licenses also prevent programs from running correctly. If-else-queries help to avoid running into problems and notify the user of invalid arguments. Exceptions should always be handled correctly, exceptions invisible to the user may also prevent scripts from working correctly.

If-queries to inform users on invalid arguments or properly handle list and string objects

 

Assigning Licenses to users in ArcGIS  works flawlessly if:

 

  • The user has the rights and is entitled for the requested license
  • The requested license is available for the user’s organization
  • The requested license is a valid license
  • Enough licenses are available
  • Unimportant exceptions are properly handled

 

3. Revoking Licenses

 

Misspelling or non-existence of licenses or Named User is also a common cause for errors. Revoking licenses will fail if a requested user, whose license should be revoked is misspelled or does not exist. License being revoked from users must be previously assigned to the user. 

 

Revoking Licenses from users in ArcGIS  works flawlessly if:

 

  • The requested user exists
  • The requested license to revoke has been assigned to the user
  • The requested license to revoke is a valid license
  • Unimportant exceptions are properly handled

 

Conclusion

 

ArcGIS API for Python provides several functions for user administration, license assignment and revoking of licenses. There are several ways of accessing these functions and use them in scripts. It is up to the programmer to implement tasks and workflows properly. Beginners should note, that the API requires at least basic know-how on programming tasks and procedures and does not check if users that should be deleted, have licenses assigned. The programmer should be aware, that non-revoked licenses may cause deleting tasks to fail. Though there are a few things to notice, it is great to have many opportunities to do user administration tasks in python with the ArcGIS API for Python. If you have any questions or comments please feel free to contact me or leave a comment in the comment section below.

Mit Web AppBuilder for ArcGIS können fokussierte 2D und 3D Web-Apps mithilfe von vielen konfigurierbaren, ready-to-use Widgets und Designs erstellt werden. Mit der Developer Edition des Web AppBuilders ist es möglich, bestehenden Widgets und Designs zu erweitern oder auch vollständig eigene zu erstellen.

 

Swipe Widget

Swipe Widget

 

Die neue Version 2.9 hat nun den gleichen funktionalen Stand wie der eingebettete Web AppBuilder in ArcGIS  vom Juni 2018 Update. Es wurden gut 15 Widgets erweitert, z.B.:

 

  • Messen von Flächen in 3D-Scenes
  • Feinere Filteroptionen
  • Vergleichen unterschiedlicher Layer mit dem Swipe Widget
  • Editieren von Features mit n:m Beziehung
  • Cost Analysis Widget ist nicht mehr in Beta
  • Uvm.

 

Vollständige Infos dazu stehen im Esri Inc. Blog oder im What's New auf dem ArcGIS Developer Portal.

Seit Anfang Juli 2018 steht das neue ArcGIS Runtime Major Release Version 100.3 zur Verfügung. ArcGIS Runtime ist eine Familie aus mehreren SDKs zum Entwickeln nativer Geo-Apps für alle relevanten Plattformen. Das Update ist beschrieben als Phase 1 der vollständigen, echten Unterstützung von 3D Web GIS durch alle APIs hinweg. Neben Bugfixes, Performanceverbesserungen und plattformspezifischen Änderungen (z.B. Nutzen des .NET Standard 2.0 im .NET SDK) gibt es neue und erweiterte Funktionalität. Hier eine Auswahl:

 

Unterstützung von 3D Web Scenes


In ArcGIS ist eine Web Map die Beschreibung einer vollständig konfigurierten 2D Karte. Web Scenes dagegen ist das Äquivalent für Karten in 3D. Diese können nun in ArcGIS Runtime werden. 3D Objekte in Scenes können identifiziert und selektiert, und deren Darstellung durch Ändern des Renderers der Scene angepasst werden.


Des Weiteren wird nun das interaktive Messen in 3d Scenes unterstützt und die Sichtbarkeitsanalyse (Viewshed) wurde verbessert (nun 360 Grad).

 

3D Web Scene

 

 

Weiter Highlights:

 

  • WMS Support wurde erweitert, so können z.B. nun Inhalte nach Zeit gefiltert und die Darstellung der Layer durch verfügbare Styles geändert werden.
  • Labeling wurde verbessert
  • Für militärische Symbole wurde die App-6(B) und App-6(D) Spezifikation hinzugefügt
  • Viele neue Samples für alle SDKs
  • uvm.

 

Ausführliche Informationen zu allen Neuerungen in ArcGIS Runtime 100.2.1 findet Ihr in diesem News Blog von Esri Inc. und in den Release Notes der verschiedenen SDKs auf dem ArcGIS for Developers Portal.

Ab sofort stehen allen Entwicklern die neuen Versionen der ArcGIS API for JavaScript zur Verfügung. In den Updates der Version 4.8 sowie 3.25 wurden wieder viele Verbesserungen vorgenommen und einige neue Features hinzugefügt. Unter anderem:

 

Heatmap Renderer

 

Underground navigation in global scenes

 

3.25 Relationship Renderer

 

Alle Neuerungen werden in diesem Blog-Post detailliert vorgestellt:

ArcGIS API for JavaScript versions 4.8 and 3.25 released 

 

Mehr dazu zeigen auch die neusten Beispielcodes:

3.25 Latest Samples

4.8 Latest Samples

 

und die Release Notes:

3.25 Release Notes

4.8 Release Notes

 

Zu den Unterschieden zwischen den beiden Versionen 3.25 und 4.8 und dazu, welche Version in welchem Anwendungsfall zu bevorzugen ist, gibt die aktualisierte FAQ einige gute Hinweise: 
Choose between version 3.25 and 4.8

 

Happy coding!

Blog filtern

Nach Datum: Nach Tag: