Register  |  Login   Search
ThinkGeo - GPS Tracking and Mapping Solutions  |  Home  |  Cygnus Track  |  Blog
 
LivePerson Chat

Map Suite
Web with AJAX .NET GIS Component

Common Questions About Map Suite Web 2.55

Click on any of the frequently asked questions below to be taken to the answer.

If I have the latitude and longitude of a point, how can I plot it on a map?

All you need to do is, 1) Create a new point, 2) Add that point to the map.

Create a new Webforms project, add a map (name it Map1) to the form, and add the following code to the form's load event:

C#

using MapSuite;

using MapSuite.Geometry;

 

// This first section is only to get a map of US to show.

Map1.MapUnit = MapLengthUnits.DecimalDegrees;

Layer lyr = new Layer(@"..\sampledata\world\cntry02.shp",true);

lyr.ZoomLevelExtentUnit = ZoomLevelExtentUnits.DecimalDegrees;

lyr.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.ZoomLevel18;

lyr.ZoomLevel01.GeoStyle = GeoAreaStyles.GetSimpleAreaStyle(GeoColor.KnownColors.LightGray, GeoColor.KnownColors.Black, 1);

Map1.Layers.Add(lyr);

 

// This second section is all you need to plot a point if you have the latitude and longitude

PointMapShape pointMapShape = new PointMapShape();

pointMapShape.Shape = new PointShape(-119.09, 34.32);

pointMapShape.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.ZoomLevel18;

pointMapShape.ZoomLevel01.GeoStyle = GeoPointStyles.City1;

pointMapShape.ZoomLevel01.GeoTextStyle = GeoTextStyles.GetSimpleTextStyle(string.Empty, "Arial", 12, GeoFontStyle.Bold, GeoColor.KnownColors.Black);

pointMapShape.Name = "Los Angles";

Map1.MapShapes.Add(pointMapShape);

VB.NET

Imports MapSuite

Imports MapSuite.Geometry

 

' This first section is only to get a map of US to show.

Map1.MapUnit = MapLengthUnits.DecimalDegrees

Dim lyr As New Layer("..\sampledata\world\cntry02.shp", True)

lyr.ZoomLevelExtentUnit = ZoomLevelExtentUnits.DecimalDegrees

lyr.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.ZoomLevel18

lyr.ZoomLevel01.GeoStyle = GeoAreaStyles.GetSimpleAreaStyle(GeoColor.KnownColors.LightGray, GeoColor.KnownColors.Black, 1)

Map1.Layers.Add(lyr)

 

' This second section is all you need to plot a point if you have the latitude and longitude

Dim pointMapShape As New PointMapShape()

pointMapShape.Shape = New PointShape(-119.09, 34.32)

pointMapShape.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.ZoomLevel18

pointMapShape.ZoomLevel01.GeoStyle = GeoPointStyles.City1

pointMapShape.ZoomLevel01.GeoTextStyle = GeoTextStyles.GetSimpleTextStyle(String.Empty, "Arial", 12, GeoFontStyle.Bold, GeoColor.KnownColors.Black)

pointMapShape.Name = "Los Angles"

Map1.MapShapes.Add(pointMapShape) 

Back to Top

I would like to have more custom properties (like a tag property) on a map shape object. How can I add my own properties?

Adding custom properties is quite easy. All you have to do is inherit from one of the classes and add your own custom properties, like in the following code:

C#

using MapSuite;

using MapSuite.Geometry;

 

public class MyPointMapShape : PointMapShape

{

    private string tag = string.Empty;

 

      public MyPointMapShape(PointShape pointShape, PointSymbol pointSymbol)

        :base(pointShape,pointSymbol)

      {

      }

 

    public string Tag

    {

        get

        {

            return tag;

        }

        set

        {

            tag = value;

        }

    }

}

VB.NET

Imports MapSuite

Imports MapSuite.Geometry

 

Public Class MyPointMapShape

    Inherits PointMapShape

    Private m_tag As String = String.Empty

 

    Public Sub New(ByVal pointShape As PointShape, ByVal pointSymbol As PointSymbol)

        MyBase.New(pointShape, pointSymbol)

    End Sub

 

    Public Property Tag() As String

        Get

            Return m_tag

        End Get

        Set(ByVal value As String)

            m_tag = value

        End Set

    End Property

End Class 

From here, you can add as many custom properties as you would like.

Back to Top

How do I convert screen coordinates into world coordinates?

The map control has a method ToWorldCoordinate which takes in a PointF object (a point in canvas / screen coordinates). Returned is a PointR object (a point in world coordinates).

C#

System.Drawing.PointF controlPointF = new System.Drawing.PointF(45, 34);

PointR pointR = Map1.ToWorldCoordinate(controlPointF);

PointShape p0 = new PointShape(pointR.X, pointR.Y);

VB.NET

Dim controlPointF As New System.Drawing.PointF(45, 34)

Dim pointR As PointR = Map1.ToWorldCoordinate(controlPointF)

Dim p0 As New PointShape(pointR.X, pointR.Y)

Back to Top

How do I convert world coordinates into screen coordinates?

The map control has a method ToCanvasCoordinate which takes in a PointR object (a point in world coordinates). Returned is a PointF object (a point in canvas / screen coordinates).

C#

PointShape pointShape = new PointShape(-119.09, 34.32);

System.Drawing.PointF screetPoint = Map1.ToCanvasCoordinate(pointShape.X, pointShape.Y);

VB.NET

Dim pointShape As New PointShape(-119.09, 34.32)

Dim screetPoint As System.Drawing.PointF = Map1.ToCanvasCoordinate(pointShape.X, pointShape.Y)

Back to Top

How can I find a map shape when the user clicks it?

