ThinkGeo Cloud
ThinkGeo UI Controls
ThinkGeo Open Source
Help and Support
External Resources
ThinkGeo Cloud
ThinkGeo UI Controls
ThinkGeo Open Source
Help and Support
External Resources
The Map Suite Web Quickstart Guide will guide you through the process of creating a sample application and will help you become familiar with Map Suite.
Welcome to Map Suite™ Web from ThinkGeo, a full-featured mapping control that makes it easy for any Microsoft .NET developer to add mapping functionality to a Microsoft .NET application quickly and efficiently. Using the intuitive object model, even developers inexperienced in Geographic Information Systems (GIS) can have fully functional maps working in minutes.
The purpose of this guide is to help you quickly get started building your own spatially aware applications. Like any new software, there is some learning to be done along the way.
How do we start to learn how to take advantage of the power of Map Suite? The best way is to make a sample application with it.
Let's start with a new ASP.NET Web Site in Microsoft Visual Studio (2015 or newer) and call it “QuickstartSample” (see Figure 1). Set the Templates to “.NET Framework 4.5” for the project.We just need to a simple template for our website, let’s select “Empty” template and do not check any other items. Click “OK” button, then a website will be created in a new solution called “QuickstartSample”.
To build this sample, we need to reference several packages from NuGet manager. There are two options for you.
In this sample, we choose an beginner way. To build this sample, we are going to reference the “MapSuiteWebForWebForms-Standard” package.
Right-click on “References” in Solution Explorer and select “Manage NuGet Packages…”
Now that we open NuGet dialog and install the three Nuget packages (See Figure 2).
Figure 2. Install NuGet package.
Now the package is installing into the project.
Click “OK” if the message box like the following pops up.
The “NetTopologySuite” is the third part assembly, so the license acceptance is required. You can click “I Accept” to agree the license.
Since we created an empty website, there isn’t any of pages under our project, let’s create our default main page. Right-click the project, select “Add” → “Web Form”. Created a new page called “WebForm1.aspx”.(See Figure 3)
Now, we have all the reference set. In the next chapter, we are going to talk about the real coding part. Now let’s look at ShapeFiles relating to the entire World. In our sample, we have such ShapeFiles:
The borders of every country in the world (“~/AppData/Countries02.shp”)
The capitals of the world countries (“~/AppData/WorldCapitals.shp”)
When you first open Microsoft Visual Studio after installing Map Suite, you may not see the control in the Toolbox. You will need to follow these steps to add the control.
1. Open “…/QuickstartSample/packages/MapSuiteWebForWebForms-Standard.10.0.0/designtime” package folder and drag “ThinkGeo.MapSuite.WebForms.dll” assembly to the Toolbox of Visual Studio.(See Figure 4)
Figure 4. Add Map Control To Toolbox.
2. Draw the Map control on the web form by clicking on the Map Control object in the Toolbox and then dragging and dropping (using the left mouse button) to the form. You can resize the map if you desire. You can leave the name of the Map control as “Map1”. Our map will display in this object.(See Figure 5)
Figure 5. Add Map Control To The Web From.
We can also add some codes to use a map:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="QuickstartSample.WebForm1" %> <%@ Register Assembly="ThinkGeo.MapSuite.WebForms" Namespace="ThinkGeo.MapSuite.WebForms" TagPrefix="cc1" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Quickstart</title> </head> <body> <form id="form1" runat="server"> <div> <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> <cc1:Map ID="Map1" runat="server" Height="600px" Width="800px"> </cc1:Map> </div> </form> </body> </html>
Now that we have “ThinkGeo.MapSuite.dll” referenced and a Map Control added. We are ready for adding the code.
After this section, you will be able to draw a map with Map Suite Web for WebForms using your own data. At the very beginning, let's have a look at the data and the important objects we will use.
In creating your “QuickstartSample” application, your first step is to set some references at the very top of your code, as you will use many classes within that. We do this so that we do not have to use the fully qualified name of the Map Suite classes throughout your code. Setting a reference to the Map Suite workspace can be done in the “code-behind” of the form by selecting the form and hitting the F7 function key. Add the references like this:
using ThinkGeo.MapSuite; using ThinkGeo.MapSuite.Drawing; using ThinkGeo.MapSuite.Layers; using ThinkGeo.MapSuite.Shapes; using ThinkGeo.MapSuite.Styles;
Now let's look at a code sample to bring this concept to fruition. We'll look at ShapeFiles relating to the entire world. In our example, we have one such ShapeFile:
(NOTE: The data used in this sample can be found in the attached sample above in the “\AppData” folder)
Our next step is to define and add our layers. All of our sample code can be placed in the “Page_Load” event of the web form. We also will want to put in a check for whether the page is posting back. This is so our Map control can load and render the data only once, during initial load, instead of repeatedly every time a post back to the web server is made. For the sample application we are making here, this check is not actually needed, as there will not be any PostBack in this application. Still, this is a good coding habit for a Web project, so let's put in the code to check for post backs in first. Then, we'll put our other code inside that structure.
protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { // Set the Map Unit. The reason for setting it to DecimalDegrees is that is what the ShapeFile’s unit of measure is inherently in. Map1.MapUnit = GeographyUnit.DecimalDegree; // We create a new Layer and pass the path to a ShapeFile into its constructor. ShapeFileFeatureLayer worldLayer = new ShapeFileFeatureLayer(MapPath("~/App_Data/Countries02.shp")); // Set the worldLayer with a preset Style AreaStyle areaStyle = new AreaStyle(); areaStyle.FillSolidBrush = new GeoSolidBrush(GeoColor.FromArgb(255, 233, 232, 214)); areaStyle.OutlinePen = new GeoPen(GeoColor.FromArgb(255, 118, 138, 69), 1); areaStyle.OutlinePen.DashStyle = LineDashStyle.Solid; worldLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = areaStyle; // This setting will apply from ZoonLevel01 to ZoomLevel20, that means we can see the world the same style with ZoomLevel01 all the time no matter how far we zoom out/in. worldLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; // Create a new Static Overlay to hold the layer we just created Map1.StaticOverlay.Layers.Add(worldLayer); // Set the default map extent, the unit is Decimal Degree. Map1.CurrentExtent = new RectangleShape(-134, 70, -56, 7); // Set the background color. Map1.MapBackground = new GeoSolidBrush(GeoColor.GeographicColors.ShallowOcean); } }
If you compile and run what you have now, your map should look like the one below. (See Figure 6).
Figure 6. A sample map of Europe.
So what has occurred here? We have created a layer and added it to the map and the map has rendered according to its default style parameters. Also, we have used ZoomLevel to display the map the way that we want.
NOTE: It is important that the “MapUnit” property of a Map object be set using the “GeographyUnit” enumeration. This is because ShapeFiles only store binary vector coordinates, which can be in DecimalDegree, feet, meters, etc. Our map has no idea about what the unit of measurement is until we set it. This information is normally found somewhere in the documentation or within the supplemental data file as discussed in the section on ShapeFiles.
With the above code, you can both display a map and navigate it. You can pan by dragging the map, zoom in by double-clicking, track zoom in by drawing a rectangle with your left mouse button mouse while holding the shift key, or zoom in and out by using the mouse wheel. Very powerful for just couple lines of code, isn't it?
That was an easy start! Now, let's add another Shapefile to the sample so that we will have a total of two layers:
protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { // Set the Map Unit. The reason for setting it to DecimalDegrees is that is what the shapefile’s unit of measure is inherently in. Map1.MapUnit = GeographyUnit.DecimalDegree; // We create a new Layer and pass the path to a Shapefile into its constructor. ShapeFileFeatureLayer worldLayer = new ShapeFileFeatureLayer(MapPath("~/App_Data/Countries02.shp")); // Set the worldLayer with a preset Style AreaStyle areaStyle = new AreaStyle(); areaStyle.FillSolidBrush = new GeoSolidBrush(GeoColor.FromArgb(255, 233, 232, 214)); areaStyle.OutlinePen = new GeoPen(GeoColor.FromArgb(255, 118, 138, 69), 1); areaStyle.OutlinePen.DashStyle = LineDashStyle.Solid; worldLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = areaStyle; // This setting will apply from ZoonLevel01 to ZoomLevel20, that means we can see the world the same style with ZoomLevel01 all the time no matter how far we zoom out/in. worldLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; ShapeFileFeatureLayer capitalLayer = new ShapeFileFeatureLayer(MapPath("~/App_Data/WorldCapitals.shp")); // Similarly, we use the presetPointStyle for cities. PointStyle pointStyle = new PointStyle(); pointStyle.SymbolType = PointSymbolType.Square; pointStyle.SymbolSolidBrush = new GeoSolidBrush(GeoColor.StandardColors.White); pointStyle.SymbolPen = new GeoPen(GeoColor.StandardColors.Black, 1); pointStyle.SymbolSize = 6; PointStyle stackStyle = new PointStyle(); stackStyle.SymbolType = PointSymbolType.Square; stackStyle.SymbolSolidBrush = new GeoSolidBrush(GeoColor.StandardColors.Maroon); stackStyle.SymbolPen = new GeoPen(GeoColor.StandardColors.Transparent, 0); stackStyle.SymbolSize = 2; pointStyle.CustomPointStyles.Add(stackStyle); capitalLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = pointStyle; // These settings will apply from ZoonLevel01 to ZoomLevel20, that means we can see city symbols the same style with ZoomLevel01 all the time no matter how far we zoom out/in. capitalLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; // We need to add both of the new layers to the Map's Static Overlay. Map1.StaticOverlay.Layers.Add(worldLayer); Map1.StaticOverlay.Layers.Add(capitalLayer); // Set the default map extent, the unit is Decimal Degree. Map1.CurrentExtent = new RectangleShape(-134, 70, -56, 7); Map1.MapBackground = new GeoSolidBrush(GeoColor.GeographicColors.ShallowOcean); } }
The result is as follows(Figure 7):
A TextStyle is used to label items on map. As every ShapeFile has a related .dbf file that includes descriptions for every record, the most common way to use TextStyle is for labeling. For example, WorldCapital ShapeFile's corresponding .dbf file contains the field “CITY_NAME”. We can use this field to label the cities on our map.
Map Suite has many TextStyles built in to help us quickly design attractive labels for the cities on our map. We can just pick the TextStyle we like and use it.
protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { // Set the Map Unit. The reason for setting it to DecimalDegrees is that is what the ShapeFile’s unit of measure is inherently in. Map1.MapUnit = GeographyUnit.DecimalDegree; // We create a new Layer and pass the path to a ShapeFile into its constructor. ShapeFileFeatureLayer worldLayer = new ShapeFileFeatureLayer(MapPath("~/App_Data/Countries02.shp")); // Set the worldLayer with a preset Style AreaStyle areaStyle = new AreaStyle(); areaStyle.FillSolidBrush = new GeoSolidBrush(GeoColor.FromArgb(255, 233, 232, 214)); areaStyle.OutlinePen = new GeoPen(GeoColor.FromArgb(255, 118, 138, 69), 1); areaStyle.OutlinePen.DashStyle = LineDashStyle.Solid; worldLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = areaStyle; // This setting will apply from ZoonLevel01 to ZoomLevel20, that means we can see the world the same style with ZoomLevel01 all the time no matter how far we zoom out/in. worldLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; ShapeFileFeatureLayer capitalLayer = new ShapeFileFeatureLayer(MapPath("~/App_Data/WorldCapitals.shp")); // Similarly, we use the presetPointStyle for cities. PointStyle pointStyle = new PointStyle(); pointStyle.SymbolType = PointSymbolType.Square; pointStyle.SymbolSolidBrush = new GeoSolidBrush(GeoColor.StandardColors.White); pointStyle.SymbolPen = new GeoPen(GeoColor.StandardColors.Black, 1); pointStyle.SymbolSize = 6; PointStyle stackStyle = new PointStyle(); stackStyle.SymbolType = PointSymbolType.Square; stackStyle.SymbolSolidBrush = new GeoSolidBrush(GeoColor.StandardColors.Maroon); stackStyle.SymbolPen = new GeoPen(GeoColor.StandardColors.Transparent, 0); stackStyle.SymbolSize = 2; pointStyle.CustomPointStyles.Add(stackStyle); capitalLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = pointStyle; // These settings will apply from ZoonLevel01 to ZoomLevel20, that means we can see city symbols the same style with ZoomLevel01 all the time no matter how far we zoom out/in. capitalLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; // We create a new Layer for labeling the capitals. ShapeFileFeatureLayer capitalLabelLayer = new ShapeFileFeatureLayer(MapPath("~/App_Data/WorldCapitals.shp")); GeoFont font = new GeoFont("Arial", 9, DrawingFontStyles.Bold); GeoSolidBrush txtBrush = new GeoSolidBrush(GeoColor.StandardColors.Maroon); TextStyle textStyle = new TextStyle("CITY_NAME", font, txtBrush); textStyle.XOffsetInPixel = 0; textStyle.YOffsetInPixel = -6; // We use the preset TextStyle. Here we passed in the “CITY_NAME”, which is the name of the field we want to label on map. capitalLabelLayer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle = textStyle; capitalLabelLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; // We need to add both of the new layers to the Map's Static Overlay. Map1.StaticOverlay.Layers.Add(worldLayer); Map1.StaticOverlay.Layers.Add(capitalLayer); Map1.StaticOverlay.Layers.Add(capitalLabelLayer); // Set the default map extent, the unit is Decimal Degree. Map1.CurrentExtent = new RectangleShape(-134, 70, -56, 7); // Set the background color. Map1.MapBackground = new GeoSolidBrush(GeoColor.GeographicColors.ShallowOcean); } }
The result is as follows (Figure 8):
Figure 8. Map of Europe with a TextStyle.
Now that we know how to render text and render symbols, let's define two different ZoomLevels in one single layer, and create our own custom Style and TextStyle.
protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { Map1.MapUnit = GeographyUnit.DecimalDegree; ShapeFileFeatureLayer worldLayer = new ShapeFileFeatureLayer(MapPath("~/App_Data/Countries02.shp")); AreaStyle areaStyle = new AreaStyle(); areaStyle.FillSolidBrush = new GeoSolidBrush(GeoColor.FromArgb(255, 233, 232, 214)); areaStyle.OutlinePen = new GeoPen(GeoColor.FromArgb(255, 118, 138, 69), 1); areaStyle.OutlinePen.DashStyle = LineDashStyle.Solid; worldLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = areaStyle; worldLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; ShapeFileFeatureLayer capitalLayer = new ShapeFileFeatureLayer(MapPath("~/App_Data/WorldCapitals.shp")); // We can customize our own Style. Here we passed in a color and a size. capitalLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyles.CreateSimpleCircleStyle(GeoColor.StandardColors.White, 7, GeoColor.StandardColors.Brown); // The Style we set here is available from ZoomLevel01 to ZoomLevel05. That means if we zoom in a bit more, the appearance we set here will not be visible anymore. capitalLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level05; PointStyle pointStyle = new PointStyle(); pointStyle.SymbolType = PointSymbolType.Square; pointStyle.SymbolSolidBrush = new GeoSolidBrush(GeoColor.StandardColors.White); pointStyle.SymbolPen = new GeoPen(GeoColor.StandardColors.Black, 1); pointStyle.SymbolSize = 6; PointStyle stackStyle = new PointStyle(); stackStyle.SymbolType = PointSymbolType.Square; stackStyle.SymbolSolidBrush = new GeoSolidBrush(GeoColor.StandardColors.Maroon); stackStyle.SymbolPen = new GeoPen(GeoColor.StandardColors.Transparent, 0); stackStyle.SymbolSize = 2; pointStyle.CustomPointStyles.Add(stackStyle); capitalLayer.ZoomLevelSet.ZoomLevel06.DefaultPointStyle = pointStyle; // The Style we set here is available from ZoomLevel06 to ZoomLevel20. That means if we zoom out a bit more, the appearance we set here will not be visible any more. capitalLayer.ZoomLevelSet.ZoomLevel06.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; ShapeFileFeatureLayer capitalLabelLayer = new ShapeFileFeatureLayer(MapPath("~/App_Data/WorldCapitals.shp")); // We can customize our own TextStyle. Here we passed in the font, the size, the style and the color. capitalLabelLayer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle = TextStyles.CreateSimpleTextStyle("CITY_NAME", "Arial", 8, DrawingFontStyles.Italic, GeoColor.StandardColors.Black, 3, 3); // The TextStyle we set here is available from ZoomLevel01 to ZoomLevel05. capitalLabelLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level05; GeoFont font = new GeoFont("Arial", 9, DrawingFontStyles.Bold); GeoSolidBrush txtBrush = new GeoSolidBrush(GeoColor.StandardColors.Maroon); TextStyle textStyle = new TextStyle("CITY_NAME", font, txtBrush); textStyle.XOffsetInPixel = 0; textStyle.YOffsetInPixel = -6; capitalLabelLayer.ZoomLevelSet.ZoomLevel06.DefaultTextStyle = textStyle; // The TextStyle we set here is available from ZoomLevel06 to ZoomLevel20. capitalLabelLayer.ZoomLevelSet.ZoomLevel06.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; Map1.StaticOverlay.Layers.Add(worldLayer); Map1.StaticOverlay.Layers.Add(capitalLayer); Map1.StaticOverlay.Layers.Add(capitalLabelLayer); Map1.CurrentExtent = new RectangleShape(-134, 70, -56, 7); // Set the background color to make the map beautiful. Map1.MapBackground = new GeoSolidBrush(GeoColor.GeographicColors.ShallowOcean); } }
Can you imagine what the map will look like now? Figure 9 below is the result. At first it looks the same as it did in Figure 8. Now zoom in, and watch the map change to resemble Figure 10 as you do.
Figure 9. A map of European cities with two ZoomLevels, before zooming in.
Figure 10. The same map with two ZoomLevels, after zooming in.
If you put the map within an update panel, you can take advantage of AJAX. To make this clearer, we will walk you through a sample.
First, let's add a marker on the map. Our first step is to add a reference to the ThinkGeo.MapSuite.WebForms
namespace at the very top of our code:
using ThinkGeo.MapSuite.WebForms;
Next, drag a button to the page and leave the name set to the default “Button1”. Double-click that button and write the following code in the Button1_Click
method:
protected void Button1_Click(object sender, EventArgs e) { if (!Map1.MarkerOverlay.FeatureSource.InternalFeatures.Contains("Marker")) { // Add a new feature as a marker Map1.MarkerOverlay.FeatureSource.InternalFeatures.Add("Marker", new Feature(-100, 40)); // Set the marker style, and make it available all over the zoomlevels. Map1.MarkerOverlay.ZoomLevelSet.ZoomLevel01.DefaultMarkerStyle.WebImage = new WebImage("../../theme/default/img/marker_blue.gif", 21, 25); Map1.MarkerOverlay.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; } }
Let's run the application and click the button. You will see a marker appear near London. (Figure 11)
Figure 11. Add a marker to the map.
We have now added a marker to the map; however, you will find that the map flickers every time you click the button.
The following code in “Default.aspx” shows how we can put the map control and the button within an update panel to solve the flickering problem. You can also put the button outside the update panel; see the following sets of example code for details:
Aspx code 1: Put both the map control and button into the update panel.
<body> <form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> <asp:UpdatePanel ID="UpdatePanel1" runat="server"> <ContentTemplate> <cc1:Map ID="Map1" runat="server" Height="600px" Width="800px"> </cc1:Map> <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" /> </ContentTemplate> </asp:UpdatePanel> </form> </body>
Aspx code 2: Put only map in an update panel.
<body> <form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional"> <ContentTemplate> <cc1:Map ID="Map1" runat="server" Height="600px" Width="800px"> </cc1:Map> </ContentTemplate> <Triggers> <asp:AsyncPostBackTrigger ControlID="Button1" EventName="Click" /> </Triggers> </asp:UpdatePanel> <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" /> </form> </body>
This completes this scenario. The next thing you might want to do is to make it run on another machine that does not have a developer license. A runtime license is the one we are looking for. Here is the guide to generate a runtime license: http://wiki.thinkgeo.com/wiki/map_suite_deployment_license_guide_for_web.
You now know the basics of using Map Suite Web Edition and are able to start adding this functionality into your own applications. Let's recap what we have learned about the object relationships and how the pieces of Map Suite work together: