Introduction
When working with customers, many times I am asked, "How do I implement a custom zoom bar into my application?" At first glance this may seem like a difficult task, but with a little explanation on a few concepts and some sample code, you can easily implement a full-featured zoom bar that meets the needs of your application. In this article I will show you how to build a custom zoom bar using the prebuilt zoom levels defined within Map Suite Web Edition; however, the same concepts apply to building a custom zoom bar using the Map Suite Desktop Edition as well.
Zoom Levels Explained
The Map Suite Desktop, Web and Engine products each come with eighteen prebuilt zoom levels to handle the most common zooming scenarios, ranging from worldwide coverage down to local streets. Having these prebuilt zoom levels at your disposal gives you complete control over how the map is rendered at each zoom level. For example, if you have a map of the world, you wouldn't want to show a lot of detail like country names or roads when the map is zoomed completely out. But as you zoom in, typically you would want to turn on more information such as labels and other map features. With Map Suite you can do just that – from tailoring ZoomLevel18 for views that show the entire globe, down to customizing ZoomLevel01 for a very detailed zoom area like local streets or small land parcels.
Note: Map Suite also allows you to specify your own zoom levels if the prebuilt levels don't meet your needs.
Getting Started
Now that we have covered how zoom levels work, let's get to the fun part: building our sample application with a custom zoom bar. To get started, you will need to create a new ASP.NET web application in Visual Studio 2005. Next, you will need to reference the Map Suite Web Edition .NET Control and drag it on to the web page. Also, don't forget to add the HTTP Handler section to your Web.config file so the map control can render properly.
Now let's add some code to the Page_Load event to initialize the Map and load up our layer representing all the countries in the world. Additionally, we will write some code to color these countries in a reddish hue and turn on country name labeling for zoom levels one to fourteen.
Page_Load Code:
if (!IsPostBack)
{
// Set property of map control
Map1.MapUnit = MapLengthUnits.DecimalDegrees;
Map1.Mode = Map.ModeType.Pan;
Rectangle Rect = new Rectangle(0, 0, (int)Map1.Width.Value, (int)Map1.Height.Value);
Map1.CanvasGeoBrush = new GeoLinearGradientBrush(Rect, GeoColor.GeographicColors.Ocean1, GeoColor.GeographicColors.Ocean2, GeoLinearGradientMode.ForwardDiagonal);
Map1.AjaxEnabled = true;
// Load world countries layer
Layer cntryLayer = new Layer(this.Server.MapPath("") + @"\SampleData\world\cntry02.shp", true);
//Color Countries with labels for all zoom level 14 and below
cntryLayer.ZoomLevel01.GeoStyle = GeoAreaStyles.GetHueFamilyStyle(6, GeoColor.KnownColors.Red, GeoColor.KnownColors.Gray);
cntryLayer.ZoomLevel01.GeoTextStyle = GeoTextStyles.Country1("CNTRY_NAME");
cntryLayer.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.ZoomLevel14;
//Color Countries with no labels to higest zoom levels
cntryLayer.ZoomLevel14.GeoStyle = GeoAreaStyles.GetHueFamilyStyle(6, GeoColor.KnownColors.Red, GeoColor.KnownColors.Gray);
cntryLayer.ZoomLevel14.ApplyUntilZoomLevel = ApplyUntilZoomLevel.ZoomLevel18;
Map1.Layers.Add(cntryLayer);
// Save some values in session
Session.Add("FullScale", Map1.CurrentScale);
}
Once you have this code implemented, you should be able to run your project and have a map displaying similar to the one below.
HTML Code
Now that we have a simple map displaying, it's time to take it to the next step and create our custom zoom bar using standard HTML. To do this, we will create a rather large zoom bar which has a button for each of the eighteen prebuilt zoom levels within Map Suite. If eighteen zoom levels seem like too many, remember that you have complete control over the number of zoom levels and you can implement the number that makes sense for your application. Below is the HTML that you'll need in order to implement a zoom bar with all eighteen levels. As you will notice, for each Zoom Button we make an AJAX call and pass in the level that each button represents. Once you have the HTML implemented, the next step is to add the server side code to zoom the map in to the proper level.
<!-- Zoom Bar -->
<p class="ZoomButton">
<img id="Level1" src="./images/zoom.gif" width="25px" height="12px" alt="" onclick="javascript:AjaxEvent('ClickLevel1','Map1');" class="imgbtn" style="cursor: hand" /> Local
</p>
<p class="ZoomButton">
<img id="Level2" src="./images/zoom.gif" width="25px" height="12px" alt="" onclick="javascript:AjaxEvent('ClickLevel2','Map1');" class="imgbtn" style="cursor: hand" />
</p>
<p class="ZoomButton">
<img id="Level3" src="./images/zoom.gif" width="25px" height="12px" alt="" onclick="javascript:AjaxEvent('ClickLevel3','Map1');" class="imgbtn" style="cursor: hand" />
</p>
<p class="ZoomButton">
<img id="Level4" src="./images/zoom.gif" width="25px" height="12px" alt="" onclick="javascript:AjaxEvent('ClickLevel4','Map1');" class="imgbtn" style="cursor: hand" />
</p>
<p class="ZoomButton">
<img id="Level5" src="./images/zoom.gif" width="25px" height="12px" alt="" onclick="javascript:AjaxEvent('ClickLevel5','Map1');" class="imgbtn" style="cursor: hand" />
</p>
<p class="ZoomButton">
<img id="Level6" src="./images/zoom.gif" width="25px" height="12px" alt="" onclick="javascript:AjaxEvent('ClickLevel6','Map1');" class="imgbtn" style="cursor: hand" /> City
</p>
<p class="ZoomButton">
<img id="Level7" src="./images/zoom.gif" width="25px" height="12px" alt="" onclick="javascript:AjaxEvent('ClickLevel7','Map1');" class="imgbtn" style="cursor: hand" />
</p>
<p class="ZoomButton">
<img id="Level8" src="./images/zoom.gif" width="25px" height="12px" alt="" onclick="javascript:AjaxEvent('ClickLevel8','Map1');" class="imgbtn" style="cursor: hand" />
</p>
<p class="ZoomButton">
<img id="Level9" src="./images/zoom.gif" width="25px" height="12px" alt="" onclick="javascript:AjaxEvent('ClickLevel9','Map1');" class="imgbtn" style="cursor: hand" />
</p>
<p class="ZoomButton">
<img id="Level10" src="./images/zoom.gif" width="25px" height="12px" alt="" onclick="javascript:AjaxEvent('ClickLevel10','Map1');" class="imgbtn" style="cursor: hand" /> Area
</p>
<p class="ZoomButton">
<img id="Level11" src="./images/zoom.gif" width="25px" height="12px" alt="" onclick="javascript:AjaxEvent('ClickLevel11','Map1');" class="imgbtn" style="cursor: hand" />
</p>
<p class="ZoomButton">
<img id="Level12" src="./images/zoom.gif" width="25px" height="12px" alt="" onclick="javascript:AjaxEvent('ClickLevel12','Map1');" class="imgbtn" style="cursor: hand" />
</p>
<p class="ZoomButton">
<img id="Level13" src="./images/zoom.gif" width="25px" height="12px" alt="" onclick="javascript:AjaxEvent('ClickLevel13','Map1');" class="imgbtn" style="cursor: hand" />
</p>
<p class="ZoomButton">
<img id="Level14" src="./images/zoom.gif" width="25px" height="12px" alt="" onclick="javascript:AjaxEvent('ClickLevel14','Map1');" class="imgbtn" style="cursor: hand" /> Country
</p>
<p class="ZoomButton">
<img id="Level15" src="./images/zoom.gif" width="25px" height="12px" alt="" onclick="javascript:AjaxEvent('ClickLevel15','Map1');" class="imgbtn" style="cursor: hand" />
</p>
<p class="ZoomButton">
<img id="Level16" src="./images/zoom.gif" width="25px" height="12px" alt="" onclick="javascript:AjaxEvent('ClickLevel16','Map1');" class="imgbtn" style="cursor: hand" />
</p>
<p class="ZoomButton">
<img id="Level17" src="./images/zoom.gif" width="25px" height="12px" alt="" onclick="javascript:AjaxEvent('ClickLevel17','Map1');" class="imgbtn" style="cursor: hand" />
</p>
<p class="ZoomButton">
<img id="Level18" src="./images/zoombar_on.gif" width="25px" height="12px" alt="" onclick="javascript:AjaxEvent('ClickLevel18','Map1');" class="imgbtn" style="cursor: hand" /> World
</p>
Server Side Code
With the zoom bar now implemented in the webpage, it's time to write some server side code to capture the AJAX event and zoom the map in to the proper level. To handle the AJAX event raised from the JavaScript click event on the zoom bar button, we need to implement the Map's AjaxPostback event, write a case statement based on the argument from each zoom bar button and set the map zoom level accordingly. Below is some sample code showing how to implement this functionality.
Map1_AjaxPostback Code:
protected void Map1_AjaxPostback(object sender, AjaxPostbackEventArgs e)
{
switch (e.EventName)
{
case "ClickLevel1":
Map1.CurrentScale = GetScaleFromZoomlevel(Map1.Layers[0].ZoomLevel01);
break;
case "ClickLevel2":
Map1.CurrentScale = GetScaleFromZoomlevel(Map1.Layers[0].ZoomLevel02);
break;
case "ClickLevel3":
Map1.CurrentScale = GetScaleFromZoomlevel(Map1.Layers[0].ZoomLevel03);
break;
case "ClickLevel4":
Map1.CurrentScale = GetScaleFromZoomlevel(Map1.Layers[0].ZoomLevel04);
break;
case "ClickLevel5":
Map1.CurrentScale = GetScaleFromZoomlevel(Map1.Layers[0].ZoomLevel05);
break;
case "ClickLevel6":
Map1.CurrentScale = GetScaleFromZoomlevel(Map1.Layers[0].ZoomLevel06);
break;
case "ClickLevel7":
Map1.CurrentScale = GetScaleFromZoomlevel(Map1.Layers[0].ZoomLevel07);
break;
case "ClickLevel8":
Map1.CurrentScale = GetScaleFromZoomlevel(Map1.Layers[0].ZoomLevel08);
break;
case "ClickLevel9":
Map1.CurrentScale = GetScaleFromZoomlevel(Map1.Layers[0].ZoomLevel09);
break;
case "ClickLevel10":
Map1.CurrentScale = GetScaleFromZoomlevel(Map1.Layers[0].ZoomLevel10);
break;
case "ClickLevel11":
Map1.CurrentScale = GetScaleFromZoomlevel(Map1.Layers[0].ZoomLevel11);
break;
case "ClickLevel12":
Map1.CurrentScale = GetScaleFromZoomlevel(Map1.Layers[0].ZoomLevel12);
break;
case "ClickLevel13":
Map1.CurrentScale = GetScaleFromZoomlevel(Map1.Layers[0].ZoomLevel13);
break;
case "ClickLevel14":
Map1.CurrentScale = GetScaleFromZoomlevel(Map1.Layers[0].ZoomLevel14);
break;
case "ClickLevel15":
Map1.CurrentScale = GetScaleFromZoomlevel(Map1.Layers[0].ZoomLevel15);
break;
case "ClickLevel16":
Map1.CurrentScale = GetScaleFromZoomlevel(Map1.Layers[0].ZoomLevel16);
break;
case "ClickLevel17":
Map1.CurrentScale = GetScaleFromZoomlevel(Map1.Layers[0].ZoomLevel17);
break;
case "ClickLevel18":
Map1.CurrentScale = (Double)Session["FullScale"];
break;
case "ZoomIn":
Map1.ZoomIn(20);
break;
case "ZoomOut":
Map1.ZoomOut(20);
break;
case "TrackZoom":
Map1.Mode = Map.ModeType.TrackZoomIn;
break;
case "PreviousExtent":
Map1.GetPreviousExtent();
break;
case "ToggleExtent":
Map1.ToggleMapExtents();
break;
case "FullExtent":
Map1.CurrentExtent = Map1.Layers[0].Extent;
break;
case "PanLeft":
Map1.Pan(PanDirection.Left, 20);
break;
case "PanRight":
Map1.Pan(PanDirection.Right, 20);
break;
case "PanUp":
Map1.Pan(PanDirection.Up, 20);
break;
case "PanDown":
Map1.Pan(PanDirection.Down, 20);
break;
case "PanNorthEast":
Map1.Pan(45, 20);
break;
case "PanNorthWest":
Map1.Pan(315, 20);
break;
case "PanSouthEast":
Map1.Pan(135, 20);
break;
case "PanSouthWest":
Map1.Pan(225, 20);
break;
// Click zoom level button in zoom bar
default:
break;
}
// Sent value back and we will deal with it in client by "CustomCallback" function
Map1.AjaxReturnArgs = "Level" + GetLevelNumber(Map1.CurrentScale).ToString();
}
As you can see from the code above, for each click level we are calling a function named GetScaleFromZoomLevel and passing in the associated zoom level. This function returns the new zoom level by calculating the midpoint of the zoom level's scale. Once the new scale is calculated, all that remains is to set this scale to the Map's Current Scale property. The code for the GetScaleFromZoomLevel function that returns the zoom level's midpoint is shown below for your reference.
private double GetScaleFromZoomlevel(PresetZoomLevel presetZoomLevel)
{
return (presetZoomLevel.UpperExtent + resetZoomLevel.LowerExtent) / 2;
}
Now the only thing left to do is return the zoom level that we are currently at, so that the zoom bar buttons can be updated accordingly. This is accomplished by utilizing the GetLevelNumber function and the Map's AjaxReturnArgs property. In case you're not familiar with the AjaxReturnArgs property, it s a mechanism for passing data back to the client code. At the end of the Map1_AjaxPostback event handler you will see the following line of code, which sets the AjaxReturnArgs property to the Zoom Level we are currently displaying:
Map1.AjaxReturnArgs = "Level" + GetLevelNumber(Map1.CurrentScale).ToString();
In case you were curious what the GetLevelNumber function does, it takes the CurrentScale of the map, compares it against all of the zoom levels and returns the current zoom level. The code for this function is provided below for your reference.
GetLevelNumber Function Code:
public int GetLevelNumber(double scale)
{
int result;
if (scale < 0)
{
throw new Exception("The Width of your Map should be more than 0");
}
else if (scale < Map1.Layers[0].ZoomLevel01.UpperExtent)
{
result = 1;
}
else if (scale < Map1.Layers[0].ZoomLevel02.UpperExtent)
{
result = 2;
}
else if (scale < Map1.Layers[0].ZoomLevel03.UpperExtent)
{
result = 3;
}
else if (scale < Map1.Layers[0].ZoomLevel04.UpperExtent)
{
result = 4;
}
else if (scale < Map1.Layers[0].ZoomLevel05.UpperExtent)
{
result = 5;
}
else if (scale < Map1.Layers[0].ZoomLevel06.UpperExtent)
{
result = 6;
}
else if (scale < Map1.Layers[0].ZoomLevel07.UpperExtent)
{
result = 7;
}
else if (scale < Map1.Layers[0].ZoomLevel08.UpperExtent)
{
result = 8;
}
else if (scale < Map1.Layers[0].ZoomLevel09.UpperExtent)
{
result = 9;
}
else if (scale < Map1.Layers[0].ZoomLevel10.UpperExtent)
{
result = 10;
}
else if (scale < Map1.Layers[0].ZoomLevel11.UpperExtent)
{
result = 11;
}
else if (scale < Map1.Layers[0].ZoomLevel12.UpperExtent)
{
result = 12;
}
else if (scale < Map1.Layers[0].ZoomLevel13.UpperExtent)
{
result = 13;
}
else if (scale < Map1.Layers[0].ZoomLevel14.UpperExtent)
{
result = 14;
}
else if (scale < Map1.Layers[0].ZoomLevel15.UpperExtent)
{
result = 15;
}
else if (scale < Map1.Layers[0].ZoomLevel16.UpperExtent)
{
result = 16;
}
else if (scale < Map1.Layers[0].ZoomLevel17.UpperExtent)
{
result = 17;
}
else
{
result = 18;
}
return result;
}
Client Side JavaScript Code
Now that the server side code is completed and the map is zoomed into the proper level, the next step is to update the zoom bar button images to identify which zoom level is currently being displayed on the map. To accomplish this, we will need to implement the CustomCallback JavaScript function on the client side. This will allow us to analyze the return arguments from the server side code and update each zoom bar button image accordingly. For an example on how to implement this, please see the code below:
CustomCallback Javascript Code:
<!--Get value from server and set the status of zoom button-->
<script type="text/javascript">
function CustomCallback(ajaxReturnArgs)
{
if(ajaxReturnArgs != '')
{
var ImageButton;
ImageButton = document.getElementById('Level1');
ImageButton.src='./images/zoombar_off.png';
ImageButton = document.getElementById('Level2');
ImageButton.src='./images/zoombar_off.png';
ImageButton = document.getElementById('Level3');
ImageButton.src='./images/zoombar_off.png';
ImageButton = document.getElementById('Level4');
ImageButton.src='./images/zoombar_off.png';
ImageButton = document.getElementById('Level5');
ImageButton.src='./images/zoombar_off.png';
ImageButton = document.getElementById('Level6');
ImageButton.src='./images/zoombar_off.png';
ImageButton = document.getElementById('Level7');
ImageButton.src='./images/zoombar_off.png';
ImageButton = document.getElementById('Level8');
ImageButton.src='./images/zoombar_off.png';
ImageButton = document.getElementById('Level9');
ImageButton.src='./images/zoombar_off.png';
ImageButton = document.getElementById('Level10');
ImageButton.src='./images/zoombar_off.png';
ImageButton = document.getElementById('Level11');
ImageButton.src='./images/zoombar_off.png';
ImageButton = document.getElementById('Level12');
ImageButton.src='./images/zoombar_off.png';
ImageButton = document.getElementById('Level13');
ImageButton.src='./images/zoombar_off.png';
ImageButton = document.getElementById('Level14');
ImageButton.src='./images/zoombar_off.png';
ImageButton = document.getElementById('Level15');
ImageButton.src='./images/zoombar_off.png';
ImageButton = document.getElementById('Level16');
ImageButton.src='./images/zoombar_off.png';
ImageButton = document.getElementById('Level17');
ImageButton.src='./images/zoombar_off.png';
ImageButton = document.getElementById('Level18');
ImageButton.src='./images/zoombar_off.png';
ImageButton = document.getElementById(ajaxReturnArgs);
ImageButton.src='./images/zoombar_on.png';
}
}
</script>
Once you have this JavaScript function implemented, the appropriate zoom bar button should be highlighted in green, like the "Country" zoom bar button is in the screen shot below.
Summary
In conclusion, you now can see how to build your own custom zoom bar to meet your specific needs. Having this flexibility allows you to control the zoom levels, zoom bar location and overall look of the zoom bar implementation. This can be very important when making the mapping screen easy to use for end users. Below, I have listed several links where you can download the full source code and project to get more familiar with the sample application described in this article. Finally, if you have any questions or suggestions please feel to post comments on the ThinkGeo Blog or Discussion Forums, as these are both great ways for us to hear from the Map Suite community.
Downloads & Online Demo
Zoom Bar Online Demo
Project and Source Code for Map Suite Zoom Bar Example
Map Suite Web ASP.NET Control (Registration Required)
Note: You will need to download and install the Map Suite Web Edition in order to run the example in this article.
Have Questions?
Do you have questions or comments about this article? Feel free post your questions on the Map Suite Discussion Forums or leave feedback at the ThinkGeo Blog.
Additional Resources
Map Suite QuickStart Guides
Map Suite API Documentation
Map Suite FAQs
About the Author
Clint Batman is co-founder and President of ThinkGeo, a software company specializing in geospatial software with an emphasis on software development tools and GPS tracking solutions.