First, set the Map.Mode to ModeType.SelectMapShapes. Second, add the SelectMapShapes Event on the MapControl  Event Control.  Once this is done, every time a map shape is clicked, the Map_SelectMapShapes event will fire, passing in the map shapes that were selected. It is the map shapes (plural) because you could have more than one map shape in one location. Therefore, when that location is clicked, it is unclear which map shape was meant. So, it is actually an array of map shapes. Here is the code to make it clearer. Note: The Geometry sample named "Information" can show you more detail on this.

C#

Map1.Mode = MapSuite.WebEdition.Map.ModeType.SelectMapShapes;

protected void Map1_SelectMapShapes(BaseMapShape[] MapShapes)

{

     if (MapShapes != null)

     {

         System.Windows.Forms.MessageBox.Show(String.Format("MapShapes Number: {0}", MapShapes.Length));

     }

}

VB.NET

Map1.Mode = MapSuite.WebEdition.Map.ModeType.SelectMapShapes

Protected Sub Map1_SelectMapShapes(ByVal MapShapes() As MapSuite.BaseMapShape) Handles Map1.SelectMapShapes

    If MapShapes IsNot Nothing Then

        System.Windows.Forms.MessageBox.Show([String].Format("MapShapes Number: {0}", MapShapes.Length))

    End If

End Sub 

Back to Top

How can I find a feature (road, city, etc.) when the user clicks it?

First, set the Map.Mode to ModeType.SelectFeatures. Once this is done, every time a feature is clicked, the Map_SelectFeatures event will fire, passing in the features that were selected. It is the features (plural) because you could have more than one feature in one location (for example, a bridge crossing over a river). Here is the code to make it clearer. Note: The Query sample named "Select Features Mode" can show you more detail on this.

C#

Map1.Mode = MapSuite.WebEdition.Map.ModeType.SelectFeatures;

protected void Map1_SelectFeatures(FeatureInfo[] FeatureInfo)

{

    if (FeatureInfo != null)

    {

         System.Windows.Forms.MessageBox.Show(String.Format("FeatureInfos Number: {0}", FeatureInfo.Length));

    }

}

VB.NET

Map1.Mode = MapSuite.WebEdition.Map.ModeType.SelectFeatures
Protected Sub Map1_SelectFeatures(ByVal FeatureInfo() As MapSuite.FeatureInfo) Handles Map1.SelectFeatures

   If FeatureInfo IsNot Nothing Then

       System.Windows.Forms.MessageBox.Show([String].Format("FeatureInfo Number: {0}", FeatureInfo.Length))

   End If

End Sub

Back to Top

How can I zoom in on an area based on a query?

First, you need to create a custom field object, but the real work comes from calling GetRecordsExtents() from the layer object to see the extent you need to use. Below is some code to make this a little clearer.

C#

//Here you would set the record numbers to something meaningful in your your system
int[] RecordNumber = new int[3];

RecordNumber[0] = 2;

RecordNumber[1] = 5;

RecordNumber[2] = 17;

 

RectangleR NewExtent = Map1.Layers[0].GetRecordsExtents(RecordNumber);

NewExtent.ScaleUp(10);

Map1.CurrentExtent = NewExtent;

VB.NET

'--Here you would set the record numbers to something meaningful in your your system
Dim RecordNumber As Integer() = New Integer(2) {}

RecordNumber(0) = 2

RecordNumber(1) = 5

RecordNumber(2) = 17

 

Dim NewExtent As RectangleR = Map1.Layers(0).GetRecordsExtents(RecordNumber)

NewExtent.ScaleUp(10)

Map1.CurrentExtent = NewExtent

Back to Top

How can I label a map feature with specific text?

The Querying sample named "Select Features Mode" can show you how to do this but the shortest version is to use the preset GeoStyles and GeoTextStyles. You need to pass in the field name (from the dbf file) that you want to use as the label. Here is some code to make it a little clearer.

C#

Map1.MapUnit = MapLengthUnits.DecimalDegrees;

Layer lyr = new Layer(@"..\sampledata\usa\austin\austinpoints.shp", true);

lyr.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.ZoomLevel18;

 

// Set the GeoStyle and GeoTextStyle for the layer, need to pass in the dbf field name.

lyr.ZoomLevel01.GeoStyle = GeoPointStyles.City1;

lyr.ZoomLevel01.GeoTextStyle = GeoTextStyles.City1("Name");

 

Map1.Layers.Add(lyr);

VB.NET

Map1.MapUnit = MapLengthUnits.DecimalDegrees

Dim lyr As New Layer("..\sampledata\usa\austin\austinpoints.shp", True)

lyr.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.ZoomLevel18

 

' Set the GeoStyle and GeoTextStyle for the layer, need to pass in the dbf field name.

lyr.ZoomLevel01.GeoStyle = GeoPointStyles.City1

lyr.ZoomLevel01.GeoTextStyle = GeoTextStyles.City1("Name")

 

Map1.Layers.Add(lyr) 

Back to Top

I see a layer can have different zoomlevels. What would I use this feature for?

Imagine you have an application which maps a traveler's journey between two points. You would, likely, start by showing the entire US as the full extent. At this level, you would show the states and maybe the interstate and US highways. As the user zooms in to a single state, you might show state highways. As they zoom in more you might show county roads. As they zoom in so they are looking at a city, you could show all the city streets.

In such an application you would need to setup different zoomlevels to control what the is shown to the user and when (otherwise, the map would be too cluttered). In this example, you would setup a zoomlevel to show states, interstate and US highways. This zoomlevel would be setup to show when the user was at any zoom level (say between 30,000 miles across and 0 miles across). Then another zoomlevel would be created to show state highways when the user is zoomed into the state level (say between 750 miles across and 0 miles across). You keep setting up more and more zoomlevels like this. Your final zoomlevel would be to show the city streets when the user is zoomed to between 10 miles across and 0 miles across). You may notice that all of the zoomlevels here are set to keep showing as the user zooms in (the second parameter is 0 miles across). You could also set one or more zoomlevels to stop showing once zoomed in too close to something.

