|
POST
|
Hey Worth, To help us narrow this down… Could you print the entire Error you get back (beyond just the localizedDescription). The additionalMessage might give us some more insight. Could you confirm that all the basemaps you're talking about above are raster? Or is "Streets" the vector tile basemap? What about Topographic? Remember the Topographic Vector with relief actually uses a raster hillshade for the relief. Ignoring the test web app, we wonder if you're OK with vector tiles (Streets) but hitting raster limits with the other two. You could set AGSRequestConfiguration.global().debugLogRequests and debugLogResponses to true and let me know what you get for the request that's sent out. You could try the AGSExportTileCacheTask.estimateTileCacheSizeJobWithParameters() and execute that job from your app to see if it matches the web app and gives sensible values in the EstimateTileCacheResult. Feel free to DM me with info if you like. Cheers, Nick. P.S. I also noticed that the TPK Estimator might be failing at its task (technically it's a TPK creator, but the web page has the wrong title )… For a (client-side-calculated) estimate of 7,580 tiles, the service actually came back with 16,093. I will have to look into that. As I mentioned, the estimator is oooooooooold, and it's quite possible that stuff has changed without me noticing and updating it.
... View more
05-29-2019
04:35 AM
|
0
|
0
|
1948
|
|
POST
|
Hey Worth Sparks. We believe we have identified the problem and have a fix. Will be included in 100.6.
... View more
05-28-2019
02:08 PM
|
1
|
0
|
3811
|
|
POST
|
Hi Jorge, In general, Identify is meant to provide feedback to user interaction, so works on visible layers in the map. So, if a layer is in the map and has identify capabilities (as defined on the service), it will be included in the IdentifyLayers operation. You could discard the results for that specific layer from the identifyLayersAsync call (you get an array of IdentifyLayerResult objects back, each of which represents a layer), or you could identify only a subset of layers by calling identifyLayerAsync on each. If you change the visibility, the user might notice that in the map view (but you might get away with it). Note that changing the layer opacity does not affect identify. Hope that helps. Nick.
... View more
05-28-2019
11:10 AM
|
1
|
1
|
999
|
|
POST
|
Hi Worth Sparks, For standard raster tiled basemaps, the OfflineMapTask will map those services appropriately (i.e. if your map uses Streets, the OfflineMapTask will use Streets for Export). The standard basemaps don't even allow for export (scroll down and compare the Supported Operations here (Standard) and here (For Export)). Those tile counts are well within the 150,000 maxExportTilesCount for Streets and Imagery (I haven't checked Topo). IMO it should just work. Based off status.arcgis.com and the date of your post, perhaps you were just bumping into the problems ArcGIS Online was having that day… Are you still having issues? Let me know. If so I can check with the ArcGIS Online team and see what they have to say. Nick P.S. When you're using Vector Tiles, the difference between the Standard and For Export versions is actually in the styles (fewer fonts for export). Both can be exported, so the OfflineMapTask does not map the services as it does for the raster basemaps.
... View more
05-26-2019
02:03 PM
|
0
|
2
|
1948
|
|
POST
|
Hi Reed, This may be a bug in 100.5 which we've fixed for 100.6. I'll check with the team in case there's a specific workaround we can use, but in the meantime are you able to move the AGSMapView.LocationDisplay.start to happen once the AGSMap is loaded? From what I understand, that should work, but I'll be able to check more specifically in a couple of days. Let me know whether that helps. Nick.
... View more
05-26-2019
01:34 PM
|
0
|
1
|
3554
|
|
POST
|
Use the GeometryEngine.DistanceGeodetic method. The result, a GeodeticDistanceResult, includes the azimuths between the two points.
... View more
05-24-2019
08:25 AM
|
0
|
6
|
7778
|
|
POST
|
Cool. Glad to help. Whether the views are defined in storyboard, NIB, or code, there should be a quick strategy to get them at least working (maybe you embed your current hierarchy in a top-level view that you set constraints on, for example).
... View more
05-22-2019
06:14 AM
|
0
|
1
|
3474
|
|
BLOG
|
This is part 3 of a 3 part series on working with Location in your Runtime applications. In parts 1 and 2 we introduced the AGSLocationDisplay and the AGSLocationDataSource and discussed how they work together to display location on your map view as well how to configure location appearance on the map view, and how the map view behaves as the location is updated. We finished off with an understanding of how AGSLocationDataSources are created. In this post we'll create a new location data source that provides realtime location of the International Space Station, and show it in use in a simple application. ISSLocationDataSource There exists a very cool, simple, open source API that provides realtime locations of the International Space Station. You can find out about it here, but put simply you make an HTTP request to http://api.open-notify.org/iss-now.json and get JSON back with the current location. Let's use that API to build a custom AGSLocationDataSource that provides the ISS's current location. We'll call it ISSLocationDataSource. Building the data source Starting with a simple project already linked to the ArcGIS Runtime, let's create a new Swift file named ISSLocationDataSource and define our subclass of AGSLocationDataSource: class ISSLocationDataSource: AGSLocationDataSource {
...
} Now let's implement doStart() and doStop(): class ISSLocationDataSource: AGSLocationDataSource {
override func doStart() {
startRequestingLocationUpdates()
// Let Runtime know we're good to go
didStartOrFailWithError(nil)
}
override func doStop() {
stopRetrievingISSLocationsFromAPI()
// Let Runtime know we're done shutting down
didStop()
}
} Once we've started, we'll hit the API URL every 5 seconds using an NSTimer, and parse the response into an AGSLocation object: ...
private var pollingTimer: Timer?
func startRequestingLocationUpdates() {
// Get ISS positions every 5 seconds (as recommended on the
// API documentation pages):
// http://open-notify.org/Open-Notify-API/ISS-Location-Now/
pollingTimer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true) {
[weak self] _ in
// Request the next ISS location from the API and build an AGSLocation.
self?.requestNextLocation { newISSLocation in
// TO AGSLocationDisplay: new location available.
self?.didUpdate(newISSLocation)
}
}
} Reading the http://api.open-notify.org/iss-now.json URL and turning the JSON response into an AGSLocation happens in requestNextLocation() function which is called every 5 seconds using an NSTimer. Notice the call to didUpdate() on line 13. As discussed in part 2 of this series, that call will pass the new AGSLocation to the AGSLocationDisplay, which in turn will make sure location is updated on the AGSMapView as needed. You can see a full implementation of the entire ISSLocationDataSource class here, including requestNextLocation() and the JSON Decoding logic. Using our custom location data source To use the new custom data source in a map view, we simply set the AGSMapView.locationDisplay.dataSource to an instance of our new class (line 8 below) and start the AGSLocationDisplay: override func viewDidLoad() {
super.viewDidLoad()
// Set the Map.
mapView.map = AGSMap(basemap: AGSBasemap.oceans())
// Use our custom ISS Tracking Location Data Source.
mapView.locationDisplay.dataSource = ISSLocationDataSource()
// Start the AGSMapView's AGSLocationDisplay. This will start the
// custom data source and begin receiving location updates from it.
mapView.locationDisplay.start { (error) in
guard error == nil else {
print("Error starting up location tracking: \(error!.localizedDescription)")
return
}
}
} It's that easy! Now you have a map that shows the live current location of the ISS. Of course, it's a little counter-intuitive to see the blue dot tracking the space station (we've been trained to associate it with our own location), so we use some of the AGSLocationDisplay configuration options to change the symbol to use an icon of the ISS. Find the entire Xcode project here. Additional details about ISSLocationDataSource.requestNextLocation(): We use an AGSRequestOperation to get the JSON response from the API (source code). We create a new AGSOperationQueue that processes 1 operation at a time. This way we don't have duplicate simultaneous calls to the API (source code). For the very first location we obtain, since we don't yet have a heading or velocity, we create an AGSLocation with lastKnown = true (source code) which means it will be displayed differently in the map view (by default a grey dot rather than a blue dot, indicating that we're still acquiring a location). We use AGSGeometryEngine to calculate the velocity of the ISS by comparing the new location with the previous location. There's also a slightly more detailed version with an overview map, reference lat/lon grids, and a path-tracking geometry here. We hope you've enjoyed this series of blog posts. The Location Display and Location Data Sources provide a powerful configurable way to integrate location into your Runtime apps, no matter what source you're using for location.
... View more
05-21-2019
05:31 PM
|
1
|
0
|
2532
|
|
BLOG
|
This is part 2 of a series of 3 blog posts covering Location and the ArcGIS Runtime SDKs. In part 1 we introduced the AGSLocationDisplay which is responsible for working with the AGSMapView to give your app a "blue dot" experience, and we talked about customizing the behavior and appearance of the current location on your map. In this post, we'll talk about the third component of AGSLocationDisplay, which is where that location information comes from: the location data source… Location Data Sources A location data source feeds location updates to the AGSLocationDisplay which in turn takes care of updating the map view according to the configuration options discussed in part 1. It is accessed via the AGSLocationDisplay.dataSource property. The ArcGIS Runtime SDK for iOS comes with a few location data sources out of the box: Data Source Type Purpose AGSCLLocationDataSource Follow your iOS device's built-in Core Location services (the default). AGSSimulatedLocationDataSource Follow a sequence of simulated locations or an AGSPolyline. AGSGPXLocationDataSource Follow the contents of a GPX file. Each of these location data sources inherits from the base AGSLocationDataSource class: By default an AGSLocationDisplay automatically creates and uses an AGSCLLocationDataSource. Just call AGSMapView.locationDisplay.start(completion) to start showing your location (but see the note here about configuring your app according to Apple's requirements for enabling location). Custom Location Data Sources What's neat is that by inheriting from AGSLocationDataSource and implementing a few simple methods, you can create your own custom data source that Runtime integrates with in exactly the same way as the 3 out-of-the-box ones mentioned above (which are themselves built using the pattern we'll discuss). This extensibility is very powerful if you're working with proprietary location technology, such as an external high-accuracy GPS unit, a beacon-based indoor location system, or some other location determining system whose manufacturers provide an API or SDK. Step-by-step, here's how you build out your own custom AGSLocationDataSource: Inherit from AGSLocationDataSource. Implement doStart(). Called by Runtime when the app calls AGSLocationDisplay.start(completion). This must call didStartOrFailWithError() to signal that your source started OK (or failed to start). When you call didStartOrFailWithError() you either pass in nil if your source started OK and is ready to start providing locations, or pass in an Error if it failed to start. Implement doStop(). Called by Runtime when the app calls AGSLocationDisplay.stop(). This must call didStop() to signal that your source stopped OK. That takes care of starting and stopping the data source when instructed to, but you also need to notify Runtime when you get new locations: Call didUpdate(location) whenever you get a new location you need to pass on. You construct an AGSLocation object and call didUpdate(), passing in that location. An AGSLocation combines an AGSPoint with a timestamp. It also includes velocity, heading, accuracy estimates, and whether this location should be considered current or is an old (or "last known") location. Some of these properties are used to determine how the location is displayed in the map view. That's it. With that implemented, you have a functioning Location Data Source. Let's discuss the documentation available to us about this, and how it all fits together. Understanding Location Data Sources First, let's look at the AGSLocationDataSource (ForSubclassEyesOnly) API, described in the reference docs: These methods determine how your custom location data source and the AGSLocationDisplay will communicate. A note on naming: do… Instructions from the AGSLocationDisplay to your custom AGSLocationDataSource begin with "do" (doStart() and doStop()). These indicate an imperative from the location display for your data source to do something. did… Feedback from your data source to the AGSLocationDisplay is done by calling functions that begin with "did" (didUpdateLocation(), didStartOrFailWithError(), didStop() etc.). These indicate feedback from your data source to update the location display (e.g. the state changed, or a new location is available). The "do" methods are expected to exist in your subclass of AGSLocationDataSource, so it's up to you to implement them. The 'did' methods are all inherited from AGSLocationDataSource, so they're already defined for use by your subclass. You don't implement them. You just call them directly. Here's how these methods work together: When an app wants to show location updates (by calling AGSMapView.locationDisplay.start(completion)), the AGSLocationDisplay will call doStart() on its dataSource. The data source initializes itself and calls didStartOrFailWithError(nil) to show it's started OK. It starts providing location updates by calling didUpdate(location) for each location update. When the app wants to stop showing location, it calls AGSMapView.locationDisplay.stop() and the AGSLocationDisplay will call doStop() on its dataSource. The data source calls didStop() and makes sure it doesn't call didUpdate(location) any more. That's it for the theory. In the next blog post, we'll look at creating a custom AGSLocationDataSource from scratch and show it in use in a simple iOS application.
... View more
05-21-2019
05:31 PM
|
0
|
0
|
2316
|
|
BLOG
|
The Blue Dot
Often your app needs to show your location, or a "blue dot", on a map. Maybe it's important to know where you are, or important to know where things are in relation to you. Often that context is critical to the core functionality of the app.
Runtime provides a robust blue dot experience. Out of the box, you simply call start() or stop() and Runtime takes care of talking to your device to get the best available location.
But Runtime takes this functionality further and provides a flexible framework to provide your own location source. Perhaps you need to connect to an external GPS unit or use a proprietary indoor location beacon system.
In this, the first of 3 posts on the topic, we'll take a look at how Runtime presents location in the map view. In part 2 we'll discuss how Runtime gets location updates from various location data sources and cover what it takes to create your own location data source. Finally, in part 3, we'll take what we've learnt so far and build a custom location data source.
Your location in the Runtime
There are 3 Runtime components that work together to put that blue dot on your map: AGSMapView, AGSLocationDisplay, and AGSLocationDataSource
Every AGSMapView has an AGSLocationDisplay. It is responsible for showing and updating the current location on that map view.
You access the AGSLocationDisplay via the AGSMapView.locationDisplay property.
Your app starts and stops tracking location by calling AGSLocationDisplay.start(completion) and AGSLocationDisplay.stop().
Swift Note: Swift translates method names automatically from Objective-C, so while the API doc references, for example, startWithCompletion:(), in Swift it will be written start(completion) and that's the form I'll use in this post.
Various properties on AGSLocationDisplay determine what the location display looks like on the map view (you don't have to use a blue dot if your app needs something else) and how the map view keeps up with the current location.
If you just want to use your device's built-in GPS, that's actually all you need to know. But let's look at some ways to control and configure that location display…
AGSLocationDisplay
There are 3 key aspects of Location Display that you can change.
Behavior: How does the map view update itself as the current location changes.
Appearance: What does the location display look like and how does it change depending on what information is available?
Data Source: Where does the location display get the current location from?
Configuring behaviour
The auto-pan mode changes how the AGSMapView keeps up with location updates, that is, how does the map view move to follow the blue dot around. Set the auto-pan mode using AGSLocationDisplay.autoPanMode.
Mode
Purpose and behavior
Off
This is the default. The blue dot is free to move around your map display (or beyond it) while the map view remains still.
Recenter
The map will follow the blue dot as it moves, based off the AGSLocationDisplay.wanderExtentFactor, a number between 0 and 1:
0 means the map view will constantly recenter on the blue dot.
1 means the map view will recenter when the blue dot reaches the edge of the map view.
The default is 0.5, which allows a bit of movement before the map view recenters.
Navigation
Good for driving. The map view updates for the current location, but orients to the direction of motion. Use the AGSLocationDisplay.navigationPointHeightFactor property to determine how far from the bottom of the display the location will be anchored.
Compass Navigation
Good for walking. The map view updates for the current location, but orients to the direction the device is pointing.
When you manipulate the map view's area of interest either programmatically or by panning/zooming it, the auto-pan mode will be reset to off. You can monitor for changes to the auto-pan mode with the AGSLocationDisplay.autoPanModeChangeHandler.
When you switch on auto-pan (i.e. it was off, but you set it to one of the other values), the map view will pan and zoom to the next location update. You can control the scale level for this pan and zoom with AGSLocationDisplay.initialZoomScale.
In most use cases, fixing the zoom like this is sensible behavior, but if you want to just recenter without zooming the map, simply set the initialZoomScale to the current AGSMapView.mapScale before you set the autoPanMode.
Configuring appearance
By default the location symbol will be a blue dot. It's augmented with a few visual aids to indicate accuracy, direction of motion (course), direction the device is pointing (heading) and whether locations are being updated (a "ping"). See these properties on AGSLocationDisplay for more details:
The Location…
Gathering the Location…
defaultSymbol
courseSymbol
headingSymbol
accuracySymbol
acquiringSymbol
pingAnimationSymbol
You control whether to use the courseSymbol when movement is detected with the AGSLocationDisplay.useCourseSymbolOnMovement property.
Lastly, if you don't want a visual indication that a new location was received, you can set AGSLocationDisplay.showPingAnimation to false.
Location Data Source
One other important configurable item on AGSLocationDisplay is the location data source. We'll look at that part 2 when I'll cover how data sources work, and in part 3 we'll create our own custom data source.
... View more
05-21-2019
05:31 PM
|
2
|
0
|
3535
|
|
POST
|
Hi. Having tested a bit, I think that must be it. Make sure that your custom view either can unambiguously determine its width and height from constraints, or set a top-level width constraint and height constraint. See the attached project. It's a simple custom view with a button and some constraints. If I remove constraints so that the containing view can't size itself properly, then I still see the button but it doesn't capture taps.
... View more
05-21-2019
02:17 PM
|
0
|
3
|
3474
|
|
POST
|
Hmm. I'll try to reproduce this later today. If you have a simple repro case to share, please DM me.
... View more
05-21-2019
09:11 AM
|
0
|
4
|
3474
|
|
POST
|
There was a change made at 100.5 requiring that the custom view provide an intrinsic content size, or have enough constraints to size itself (see the release notes😞 A callout with a custom view now uses AutoLayout to size itself to fit that view. A custom view will need to either provide an intrinsic content size or have enough constraints to define it's size. Previously the size of the view's frame was used to size the callout. For views without an intrinsic content size, that same behavior can still be achieved by adding width and height constraints to the view. I wonder if that's what's happening here?
... View more
05-21-2019
08:30 AM
|
0
|
6
|
3474
|
|
POST
|
Hey Kirk. Granted I'm not familiar with the Local Server samples (I'm an iOS Runtime kind of guy and we don't have Local Server) so I could be mistaken, but it looks like a bug in the sample, tbh. I imagine the sample is opening a shapefile, and you picked one with polygons in it. If you try to render a polygon class with a line symbol, you'll likely not see what you want. See this sample which is rendering the same Subdivisions shapefile, albeit without Local Server in the mix. But again, I could be wrong. Do try setting up the _shapefileSublayer.Renderer with a polygon symbol as per the other sample and see if that works. But it looks like either the sample or the SDK is broken. Nick.
... View more
05-20-2019
02:56 PM
|
0
|
0
|
2047
|
|
POST
|
A Feature is a GeoElement, so you can use AGSPopup.popupWithGeoElement(). I believe this may be smart enough to look at the Feature's source table to derive its PopupDefinition, but if not you can read that from the feature table directly using AGSArcGISFeatureTable.popupDefinition, or from the layer in AGSFeatureLayer.popupDefinition, and pass that into AGSPopup.popupWithGeoElement:PopupDefinition(). Note you can get to the featureTable from the feature using the featureTable property. If you just want to display the popup, you can use the AGSPopupsViewController. This sample might help too.
... View more
05-20-2019
12:55 PM
|
0
|
1
|
2129
|
| Title | Kudos | Posted |
|---|---|---|
| 2 | 05-14-2026 07:07 AM | |
| 2 | 04-30-2026 10:59 AM | |
| 4 | 04-22-2026 08:07 AM | |
| 1 | 01-29-2026 09:39 AM | |
| 1 | 12-17-2025 10:12 AM |