The Applications Prototype Lab at ESRI have created a few proof-of-concepts for the Surface using the ArcGIS API for WPF.  Examples of which can be seen here and here.

Surface applications are essentially WPF applications running in full screen mode.  When a user interacts with an application on a Surface device is not through the standard mouse API but through a specific Surface API.  The code below describes how to Surface-enable the map control that comes with the ArcGIS API for WPF.  This is just a basic implementation and should be treated as a developer sample rather than anything official.

SurfaceMap.xaml

After installing the Microsoft Surface SDK 1.0 (or 1.1) you will see a few extra items in the new projects dialog of Microsoft Visual Studio 2008.  Select Surface Application, add a reference to the ArcGIS API for WPF assemblies and then add a new resource file called SurfaceMap.xaml.  Ensure that the build action is set to page.

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:local="clr-namespace:ESRI.PrototypeLab.Surface.Ccm"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:s="http://schemas.microsoft.com/surface/2008"
    xmlns:esri="clr-namespace:ESRI.ArcGIS.Client;assembly=ESRI.ArcGIS.Client"
    >
    <Style TargetType="{x:Type local:SurfaceMap}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:SurfaceMap}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            Width="{TemplateBinding Width}"
                            Height="{TemplateBinding Height}"
                            >
                        <esri:Map Name="PART_map" PanDuration="0" ZoomDuration="0" />
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

App.xaml

Next you need to inform the compiler to load SurfaceMap.xaml as a resource.  To do so, add an entry to the App.xaml file as shown below.

<Application x:Class="ESRI.PrototypeLab.Surface.Ccm.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="SurfaceWindow1.xaml"
    >
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="...generic.xaml"/>
                <ResourceDictionary Source="/ESRI.PrototypeLab.Surface.Ccm;component/SurfaceMap.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

SurfaceMap.cs

Add a new code file called SurfaceMap.cs and make sure that the build action is set to compile.  The code below contains the bulk of the logic to interpret contact (i.e. finger) manipulation.  The two key points to note is the manipulation processor and the inertia processor.  The manipulation processor will raise events when users manipulate performs a panning or zooming action.  The inertia processor is used to continue panning if the user flicks map.

using System;
using System.Windows;
using System.Windows.Input;
using ESRI.ArcGIS.Client;
using ESRI.ArcGIS.Client.Geometry;
using Microsoft.Surface.Presentation;
using Microsoft.Surface.Presentation.Controls;
using Microsoft.Surface.Presentation.Manipulations;
using Microsoft.Surface;