The Misc sample named "ZoomLevels" can show you in more detail how to use zoomlevels.

Back to Top

How can I draw a scale bar that displays to the side of the map (not on top of the map)?

In Desktop Edition we can implement this effect, but cannot in WebEdition. In WebEditiion, the desired location has to be within the Map and some options provided to locate the ScaleBar using the following code. Besides, we also provide some properties to denote the ScaleBar effects.

C#

Map1.ScaleBar.Location = ScaleBarLocationEnum.UpperLeft;

Map1.ScaleBar.Visible = true;

VB.NET

Map1.ScaleBar.Location = ScaleBarLocationEnum.UpperLeft

Map1.ScaleBar.Visible = True 

The sample named "LayerInfoApp" includes this code. If you review this sample, you should understand a bit better.

Back to Top

How can I find out if a certain point is contained within a certain rectangular area?

You should call Layer.SpatialQuery on the layer that contains the point in question. You should pass in the rectangle (or other shape) that you want to search. You will also need to pass in the containment rule, in this case SaptialQueryContainment.Contained. Returned will be an array of record numbers of the items within the shape you passed in. You can test this array to see if the point you are interested in is in the there.

C#

protected void Map1_AjaxFinishedTrackShape(object sender, AjaxFinishTrackShapeEventArgs e)

{

      SpatialQuery (e.Shape);

}

private void SpatialQuery (BaseShape Shape)
{
bool PointIsInRectangle = false;

 

Layer nlayer = Map1.Layers[0];

SpatialQueryContainment SpatialRule = SpatialQueryContainment.Contained;
     
int[] recordNumbers = nlayer.SpatialQuery(Shape, SpatialRule);
     
foreach (int i in recordNumbers)

{

            // Here we are using 23 to represent the record number of the point in question.

            if (i == 23)

            {

               // Put your logic here to do something special if the point is selected.

               PointIsInRectangle = true;

            }

      }

}

VB.NET

Protected Sub Map1_AjaxFinishedTrackShape(ByVal sender As Object, ByVal e As AjaxFinishTrackShapeEventArgs)

    SpatialQuery(e.Shape)

End Sub

 

Private Sub SpatialQuery(ByVal Shape As BaseShape)

    Dim PointIsInRectangle As Boolean = False

 

    Dim nlayer As Layer = Map1.Layers(0)

    Dim SpatialRule As SpatialQueryContainment = SpatialQueryContainment.Contained

    Dim recordNumbers As Integer() = nlayer.SpatialQuery(Shape, SpatialRule)

    For Each i As Integer In recordNumbers

        ' Here we are using 23 to represent the record number of the point in question.

        If i = 23 Then

            ' Put your logic here to do something special if the point is selected.

             PointIsInRectangle = True

        End If

    Next

End Sub 

The Querying sample named "Spatial Query" covers this topic in greater detail.

Back to Top

How can I get information about point or feature from a dbf file?

Using Layer.DataQuery you can get all the information available in the dbf file. This routine takes in either a SQL string or record number(s). If you have the record number of the point you want information about (23 in this example), you would use the following code to get the data about that point from the dbf file into a DataTable object:

C#

DataTable dt = Map1.Layers[0].DataQuery(23, false);

VB.NET

Dim dt As DataTable = Map1.Layers(0).DataQuery(23, False) 

The Querying sample "Combination Query" will show you more detail on this topic.

Back to Top

Once I have a record number, how can I get the shape for that record?

Using Layer.GetShape you can get the shape object for a record (in this example, 23). The following code would accomplish this:

C#

BaseShape shape = Map1.Layers[0].GetShape(23);

VB.NET

Dim shape As MapSuite.Geometry.BaseShape = Map1.Layers(0).GetShape(23) 

You could also use Layer.DataQuery with the following code (this will return all the dbf file information as well as the shape):

C#

DataTable dt = Map1.Layers[0].DataQuery(23, false);

VB.NET

Dim dt As DataTable = Map1.Layers(0).DataQuery(23, False)  

Back to Top

How can I zoom in or out programmatically?

Zooming in or out is quite easy – you can do it with a single line of code:

C#

Map1.ZoomIn (40); // this will zoom in 40%

Map1.ZoomOut (40); // this will zoom out 40%

VB.NET

Map1.ZoomIn (40) '-- This will zoom in 40%

Map1.ZoomOut (40) '-- This will zoom out 40%

You can see this code in every sample under the routine PerformAction which is used by the menu and the toolbar.

Back to Top

How can I stop a user from zooming out too far? Is there a way to limit zooming out?

Before you zoom out via code, you can test the current width of the map and either zoom out or not depending on what you find. The following code could be used for this:

C#

using MapSuite;

using MapSuite.Geometry;

 

//This will zoom out 40% only if the map is currently showing less than 900 miles across.

if (Map1.CurrentExtent.get_Width(MapLengthUnits.DecimalDegrees, MapLengthUnits.miles) < 900)

{

     Map1.ZoomOut(40);

}

VB.NET

Imports MapSuite

Imports MapSuite.Geometry

 

'This will zoom out 40% only if the map is currently showing less than 900 miles across.

If (Map1.CurrentExtent.Width(MapLengthUnits.DecimalDegrees, MapLengthUnits.miles) < 900) Then

    Map1.ZoomOut(40)

End If 

Back to Top

How can I set the full extent of a map to something specific?

The Map1.FullExtent is a read-only property so you cannot change it but you can easily accomplish your task by creating your own extent and when the user clicks on your "Full Extent" menu item/toobar button you just assign your custom extent to the map's current extent. The following code shows you how.

C#

// First you need a module level variable to hold the custom full extent.

RectangleR rect;

// Then (in some routine) set the map so that it is showing the extent that

// will be your custom full extent, saving that in the variable.

rect = Map1.CurrentExtent;

// Then, when you want to go to your custom full extent, just assign the variable to the map's current extent.

