Hi everyone, I would like to share with you some thoughts about the topic of this discussion. We had to edit the Flex Viewer source code to enable changing map spatial reference for our project and I saw that a lot of people were asking similar question here so I think I can give you my solution.
First of all I would like to thank Dasa Paddock for some thoughts in this thread: http://forums.arcgis.com/threads/693...is-it-possible.
I'm aware my solution might not be the best solution out there but still it might give someone some insight on the topic. Before I start with some code I need to make sure you understand that this is solution specific for our project! Few things are needed but few things you will have to adjust to your needs(i will mark them in code).
Ok let's start:
Config.xml -> map tag, change the mapwraparound180 to false.
In MapManager.mxml we defined these variables:
Now i want to populate opLayerArr with operational layers loaded from config.xml. So in MapManager.mxml find function "addLayerToMap", change the definition of this function:
Now find functions: private function loadNextOpertionalLayer():void and private function loadNextBasemapLayer():void
Now go to private function basemapSwitchHandler(event:AppEvent):void
Now function LoadBaseMaps:
Now project map.extent.center to new spatial reference so we can pan the map to the right place:
Next is ChangeSpatialRef function:
After changing spatial reference we need to refresh all operational layers plus I want to 'remember' which op layers were visible:
Now when the Geometry Service completes projection do this:
Ok so let's check the extent(to be precise - let's check the center point of extent). I dont know why but honestly from the beginning there was a problem with recentering the map in onProjectComplete function so we had to add timer to make sure the extent will change.
And the last function(note: I wanted to be sure that I turn on layers only when the extent is correct so making them visible is the last thing to do)
So this is it. I'm aware many of you would do this better, faster etc. but this is a discussion so you can point me few things that should be done different.
Few notes:
1.You will have to deal with LODs for dynamic/wms map services - if you don't want them just clear the map.lods array -> you can show dynamic services in scales of one of your tiled service.
2.We tested this with LayerListWidget, Legend and few other(CoordinateMenuWidget, BookmarkWidget[*], DrawAndMeasureWidget..) and they all works. No errors at all.
3.As I said - adjust this to your project!
4.Solution for OverviewMap in next post - this is already too long;)
*In bookmark widget you'll have to make few changes to make it work in all spatial refenerces in your project.
Regards
MDruzgala
First of all I would like to thank Dasa Paddock for some thoughts in this thread: http://forums.arcgis.com/threads/693...is-it-possible.
I'm aware my solution might not be the best solution out there but still it might give someone some insight on the topic. Before I start with some code I need to make sure you understand that this is solution specific for our project! Few things are needed but few things you will have to adjust to your needs(i will mark them in code).
Ok let's start:
Config.xml -> map tag, change the mapwraparound180 to false.
In MapManager.mxml we defined these variables:
Code:
//needed
private var opLayerArr:Array = new Array();
private var timer:Timer = new Timer(200); // delay of the timer is
private var visibleLayers:ArrayCollection;
private var mPoint:MapPoint;
private var visibleBasemaps:ArrayCollection = new ArrayCollection();
private var tiled:String = "tiled";
private var osm:String = "osm";
private var bing:String = "bing";
//for our project
private var webMercator:Number = 102100;
private var pol92:Number = 2180;
private var Compass:String = "Compass";
Code:
private function addLayerToMap(layerObject:Object, isOperationalLayer:Boolean):void
//next inside this function add:
if(isOperationalLayer == true)
{
opLayerArr.push(layer);
}
Code:
private function loadNextBasemapLayer():void
{
var basemapLayerObject:Object = m_basemapLayers[m_basemapLayerIndex];
addLayerToMap(basemapLayerObject, false);
configureLayerRenderer(basemapLayerObject, false);
}
private function loadNextOpertionalLayer():void
{
var optLayerObject:Object = m_operationalLayers[m_operationalLayerIndex];
addLayerToMap(optLayerObject, true);
configureLayerRenderer(optLayerObject, true);
}
Code:
if (layer.id == basemapLabel)
{
if (layer.id == selectedLabel)
{
var layerType:String = configBasemaps[i].type; //get type of the basemap service
LoadBaseMaps(selectedLabel, layerType, layer, i, layers); //call LoadBaseMaps function
}
else
{
layer.visible = false;
}
}
Code:
var currentCenterPoint:MapPoint = map.extent.center;
var currentWKID:Number = map.spatialReference.wkid;
if(layerType == tiled || layerType == osm || layerType == bing)
{
var toWKID:Number;
(selectedLabel == Compass) ? toWKID = pol92 : toWKID = webMercator; // ok this is for our project you
// will have to adjust this to your needs- we know that only one mapservice has different spatial reference and rest is in
// web mercator
if(toWKID != currentWKID)
{
ProjectPoint(currentCenterPoint, toWKID);
ChangeSpatialRef(toWKID);
map.lods = layers[i].tileInfo.lods;
visibleBasemaps.addItem(layer);
}
else
{
layer.visible = true;
map.lods = layers[i].tileInfo.lods;
}
}
else
{
layer.visible = true;
}
//if layer is tiled(or bing or osm) do some logic, else just turn it visible
Code:
private function ProjectPoint(mapPoint:MapPoint, toWKID:Number):void
{
try
{
var projectParams:ProjectParameters = new ProjectParameters();
projectParams.geometries = [mapPoint];
projectParams.outSpatialReference = new SpatialReference(toWKID);
geometryService.project(projectParams);
}
catch(er:Error)
{
//your logic for error
}
}
Code:
private function ChangeSpatialRef(toWKID:Number):void
{
map.spatialReference.wkid = toWKID;
RefreshLayers();
}
Code:
private function RefreshLayers():void
{
visibleLayers = new ArrayCollection();
for each (var layer:Layer in opLayerArr)//this is what why we need the opLayerArr
{
for each(var layerW:Layer in map.layers)
{
if(layer == layerW)
{
if(layerW.visible == true)
{
visibleLayers.addItem(layerW);
layerW.visible = false;
}
layerW.refresh();
}
}
}
}
Code:
private function onProjectComplete(event:GeometryServiceEvent):void
{
mPoint = event.result[0] as MapPoint;
map.centerAt(mPoint);
timer.start();//i want to be sure that map recentered so i will check it with timer
// in private function this_creationCompleteHandler():void add -> timer.addEventListener(TimerEvent.TIMER, CheckExtent);
}
Code:
private function CheckExtent(event:TimerEvent):void
{
if(map.extent.center != mPoint)
{
map.centerAt(mPoint);
SetLayersVisible();
timer.stop();
}
else
{
SetLayersVisible();
timer.stop();
}
}
Code:
private function SetLayersVisible():void
{
for each(var l:Layer in visibleBasemaps)
{
l.visible = true;
}
for each(var layer:Layer in visibleLayers)
{
for each(var lay:Layer in map.layers)
{
if(layer == lay)
{
lay.visible = true;
}
}
}
visibleBasemaps.removeAll();
visibleLayers.removeAll();
}
Few notes:
1.You will have to deal with LODs for dynamic/wms map services - if you don't want them just clear the map.lods array -> you can show dynamic services in scales of one of your tiled service.
2.We tested this with LayerListWidget, Legend and few other(CoordinateMenuWidget, BookmarkWidget[*], DrawAndMeasureWidget..) and they all works. No errors at all.
3.As I said - adjust this to your project!
4.Solution for OverviewMap in next post - this is already too long;)
*In bookmark widget you'll have to make few changes to make it work in all spatial refenerces in your project.
Regards
MDruzgala