namespace ESRI.PrototypeLab.Surface.Ccm {
    public partial class SurfaceMap : SurfaceUserControl {
        private Map m_map = null;
        private Affine2DManipulationProcessor m_manipulationProcessor = null;
        private Affine2DInertiaProcessor m_inertiaProcessorMove = null;
        static SurfaceMap() {
            FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(SurfaceMap),
new FrameworkPropertyMetadata(typeof(SurfaceMap))); } public SurfaceMap() : base() { // Define manipulation processor used or panning and Zooming this.m_manipulationProcessor = new Affine2DManipulationProcessor( Affine2DManipulations.TranslateX | Affine2DManipulations.TranslateY | Affine2DManipulations.Scale, this, true); this.m_manipulationProcessor.Affine2DManipulationStarted +=
new EventHandler<Affine2DOperationStartedEventArgs>
(this.ManipulationProcessor_Affine2DManipulationStarted); this.m_manipulationProcessor.Affine2DManipulationDelta +=
new EventHandler<Affine2DOperationDeltaEventArgs>
(this.ManipulationProcessor_Affine2DManipulationDelta); this.m_manipulationProcessor.Affine2DManipulationCompleted +=
new EventHandler<Affine2DOperationCompletedEventArgs>
(this.ManipulationProcessor_Affine2DManipulationCompleted); // Define inertia proceesor for panning this.m_inertiaProcessorMove = new Affine2DInertiaProcessor(); this.m_inertiaProcessorMove.Affine2DInertiaDelta +=
new EventHandler<Affine2DOperationDeltaEventArgs>
(this.InertiaProcessorMove_Affine2DInertiaDelta); this.m_inertiaProcessorMove.Affine2DInertiaCompleted +=
new EventHandler<Affine2DOperationCompletedEventArgs>
(this.InertiaProcessorMove_Affine2DInertiaCompleted); } public override void OnApplyTemplate() { base.OnApplyTemplate(); this.m_map = (Map)this.Template.FindName("PART_map", this); } public Map Map { get { return this.m_map; } set { this.m_map = value; } } protected override void OnContactDown(ContactEventArgs e) { base.OnContactDown(e); if (!e.Contact.IsFingerRecognized) { return; } e.Contact.Capture(this, CaptureMode.SubTree); this.m_manipulationProcessor.BeginTrack(e.Contact); e.Handled = true; } protected override void OnContactChanged(ContactEventArgs e) { base.OnContactChanged(e); if (!e.Contact.IsFingerRecognized) { return; } Point position = e.Contact.GetPosition(this); if (position.X < 0 || position.Y < 0 || position.X > this.ActualWidth || position.Y > this.ActualHeight) { e.Contact.Capture(this, CaptureMode.None); e.Handled = true; return; } e.Contact.Capture(this, CaptureMode.SubTree); this.m_manipulationProcessor.BeginTrack(e.Contact); e.Handled = true; } protected override void OnContactUp(ContactEventArgs e) { base.OnContactUp(e); if (!e.Contact.IsFingerRecognized) { return; } e.Contact.Capture(this, CaptureMode.None); } private void ManipulationProcessor_Affine2DManipulationStarted(
object sender, Affine2DOperationStartedEventArgs e) { if (this.m_inertiaProcessorMove.IsRunning) { this.m_inertiaProcessorMove.End(); } } private void ManipulationProcessor_Affine2DManipulationDelta(
object sender, Affine2DOperationDeltaEventArgs e) { if (this.m_map == null) { return; } if (this.m_map.Extent == null) { return; } if ((e.Delta.X == 0) && (e.Delta.Y == 0) && (e.ScaleDelta == 0)) { return; } if ((e.Delta.X != 0) || (e.Delta.Y != 0)) { MapPoint center = this.m_map.Extent.GetCenter(); Point screen = this.m_map.MapToScreen(center); Point newScreen; switch(ApplicationLauncher.Orientation){ case UserOrientation.Top: // Surface is upside-down newScreen = Point.Add(screen, e.Delta); break; case UserOrientation.Bottom: // Surface has normal orientation newScreen = Point.Subtract(screen, e.Delta); break; default: return; } MapPoint newCenter = this.m_map.ScreenToMap(newScreen); this.m_map.PanTo(newCenter); Window w = SurfaceWindow.GetWindow(this); } if (e.ScaleDelta != 0) { if (Contacts.GetContactsCaptured(this).Count > 1) { this.m_map.ZoomToResolution(this.m_map.Resolution / e.ScaleDelta); } } } private void ManipulationProcessor_Affine2DManipulationCompleted(
object sender, Affine2DOperationCompletedEventArgs e) { this.m_inertiaProcessorMove.InitialOrigin = new Point(0, 0); this.m_inertiaProcessorMove.InitialVelocity = e.Velocity * 10; this.m_inertiaProcessorMove.DesiredDeceleration = 0.005; this.m_inertiaProcessorMove.Begin(); } private void InertiaProcessorMove_Affine2DInertiaDelta(
object sender, Affine2DOperationDeltaEventArgs e) { if ((e.Velocity.X == 0) && (e.Velocity.Y == 0)) { return; } MapPoint center = this.m_map.Extent.GetCenter(); Point screen = this.m_map.MapToScreen(center); Point newScreen; switch (ApplicationLauncher.Orientation) { case UserOrientation.Top: // Surface is upside-down newScreen = Point.Add(screen, e.Velocity); break; case UserOrientation.Bottom: // Surface has normal orientation newScreen = Point.Subtract(screen, e.Velocity); break; default: return; } MapPoint newCenter = this.m_map.ScreenToMap(newScreen); this.m_map.PanTo(newCenter); } private void InertiaProcessorMove_Affine2DInertiaCompleted(
object sender, Affine2DOperationCompletedEventArgs e) { } } }

SurfaceWindow1.xaml

The snippet below demonstrates how to add a reference to the SurfaceMap defined in the snippets above.

<s:SurfaceWindow
    x:Class="ESRI.PrototypeLab.Surface.Ccm.SurfaceWindow1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:s="http://schemas.microsoft.com/surface/2008"
    xmlns:local="clr-namespace:ESRI.PrototypeLab.Surface.Ccm"
    Title="my Title"
    Height="768"
    Width="1024"
    Loaded="SurfaceWindow_Loaded"
    >
    <Grid>
        <local:SurfaceMap x:Name="surfaceMap" />
    </Grid>
</s:SurfaceWindow>

 

SurfaceWindow1.xaml.cs (code behind)

In the code-behind of the Surface window, the map extent is defined and the ArcGIS Online world street map layer is added.

private void SurfaceWindow_Loaded(object sender, RoutedEventArgs e) {
    // Add the ArcGIS Online street map
    ArcGISTiledMapServiceLayer streets = new ArcGISTiledMapServiceLayer() {
        ID = "street",
        Url = "http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer",
        Opacity = 1
    };
    this.surfaceMap.Map.Extent = new Envelope(-116.992383, 33.126732, -116.560400, 32.797143);
    this.surfaceMap.Map.Layers.Add(streets);

    // Listen to map events
    this.surfaceMap.Map.ExtentChanging += new EventHandler<ExtentEventArgs>(this.Map_ExtentChanging);
    this.surfaceMap.Map.ExtentChanged += new EventHandler<ExtentEventArgs>(this.Map_ExtentChanged);
}

This concludes this tutorial on adding Surface support to the ArcGIS API for WPF map control. For more information, please visit the ArcGIS API for Silverlight/WPF home page, support forum and resource center.


Yesterday the Applications Prototype Lab at ESRI released demonstration videos of two Microsoft Surface applications.  The first was a demonstration of a simulated police dispatcher (announced here) and the second is a cross country mobility application discussed in this post.

This Surface application is built with ESRI’s ArcGIS API for WPF and references map and geoprocessing services from ArcGIS Server.  Cross country mobility is the name giving to an exercise of determining the most efficient path between two locations.  Depending on the data (and parameters) the end user can find a route that is the fastest, shortest, most fuel efficient, avoids urban areas, flattest or any other condition.

The first step illustrated in the video is the rating of three geographic layers: slope, vegetation and transportation.  The user can assign a preference to weight one more than others.  For example, slope could be a larger consideration if moving heavy equipment than the vegetation type.  Secondly, items within each layer can also be rated.  For example, the user can indicate that low slope is preferable to steep slopes and that grades great than 40° are “no go” (or impossible to traverse).

The next step is to indicate the intended target location for the three flagged vehicles/people/units.  In the demonstration video the target is represented by a bulls eye button than can dragged into position.

After the three geographic layer have been rated and the target placed into position, a request is sent to ArcGIS Server to perform a weighted overlay using the user defined parameters.  The result is a new geographic layer called a cost surface.  A cost surface is like an image where each pixel contains a cost value, that is, the cost for an object to traverse it.

The next step, uses the cost surface to find the least cost path from the three flagged objects to the target.

The final step is the creation of a cost corridor.  A cost corridor is an area around the least cost path with a plus or minus one, two and three percent variation.  Basically, what alternative path could the three flagged objects take by sacrificing one to three percent cost (in time, money, fuel etc).

This is a very brief discussion of one of many geoprocessing capabilities in the ArcGIS product suite.  I would encourage you to explore this exciting technology at the ESRI website.


In May 2009, the Applications Prototype Lab published a web application called “Police Dispatcher”.  The application simulated a police dispatch system with real time incidents and the tracking of police vehicles.  The application was built using Silverlight 2 and the ArcGIS API for Silverlight.

Police Dispatcher for Microsoft Silverlight

The police dispatcher demonstration was recently ported to the Microsoft Surface as a Surface application.  Surface applications are similar to standard WPF application except that they target the Surface hardware and include references to a few extra libraries.  The transition was relatively trivial, for example, the application references the ArcGIS API for WPF rather than the ArcGIS API for Silverlight.

In the Surface application we took advantage of some the goodness of WPF such as drop shadows and glow bitmap effects.


Don’t beg like NPR…unless you’re NPR

Last week, my local public radio station (KCFR) was holding its annual pledge drive. I love NPR and local public radio and always give to support it. But, it’s kind of annoying when they spend an entire week asking for pledges, making me feel guilty if I don’t give, and worst of all, providing just [...] Related posts:
  1. Releasing buggy software intentionally
  2. Agile marketing?

I am sad and tired. First ground rule to this post – do not write “keep it up” or “you gotta be positive” or any of that nonsense in my comments. I know all of that already and you telling me that either makes me feel inadequate or annoyed. So let’s save us all the [...]

Facebook Username’s are Live! What’s yours?

Well, it’s official now, Facebook usernames are live and doing well. In a wild frenzy to grab their custom vanity URL’s, Facebook users created over 200,000 custom user names in the first 3 minutes of Saturday morning (and yup, I was one them too). After 15 minutes, Facebook reported over 500,000 new user names. One [...] Related posts:
  1. Retrospectives: You live, you learn

Enough with Bad Auto DM’s Already

OK, maybe this is going to sound cranky, and I’ve talked about it before, but if you’re on Twitter I’m begging you to please, please, please stop sending out bad automatic direct messages to everyone who follows you. I’ve already followed you, and now we’re following each other and I really, sincerely appreciate the fact [...] Related posts:
  1. Where 2.0: Online videos of Where 2.0 talks

PET scan done (aka Cancer has a sugar addiction)

Today I had the PET scan. The basic idea is that I fast and then they inject me with radioactive sugar. I take a nap for 45 minutes, wake up, lie on a big spinning magnet for a half hour and then they take some images. Since cancer cells LOVE sugar they tend to stand [...]

So here it is – I have cancer

More specifically – I have B-Cell Lymphoma. Met my oncologist on Thursday last week and he, Dr. Derrick Wong, is awesome. He tolerates me well, extracts bone marrow in record time and has a great sense of humor. For the record, having bone marrow taken out hurts more than skinning your knee but less that root [...]

Social Media Marketers: Please take your tongue out of my mouth!

How many emails have you received that start this way: “Hello, My name is Van Curtis. I work as an international auditor for the Delta Lloyd Bank (ALM) Asset Liability Managerial department monitoring five branches including Singapore, Belgium and Netherlands. I have taken pains to find your contact through personal endeavors which I may explain [...] Related posts:
  1. Social Media and Your Business
  2. The power of social media and word of mouth
  3. What the F**k is Social Media?
  4. Enough with Bad Auto DM’s Already

What the F**k is Social Media?

Wow! Bet that title got your attention. It got mine too! It’s actually the title of a great presentation I stumbled across on SlideShare this weekend from Marta Kagan. Marta is the Managing Director at Espresso and she’s also the author of a great blog The Secret Diary of a Bonafide Marketing Genius. Dropping the [...] Related posts:
  1. Social Media and Your Business
  2. Social Media Marketers: Please take your tongue out of my mouth!
  3. The power of social media and word of mouth

Applied Spatial Databases Presentation Slide Deck

I recently put together a presentation for a graduate database class on the topic of Applied Spatial Databases.  Thought I’d make the presentation available to anyone who might get some use out of it.

Developing with ArcObjects on Windows 64-bit OS

Just a week into running on my new development box, Windows Server 2008 64, and everything had been smooth… until this bump in the road. While writing a utility COM component to extend ArcGIS Server, I ran into a serious gotcha. The issue actually was exposed while I was writing/running unit tests. Spinning up any [...]

Google Earth 5.0 Released

Google Earth 5.0 was released today with some excellent new features. Obviously Google Ocean is the most impressive but there are also many changes to KML spec as well. Actually, not the official KML spec that is under OGC guidance, but a *new* XML namespace that extends the OGC one.

The “gx” namespace contains several new tags that focus on the undersea functionality (gx:altitudeMode), the historical imagery (gx:timeStamp) and the new Touring engine in GE5 (gx:Tour, gx:flyTo, gx:AnimatedUpdate etc). Going forward, this is undoubtedly how they will sidestep OGC when they need to add new visualization functionality to GE in, shall we say, a timely manner.

We updated Arc2Earth to take advantage of some of these new features so if you are a current 2.0+ user, feel free to download the latest version. Here are some quick examples:

Gulf of Mexico – Oil/Gas Pipelines and Wells Demo – shows clamping to the seafloor and a new Arc2Earth feature to use 3D models in place of points when exporting - KMZ Link