Map1.CurrentExtent = rect;

VB.NET

' First you need a module level variable to hold the custom full extent.

Dim rect As RectangleR

' Then (in some routine) set the map so that it is showing the extent that

' will be your custom full extent, saving that in the variable.

rect = Map1.CurrentExtent

 

' Then, when you want to go to your custom full extent, just assign the variable to the map's current extent.

Map1.CurrentExtent = rect

Back to Top

How can I display my data so each item falls within some group? For example, if I have several cities with different populations, how could I group these cities into the categories of small, medium, and large, each with its own symbol on the map?

To accomplish this you would use class breaks. You can see the Rendering sample named "Label Value Renderer" (or another one is Class Break Renderer) for more detail. Basically, you need to create a series of class breaks and one class break cap to group the data. For example, let's use the example of cities, like in Label Value Renderer. In that sample, each listed city falls into one of five categories: Less than 500,000; 500,000 - 999,999; 1,000,000 - 1,999,999; 2,000,000 - 4,999,999; and 5,000,000 and over. When we setup the class breaks, you'll see how it works. The code below accomplishes the task.

C#

// First we need to setup the zoomlevel and collection.

ZoomLevel zoomLevel = new ZoomLevel(10000, 2500);

SymbolClassBreakCollection classBreaks = new SymbolClassBreakCollection();

 

// Create first break, which is 'Under 500,000' and add it to the collection.

SymbolClassBreakRenderer.ClassBreak break1 = new SymbolClassBreakRenderer.ClassBreak(500000, mCustomPointSymbol1);

classBreaks.Add(break1);

 

// Create second break, which is 'Under 1,000,000' and add it to the collection

SymbolClassBreakRenderer.ClassBreak break2 = new SymbolClassBreakRenderer.ClassBreak(1000000, mCustomPointSymbol2);

classBreaks.Add(break2);

 

// Create third break, which is 'Under 2,000,000' and add it to the collection

SymbolClassBreakRenderer.ClassBreak break3 = new SymbolClassBreakRenderer.ClassBreak(2000000, mCustomPointSymbol3);

classBreaks.Add(break3);

 

// Create cap, which will handle the final two categories. Every class break collection must end with a cap

// In this case, the cap says, everything over 5,000,000 should get Symbol5 and under 5,000,000 will get Symbol4

SymbolClassBreakRenderer.ClassBreakCap cap = new SymbolClassBreakRenderer.ClassBreakCap(5000000, mCustomPointSymbol5, mCustomPointSymbol4);

classBreaks.Add(cap);

 

// Now, we just add the class break collection to a renderer and add the renderer to the zoomlevel.

SymbolClassBreakRenderer rend = new SymbolClassBreakRenderer("population", classBreaks);

zoomLevel.GeoStyle.SymbolRenderers.Add(rend);

 

// At this point, we have setup our class breaks.

VB.NET

' First we need to setup the zoomlevel and collection.

Dim zoomLevel As New ZoomLevel(10000, 2500)

Dim classBreaks As New SymbolClassBreakCollection()

 

' Create first break, which is 'Under 500,000' and add it to the collection.

Dim break1 As New SymbolClassBreakRenderer.ClassBreak(500000, mCustomPointSymbol1)

classBreaks.Add(break1)

 

' Create second break, which is 'Under 1,000,000' and add it to the collection

Dim break2 As New SymbolClassBreakRenderer.ClassBreak(1000000, mCustomPointSymbol2)

classBreaks.Add(break2)

 

' Create third break, which is 'Under 2,000,000' and add it to the collection

Dim break3 As New SymbolClassBreakRenderer.ClassBreak(2000000, mCustomPointSymbol3)

classBreaks.Add(break3)

 

' Create cap, which will handle the final two categories. Every class break collection must end with a cap

' In this case, the cap says, everything over 5,000,000 should get Symbol5 and under 5,000,000 will get Symbol4

Dim cap As New SymbolClassBreakRenderer.ClassBreakCap(5000000, mCustomPointSymbol5, mCustomPointSymbol4)

classBreaks.Add(cap)

 

' Now, we just add the class break collection to a renderer and add the renderer to the zoomlevel.

Dim rend As New SymbolClassBreakRenderer("population", classBreaks)

zoomLevel.GeoStyle.SymbolRenderers.Add(rend)

 

' At this point, we have setup our class breaks. 

When you are this far, you have the class breaks setup. It is important that you remember that the sequence is quite important. The sequence in which the class breaks are added to the collection will determine into which class each value falls. The logic will work something like the following.

  • For each value to be put into a class break (for each city in this example)
  • Compare to each class break
  • Does the current value fall below the current class break level?
  • If yes, then the current value is assigned to the current class break, go to the next value (city).
  • If no, then go to the next class break.
  • If we get to the class break cap and the current value is higher than the cap (5,000,000 in this example) then assign to the highest class break, regardless of how high the value is.

So, if you add the class breaks in a different order, expect different results.

Back to Top

­How can I display my data so each item is represented with a special symbol based on a exact textual match (not categories, classes or ranges)? For example, a lake should be blue, a dry lake should be brown, etc.

To accomplish this you would use symbol value renderers. You can see the Rendering sample named "Value Renderer" for more detail. You need to create a collection to hold the values to match and then setup a symbol for each value ('Lake', 'Dry Lake', etc.). See the following code.

C#

// First we need to setup the zoomlevel and collection.

ZoomLevel zoomLevel = new ZoomLevel(10000, 0);

SymbolValueCollection values = new SymbolValueCollection();

SymbolValueRenderer.Value val;

AreaSymbol sym;

 

// Add renderer value for any record named "Lake". This will be a simple light sky blue color for a lake.

sym = new AreaSymbol(new GeoPen(GeoColor.KnownColors.Black), new GeoSolidBrush(GeoColor.KnownColors.LightSkyBlue));

