Tag: Rasters

Working with custom renderers in the .NET Web ADF

Custom 2.5D renderer for Washington DCThe Web ADF allows you to go beyond the default symbols for graphics layers by creating custom renderers. This post will show how to create custom renderers and apply them to FeatureGraphicsLayers using the IRenderer interface. The IRenderer interface allows you to take full control of how a specific feature is rendered on the map by using .NET’s System.Drawing classes.

The IRenderer interface consists of five methods, but if you can do without support for the Table of Contents (TOC) control, only one of them is really needed, and you can use some very simple implementations of the remaining four methods.

The five methods are:

  • GenerateSwatches – Generates swatches for this renderer for display in a table of contents
  • GetAllSymbols – Returns all FeatureSymbols used by this object, if any
  • GetMaxSwatchDimensions – Gets the maximum dimensions of the swatches generated by this renderer
  • Clone – Returns a clone of this renderer
  • Render – Draws the specified geometry to the specified graphics

For the simplest renderer, the following is sufficient for the first four methods:

public SwatchCollection GenerateSwatches(SwatchInfo swatchInfo, string fileName, string minScale, string maxScale)
{
return new SwatchCollection();
}
public void GetAllSymbols(List< FeatureSymbol> symbols) { }
public void GetMaxSwatchDimensions(ref int width, ref int height) { }
public object Clone() { return this.MemberwiseClone(); }

This implementation will not support swatches, but we will later get back to how to also support this.

The main method we need to look at is “Render”. As input you get three parameters: The row with attributes you are rendering, a reference to the graphics instance that you should render to, and the name of the column in the datarow that contains the geometry data. The geometry data that is parsed in here is not in map units, but has already been converted to screen coordinates, so you don’t have to worry about translating your feature to the screen.

So the very first thing we do in our renderer is to fetch the geometry that we want to render. In most cases the first few lines of a renderer will look something like this:

