Bespoke Applications – Building your own website

6. Creating a custom control - Adding a scale bar from OpenLayers

Many of the controls in Open Layers have been encapsulated in a server side control. Some controls however can be added using the OLGenericControl.

https://help.cadcorp.com/en/9.0/api-Server/html/T_Cadcorp_Web_UI_OpenLayers_OLGenericControl.htm

Any control added to the map on the server must be derived from the OLControlBase.

https://help.cadcorp.com/en/9.0/api-Server/html/T_Cadcorp_Web_UI_OpenLayers_OLControlBase.htm

In this topic we will create a simple control to add a scale line (http://dev.openlayers.org/docs/files/OpenLayers/Control/ScaleLine-js.html ) to the map. To keep things simple we will add the custom control to our web application.

Preparing the Project

  1. Add a reference to System.Web
  2. Add a new folder called Controls.

Add the new control

  1. Add a new item to the new folder, select a Web Forms Server Control template. Call it ScaleLine.cs.
  2. Replace the code in ScaleLine.cs with the following snippet:
  3. Copy
    using Cadcorp.Web.UI.OpenLayers;
    using System.Text;
    using System.Web.UI;


    namespace GettingStartedWithWebApi.Controls
    {
        /// <summary>
        /// The ScaleLine displays a small line indicator representing the current map scale on the map
        /// </summary>
        [ToolboxData("<{0}:ScaleLine runat=server></{0}:ScaleLine>")]
        public class ScaleLine : OLControlBase
        {
            /// <summary>
            /// Maximum width of the scale line in pixels.
            /// </summary>
            public int MaxWidth
            {
                get;
                set;
            }
            /// <summary>
            /// Units for zoomed out on top bar.  Default is km.
            /// </summary>
            public string TopOutUnits
            {
                get;
                set;
            }
            /// <summary>
            /// Units for zoomed in on top bar.  Default is m.
            /// </summary>
            public string TopInUnits
            {
                get;
                set;
            }
            /// <summary>
            /// Units for zoomed out on bottom bar.  Default is mi.
            /// </summary>
            public string BottomOutUnits
            {
                get;
                set;
            }
            /// <summary>
            /// Units for zoomed in on bottom bar.  Default is ft.
            /// </summary>
            public string BottomInUnits
            {
                get;
                set;
            }
            /// <summary>
            /// Use geodesic measurement.  Default is false.  
            /// </summary>
            /// <remarks>The recommended setting for maps in EPSG:4326 is false, 
    and true EPSG:3857.  If set to true, the scale will be calculated based on the horizontal 
    size of the pixel in the center of the map viewport.</remarks>
            public bool UseGeoDesic
            {
                get;
                set;
            }
            /// <summary>
            /// Create a new scale line control
            /// </summary>
            public ScaleLine()
            {
                MaxWidth = 100;
                TopOutUnits = "km";
                TopInUnits = "m";
                BottomOutUnits = "mi";
                BottomInUnits = "ft";
                UseGeoDesic = false;
            }
            /// <summary>
            /// Creates the javascript to create this control
            /// </summary>
            /// <param name="mapID">The ID of the map control</param>
            /// <returns>The javascript to create this open layers control</returns>
            public override string Render(string mapID)
            {
                string returnVal = "";
                if (Visible)// only render anything if we're visible
                {
                    returnVal = string.Format("var {0} = new OpenLayers.Control.ScaleLine
            ( {{ {1} }});\r\n", ID, GetOptionsJS());
                }
                return returnVal;
            }
            /// <summary>
            /// Gets the options for this control
            /// </summary>
            /// <returns>A string containing the options for this control</returns>
            protected string GetOptionsJS()
            {
                StringBuilder tmpStr = new StringBuilder();
                if (!string.IsNullOrEmpty(ID))
                {
                    tmpStr.AppendFormat("id:'{0}',", ID);
                }
                tmpStr.AppendFormat("maxWidth:{0},", MaxWidth);
                if (!string.IsNullOrEmpty(TopOutUnits))
                {
                    tmpStr.AppendFormat("topOutUnits:'{0}',", TopOutUnits);
                }
                if (!string.IsNullOrEmpty(TopInUnits))
                {
                    tmpStr.AppendFormat("topInUnits:'{0}',", TopInUnits);
                }
                if (!string.IsNullOrEmpty(BottomOutUnits))
                {
                    tmpStr.AppendFormat("bottomOutUnits:'{0}',", BottomOutUnits);
                }
                if (!string.IsNullOrEmpty(BottomInUnits))
                {
                    tmpStr.AppendFormat("bottomInUnits:'{0}',", BottomInUnits);
                }
                tmpStr.AppendFormat("geodesic:{0}", UseGeoDesic.ToString().ToLower());

                return tmpStr.ToString();
            }
        }
    }

Modify Web.config

  1. Modify Web.config, add the following to System.web>pages>controls
<add tagPrefix="GettingStartedWithWebApi" 
namespace="GettingStartedWithWebApi.Controls" assembly="GettingStartedWithWebApi" />

Modify map.aspx

  1. Add the following to OLControls
  2. Copy
    <GettingStartedWithWebApi:ScaleLine ID="scaleLine" MaxWidth="200" runat="server" />
  1. When the project is run the scale line should be visible on the map. Position and colour of the scale line is controlled by the style sheet, openlayers.css, the style rules for this control are olControlScaleLine, olControlScaleLineBottom and olControlScaleLineTop.

The code explained

There are two important functions in the ScaleLine class, Render and GetOptionsJS.

public override string Render(string mapID)
 {
     string returnVal = "";
     if (Visible)// only render anything if we're visible
     {
         returnVal = string.Format("var {0} = new OpenLayers.Control.ScaleLine( {{ {1} }});\r\n", ID, GetOptionsJS());
      }
      return returnVal;
 }

Render implements the abstract function defined in the base class. It creates the JavaScript to create the client side Open Layers control.

protected string GetOptionsJS()
{
    StringBuilder tmpStr = new StringBuilder();
    if (!string.IsNullOrEmpty(ID))
    {
          tmpStr.AppendFormat("id:'{0}',", ID);
    }
    tmpStr.AppendFormat("maxWidth:{0},", MaxWidth);
    if (!string.IsNullOrEmpty(TopOutUnits))
    {
          tmpStr.AppendFormat("topOutUnits:'{0}',", TopOutUnits);
    }
    if (!string.IsNullOrEmpty(TopInUnits))
     {
         tmpStr.AppendFormat("topInUnits:'{0}',", TopInUnits);
     }
     if (!string.IsNullOrEmpty(BottomOutUnits))
     {
         tmpStr.AppendFormat("bottomOutUnits:'{0}',", BottomOutUnits);
     }
     if (!string.IsNullOrEmpty(BottomInUnits))
     {
         tmpStr.AppendFormat("bottomInUnits:'{0}',", BottomInUnits);
     }
     tmpStr.AppendFormat("geodesic:{0}", UseGeoDesic.ToString().ToLower());

     return tmpStr.ToString();
}

GetOptionsJS creates the json object used to configure the client side object.