val = new SymbolValueRenderer.Value("Lake", sym);

values.Add(val);

 

// Add renderer value for any record named "Dry Lake". This will be an actual graphic that looks like a dry lake.

Bitmap bmp = new Bitmap(@"..\SampleData\Texures\rust pebbles.bmp");

sym = new AreaSymbol(new GeoPen(GeoColor.FromArgb(0,0,0,0)),new GeoTextureBrush(bmp));

val = new SymbolValueRenderer.Value("Dry Lake", sym);

values.Add(val);

 

// Now, we must create the renderer (collection of values) and add it to the zoomlevel.

SymbolValueRenderer rend = new SymbolValueRenderer("Feature", values);

zoomLevel.GeoStyle.SymbolRenderers.Add(rend);

 

// At this point, lakes and dry lakes are configured to show using the symbols we specified

// All you need to do now is add the zoomlevel to the layer and add the layer to the map.

 

VB.NET

' First we need to setup the zoomlevel and collection.

Dim zoomLevel As New ZoomLevel(10000, 0)

Dim values As New SymbolValueCollection()

Dim val As SymbolValueRenderer.Value

Dim sym As AreaSymbol

 

' Add renderer value for any record named "Lake". This will be a simple light sky blue color for a lake.

sym = New AreaSymbol(New GeoPen(GeoColor.KnownColors.Black), New GeoSolidBrush(GeoColor.KnownColors.LightSkyBlue))

val = New SymbolValueRenderer.Value("Lake", sym)

values.Add(val)

 

' Add renderer value for any record named "Dry Lake". This will be an actual graphic that looks like a dry lake.

Dim bmp As New Bitmap("..\SampleData\Texures\rust pebbles.bmp")

sym = New AreaSymbol(New GeoPen(GeoColor.FromArgb(0, 0, 0, 0)), New GeoTextureBrush(bmp))

val = New SymbolValueRenderer.Value("Dry Lake", sym)

values.Add(val)

 

' Now, we must create the renderer (collection of values) and add it to the zoomlevel.

Dim rend As New SymbolValueRenderer("Feature", values)

zoomLevel.GeoStyle.SymbolRenderers.Add(rend)

 

' At this point, lakes and dry lakes are configured to show using the symbols we specified

' All you need to do now is add the zoomlevel to the layer and add the layer to the map. 

Back to Top

How can I use my own rendering logic when the symbol representing an place's location is being drawn?

Setting up your own rendering logic for this is quite easy. You can see the Rendering sample named "Custom Symbols" for a more detailed example on how to accomplish this but simply put, all you need to do is create a module level variable of type PointSymbol and then wire-up a custom draw event to handle that object's drawing. The following code should make it clearer:

C#

// Module-level variable to represent the point symbol for each location.

private PointSymbol mCustomPointSymbol;


// Then, create the custom draw routine
private void mCustomPointSymbol_CustomDraw(Graphics graphics, PointF pointF, PointSymbol symbol)

{

     int xCoordinate = Convert.ToInt32(pointF.X - 7);

     int yCoordinate = Convert.ToInt32(pointF.Y - 7);

     Rectangle rect = new Rectangle(xCoordinate, yCoordinate, 14, 14);

 

     GraphicsPath graphicsPath = new GraphicsPath();

     graphicsPath.AddEllipse(rect);

 

     PathGradientBrush brush = new PathGradientBrush(graphicsPath.PathPoints);

 

     Color[] colors = { Color.FromArgb(170, 37, 137, 43) };

     brush.CenterColor = Color.FromArgb(255, 32, 115, 36);

     brush.SurroundColors = colors;

     brush.FocusScales = new PointF(Convert.ToSingle(0.01), Convert.ToSingle(0.01));

 

     graphics.FillEllipse(brush, rect);

     brush.Dispose();

}



// Then, in the page's load event, instantiate the variable and wire-up the custom draw routine
protected void Page_Load (object sender, System.EventArgs e)
{

mCustomPointSymbol = new PointSymbol(PointStyleEnum.Custom);
     
mCustomPointSymbol.CustomDraw += new PointSymbol.CustomDrawEventHandler(mCustomPointSymbol_CustomDraw);
}

VB.NET

' Module-level variable to represent the point symbol for each location.

Private mCustomPointSymbol As PointSymbol

' Then, create the custom draw routine

Private Sub mCustomPointSymbol_CustomDraw(ByVal graphics As Graphics, ByVal pointF As PointF, ByVal symbol As PointSymbol)

    Dim xCoordinate As Integer = Convert.ToInt32(pointF.X - 7)

    Dim yCoordinate As Integer = Convert.ToInt32(pointF.Y - 7)

    Dim rect As New Rectangle(xCoordinate, yCoordinate, 14, 14)

 

    Dim graphicsPath As New GraphicsPath()

    graphicsPath.AddEllipse(rect)

 

    Dim brush As New PathGradientBrush(graphicsPath.PathPoints)

 

    Dim colors As Color() = {Color.FromArgb(170, 37, 137, 43)}

    brush.CenterColor = Color.FromArgb(255, 32, 115, 36)

    brush.SurroundColors = colors

    brush.FocusScales = New PointF(Convert.ToSingle(0.01), Convert.ToSingle(0.01))

 

    graphics.FillEllipse(brush, rect)

    brush.Dispose()

End Sub 

 

'Then, in the page's load event, instantiate the variable and wire-up the custom draw routine

Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)

   mCustomPointSymbol = New PointSymbol(PointStyleEnum.[Custom])

   AddHandler mCustomPointSymbol.CustomDraw, AddressOf mCustomPointSymbol_CustomDraw

End Sub

 

Back to Top

How can I have items labeled differently based on a value in a field in the shape file? For example, if I have several cities in each country in Europe, I want to show capitals in a larger font than non-capitals.

