I extended ESRI’s ArcWeb Flex API’s RasterTileLayer class which normally supports only geographic tile layouts, and made it work with Mercator. Picture a lot of trial and error, and a few functioning yet not working tile-layouts that were plain silly.
ESRI’s ArcWeb Flex API supports making web maps from ArcWeb data-sources and from some custom data-sources such as ArcIMS and ArcGIS Server. A couple of code-samples infer that writing your own custom imagery provider is easy. But I wouldn’t call it easy. The ArcWeb Flex API is closed source, the documentation extends only to public methods/properties, and does not cover all classes in the API.
Luckily, there are ways of digging. The Flex API ships as an SWC file — a compiled Flash/Flex library. These files are well known to be ZIP files containing a CATALOG.XML file. This catalog file lists all of the class names in the API along with dependency classes. Its a more convenient way of getting to know the hidden API than blindly exploring the “import com.esri.awx…” intellisense code-hints available within Flex Builder.
Once you’ve found an interesting class, cross your fingers and pray that its implementation is obvious. Again, code-hinting goes a long way. Its trivial to instantiate a class and see what public methods and properties are available. Sub-class using the ”extends” keyword and you’ll gain access to the internal and protected property and method names. Within the Flex API, the class names, code-hinting, etc. are usually descriptive enough to get by.
When the path is less clear, you’ll need to use Flex’s debugging to find your way. I eventually sub-classed and overrode every class method/getter/setter with a simple call to the super-class. This allowed me to follow the logical order of method calls, and keep an eye on the Flex debug Variables at every step of the class’s lifecycle.
Did I mention trial-and-error? I still don’t know how or why some of the code I wrote works. To me, the math hacks are what makes this cool … we say the earth is 360×360 to make things square, but fudge the latitude to fix tile Y-positioning.
package com.esri.aws.awx.map.layers
{
import com.esri.aws.awx.map.projection.*;
import com.esri.aws.awx.map.layers.tiles.*;
public class MercatorTileLayer extends RasterTileLayer
{
private var _mercLayout : ITileLayout;
public function MercatorTileLayer()
{
m_scheme = new ClientPowerOfTwoTilingSchemeImpl(true, 17, 256, 256, 1, 1, -180, -180, 180, 180, "");
m_tileLayout = _mercLayout = new MercatorTileLayout(m_scheme);
}
override protected function commitProperties():void{
m_schemes[dataSource] = m_scheme; // setting m_schemes[] seems to prevent m_scheme resets
super.commitProperties(); // This still resets m_tileLayout, I can't figure a way around it
m_tileLayout = _mercLayout; // So we'll fix m_tileLayout ourselves
}
override public function get supportedProjections():Array
{
return [ProjUtils.PROJECTION_STYLE_MERCATOR];
}
override protected function constructUrl(tileKey:TileKey, token:String):String{
return "http://localhost./TileServer/" + dataSource + "/" + getZoomString( tileKey ) + ".ashx";
}
}
}
package com.esri.aws.awx.map.layers.tiles
{
public class MercatorTileLayout extends TileLayoutImpl implements ITileLayout
{
internal static var toDegrees:Number = 180.0 / Math.PI;
internal static var toRadians:Number = Math.PI / 180.0;
public function MercatorTileLayout(tilingScheme:ITilingScheme)
{
super(tilingScheme);
}
override public function determineTilesForView(list:TilesList, centerX:Number, centerY:Number, mapScale:Number, displayWidth:int, displayHeight:int):TilesList
{
if (centerY > 85.05113) centerY = 85.05113;
if (centerY < -85.05113) centerY = -85.05113;
centerY = centerY * toRadians;
centerY = Math.log( Math.abs(Math.tan( (Math.PI/4) + (centerY/2) )) );
centerY = centerY * toDegrees;
return super.determineTilesForView(list, centerX, centerY, mapScale, displayWidth, displayHeight);
}
}
}
One final note is that this won’t get you too far using Google or Microsoft’s Mercator tiles. Flash famously has the ability to bypass cross-domain restrictions using CrossDomain.xml files. Lesser known is Flash’s lameness in using images across domains. You oddly cannot smooth/resize/alter an image loaded from another domain without a CrossDomain.xml file. The Flex API does image smoothing and resizing, so no-go for commercial imagery providers without crossdomain.xml files. Ridiculous!