 Larger Image

 Larger Image

Galapagos Bathymetry – KML Vector Regions of underwater contour lines around the Galapagos Islands - KMZ Link

  Larger Image

I’ll have more info in the future on some cool Tour exports as well

Listening To: Acoustique Parfum - Drowning Sun Part 2 (Guardner's Mix)


The files listed here should be included in the geoprocessing help for geog. transformations. So if you are out there doing a projection from NAD27 to WGS84 and you don’t know which of the 11 or so different transformations to pick please come back to this link to find the link to the help page [...]

Ok before I start this post some warnings 1. My pottty mouth is ramping up so if you are offended by those types of words please be careful or stop reading now 2. I am going to be really frank about my cancer  – I have it and by writing about it here it is another small [...]

The PropertyGrid control is convenient for adding object editing support with minimal code.  However, for some reason it does not support property navigation with the tab key.  Instead, clicking tab key will progressively set focus to other controls in your form.  This post provides a simple subclassed PropertyGrid with support for tab-key navigation of properties.

image

Below is the source code to a subclassed PropertyGrid control called TabbedPropertyGrid.  There were two major issues that needed to be overcome.  The first is that the PropertyGrid does not raise any keyboard events, to workaround this the subclassed PropertyGrid must hijack keyboard events from the parent form.  The second issue is that there is no intuitive way to navigate GridItems.  However, this MSDN forum thread provided a few clues to solve this using the Griditems and Parent property.

public class TabbedPropertyGrid : PropertyGrid {
    public TabbedPropertyGrid() : base() { }
    public void SetParent(Form form) {
        // Catch null arguments
        if (form == null) {
            throw new ArgumentNullException("form");
        }

        // Set this property to intercept all events
        form.KeyPreview = true;

        // Listen for keydown event
        form.KeyDown += new KeyEventHandler(this.Form_KeyDown);
    }
    private void Form_KeyDown(object sender, KeyEventArgs e) {
        // Exit if cursor not in control
        if (!this.RectangleToScreen(this.ClientRectangle).Contains(Cursor.Position)) {
            return;
        }

        // Handle tab key
        if (e.KeyCode != Keys.Tab) { return; }
        e.Handled = true;
        e.SuppressKeyPress = true;

        // Get selected griditem
        GridItem gridItem = this.SelectedGridItem;
        if (gridItem == null) { return; }

        // Create a collection all visible child griditems in propertygrid
        GridItem root = gridItem;
        while (root.GridItemType != GridItemType.Root) {
            root = root.Parent;
        }
        List<GridItem> gridItems = new List<GridItem>();
        this.FindItems(root, gridItems);

        // Get position of selected griditem in collection
        int index = gridItems.IndexOf(gridItem);

        // Select next griditem in collection
        this.SelectedGridItem = gridItems[++index];
    }
    private void FindItems(GridItem item, List<GridItem> gridItems) {
        switch (item.GridItemType) {
            case GridItemType.Root:
            case GridItemType.Category:
                foreach (GridItem i in item.GridItems) {
                    this.FindItems(i, gridItems);
                }
                break;
            case GridItemType.Property:
                gridItems.Add(item);
                if (item.Expanded) {
                    foreach (GridItem i in item.GridItems) {
                        this.FindItems(i, gridItems);
                    }
                }
                break;
            case GridItemType.ArrayValue:
                break;
        }
    }
}

After adding the TabbedPropertyGrid to your form, the form must be parsed into the control using the SetParent method.

public partial class Form1 : Form {
    public Form1() {
        InitializeComponent();

        // Assign the form to the propertygrid
        this.tabbedPropertyGrid1.SetParent(this);
        this.tabbedPropertyGrid1.SelectedObject = this;
    }
}

Known Issues:  Shift-Tab does not select properties in reverse order.

Technorati Tags: ,,


The ArcGIS Server Explorer is a new contribution on the ESRI Code Gallery for dynamically generating a catalog of map services.  The Silverlight control supports multiple servers.  The contribution includes a sample web application that will preview map services selected in the treeviewClick here to view the live sample.  The explorer control is based on the TreeView from the Silverlight 2 Toolkit.

ArcGIS Server Explorer for Silverlight

The snippet below demonstrates how to add a reference the ArcGIS Server Explorer control into a web application.  The web application is listening to the page load event and the event that is raised when a user clicks on a map service.

<UserControl
    x:Class="ServerExplorerSample.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:esri="clr-namespace:ESRI.ArcGIS;assembly=ESRI.ArcGIS"
    xmlns:se="clr-namespace:ESRI.ArcGIS.ServerExplorer;assembly=ESRI.ArcGIS.ServerExplorer"
    Loaded="UserControl_Loaded"
    >
    <Grid>
        <se:ServerTreeView x:Name="serverTreeView" LayerClicked="ServerTreeView_LayerClicked" />
    </Grid>
</UserControl>

In this example, the page load event is used to add a reference to a public ArcGIS Server, namely, ArcGIS Online.  You can only add a reference to local server if you are hosting the web application on your intranet.  This is a Silverlight security limitation.

private void UserControl_Loaded(object sender, RoutedEventArgs e) {
    Uri uri = new Uri("http://services.arcgisonline.com/arcgis/rest/services");
    Server server = new Server(uri, "ArcGIS Online");
    this.serverTreeView.Servers.Add(server);
}

And finally, the snippet below demonstrates how the web application is responding to the a clicked map service.  The event handler contains a reference to a layer object that can be added directly to an Silverlight map control.

private void ServerTreeView_LayerClicked(object sender, LayerEventArgs e) {
    // Add Selected Layer
    this.map.Layers.Clear();
    e.Layer.Initialized += (evtsender, args) => {
        this.map.ZoomTo(e.Layer.InitialExtent);
    };
    this.map.Layers.Add(e.Layer);
}


Google Earth 5.0 - Tours

I’ve been working to include the new KML Tour tags from GE5 into Arc2Earth and our Cloud Services and the more I worked with them, the more I realized how powerful they could be. That being said, we’ll be adding a new A2E Tour Builder into Arc2Earth and probably release it as a stand alone product as well (since it really isn’t tied to GIS data imports).

Some points of interest regarding the tour builder:

1) Independent camera track and focus points allow you to move the camera around and look at a variable number of locations along the way
2) Independent speed track allows you to change the velocity of the camera movement along the timeline
3) Sounds, Balloons and Pauses tracks allow you to place these easily into the Tour timeline
4) Animations – simple control of Placemark and Model attributes and locations (no demo for this yet). 