To accomplish this you would use the label value renderer. You can see the Rendering sample named "Label Value Renderer" for more detail. You need to create a label value collection and add to that collection one label value for each value to be match. In this example, we will have two label values; one for "Y" and one for "N" in the field named "Capital." The code below does just that.

C#

// First we need to setup the zoomlevel and collection.

ZoomLevel zoomLevel = new ZoomLevel(2500, 0);

LabelValueCollection col = new LabelValueCollection();

LabelValueRenderer.LabelValue val;

TextSymbol sym;

 

// Setup for captitals.

sym = new TextSymbol(new GeoFont("Arial",12,GeoFontStyle.Bold),new GeoSolidBrush(GeoColor.KnownColors.Black),0,-8);

val = new LabelValueRenderer.LabelValue("Y",sym);

col.Add(sym);

 

// Setup for non-captitals.

sym = new TextSymbol(new GeoFont("Arial",8, GeoFontStyle.Bold),new GeoSolidBrush(GeoColor.KnownColors.Black),0,-6);

val = new LabelValueRenderer.LabelValue("N",sym);

col.Add(val);

 

// Create renderer, testing field "Capital" but displaying field "Name".

LabelValueRenderer render = new LabelValueRenderer("Captical", "Name", col);

 

// Add renderer to the zoomlevel.

zoomLevel.GeoTextStyle.LabelRenderers.Add(render); 

 

VB.NET

' First we need to setup the zoomlevel and collection.

Dim zoomLevel As New ZoomLevel(2500, 0)

Dim col As New LabelValueCollection()

Dim val As LabelValueRenderer.LabelValue

Dim sym As TextSymbol

 

' Setup for captitals.

sym = New TextSymbol(New GeoFont("Arial", 12, GeoFontStyle.Bold), New GeoSolidBrush(GeoColor.KnownColors.Black), 0, -8)

val = New LabelValueRenderer.LabelValue("Y", sym)

col.Add(sym)

 

' Setup for non-captitals.

sym = New TextSymbol(New GeoFont("Arial", 8, GeoFontStyle.Bold), New GeoSolidBrush(GeoColor.KnownColors.Black), 0, -6)

val = New LabelValueRenderer.LabelValue("N", sym)

col.Add(val)

 

' Create renderer, testing field "Capital" but displaying field "Name".

Dim render As New LabelValueRenderer("Captical", "Name", col)

 

' Add renderer to the zoomlevel.

zoomLevel.GeoTextStyle.LabelRenderers.Add(render) 

Back to Top

I see that a map can have multiple layers. Why would I use multiple layers?