public override void Render(DataRow row, Graphics graphics, DataColumn geometryColumn)
{
if (row == null || graphics == null || geometryColumn == null)
return;
Geometry geometry = row[geometryColumn] as Geometry;

In this first part, we will only support rendering points, so the next stop would be to limit by geometry type:

if (geometry == null || !geometry is ESRI.ArcGIS.ADF.Web.Geometry.Point)
return;

Next we can use System.Drawing classes to draw an image at the point, which completes our very simple point renderer:

ESRI.ArcGIS.ADF.Web.Geometry.Point p = geometry as ESRI.ArcGIS.ADF.Web.Geometry.Point;
using(System.Drawing.Image img = System.Drawing.Image.FromFile(@"C:inetpubwwwrootmyAppimagesicon.png"))
{
graphics.DrawImageUnscaled(img,Convert.ToInt32(p.X),Convert.ToInt32(p.Y));
img.Dispose();
}

Here’s the complete renderer implementation:

using System;
using System.Collections.Generic;
using System.Text;
using ESRI.ArcGIS.ADF.Web.Geometry;
using ESRI.ArcGIS.ADF.Web.Display.Swatch;
using ESRI.ArcGIS.ADF.Web.Display.Symbol;

namespace WebADF.Datasources.Renderers
{
public class SimplePointRenderer : ESRI.ArcGIS.ADF.Web.Display.Renderer.IRenderer
{
public SwatchCollection GenerateSwatches(SwatchInfo swatchInfo, string fileName,
string minScale, string maxScale)
{
return new SwatchCollection();
}
public void GetAllSymbols(List<FeatureSymbol> symbols) { }

public void GetMaxSwatchDimensions(ref int width, ref int height) { }

public void Render(System.Data.DataRow row, System.Drawing.Graphics graphics,
System.Data.DataColumn geometryColumn)
{
if (row == null || graphics == null || geometryColumn == null)
return;
Geometry geometry = row[geometryColumn] as Geometry;
if (geometry == null || !(geometry is ESRI.ArcGIS.ADF.Web.Geometry.Point))
return;

ESRI.ArcGIS.ADF.Web.Geometry.Point p = geometry as ESRI.ArcGIS.ADF.Web.Geometry.Point;
using (System.Drawing.Image img = System.Drawing.Image.FromFile(ImageIcon))
{
graphics.DrawImageUnscaled(img, Convert.ToInt32(p.X – img.Width/2),
Convert.ToInt32(p.Y) - img.Height/2);
img.Dispose();
}
}

public object Clone() { return this.MemberwiseClone(); }

private string imageIcon = @"C:inetpubwwwrootmyAppimagesicon.png";

public string ImageIcon
{
get { return imageIcon; }
set { imageIcon = value; }
}
}
}

If you create a graphics dataset, you can now apply this renderer to your individual FeatureGraphicsLayers. You can easily extend it to use any of the existing attributes in the DataRow to determine which image icon to use, making it a simple thematic map renderer.

Points are simple to render, but it gets slightly trickier with lines and polygons. We will have to convert these to a System.Drawing.GraphicsPath instance that the graphics object knows how to render. This is fairly straightforward, but to save you the trouble here are the methods needed to perform this conversion:

public static GraphicsPath PolygonToPath(Polygon polygon)
{
GraphicsPath path = new GraphicsPath();
foreach (Ring p in polygon.Rings)
{
path.AddPolygon(pointCollectionToPointArray(p.Points));
foreach (Hole ring in p.Holes)
path.AddPolygon(pointCollectionToPointArray(ring.Points));
}
return path;
}

public static GraphicsPath PolylineToPath(Polyline polyline)
{
GraphicsPath path = new GraphicsPath();
foreach (Path line in polyline.Paths)
{
path.AddLines(pointCollectionToPointArray(line.Points));
}
return path;
}

private static Point[] pointCollectionToPointArray(PointCollection points)
{
Point[] pointArr = new Point[points.Count];
for (int i = 0; i < points.Count; i++)
{
pointArr[i] = new Point(Convert.ToInt32(points[i].X), Convert.ToInt32(points[i].Y));
}
return pointArr;
}

This is essentially all we need to make a renderer supporting all geometry types. Example:

using (GraphicsPath path = PolygonToPath(polygon)); //or PolylinetoPath for polylines
{
using (Pen pen = new Pen(System.Drawing.Colors.Black,1))
{
graphics.DrawPath(pen, path);
pen.Dispose();
}
path.Dispose();
}

If you want to show the feature with a fill, remember to also use FillPath prior to drawing the outline as shown above:

using (SolidBrush brush = new SolidBrush(System.Drawing.Colors.Red))
{
graphics.FillPath(brush, path);
brush.Dispose();
}

Using the principles described in this article, I’ve created a 2.5D renderer that can extrude polygons and lines based on a numeric attribute. The effect is very much like what you might have seen Google Maps using to show simple building outlines in metropolitan areas. You can indeed use it for this, or you can choose to extrude polygons based on for instance population density or whatever you want to show. I won’t go through the details of the code here, but most of the code is used for building a 3D-like mesh of a polygon and figuring out how to shade it depending on the direction of an imaginary light-source.

Adding support for legends

As mentioned in the beginning, we skipped implementing support for the table of contents control, and in many use cases of custom renderers (like displaying results) this is not needed. However adding support for TOC is fairly straightforward.

We can reuse existing functionality in the ADF to render our symbols. Let’s say we have a point layer using three image symbols, 1.gif, 2.gif and 3.gif. We use the RasterMarkerSymbol and the SwatchUtility to render our swatches.

public 
SwatchCollection GenerateSwatches(SwatchInfo swatchInfo, string fileName, string minScale, string maxScale) {
SwatchCollection
swatches = new SwatchCollection(); SwatchUtility
swatchUtil = new SwatchUtility(swatchInfo); for(int
i= 1;i<=3;i++) {
CartoImage img = swatchUtil.DrawNewSwatch(new RasterMarkerSymbol(
Server.MapPath(string.Format("~/images/{0}.gif", i))), null);
swatches.Add(new Swatch(img, "Marker #" + i.ToString(), null, null));
}
return swatches;
}

This will return a collection of 3 images to use for the legend. When adding a TOC to the page, you’ll see something like the following:

Swatch images in TOC

Get the Custom Renderer sample from the Code Gallery

Contributed by Morten Nielsen of the ArcGIS Server .NET software development team.

Posted in Services | Tagged , , | 2 Comments

ArcGIS Server 9.3 Nationwide Seminar Series occurring now

ESRI has been working on two, half-day
ArcGIS Server 9.3 Seminars
. These seminars started September 23rd and
are taking place through November within the U.S. This is a great opportunity
to see how to implement ArcGIS Server to its fullest capabilities.

The first seminar, which takes place during the morning, is “Tips and Tricks”.
It was derived by gathering the most common questions people have when
implementing ArcGIS Server and best practices. There are three main sections:
configuration and management, caching, and geoprocessing. This seminar provides
useful tips for configuring ArcGIS Server and understanding architecture, how
you can set up caching strategies and workflows for high performing web
applications and how to author and publish geoprocessing services for advanced
analysis over the web.

The second seminar, which takes place during the afternoon, is titled “Creating
Mashups Using the ArcGIS API for JavaScript”. The ArcGIS Server API for
JavaScript is new at 9.3 and provides html and JavaScript developers a quick
path for making great web mapping applications. This seminar covers the basics
and getting started with the API for JavaScript. In addition to creating
mashups, discussion on query tasks, geoprocessing, geocoding and other topics
are covered so you can see how GIS analysis can be done over this easy to use
API. You can take a quick glance of the demos that will be discussed by
downloading the sample code from the ArcGIS JavaScript API
Code Gallery
.

Both seminars provide a great resource for maximizing the potential of ArcGIS
Server. The seminars also provide workbooks to attendees so they can revisit
the useful tips back in the office. Sign up online to attend an
ArcGIS Server 9.3 Seminar
.

The ESRI technical staff hope to see you at a seminar in a city near you!

Contributed by Jeremiah Lindemann, co-designer of the “Creating Mashups Using the
ArcGIS API for JavaScript” seminar.

Posted in Services | Tagged , , , , , , | 2 Comments

Video explains "Parcel Notification List" JavaScript example

Currently the most popular download on the
ArcGIS JavaScript API Code Gallery
is the
Parcel Notification List
application written and submitted by Jeff
Archer from ESRI. In
this video
Jeff takes a few minutes to show how the sample works and
gives a quick run-through of the code and components under the hood.

While local governments may be able use the application “as-is”, there is enough
starter material for any Web application that needs to select features based on
a distance from other features and return tabular attributes of the results.

Download it, use it, modify it… it’s up to you. And please leave comments on
the download page if you have any questions or suggestions you think might help.

Contributed by Jim Barry of the EDN team.

Posted in Services | Tagged , , , , , | 3 Comments

Using 9.3 Web ADF controls in an ASP.NET Web Part and SharePoint 2007

My previous post about integrating 9.2 Web ADF controls in ASP.NET Web Parts discussed a number of workarounds required to successfully utilize ADF controls within a Web Part. For 9.3 the ArcGIS Server .NET development team took some time to evaluate and fix any issues encountered while using ADF controls in a custom user control, composite control or ASP.NET Web Part. We tested Web Part deployment within SharePoint 2007 and confirmed that it worked without any ADF specific workarounds. As a result, the 9.3 Web ADF provides a solid foundation for integrating GIS components in Web Parts designed for SharePoint deployment.

Click here to download a comprehensive Web ADF-Web Part sample (C# and VB.NET). The sample code includes two projects: a class library which contains Web Parts, and a Web application to assist in deployment and testing. The sample also includes a ReadMe.txt to get started and a Word document which steps through the SharePoint 2007 deployment process for ASP.NET AJAX-enabled Web Parts.

The class library project (ADFWebPart) contains two Web Parts: MapWebPart and MapGridViewWebPart. MapWebPart contains MapResourceManager, Map,Toolbar, and Toc controls. This sample illustrates how to add, structure, and initialize the aforementioned controls, add a custom tool, and expose properties for use in SharePoint.

MapGridViewWebPart contains a MapResourceManager and Map. It also contains an UpdatePanel with a GridView. It requires that a ScriptManager be in the page to enable asynchronous updates of the GridView (via the UpdatePanel).

This sample illustrates how to work with interactive graphics in the client via a map and table. A selection set is generated from a feature layer in an ArcGIS Server map service and managed as a Web-tier graphics layer. The graphics layer is rendered on the client using Web ADF JavaScript graphic features. Attributes of the selected set of features are displayed in the GridView. The visible fields and alias can be explicitly defined. Hovering over a row in the table will highlight the corresponding graphic feature in the map. Clicking on the row will zoom or pan to the feature.

All properties for setting the dynamic resource, data layer for display, feature limits and field aliases are public and presentable within SharePoint. An ArcGIS Online cached map service (StreetMap) is used as a background map resource to provide spatial context.

The following screenshot provides an example of both Web Parts deployed within SharePoint 2007.

 Web Parts in Share Point

To utilize either Web Part outside of SharePoint or to test before SharePoint deployment, use the file system Web application (CustomControlsWebSite) included with the sample. The Web application contains a simple aspx page designed to emulate a runtime scenario where an end user wants to add a Web Part within the current session. To personalize the page (e.g. add a Web Part at runtime) the current session must be associated with an authenticated user. By default, a file system Web site will use integrated authentication. If deploying as a Web application in IIS, you will need to disable anonymous access to the Web application in IIS. Enabling integrated authentication may offer the easiest solution since you do not need to configure or explicitly define authentication details; instead the authenticated user will be the user account under which the client (browser) is running.

The default personalization provider for ASP.NET 2.0 is SQL Express. If you do not have SQL Express installed, a personalization store will not be created (upon initial execution of the application) and an error will be returned when attempting to add the custom Web Part to the page at runtime. To alleviate this requirement, the Web site uses a custom personalization provider that stores information in text files. The code, markup, and discussion for this technique is provided in the Microsoft article Web Parts Personalization Providers.

Contributed by Rex Hansen of the ArcGIS Server .NET software development team

Posted in Services | Tagged , , , | 5 Comments

Visualizing task results in the Java Web ADF

In the ArcGIS Server 9.3 Java Web ADF, you can visualize task results in a couple of ways:

  • Data representation: shown in the result panel.
  • Visual representation: shown on the map as a callout.

Callout functions are enabled by default in the Web Mapping Application you generate with ArcGIS Server Manager or your Developer IDE. Any layer in a LayerDefintion can have its results from a query task returned in a callout.

There are several approaches you can take to customize a callout:

  • Customize through ArcGIS Server Manager
  • Customize through development

These two approaches both interact with the LayerDefintion. The Manager approach offers convenience through automation while the developer approach offers more flexibility.

The ArcGIS Server Resource Center offers a help topic that discusses both approaches. Developers who have some previous experience with the Java Web ADF will also appreciate this video demo of a custom search task application.

Contributed by Dan O’Neill of the ArcGIS Server Java software development team.

Posted in Services | Tagged , , , , , | Leave a comment

Strategies for on-demand caching

ArcGIS Server 9.3 introduces the option to create map cache tiles “on demand” as they are visited by users. The first user to navigate to an uncached area must wait while the corresponding tiles are drawn by the server. The tiles are then added to the service’s cache folder and remain on the server until updated or deleted by the server administrator. This means that subsequent visitors to the area will not have to wait for the tile to be created.

When used wisely, on-demand caching can save you much time and disk space. Most maps show some area that is barren, unusable, or uninteresting to the map audience, especially at large scales (zoomed in). Caching on demand relieves you of the burden of creating and storing these unneeded tiles, but leaves the possibility that a user could still view the area if needed.

Although on-demand caching is a useful feature, it can put an unnecessary hit on performance when misused or overused. This topic contains tips for using on-demand caching in the most effective way.

Achieving the best performance

One benefit of full map caching is that you can serve beautiful, complex maps very quickly because the server is just distributing tiled images of the map; it isn’t drawing the map on every request. However, when you use on-demand caching, the server does have to draw tiles dynamically when a user navigates to an uncached area. This dynamic draw actually takes longer than a regular request because the server creates a group of tiles at once. This group of tiles is 4096 x 4096 pixels in size (equivalent to 64 tiles of 512 x 512 pixels).

Why doesn’t the server just create one tile at a time? If it did, you would see many duplicate labels because there is no way for the labeling engine to determine what labels exist on adjacent tiles. Hence the server creates a group of tiles at once and you must prepare your map for drawing large areas at an acceptable speed. This section discusses several ways to reduce the performance cost of on-demand caching.

Determining where you will cache on demand

The most important thing you will determine when configuring on-demand caching is which areas will be created on demand and which areas you will pre-cache. Never use on-demand caching to build your entire cache. You should always pre-create some tiles in the areas of the map you expect to have the most user traffic, thereby minimizing the chance that a user will consume server resources by requesting a tile on demand.

How do you determine which areas of your map will be most popular? This largely depends on the purpose and audience of your map. In a general base map, populated places, roads, coastlines, parks, and other points of interest have the potential to be visited more often than other areas. Microsoft Hotmap is an interesting case study that shows popularity of tiles in the Virtual Earth base map at multiple scales. Notice that at larger scales, the percentage of unused tiles increases.

Thematic maps might show very different trends of popular places. For example, maps used by a mining company might have highest usage in areas where there is the greatest density of mines. This could occur in unpopulated or mountainous areas that would be uninteresting to the general population.

To determine which areas you should pre-cache, examine the usage patterns of your current maps, either online or on the desktop. You can learn a lot through informal observations of where your users tend to navigate and which features they query.

Your data availability and resolution is also important. If your data is poor or nonexistent in certain areas, you can skip caching those areas. Even if someone does request an on-demand tile, it won’t take much time to draw if there’s nothing to show.

Your data also might be closely tied to the purpose of the map. For example, if you’re working with a department of transportation, you’ll want to make sure areas with a high density of roads and rails are pre-cached. Spatial analysis tools such as Kernel Density can help you determine which general areas are thick with interesting features.

After determining where users will most often visit, you should create a feature class that isolates these areas. You’ll reference this feature class when you run the Manage Map Server Cache Tiles tool, to ensure that tiles are only created within the feature class boundaries.

You might chain several tools together in a model or script to get this feature class of popular places. The model could contain various inputs of features anticipated to be popular, optionally buffer the features or determine their density, and finally perform post-processing on the output to ensure that the resulting feature class is suitable for a caching template. For example, the feature class whose boundaries you cache against should not contain numerous, small features. The Aggregate Polygons tool can eliminate small holes and polygons, and the Dissolve tool can create one multipart feature from numerous features.

The more you can isolate popular areas of your map, the more requests you can satisfy with pre-cached tiles instead of creating tiles on demand. For example, you may find that at a large scale level, you only need to cache a small fraction of your map area to accommodate 99% of user requests. You may decide to use the disk space that you save to strategically cache additional scale levels.

Testing and optimizing the map

Many organizations have complex map documents (MXDs) that were originally prepared for desktop GIS purposes. These maps often need adjustments to meet the fast response times expected by Web users.

Before you change your map, you may want to create a test cache of a small area to give you some baseline figures. Choose an area that contains a good mix of geography represented in your map, for example, urban and rural, flat and mountainous, and so on. Note the time it takes to create the test cache. Then enable on-demand caching and zoom to an uncached area. Note how long it takes for the tiles to appear at various scales. If performance is acceptable at this point, you can choose to not make any adjustments.

If you want to improve performance of the on-demand tile creation or even the general cache creation speed, you can follow some of the tips presented in Map authoring considerations for ArcGIS Server. This topic explains ways to optimize your map document for performance on the Web. Look in the section “Performance tips for non-cached maps” for these tips. In general, you should remove unneeded layers and use the simplest symbology acceptable for the features you do choose to show.

One way to detect inefficient layers in your map service is to set the ArcGIS Server logging level to Info:Detailed. Make one draw request to the map service, such as zooming to a bookmark in ArcMap. Then examine the ExportMapImage request in the logs and note the draw time for each layer. You’ll quickly be able to tell which layers are taking the most time. It’s a good idea to repeat this exercise at your different cached scales in random areas of the map. Remember to set the logging level back to Normal when you are finished, as Info:Detailed writes more log information than you normally need.

Once you’ve optimized your map, make another test cache and note how long it takes to create a tile on demand. If performance is still not acceptable, you can opt to do one of the following things:

  • Pre-cache a larger area. This way the chance of encountering an on-demand tile is diminished. You can attempt to limit on-demand caching to only the most barren areas at the largest scales, thereby ensuring that not many features will have to be drawn at once.
  • Make a full cache. By pre-caching all of the tiles, you won’t have to create tiles on demand. This could be the best option if you have the time and space to create a full cache and it won’t be updated often. If server downtime while caching is a concern, you can script caching jobs to occur on nights and weekends to steadily build your cache until it is full. You can also choose to devote just one service instance to caching while other instances handle user requests.
  • Use a dynamic service. If building a full cache is not feasible and performance is acceptable with a dynamic service, you might choose to skip caching entirely. Although this option does not give the best performance, the maps you show will always be up to date and you will not have to create or manage a cache.

Updating tiles

When you edit your source database, you need to update the cache before users can see the changes. If you follow the recommendation of pre-caching an area based on a feature class and filling in the rest of your cache on demand, you’ll need to be careful that the updates include all the necessary areas.

There are two strategies you can follow to update your cache when you’ve been creating tiles on demand:

  • Delete all tiles that were created on demand before you perform an update. If you’re creating tiles on demand, you probably pre-cached a certain area based on a feature class. Normally you’ll also perform the update based on that feature class, and the on-demand tiles will become out-of-date if you do not delete them.

    To delete the tiles, run Manage Map Server Cache Tiles using the Delete Tiles mode. You should delete tiles based on the inverse of the feature class you pre-cached against. You can use ArcGIS editing tools to make a polygon representing the full extent of your map and cut a hole in it for the area that was pre-cached. The resulting “donut polygon” is the area where tiles should be deleted. See Common Polygon Editing Tasks for one explanation of how to cut a hole in a polygon using the Clip command.

    Alternatively, you can delete all tiles in the cache before you start the update, but this might add some overhead if your cache is large.

    If you’re worried that users will have to wait for a certain place to be cached on demand after every update, you should think about adding this place to the area that is pre-cached. When you’ve pre-cached wisely, on-demand caching should only occur infrequently in random patterns in the less-interesting areas of your map. If users are constantly returning to a place, it should be pre-cached.

  • Target your cache updates to cover only the areas where data was edited. One way to do this is to use geodatabase archiving or a custom tool to track all the changes since the last update, then export these changed areas to a feature class and update tiles based on the feature class boundary. Tom Brenneman’s tool Show Edits Since Reconcile can be helpful for this workflow. Alternatively you could use the Feature Compare tool to compare an edited copy of a feature class with an old copy and export the changed features.

    If you’re sure that you’re only updating areas where edits occurred, you don’t have to delete all the tiles that were created on demand.

Contributed by Sterling Quinn of the ArcGIS Server software development team

This information was recently added to the ArcGIS Server Web-based help as Strategies for on-demand caching

Posted in Services | Tagged , , , | Leave a comment

How to get IntelliSense with the .NET Web ADF JavaScript Library

In the 9.3 release of the
.NET Web ADF JavaScript Library
(not to be confused with the ArcGIS
JavaScript API) we extensively used
JavaScript code summaries
not only to automate creation of API
documentation, but also to provide developers with the new JScript IntelliSense
feature in Visual Studio 2008. However a bug in Visual Studio prevented us from
fully exposing this. The good news is that
Service Pack 1 for VS2008
is out which fixes the problem.

To take advantage of the Jscript IntelliSense feature:

  1. Install VS2008
    SP1
    .
  2. Open your Web mapping application in VS2008 and add a new JScript file.
  3. At the very top of the file add the following line:

    /// <reference assembly="ESRI.ArcGIS.ADF.Web.UI.WebControls" name="ESRI.ArcGIS.ADF.Web.UI.WebControls.Runtime.JavaScript.references.js"/>
  4. Wait a few seconds for the JScript IntelliSense to update (keep an eye on the
    status bar). You can also force it by hitting CTRL+Shift+J.
  5. Type “ESRI.” and see the IntelliSense dropdown do its magic.

    Viewing the IntelliSense

The idea is that the reference tag tells Visual Studio to also include
IntelliSense from the JavaScript file embedded within the Web control assembly.
This “reference” file will automatically reference all other JavaScript files
in the Web ADF.

Note that the reference tag does not work inside an ASP.NET page, but only in
dedicated JavaScript files. In Web pages you only get IntelliSense on
JavaScript files that are specifically included into the page either using a
<script src=…> tag or referenced with the ScriptManager. JavaScript
files emitted by Web controls like the Web ADF controls are not processed for
IntelliSense. This is a known limitation in Visual Studio.

Below are a couple of screenshots of what the IntelliSense looks like in Visual Studio.

Instantiating a new object:

Instantiating an object

Accessing properties on an object:

Accessing properties

Objects returned from methods that specify a specific return type automatically
get IntelliSense too:

IntelliSense on an object returned from a method

There are a few limitations though. Since JavaScript doesn’t have casting, there
is no way to tell Visual Studio the type of an object, so methods that return
super-class objects don’t give you IntelliSense on methods on the subclass.
An example of this is $find which returns a Sys.Component type. In the
following case it returns the map instance, but we don’t get to see all the
methods of the map. We only see those that are on the base Sys.Component type that
the map inherits from:

Methods from the base class

If you want to browse the properties, events, and methods using IntelliSense, you
will have to temporarily help Visual Studio by re-constructing the map object,
but remember to delete the constructor before you run it:

Browsing properties, events, and methods on a re-constructed object

Alternatively you can go to the SDK and browse all the objects available to you.
Go here
and click “Developing Web applications using the Web ADF” –
“Web ADF JavaScript Library” – “Library Reference” – “API”.

You can also
download the object model diagram as PDF
.

Contributed by Morten Nielsen of the ArcGIS Server .NET software development team.

Posted in Services | Tagged , , , , | 1 Comment

Developing ArcGIS JavaScript API portlets with NetBeans

It is quite easy to use the ArcGIS JavaScript API in a portal environment,
although there are some considerations that have to do with portlet development
as opposed to jsp/servlet development. The samples provided in the ArcGIS
JavaScript API Resource Center are not intended to be deployed in a portlet
container but with some minor tweaks we can get any of them up and running.

A Portal page is a single web page that is used to display content collected
from multiple sources. Portlets are individual web applications intended to
display content on a portal page. To the user, a portlet is a single window on
a portal page. To developers, portlets are Java based modules that can be
plugged into a larger portal page. Finally, a portlet application is a
collection of portlet modules that are packaged together for deployment.
Portlets within the same portlet application can share information and context
allowing inter-portlet communication and sharing of resources, property files,
and support classes. Portlets are managed by a portlet container and
consequently they have to be prepared and deployed in a portlet specific manner
according to either vendor or portlet version specifications.

Let’s walk through the steps to create a simple ArcGIS JavaScript API JSR 168
Portlet application. The steps will use NetBeans
6.1 with Portal Pack 2.0 plug-in
installed and we will deploy to GlassFish
server with OpenPortal Portlet
Container
installed. Portal Pack is a set of plug-ins for NetBeans IDE which provide portlet development and deployment support. Open Portal Portlet container is an enterprise-class standard Java Portlet Container (Portlet 1.0/2.0).

Create a Portlet Project

  1. In NetBeans, select File -> New Project -> Web -> Web Application.

    Create a new Web application

  2. Enter the Project Name and location and click Next.

    Enter the project name

  3. Ensure the Portal Server Container is selected and click Next.

    Select OpenPortal Portlet Container

  4. Under Frameworks, select ‘Portlet Support’ and choose Version 1.0 to build a
    JSR 168 portlet project (Version 2.0 is for JSR 286 portlet projects). Check
    ‘Create Portlet’ and ‘Create Jsps’ and fill in the Package and Portlet Class
    Name. Uncheck the Portlet Mode ‘Edit’.

    Select Portlet Support

The portlet application is now created with a default portlet class and relevant
jsp files. The portlet configuration file, portlet.xml, is updated with the
portlet we created through the wizard. We will now edit the view mode jsp file
to add a simple
ArcGIS JavaScript API
map.

Update source

The new project wizard created the Portlet class and jsps for view and help
modes. Your directory structure should look similar to this:

Directory structure 

Open up your view mode jsp file, AgsJsApiPortlet_view.jsp, and delete all
generated content. We will now edit the page to include an ArcGIS JavaScript
simple map sample. Copy and paste the code below into your view mode jsp.

<%@page contentType="text/html; charset=ISO-8859-1"%>
<%@page pageEncoding="UTF-8"%>

<%@taglib uri="http://java.sun.com/portlet" prefix="portlet" %>

<portlet:defineObjects/>

<div id="esrimap">
<link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/1.1/js/dojo/dijit/themes/tundra/tundra.css">
<script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=1.1"></script>

<script type="text/JavaScript">
dojo.require("esri.map");

function init() {
var map = new esri.Map("<portlet:namespace/>");
map.addLayer(new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_Imagery_World_2D/MapServer"));
}

dojo.addOnLoad(init);
</script>
<div id="<portlet:namespace/>" class="tundra" style="width:400px; height:300px; border:1px solid #000;"></div>
</div>

The jsp is like any typical jsp with an added
<portlet:defineObjects> tag. The portlet specification mandates the
portlet container to provide an implementation of the portlet tag library. The
portlet tag library enables jsp’s included in portlet projects to have access
to portlet objects. In order to use the tag library we declare it with the
statement:

<%@taglib uri="http://java.sun.com/portlet" prefix="portlet" %>

When using the ArcGIS JavaScript API, we typically include at least one style
sheet and required scripts. Our simple map portlet uses the following style
sheet for graphic elements inside our map DIV:

<link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/1.1/js/dojo/dijit/themes/tundra/tundra.css">

And this is a reference to the location of the ArcGIS Server JavaScript API
files:

<script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=1.1"></script>

The next script is where we put our JavaScript code for working with the map.
First we reference a package, initialize a map, and then add an event:

<!-- map package referenced using dojo.require()   -->
dojo.require("esri.map");

<!-- initialization function to add a layer to the map -->
function init() {
var map = new esri.Map("<portlet:namespace/>");
map.addLayer(new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_Imagery_World_2D/MapServer"));
}

<!-- the addOnLoad() event which takes in the init function as a parameter. -->
dojo.addOnLoad(init);

Although we do not need to edit our portlet class file generated by NetBeans,
let’s have a look at the doView() method to inspect what is happening. I added
some comments to help understand the generated code.

 
public void doView(RenderRequest request,RenderResponse response) throws PortletException,IOException {
// Set the MIME type for the render response
response.setContentType("text/html");
// Invoke the JSP to render and include the response
PortletRequestDispatcher dispatcher =
getPortletContext().getRequestDispatcher("/WEB-INF/jsp/AgsJsApiPortlet_view.jsp");
dispatcher.include(request, response);
}

Deploy and test

To run the portlet, right click on the project and click “Run”. NetBeans will
first deploy the portlet on the portlet container configured with the project.
If deployment is successful, NetBeans will open the configured browser and
display your portlet within the Portlet Container Driver as shown below:

Displaying the portlet 

Can I have multiple maps in a single portal page independent of each other?

Yes, in order to have multiple maps in a single portal page, you must make the
same considerations as required in a standard HTML page containing multiple
instances of the same ArcGIS JavaScript API applications. There are two main
requirements to consider, 1. A portal page can only have a single reference to
the ArcGIS JavaScript API from any of the portlets it includes and 2. Use a
unique identifier for each map (the <portlet:namespace/> tag generates a
unique id and is recommended here). Using the example provided above, we could
add another ArcGIS JavaScript Map Portlet with the following code, taking note
of the comments where we remove the ArcGIS JavaScript API reference and ensure
our map has a unique identifier:

<%@page contentType="text/html; charset=ISO-8859-1"%>
<%@page pageEncoding="UTF-8"%>

<%@taglib uri="http://java.sun.com/portlet" prefix="portlet" %>

<portlet:defineObjects/>

<div id="esrimap">
<!-- REMOVED JSAPI SCRIPT AND STYLESHEET REFERENCE -->

<script type="text/JavaScript">
dojo.require("esri.map");

function init() {
<!-- UNIQUE IDENTIFIER FOR EACH MAP -->
var map = new esri.Map("<portlet:namespace/>");
map.addLayer(new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer"));
}

dojo.addOnLoad(init);
</script>
<!-- REFERENCE UNIQUE IDENTIFIER FOR EACH MAP -->
<div id="<portlet:namespace/>" class="tundra" style="width:400px; height:300px; border:1px solid #000;"></div>
</div>
Two portlets 

Contributed by Dan O’Neill of the ArcGIS Server Java development team.

Posted in Services | Tagged , , , , | Leave a comment

"Operation aborted" error in Internet Explorer

A few users have reported encountering an “Operation aborted” error in Internet Explorer when attempting to access a web application built using the .NET Web ADF.

Operation Aborted error 

The issue can be traced to a race condition that occurs due to an Internet Explorer/ASP.Net AJAX bug. The probability of encountering this issue increases when the application has a significant number of ADF web controls and/or other ASP.Net AJAX enabled server controls on the web page.

Joel Rumerman has a blog post which describes the issue. Fortunately, he also has a workaround for the problem. He also posted the solution here on the MSDN code gallery. (Note on Oct 16, 2008: Received a note from Joel that he has updated his code.)

To apply the workaround, put the following code block into the markup of the web page before the actual call to Sys.Application.initialize(), or simply place the code after the </form> tag if a ScriptManager control doesn’t exist on the web page.

The exact location of the Sys.Application.initialize() call on a web page containing the ScriptManager web control can be located by viewing source on the web page (Right click + View Source) inside a browser. Typically this call will be towards the bottom of the page, close to the </form> tag. It is important that this code block is declared before the actual method call because it overrides the Sys.Application.initialize() function.

If this is a Web Mapping application built using Manager or the Web Mapping Application template, the code block can be inserted above the sever control tag for the identify control, which looks like this:

<uc1:MapIdentify ID="MapIdentify1" runat="server" MapBuddyId="Map1" />

Here’s the block of code you need to insert:

<script type="text/javascript">
Sys.Application.initialize = function Sys$_Application$initialize() {
if(!this._initialized && !this._initializing) {
this._initializing = true;
var loadMethodSet = false;
var initializeDelegate = Function.createDelegate(this, this._doInitialize);
if (document.addEventListener) {
loadMethodSet = true;
document.addEventListener("DOMContentLoaded", initializeDelegate, false);
}
if (/WebKit/i.test(navigator.userAgent))
{
loadMethodSet = true;
this._load_timer = setInterval(function()
{
if (/loaded|complete/.test(document.readyState))
{
initializeDelegate();
}
}, 10);
}
else
{
/*@cc_on @*/
/*@if (@_win32)
loadMethodSet = true;
document.write("<script id=__ie_onload defer src=javascript:void(0)></scr" + "ipt>");
var deferScript = document.getElementById("__ie_onload");
if (deferScript) {
deferScript.onreadystatechange = function() {
if (this.readyState == "complete") {
initializeDelegate();
}
};
}
/*@end @*/
}

// only if no other method will execute initializeDelegate is
// it wired to the window's load method.
if (!loadMethodSet)
{
$addHandler(window, "load", initializeDelegate);
}
}
}

Sys.Application._doInitialize = function Sys$_Application$_doInitialize() {
if (this._load_timer !== null)
{
clearInterval(this._load_timer);
this._load_timer = null;
}

Sys._Application.callBaseMethod(this, 'initialize');

var handler = this.get_events().getHandler("init");
if (handler) {
this.beginCreateComponents();
handler(this, Sys.EventArgs.Empty);
this.endCreateComponents();
}
this.raiseLoad();
this._initializing = false;
}

Sys.Application._loadHandler = function Sys$_Application$_loadHandler() {
if(this._loadHandlerDelegate) {
Sys.UI.DomEvent.removeHandler(window, "load",
this._loadHandlerDelegate);
this._loadHandlerDelegate = null;
}
this._initializing = true;
this._doInitialize();
}
</script>

Disclaimer: This workaround has been identified to resolve the above stated issue affecting Internet Explorer for ASP.Net AJAX version 1.0 and version 3.5 SP1. Because of the nature of this workaround, subsequent updates to ASP.Net AJAX by Microsoft might make the workaround irrelevant and/or cause other issues. We are actively working with Microsoft to resolve this issue as soon as possible.

Contributed by Nikhil Shampur of the ArcGIS Server .NET software development team

Posted in Services | Tagged , , , | Leave a comment

Video: ArcGIS Server .NET team members show three Code Gallery samples

In this video, ArcGIS Server .NET development team members show three new samples they’ve posted to the Code Gallery. You’ll see an “Add Data” custom control, a Flickr search task that uses the client side graphics capabilities of the Web ADF, and some custom renderers that give the appearance of 3D. The video also shows how you can download the samples.

Posted in Services | Tagged , , , , | Leave a comment