It will take a bit of time to get the Timeline UI right but in the mean time, here’s a couple exports that show the variable camera movement in action:

New York City Tour – turn on 3D building for the best view. You might have to run it once/twice for all the building to load completely
http://www.arc2earth.com/public/NYC_Tour.kml

San Francisco Tour - same thing as above but this time you can turn on the Time of Day button in GE (the little Sun icon). The time will change from 6:30am to 6:30pm over the duration of the tour
http://www.arc2earth.com/public/SF_Tour.kml

Listening To: Sounds From The Ground - Eclipse On 5th


Arc2Earth Cloud Services - Videos

A lot of people want to see some of this in action but unfortunately, we're not quite ready for live testing yet. so here are some quick videos of Arc2Earth Cloud Services in action. Sorry there's no sound, one of these days I'll get this working on my machine...

Video 1 - Upload a Layer to the Cloud  - shows creating a map, loading a layer directly from ArcMap and then accessing the layer's online catalog. From there it shows some spatial selection operations on the newly uploaded data. Finally, it shows displaying the layer in Google Earth where we can manipulate how the layer looks from with GE using the new layer property pages.


Link to Video

Video 2 - Live Editing of a Cloud Layer - this shows 2 ArcMaps (one on a Vista machine via Terminal Services) editing a single cloud layer. First, adding a new feature and how it automatically shows up in the other ArcMap session as well as Google Earth. Next, attribute values are changed and the results are viewed in real time inside Google Earth.


Link to Video

 

Listening To: Nickodemus - Cleopatra in New York


well it’s a new year and I’ve been mostly silent on this blog for quite some time so it’s certainly time to give an update on what’s going on with Arc2Earth. The vast majority of my time the past 8 months has been dedicated to building our Cloud Services infrastructure but a lot of other updates have occurred as well.

Arc2Earth Reseller Program – Last year we started a reseller program and are quite happy with the companies that have signed up to help us distribute A2E. A lot of work went into this process and we’re thankful for all those who helped out in the process. I’d really like to thank the following companies who jumped on board quickly and in some cases, have devoted serious amounts of time and effort in the marketing and sales of A2E.