Since a layer is the object that holds the data (that is a layer has one and only one shape file as it's data source) if you want to have multiple data sources then you need multiple layers. The Misc sample named "ZoomLevels" can show you more details about this. In this sample, you will see six layers created. One layer has the streets of Austin, one layer has the US highways, one layer has the details about the US states, etc. The zoomlevels in this sample just, in effect, tell each layer to render only at certain zoom factors. The point is that each layer actually has the data from the shape file. So, multiple shape files mean multiple layers.

Back to Top

When a user selects a certain feature, I want to be able to change its symbol to show it is different from the other features. How would I "highlight" a feature when it is selected?

In the Querying sample named "Select Features Mode," you can see exactly how to do this. The basics are this: Loop through each shape, clear the shape's symbols (so only the shape shows but no highlighting symbols show), then if the shape from the current round in the loop is the one that was selected, then add to it the symbols that you would like to use for highlighting. The following code will illustrate this.

C#

// This is a simplified version of the code in the Select Features Mode sample app

// This code assumes that all shapes on the map are point shapes (there are no line or area shapes).
private void UpdateSelectedSymols(int index)

{

    for( int i = 0 ; i < Map1.MapShapes.Count ; i++)

    {

       Map1.MapShapes[i].Symbols.Clear();

       if(i == index)

       {

          GeoSolidBrush brush = new GeoSolidBrush(GeoColor.FromArgb(150,GeoColor.KnownColors.Red));

          Map1.MapShapes[i].Symbols.Add(new AreaSymbol(new GeoPen(GeoColor.KnownColors.Black),brush));

       }

       else

       {

          GeoSolidBrush brush = new GeoSolidBrush(GeoColor.FromArgb(150,GeoColor.KnownColors.Orange));

          Map1.MapShapes[i].Symbols.Add(new AreaSymbol(new GeoPen(GeoColor.KnownColors.Black),brush));

       }

    }

}

VB.NET

' This is a simplified version of the code in the Select Features Mode sample app

' This code assumes that all shapes on the map are point shapes (there are no line or area shapes).

Private Sub UpdateSelectedSymols(ByVal index As Integer)

   For i As Integer = 0 To Map1.MapShapes.Count - 1

     Map1.MapShapes(i).Symbols.Clear()

      If i = index Then

          Dim brush As New GeoSolidBrush(GeoColor.FromArgb(150, GeoColor.KnownColors.Red))

          Map1.MapShapes(i).Symbols.Add(New AreaSymbol(New GeoPen(GeoColor.KnownColors.Black), brush))

      Else

          Dim brush As New GeoSolidBrush(GeoColor.FromArgb(150, GeoColor.KnownColors.Orange))

          Map1.MapShapes(i).Symbols.Add(New AreaSymbol(New GeoPen(GeoColor.KnownColors.Black), brush))

      End If

    Next

End Sub 

Back to Top

I want a user to be able to draw various shapes (circles, rectangles, etc.) and I want to execute some custom logic while the shape is being created. How can I do this?

The Misc sample named "Track Shapes" will be very helpful to you in understanding how to accomplish this. In this sample there are no layers, no shape files, just track shapes being drawn (they can also be moved). As you can see from the code in this sample, there are plenty of events which you can tie into. You can execute your logic when the shape is just starting to be dragged, when the dragging is complete, or while the dragging is happening. As well, you can run your logic while the track shape is being drawn or when the drawing is complete. All of these events are used in the sample.

While the track shape is being drawn, you will see that there is logic to show the total area / perimeter / radius of the shape. When the track shape is finished being drawn, you will see logic to make the shape permanent (actually add it to the map as a map shape).

Explore this sample and it should be pretty clear how to accomplish these things. Below is a bit of the logic from the sample which is in the Map1_TrackShapesDraw event.

C#

protected void Map1_AjaxFinishedTrackShape(object sender, MapSuite.WebEdition.AjaxFinishTrackShapeEventArgs e)
{

   BaseShape baseshpae = e.Shape;

 

   double area, perimeter;

   if (baseshpae is BaseAreaShape)

   {

       BaseAreaShape baseArea = baseshpae as BaseAreaShape;

       area = baseArea.get_Area(MapLengthUnits.kilometres, MapAreaUnits.squarekm);

       perimeter = baseArea.get_Perimeter(MapLengthUnits.kilometres, MapLengthUnits.kilometres);

   }

}

VB.NET

Protected Sub Map1_AjaxFinishedTrackShape(ByVal sender As Object, ByVal e As MapSuite.WebEdition.AjaxFinishTrackShapeEventArgs)

Dim baseshpae As BaseShape = e.Shape

 

  Dim area As Double, perimeter As Double

  If TypeOf baseshpae Is BaseAreaShape Then

      Dim baseArea As BaseAreaShape = TryCast(baseshpae, BaseAreaShape)

      area = baseArea.Area(MapLengthUnits.kilometres, MapAreaUnits.squarekm)

      perimeter = baseArea.Perimeter(MapLengthUnits.kilometres, MapLengthUnits.kilometres)

  End If

End Sub 

Back to Top

What are map shapes and how can I use them?

The Misc sample named "Track Shapes" will show you how to create map shapes based on a track shape (a shape a user draws). A map shape is a shape that is added via code and not from a shape file. That is, mostly shapes will be added from shape files (roads, buildings, etc.) but you might want to have your own shapes. Your own shapes might include proposed buildings or even vehicles driving down the street.

Map shapes can be easily moved and reside outside the context of layers. Map shapes are on the map, not on a layer. Let's say you want to allow a user to plot the points, on a map of the world, where they have visited. For this, you would load a layer with data of the world. Then you would set the map into track point mode. Then, let the user click creating the various points. Each time the user clicks, the Map1_FinishedTrackShape event will fire – here you will add the map shape and record any data in a data store (for example, storing the latitude and longitude in a database).

The following code should make it clear:

C#

// Put this code in the form's load event. This will show a map of the world.

Map1.MapUnit = MapLengthUnits.DecimalDegrees;

Layer lyr = new Layer(@"..\sampledata\world\cntry02.shp", true);

lyr.ZoomLevelExtentUnit = ZoomLevelExtentUnits.DecimalDegrees;

lyr.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.ZoomLevel18;

lyr.ZoomLevel01.GeoStyle = GeoAreaStyles.GetSimpleAreaStyle(GeoColor.KnownColors.LightGray, GeoColor.KnownColors.Black, 1);

Map1.Layers.Add(lyr);

// Then, set the map's mode to track point so that every time the user clicks, a point shape will be created.

Map1.Mode = MapSuite.WebEdition.Map.ModeType.TrackPoint;

// Finally, in the FinishedTrackShape event, add the code to add the point to the map as a map shape.
protected void Map1_AjaxFinishedTrackShape(object sender, MapSuite.WebEdition.AjaxFinishTrackShapeEventArgs e)

{

    if(e.Shape is BasePointShape)

    {

      BasePointShape pnt = e.Shape as BasePointShape;

       Map1.MapShapes.Add(new PointMapShape(pnt));

    }

}

VB.NET

' Put this code in the form's load event. This will show a map of the world.

Map1.MapUnit = MapLengthUnits.DecimalDegrees

Dim lyr As New Layer("..\sampledata\world\cntry02.shp", True)

lyr.ZoomLevelExtentUnit = ZoomLevelExtentUnits.DecimalDegrees

lyr.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.ZoomLevel18

lyr.ZoomLevel01.GeoStyle = GeoAreaStyles.GetSimpleAreaStyle(GeoColor.KnownColors.LightGray, GeoColor.KnownColors.Black, 1)

Map1.Layers.Add(lyr)

' Then, set the map's mode to track point so that every time the user clicks, a point shape will be created.

Map1.Mode = MapSuite.WebEdition.Map.ModeType.TrackPoint

' Finally, in the FinishedTrackShape event, add the code to add the point to the map as a map shape.

Protected Sub Map1_AjaxFinishedTrackShape(ByVal sender As Object, ByVal e As MapSuite.WebEdition.AjaxFinishTrackShapeEventArgs)

   If TypeOf e.Shape Is BasePointShape Then

       Dim pnt As BasePointShape = TryCast(e.Shape, BasePointShape)

       Map1.MapShapes.Add(New PointMapShape(pnt))

   End If

End Sub

 

As you can see, there is very little code to actually add a map shape to a map (two lines). Most of the code will depend on how you want to store the data about the points the user selected.

Back to Top

How can I define my own custom labeling plug-in?

The Rendering sample named "Custom Labeler" goes over this is greater detail but what you will need to do is create a class that inherits from MapSuite.ILabeler. There are several methods to implement, all named DrawLabels (taking in different parameters). In the sample, you will see DrawLabels implemented for Polygons and MultiLines. The code for polygons is below:

C#

// Class declaration

public class CustomLabeler : MapSuite.ILabeler

{

    // DrawLabels routine

    public void DrawLabels(Graphics g, Array[] TextSymbolArrays, Array[] SymbolArray, MapSuite.Geometry.PolygonF[] Polygons, ref SimplePolygonF[] LabeledAreas, int CanvasWidth, int CanvasHeight)

    {

        // Drawing labels for polygons

        StringFormat Format = new StringFormat();

        Format.Alignment = StringAlignment.Center;

        for (int i = 0; i <= Polygons.Length - 1; i++)

        {

            TextSymbol[] TextSymbols = (TextSymbol[])TextSymbolArrays[i];

            for (int j = 0; j <= Polygons[i].Parts.Length - 1; j++)

            {

                for (int k = 0; k <= TextSymbols.Length - 1; k++)

                {

                    g.DrawString(TextSymbols[k].TextValue, TextSymbols[k].Font, TextSymbols[k].Brush, Polygons[i].Parts[j].Centroid.X + TextSymbols[k].XOffset, Polygons[i].Parts[j].Centroid.Y + TextSymbols[k].YOffset, Format);

                }

            }

        }

    }

 

    public void DrawLabels(Graphics g, Array[] TextSymbolArrays, Array[] SymbolArrays, PointF[] Points, ref SimplePolygonF[] LabeledAreas, int CanvasWidth, int CanvasHeight)

    {

        throw new Exception("The method or operation is not implemented.");

    }

 

    public void DrawLabels(Graphics g, Array[] TextSymbolArrays, Array[] SymbolArrays, MultiPointF[] MultiPoints, ref SimplePolygonF[] LabeledAreas, int CanvasWidth, int CanvasHeight)

    {

        throw new Exception("The method or operation is not implemented.");

    }

 

    public void DrawLabels(Graphics g, Array[] TextSymbolArrays, Array[] SymbolArrays, MultiLineF[] MultiLines, ref SimplePolygonF[] LabeledAreas, int CanvasWidth, int CanvasHeight)

    {

        throw new Exception("The method or operation is not implemented.");

    }

} 

 

VB.NET

' Class declaration

Public Class CustomLabeler

    Implements ILabeler

 

    ' DrawLabels routine

    Public Sub DrawLabels(ByVal g As Graphics, ByVal TextSymbolArrays As Array(), ByVal SymbolArray As Array(), ByVal Polygons As MapSuite.Geometry.PolygonF(), ByRef LabeledAreas As SimplePolygonF(), ByVal CanvasWidth As Integer, _

    ByVal CanvasHeight As Integer) Implements ILabeler.DrawLabels

        ' Drawing labels for polygons

        Dim Format As New StringFormat()

        Format.Alignment = StringAlignment.Center

        For i As Integer = 0 To Polygons.Length - 1

            Dim TextSymbols As TextSymbol() = DirectCast(TextSymbolArrays(i), TextSymbol())

            For j As Integer = 0 To Polygons(i).Parts.Length - 1

                For k As Integer = 0 To TextSymbols.Length - 1

                    g.DrawString(TextSymbols(k).TextValue, TextSymbols(k).Font, TextSymbols(k).Brush, Polygons(i).Parts(j).Centroid.X + TextSymbols(k).XOffset, Polygons(i).Parts(j).Centroid.Y + TextSymbols(k).YOffset, Format)

                Next

            Next

        Next

    End Sub

 

    Public Sub DrawLabels(ByVal g As Graphics, ByVal TextSymbolArrays As Array(), ByVal SymbolArrays As Array(), ByVal Points As PointF(), ByRef LabeledAreas As SimplePolygonF(), ByVal CanvasWidth As Integer, _

    ByVal CanvasHeight As Integer) Implements ILabeler.DrawLabels

        Throw New Exception("The method or operation is not implemented.")

    End Sub

 

    Public Sub DrawLabels(ByVal g As Graphics, ByVal TextSymbolArrays As Array(), ByVal SymbolArrays As Array(), ByVal MultiPoints As MultiPointF(), ByRef LabeledAreas As SimplePolygonF(), ByVal CanvasWidth As Integer, _

    ByVal CanvasHeight As Integer) Implements ILabeler.DrawLabels

        Throw New Exception("The method or operation is not implemented.")

    End Sub

 

    Public Sub DrawLabels(ByVal g As Graphics, ByVal TextSymbolArrays As Array(), ByVal SymbolArrays As Array(), ByVal MultiLines As MultiLineF(), ByRef LabeledAreas As SimplePolygonF(), ByVal CanvasWidth As Integer, _

    ByVal CanvasHeight As Integer) Implements ILabeler.DrawLabels

        Throw New Exception("The method or operation is not implemented.")

    End Sub

 

End Class 

Now, to use your custom labeler, you just need to create it and plug it in. Like the following:

C#

// this assumes you have a zoomlevel object declared as zoomlevel.

CustomLabeler cl = new CustomLabeler();

zoomlevel.LabelerPlugin = cl;

VB.NET

' this assumes you have a zoomlevel object declared as zoomlevel.

Dim cl As CustomLabeler = New CustomLabeler()

zoomlevel.LabelerPlugin = cl 

Back to Top

How can I get data from a shape file? Can I use SQL queries?

Yes, you can use SQL queries to get data from shape files. The Querying sample named "SQL Query" is the sample that best illustrates this but below you will see some code that will help you.

C#

string SQL = "Select * From TexasCounties where pop2001 > 100000 and pop2001 < 500000";

// false = don't include shapes in returned data.

DataTable dt = Map1.Layers[0].SQLQuery(SQL, false,"Population");

VB.NET

Dim SQL As String = "Select * From TexasCounties where pop2001 > 100000 and pop2001 < 500000"

' false = don't include shapes in returned data.

Dim dt As DataTable = Map1.Layers(0).SQLQuery(SQL, False, "Population") 

That's it. Since a layer is really just a representation of a shape file, you can query the shape file by querying the layer – all with only two lines of code.

Back to Top

Can I change the data in a shape file, and if so, how?

Yes, you can. To delete shapes in the file, use the Layer.DeleteShape method which takes in a record number. If you want to change the data in a shape file, first you must call Layer.BeginEdit and then follow that with either Layer.CommitEdit or Layer.RollbackEdit. Between calling BeingEdit and Commi