United States

  • Allen Instruments - Scottsdale, Arizona - http//www.alleninstruments.com
  • GeoSpatial Training Service - San Antonio, Texas - http://www.geospatialtraining.com/
  • New Light Technologies - Washington D.C. - http://www.newlighttechnologies.com/
  • Zekiah Technologies - LaPlata, Maryland - http://www.zekiah.com/
    • Europe, Middle East and Africa

      more information will be available at this link as the program advances: Arc2Earth Resellers

      Arc2Earth Version 2.1 - Last month we released V2.1 of the A2E, it contains lots of new features and bug fixes. You can download the Trial version by visiting our user forum, creating an account and then going to the Downloads section. The online change log is available here and you can see a list of reasons why you might want to use Arc2Earth versus ArcGIS 9.3 native KML Exporter. Version 2.1 will have several more patches before Version 2.2 which contains the UI for creating and consuming Arc2Earth Cloud Services

       

      Arc2Earth Cloud Services - Wow, so much has changed since we first announced work on the Cloud last July. The intent and vision is the same but both technical hurdles and feature creep have slightly delayed our public beta. That being said, I am incredibly excited about this service and what it will enable our users to accomplish, I can’t wait to get it into their hands.

      Update - Added some quick videos here 

       

      here’s a quick peak:

      ArcMap Integration – create and edit your maps directly from ArcMap using some new A2E toolbars and windows. You can add “cloud layers” directly to your local map and then use the native editing tools in ArcMap to make changes. Every resource in your cloud instance is controlled by login and ACL lists so you can create groups users who all work remotely on the live data. There are also bulk upload/download tools so you can get a fresh copy of any layer anytime you need to perform heavy lifting GIS analysis.

       Larger Image

      KML – The KML engine used in the service can be applied to any resource that serves features. There are a couple of endpoints where KML can be returned but in the samples below, it is the "search" resource. All aspects of the KML (labeling, balloon templates, styling, height, filtering etc) are applied at runtime and streamed out. In general, Arc2Earth will always be able to create and serve static files but the focus in the Cloud is the dynamic creation of KML. What’s even better is that any of these endpoints support REST parameters that allow you to control this from the client. For instance, here are four different representations of the same proximity search:

      HTML View

        Larger Image

      KML View – just labels applied

      .../Demographics/StarbucksWorld/MapServer/0/search?q=near(Midtown,+NYC,+1mi)&limit=20&f=kml&p={"label":"[!address]"}

       Larger Image

      KML View – Simple Renderer, 3D Marker Symbols

      .../Demographics/StarbucksWorld/MapServer/0/search?q=near(Midtown,+NYC,+1mi)&limit=20&f=km &p={"rend":{"type":"Simple","symbol":{"type":"Simple3DMarkerSymbol","name":"cylinder","color":{"html":"FF00FF"},"scale":15}}}

       Larger Image

      KML View – Class Breaks Renderer on distance, 3D Marker Symbols

      .../Demographics/StarbucksWorld/MapServer/0/search?q=near(Midtown,+NYC,+1mi)&limit=30&f=kml &p={"rend":{"type":"ClassBreaks","field":"distance","breaks":[150,500,1500],"symbols":[{"type":"Simple3DMarkerSymbol","name":"Cylinder","color":"FF00FF","scale":25},{"type":"Simple3DMarkerSymbol","name":"Cylinder","color":"FFFF00","scale":15},{"type":"Simple3DMarkerSymbol","name":"Cylinder","color":"0000FF","scale":5}]}}

       Larger Image

      While it is very useful for one off links or scripting, sending json via the query string can be an issue so any of these can also be accessed by url as well. Taken to its extreme, we use the KML Rest API to create a Google Earth viewer for every map and layer. As you can see from this screengrab, the user can access and set any of the parameters directly from Google Earth, hit save and KML Regions and Updates tags automatically change the layer view they see in Google Earth. (these update tags are also how we keep the GE Viewer up to date with any live edits that occur). All in all, the KML support and api you have available for all your layers is very flexible and quite powerful

       Larger Image

      Viewers – Google Earth, Flash Editor, ArcMap, Android, OpenLayers – we’ll start with the basics and keep adding viewers. and since we are still compatible with ArcGIS Server REST api, you will be able to use those scripting and Flex libraries as well.

      Datastore - I can’t tell you how much time I’ve spent going over the merits of a distributed Big Table datastore (like Google App Engine) versus running clusters of PostGIS on Amazon EC2. I am hardly qualified as an authority on the matter but the reality is that both have positives and negatives and in the end, a hybrid between the two seems to work well. This topic deserves several posts in and of itself so in the future I will try to layout why we chose GAE’s Big Table for our cloud’s data storage and how we went from geohash to quadkeys to finally packing grids of data separately into Big Table (or “quadtrees full of r-trees” as I like to call them). It is no replacement for a good RDBMS for sure but it is highly optimized for distributed access and querying of the spatial data, the exact kind of access seen in todays web clients like Google Earth. The automatic scalability of GAE (as long as you play by their rules) is both extremely attractive and cost effective for small company such as ours.

      ok, enough for now. I’ll post about these features and more in detail in the coming weeks


      I just finished reading a new book by Gretchen Peterson called GIS Cartography: A Guide to Effective Map Design and I really enjoyed it.  Gretchen wrote this book independent of any GIS tools so that you can apply it anywhere, from ESRI and Autodesk to PowerPoint and Web Mapping.  So ...

      Movements afoot!

      Its been a long time between posts lately but there is a lot of things I’d like to report. Thanks to everyone who has reminded me how lazy i have become at every industry event i seem to attend First up, I have resigned from my position at Landgate starting December 1. Its been [...]

      So I searched for an event I could hook into to to get notification when all layers have finished drawing on the map.

      Microsoft Save as PDF or XPS

      Yesterday I was creating user and install guides for some software we’re wrapping up. Typically I use the open source PDFCreator print driver from Word, but it doesn’t create bookmarks from headings in the Word documents and the images lose quality. Not to worry… 2007 Microsoft Office Add-in: Microsoft Save as PDF or XPS does [...]

      CarbonArc revisited

      Jeff Harrison’s mass email caught my eye today with the free trial of CarbonArc. I had the pleasure of taking an early release of CarbonArc for a spin last year and while it was a good start there were a few key things missing from my point of view. Having pushed and prodded Mapinfo 9.5 [...]

      I'm attending the ESRI Developers Conference for the first time ever, and was hunting for hotel suggestions.  There are comments on James Fee's blog from last year that recommend Zoso over the Wyndham.  TripAdvisor skews towards the tiny romatic places... any recommandations on a cheaper place for the barely-under 30 ...

      I'm departing from my normal show a lot of code methods here, to talk about an idea. ASP.NET MVC denegrates ASP.NET Web Form's old state-maintenance construct called Viewstate.  Without Viewstate, many developers are wondering how -- more aptly where -- to preserve the state of a web-application.  Here I will be ...

      Java GIS Development Setup (Part 1)

      In recent months I’ve been transitioning over to Java GIS development from .NET.  One of the first hurdles going into any new language is tool selection, in addition to installing and setting each one up.  This tutorial is geared towards those facing the same transition, or for those purely interested to see how to create [...]

      Earn ~$70k, 5 weeks vacation, 3 weeks sick, with awesome people, for a good cause (the National Parks Service).  Take my old job.  Deadline is the 22nd. http://www.cemml.colostate.edu/Jobs/351.pdf Please forward / link this post!!

      The blogs are abuzz today with Google's new cross-browser, cross-platform plugin that allows native x86 code to be run from a browser with minimal code tweaking. Called Native Client, its complete with sandboxing, Javascript interop, a Quake demo and ...  Yet Another Globe Application!! This really escalates the Javascript / Flash / ...

      Cache Dependency in ASP.NET

      Cool things with System.Web.Caching.CacheDependency.

      I know I shouldn't be looking at these things before coffee.  Still, when a SQL Import task complained about my Geometry column type, I tried to fix this. I editted my "C:\Program Files\Microsoft SQL Server\100\DTS\MappingFiles\MSSQLToSSIS10.XML" file, duplicating the entry for varbinary(max), but changing the data type name to "geometry." Bingo.  Everything now ...

      Arc2Earth Cloud Services

       

      When we first started Arc2Earth, one of the primary goals was to bring the power of the web based visualization to your average ArcGIS desktop user. By allowing them to export KML to Google Earth and then later to create map tiles for Google Maps and Microsoft Virtual Earth, we allowed our users to publish their data to a much larger audience without the need for servers or server software. In this regard, I think we’ve done pretty well in serving the need, there is always room for improvement but for the most part, we added another useful tool into their bag of tricks. We plan to continue building on this base but have also embarked on a plan to provide even more powerful tools for our users.

      After exporting and publishing their data, one of the first questions our clients usually ask is: “This is great but is there any way to search the data?” or “Can I click on the features?” For the most part, once our export took place, we had to rely on the functionality of Google Earth, Google Maps or MS VE for ad-hoc searching/clicking or provide additional custom programming to enable an application beyond the exported data. The former will certainly get better over time but is somewhat lacking right now and the latter, while lucrative, does not fit with the original vision of “one click” export to publish your data to the web.

      So, another model is needed to provide this additional, runtime functionality to those users who do not have the time, expertise or funding for their own servers. To fulfill these needs, we will be providing an online service that allows users to host their maps and layers online while providing REST based access for queries, editing and spatial analysis (limited as it may be). We will also provide a new desktop application that automatically synchronizes data between your local drive and online services. As edits occur online, they are automatically pulled down into your original source data (optionally of course)

      1) A2E Sync Client – Synchronizes any number of local data sources with online AtomPub feeds. Arc2Earth Online provides an APP feed for every uploaded layer but this software can also be used with other APP compliant sources (several of which are likely to come online in the future).

       

      2) A2E Cloud Services – Based on Google AppEngine, this is the engine that allows us to host, query and edit large amounts of data on Google’s server infrastructure. While our service is not even in beta release yet, we feel it holds great promise for online GIS services and will be of great value to Arc2Earth clients and their users. Initially, it is unlikely to include the sophisticated abilities of existing GIS servers but it will provide the 20% of functionality that is used 80% of the time. This is a perfect fit for the vast majority of Arc2Earth users who need to add real time functionality and collaboration to their exports. Some things it will include are:

      • Support for Points, Lines, Polygons 
      • Layer Queries – both spatial and attribute based
      • Feature editing – AtomPub feeds as well as other RESTful endpoints
      • RESTful API – Access your folders, maps and layers via simple Urls. We also provide compatibility with other GIS Servers RESTful APIs so that your client side code can work without changes. Initially, we will support a subset of the new ArcGIS 9.3 REST API but will also look to support the other APIs provided by MapGuide and GeoServer communities.
      • Support for Google Earth, Google Maps, MS Virtual Earth and OpenLayers
      • Support for different formats – KML, KMZ, GeoJson, ESRI Json, GeoRSS, Simple GML. These formats can be specified as the input and output format for any query or editing operation
      • Online Editor – a Google Earth plugin application (based on our GETools code) that provides basic map and layer management as well as editing tools for updating your data directly online. The editing tools include important tasks like measurement and snapping. Likewise, with proper permission, you can allow other users to load and edit your data from other locations.
      • Arc2Earth desktop is used for bulk loading and exporting of your data

             

      What it can’t do now:

      • On the fly map drawing – there is no ability to draw maps right now but as GAE evolves we will be looking into it. However, users can create map tile caches with Arc2Earth and then upload them into the cloud
      • Geoprocessing – although you can simulate some forms of GeoProcessing by chaining together different request from the client
      • Long running, synchronous queries that return lots of data – we are working on ways to initiate very large queries and then provide an asynchronous callback to download the results.

       

      Here are some quick demos, please note that they are running live on Google AppEngine but that GAE is still in pre-release itself (and we might go over our beta quotas). Also, for the Google Earth Plugin sample, some computer video cards might have issues displaying the Identify result.

      as mentioned, this service is not even in beta and we are still working out the financial model. Also, we’re still actively coding and trying new techniques on Google AppEngine and are hopeful that future additions to GAE will dramatically reduce execution time but as of now, it’s a work in progress.

      Inevitably, there will also be comparisons between what this service will do and what will be provided by other vendors (e.g. WeoGeo/Safe etc). I think there is more then enough room for multiple “Cloud” GIS services and we're likely to see many more in the future. This ability to build on top of infrastructure from Google, Amazon and others also allows much smaller companies into a marketplace that in the past, would have been dominated by larger ones with deep pockets. I for one am looking forward to what is built using these services in the future


      I’ll be helping to man the Arc2Earth booth at the UC next week so if you’re in around, please feel free to stop by and say hi.

      (please visit Arc2Earth at the 2008 ESRI User Conference in San Diego next week – Booth 2217)


      Flat Out Resuscitation

      One of my goals this year was to revive my GIS blog, which suffered much neglect over the last year. In fact, I was even scrapped after the Planet Spatial Reboot. After reviewing some of my older posts I decided to start with a clean slate. The posts really didn’t add any [...]

      WFS-T adventures with Mapinfo 9.5

      So i’ve been a bit late taking a look at the new Mapinfo Professional v9.5. With the consistent dissapointment towards the consumption of OGC standards in commercial apps I wasn’t holding my breath … but wait a sec, it did work and it worked damn well. I mean, it worked flawlessly; updates, inserts, deletes, lock [...]

      LBS has arrived

      Finally a consumer personal navigational device with internet connectivity, meet Dash Express. See also Engadget review. The opportunities this opens up to both the Geo community and also Joe Public is quite huge. Enter GeoRSS. Your time to shine has arrived Many websites have geo-relevant content – including, but not limited to, Google Maps, [...]

      gvSig mobile release & other thoughts

      Seems as though a lot of people missed this release last week. It gives us great pleasure to announce that the pilot application awarded the development contract for the gvSIG Mobile application by the Regional Ministry of Infrastructure and Transport is available. gvSIG Mobile is a smaller version of gvSIG which has been adapted for use [...]

      More than just PushPins

      I’m currently going through the preliminary stages of looking to move house, this means that I seem to be coming across an awful lot of pushpin maps and Google mashups on a variety of property web sites. Most of these sites are very good at aggregating data into a simple map view displaying a number of [...]

      On Location mashup*

      I happened to be working in Canary Wharf on Tuesday, so on the way home I made a last minute decision to detour to the mashup* event which was themed ‘On Location’.  I’d made a mental note of it a while ago, but then completely forgotten, anyway I’m glad I  went as it was pretty interesting.  There was a [...]

      OpenStreetMap Data in ArcGIS

      ***Update***  I should probably point out at this point that the tool currently linked from here does not work with the  current xml format of openstreetmap.  I will post a new script soon that does, although you can probably tell from how long ago the format changed that I have had a few othe real-life things get [...]

      Build your own touchtable

      I was lucky enough recently to see a great demo of the giant TouchTable, and I had forgotten since seeing it 3 years ago at the user conference, what a very very cool piece of kit it is.  With microsoft recently announcing their forthcoming Surface platform, I got to wondering what would be involved if i wanted [...]

      So ESRI has a new product arriving: Another major/joint effort involves the development of a new ESRI product called MapIt. This technology provides simple geocoding and mapping capability for the Microsoft environment. MapIt enables developers to create maps of their enterprise data stored SQL Server 2008 and Excel. MapIt is designed ...

      The ArcGIS Server Development Blog has moved to the ESRI blogs home at http://blogs.esri.com/arcgisserver. Please update your bookmarks and RSS feeds to reference the new location.

      As part of the move, any current accounts you’ve created on this blog will be unavailable on the new site. Instead, you can use your ESRI Global Account if you wish to sign in to the new site. Creating an ESRI Global Account is free and available to everyone.

      The blog will still be written by the ArcGIS Server development team, and you’ll be able to see all previous posts and comments. We apologize for any inconvenience caused by this move, and look forward to your continued support and readership.


      Every year ESRI sends out a questionnaire to attendees of the UC and they've just posted the results from this year.  Some of the questions are C-level and probably not interesting to this crowd, but it does get into some of the 9.4 (as was seen at the DevSummit), map ...

      The wait is over, OpenLayers 2.8 has been released.  Some of the highlights I think are important: Add support for multi-layer feature selection when using vector features Added support for "XYZ" layers to interact with standard caches of tiles; includes OSM support built in Add support for drawing text on vector layers Support ...

      From Bryan Baker, a product engineer working on the .NET SDK: 

      I wrote an earlier post that showed how to extend the QueryAttributes task so that all features are immediately highlighted. Several users have asked about also zooming to the selected features. I'll show that here, though keep in mind that the user can also zoom to the selected features by right-clicking on the node for the layer (Cities in the graphic at the top of the earlier post) and choosing to zoom to selected features.

      It turns out that it's a little more difficult to zoom to the features than I originally thought, because the FullExtent property of the graphics layer is null for queries like this. Instead, we have to construct our own envelope around all the features by looping through them. This isn't that difficult, though of course it does require more processing.

      I’ve included code below that does the zooming. This code should be added to near the bottom of the existing code in the earlier post. If for some reason you didn’t want to highlight all the features, you could omit or comment out the line in the loop that sets the selectedCol to true.

      The code below first creates an envelope to use, then in the existing loop that selects each feature, it widens the envelope to surround each feature. Once it has the envelope, it gets a reference to the Map control so it can set the Map’s extent. This takes some work, since the task itself has no reference to the Map. We have to get the ID of the Map and then search the page’s control tree. Since the Map control could be nested within another control, such as in a FloatingPanel, we search for it recursively using a custom function (found at the bottom of this listing).

      One more thing before we zoom the map: the task could be querying a point layer, and if only one point is found, the “envelope” around all features is a point. We can’t zoom to a point, so instead we set the envelope to a percentage of the full extent of the Map (five percent—this value is hard-coded here, and you can change it depending on tightly you want to zoom in this one-point case).

      Finally, we’ve got an envelope that will work, and we set the Map to this extent, refresh the Map, and copy its CallbackResults to the task’s CallbackResults. This last step is necessary because a callback only works with one control (the task in this case), and we need to tell another control (the Map) to update its contents.

          ' Set up the items to hold the extent of all features

          Dim geom As ESRI.ArcGIS.ADF.Web.Geometry.Geometry

          Dim layerEnv As New _

             ESRI.ArcGIS.ADF.Web.Geometry.Envelope( _

             Double.MaxValue, Double.MaxValue, _

             Double.MinValue, Double.MinValue)

          ' Set each feature to selected (this loop is

          ' at the end the code in my previous blog post)

      For Each row As DataRow In graphicsLayer.Rows

         row(selectedCol) = True

          ' Enlarge the overall envelope to

          '  include the current feature

         geom = graphicsLayer.GeometryFromRow(row)

         layerEnv.Union(geom)

      Next

          ' If any records found, zoom to them

      If graphicsLayer.Rows.Count > 0 Then

          ' Get a reference to the Map - have to search the Page since

          '  task itself has no direct reference to the Map

          ' (the task's TaskResults does have the ID of the map)

          Dim mapCtrl As Map = Nothing

         Dim taskResultsId As String =

            Me.TaskResultsContainers(0).Name

          Dim taskResults As TaskResults = _

             CType(FindControlRecursive( _

             Me.Page, taskResultsId), TaskResults)

         If Not TaskResults Is Nothing Then

            mapCtrl = CType(FindControlRecursive( _

               Me.Page, taskResults.Map), Map)

         End If

         If Not mapCtrl Is Nothing Then

          ' If only one point found, envelope will be a point

          '   -- set to a percentage of the full extent

            If layerEnv.XMin = layerEnv.XMax AndAlso _

               layerEnv.YMin = layerEnv.YMax AndAlso _

               Not IsNothing(mapCtrl) Then

          ' Percentage of the full extent to use when zooming to point

          Dim zoomToPointPercentage As Integer = 5

          Dim NewWidth As Double = mapCtrl.GetFullExtent().Width _

             * (zoomToPointPercentage / 100)

          Dim NewHeight As Double = mapCtrl.GetFullExtent().Height _

             * (zoomToPointPercentage / 100)

               layerEnv.XMin -= NewWidth / 2

               layerEnv.XMax += NewWidth / 2

               layerEnv.YMin -= NewHeight / 2

               layerEnv.YMax += NewHeight / 2

            End If

          ' Now we can zoom the map to the extent of the features

            mapCtrl.Extent = layerEnv

            mapCtrl.Refresh()

          ' We have to tell the client to refresh, using CallbackResults

            Me.CallbackResults.CopyFrom(mapCtrl.CallbackResults)

         End If

      End If

      Below is the function called in the above code. This searches the page and its child controls for the control with the given ID. Put this after the end of the Execute method (End Sub), but inside the Class (before the End Class statement).

          ' Finds the control in the Page's control tree

          Public Function FindControlRecursive(ByVal root As _

             Control, ByVal id As String) As Control

              If root.ID = id Then

                  Return root

              End If

              Dim c As Control

              For Each c In root.Controls

                  Dim t As Control = FindControlRecursive(c, id)

                  If Not t Is Nothing Then

                      Return t

                  End If

              Next

              Return Nothing

          End Function

      If you add the code above to the custom task as outlined in the earlier blog post, it should automatically zoom to the extent of all features found by the task.

       


      Customizing the Web Editor task

       James Goodrich, a developer on the .NET Web ADF team, contributed this information about some Service Pack 2 enhancements to the Editor task:

       When the Editor task was released at version 9.2 of the Web ADF for the .NET Framework, a common question was "How can I customize the Editor task?". Service Pack 2 provides an answer to this question. You can now customize the Editor task with custom tools and Editor Panels and we have added more events that allow you to hook into the Editor task.

      In addition to these new customization options for developers, the Editor task has another key change at Service Pack 2 which it allows it to be configured with a pooled map service. You can edit non-versioned data using a pooled map service.

      See the Editor Task control discussion in the Developer Help for samples and instructions.

      Customized Editor Task with added tools


      Rex Hansen contributed this post about how to use some of the enhanced JavaScript in Service Pack 2 to track pending tiles and display a busy indicator (such as an animated "Loading" graphic) over the Web ADF's Map control: 

      As a Web ADF developer working in an asynchronous communication environment, it is often beneficial to provide an end user with some indication that a user action is being processed. Since most Web ADF applications are centered on working with a map, the ability of an end user to effectively interact with map contents is essential. The Web ADF has the ability to asynchronously retrieve map data from multiple sources and consolidate it in a single map control. In general, data sources often differ in the time it takes to respond to a request. Since the Web ADF Map control is capable of rendering map data as it is returned to the browser, it’s possible that some portion of data in the map is visible and accessible before another portion. In this case, it will likely be important to let the end user know when the map control has finished loading map data from any and all sources.

      To support this capability, 9.2 service pack 2 includes an enhanced Web ADF JavaScript Map object. The JavaScript Map object has a set of “event handlers” on the pendingTiles property. The pendingTiles property references an array of map image tiles to be rendered. The array is updated when the map needs new image tiles based on the current extent. Events on the pendingTiles property are listed below:

      Event Description
      add_onRequestsPending Triggered when the number of items in the pendingTiles array changes from 0 to a higher value
      add_onRequestsRemove Triggered when an item is removed from the pendingTiles array
      add_onRequestsCompleted Triggered when the number of item in the pendingTiles array changes to 0

      Use these handlers on the Map object’s pendingTiles property to register a JavaScript function with the event. For example:

      map.pendingTiles.add_onRequestsPending(showBusyIndicator)

      where map is the Map object and showBusyIndicator is a JavaScript function to call when the number of items in the pendingTiles array changes from 0 to a higher value.

      The JavaScript function showBusyIndicator may appear as follows.

      function showBusyIndicator(sender) {

                  showLayer("BusyIndicator");

                  if (sender!=null) {

                      window.status = "Pending Tiles: " + sender.pendingTiles.length;

                  }

      The argument to the function is a reference to the JavaScript Map object. This argument can be used to gain access to map properties, such as the number of map image tiles left in the pendingTiles array. In this example, the number of pending tiles is output to the browser window’s status bar. If the argument is null, the pendingTiles array contains 0 items. The Web ADF includes two convenient JavaScript functions to show or hide a layer (div) based on its id, named showLayer and hideLayer, respectively. The functions are contained in the display_common.js file which is by default embedded with the Web ADF controls. In this example, the showLayer function is used to make the contents in the div tag with an id of “BusyIndicator” visible.

      You can show the number of pending tiles and a "Busy indicator" in your Web application
       

      Included below is a simple Web page with a MapResourceManager, Map, and a div tag containing an image. The JavaScript Map object events are handled after the form to let the content of the form load before interacting with it.
       

      <%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>

      <%@ Register Assembly="ESRI.ArcGIS.ADF.Web.UI.WebControls, Version=9.2.2.1350, Culture=neutral, PublicKeyToken=8fc3cc631e44ad86"

          Namespace="ESRI.ArcGIS.ADF.Web.UI.WebControls" TagPrefix="esri" %>

      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

      <html xmlns="http://www.w3.org/1999/xhtml" >

      <head runat="server">

          <title>Untitled Page</title>

      </head>

      <body>

          <form id="form1" runat="server">

          <div>

              <esri:MapResourceManager ID="MapResourceManager1" runat="server">

                  <ResourceItems>

                  </ResourceItems>

              </esri:MapResourceManager>

       

              <esri:Map ID="Map1" runat="server" Height="453px" Width="556px" MapResourceManager="MapResourceManager1">

              </esri:Map>   

          </div>        

          

           <div id="BusyIndicator" style="z-index: 1000; left: 25px; width: 100px; position: absolute; top: 422px;height: 100px">

              <img src="images/CircleThickbox.gif" />

           </div>

         </form>

       

         <script language="javascript" type="text/javascript">

                 

              function showBusyIndicator(sender) {

                  showLayer("BusyIndicator");

                  if (sender!=null) {

                      window.status = "Pending Tiles: " + sender.pendingTiles.length;

                  } 

              }

             

              function showPendingTiles(sender) {

                  if (sender!=null) {

                      window.status = "Pending Tiles: " + sender.pendingTiles.length;

                  } 

              }

             

              function hideBusyIndicator(sender) {

                  hideLayer("BusyIndicator");

                  if (sender!=null) {

                      window.status = "";

                  } 

              }

             

              // add busy indicator functions to the map

              map = Maps["Map1"];

              map.pendingTiles.add_onRequestsPending(showBusyIndicator);

              map.pendingTiles.add_onRequestsRemove(showPendingTiles);

              map.pendingTiles.add_onRequestsCompleted(hideBusyIndicator);   

             

         </script>

       

      </body>

      </html>


      Sterling Quinn of the Server team contributed this post on configuring your web server to display custom tiles in areas where you have not yet completed your map cache.

       

      At the ESRI Developer Summit, several of you asked how we displayed a “Data not available” tile in empty areas of the ArcGIS Online services. This kind of tile can be useful if someone pans to the edge of the map or navigates to an area that you have not completed caching. Configuring your server to return a “Data not available” tile can in some cases yield a better user experience than returning nothing.


       

       

      To display the tile, you need to create a custom error response on your virtual cache directory for HTTP Error 404: “Not Found”. Instead of an error message, the Web server returns the tile.

       
      Following are steps for this process in IIS. Before you perform these steps, you should put the blank or “Data not available” tile in your cache directory. The tile you use must have the same dimensions and image format as the other tiles in the cache.

       

      1. In IIS Manager, right-click the Virtual Directory for the specific cache and select Properties.

       

      2. Click the Custom Errors tab, scroll down, and select the 404 error code.

       

      3. Click the Edit button. In the URL box, specify the tile that IIS should return whenever a tile is missing. It is important to use a URL and not just a path to a file.

       

      4. Click OK. Your dialog should look similar to the one below. Click OK again to return to IIS Manager.

       

       

      You can download a sample, "Map data not yet available" tile (512 X 512 JPG) that you can use here

       


      Something I wanted to streamline for my development team was icon and bitmap management; or rather taking as much of the decision making process out of the equation. The strategies I have taken have the following benefits. Time / Efficiency I don’t want developers spending any time digging around for or capturing an icon/bitmap. Period. I don’t want [...]

      Safe was nice enough to let me post the video from my keynote on my blog. I really enjoyed the opportunity to speak at FME UC and had a wonderful time meeting everyone there.

      GIS Tech 2007 Agenda Online.

      The Agenda for GIS Tech is up on the website The green tracks are the more technically oriented sessions, mostly being given by people from the consultancy group.  There’s some good AGS talks, particularly on the second day, I’ve had a preview of some of the demo’s that Matt and Dan are doing in their Ajax\Web [...]
      You can subscribe to the aggregate feed by clicking the icon to the left, or the feed bunder badge below.
      About

      ArcExperts.net is a simple aggregator of blogs related to development of software using ESRI products.

      This site is maintained by Dave Bouwman as a free service to the GIS Developer community

      OPML File
      You can download the blog list as an OPML file from here.
      ArcDeveloper.net