User Tools

Site Tools


source_code_webapieditionsample_siteselection.zip

Source Code WebAPIEditionSample SiteSelection.zip

SiteSelectionController.cs

 using System;  
 using System.Collections.Generic;  
 using System.Collections.ObjectModel;  
 using System.Drawing;  
 using System.Drawing.Imaging;  
 using System.Globalization;  
 using System.IO;  
 using System.Linq;  
 using System.Net;  
 using System.Net.Http;  
 using System.Net.Http.Headers;  
 using System.Web;  
 using System.Web.Http;  
 using Newtonsoft.Json;  
 using SiteSelection.Properties;  
 using ThinkGeo.MapSuite.Core;  
 using ThinkGeo.MapSuite.Routing;  
 using ThinkGeo.MapSuite.WebApiEdition;  
 
 namespace SiteSelection.Controllers  
 {  
     [RoutePrefix("SiteSelection")]  
     public class SiteSelectionController : ApiController  
     {  
         private static Dictionary<string, Collection<string>> poiTypes;  
         private static LayerOverlay poiOverlay;  
         private static RoutingEngine routingEngine;  
 
         static SiteSelectionController()  
         {  
             // Create the static POI Overlay.  
             poiOverlay = new LayerOverlay();  
 
             ManagedProj4Projection wgs84ToMercatorProj4Projection = new ManagedProj4Projection();  
             wgs84ToMercatorProj4Projection.InternalProjectionParametersString = Proj4Projection.GetWgs84ParametersString();  
             wgs84ToMercatorProj4Projection.ExternalProjectionParametersString = Proj4Projection.GetSphericalMercatorParametersString();  
             wgs84ToMercatorProj4Projection.Open();  
 
             ShapeFileFeatureLayer friscoBoundaryLayer = new ShapeFileFeatureLayer(InternalHelper.GetFullPath(@"App_Data\CityLimitPolygon.shp"));  
             friscoBoundaryLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(new AreaStyle(new GeoPen(GeoColor.SimpleColors.White, 5.5f), new GeoSolidBrush(GeoColor.SimpleColors.Transparent)));  
             friscoBoundaryLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(new AreaStyle(new GeoPen(GeoColor.SimpleColors.Red, 1.5f) { DashStyle = LineDashStyle.Dash }, new GeoSolidBrush(GeoColor.SimpleColors.Transparent)));  
             friscoBoundaryLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;  
             friscoBoundaryLayer.FeatureSource.Projection = wgs84ToMercatorProj4Projection;  
             poiOverlay.Layers.Add("friscoBoundary", friscoBoundaryLayer);  
 
             ShapeFileFeatureLayer hotelsLayer = new ShapeFileFeatureLayer(InternalHelper.GetFullPath(@"App_Data\POIs\Hotels.shp"));  
             hotelsLayer.Transparency = 200f;  
             hotelsLayer.ZoomLevelSet.ZoomLevel10.DefaultPointStyle = new PointStyle(new GeoImage(InternalHelper.GetFullPath(@"Images\Hotel.png")));  
             hotelsLayer.ZoomLevelSet.ZoomLevel10.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;  
             hotelsLayer.FeatureSource.Projection = wgs84ToMercatorProj4Projection;  
             poiOverlay.Layers.Add("hotelsLayer", hotelsLayer);  
 
             ShapeFileFeatureLayer medicalFacilitesLayer = new ShapeFileFeatureLayer(InternalHelper.GetFullPath(@"App_Data\POIs\Medical_Facilities.shp"));  
             medicalFacilitesLayer.Transparency = 200f;  
             medicalFacilitesLayer.ZoomLevelSet.ZoomLevel10.DefaultPointStyle = new PointStyle(new GeoImage(InternalHelper.GetFullPath(@"Images\DrugStore.png")));  
             medicalFacilitesLayer.ZoomLevelSet.ZoomLevel10.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;  
             medicalFacilitesLayer.FeatureSource.Projection = wgs84ToMercatorProj4Projection;  
             poiOverlay.Layers.Add("Medical Facilites", medicalFacilitesLayer);  
 
             ShapeFileFeatureLayer publicFacilitesLayer = new ShapeFileFeatureLayer(InternalHelper.GetFullPath(@"App_Data\POIs\Public_Facilities.shp"));  
             publicFacilitesLayer.Transparency = 200f;  
             publicFacilitesLayer.ZoomLevelSet.ZoomLevel10.DefaultPointStyle = new PointStyle(new GeoImage(InternalHelper.GetFullPath(@"Images\public_facility.png")));  
             publicFacilitesLayer.ZoomLevelSet.ZoomLevel10.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;  
             publicFacilitesLayer.FeatureSource.Projection = wgs84ToMercatorProj4Projection;  
             poiOverlay.Layers.Add(publicFacilitesLayer);  
 
             ShapeFileFeatureLayer restaurantsLayer = new ShapeFileFeatureLayer(InternalHelper.GetFullPath(@"App_Data\POIs\Restaurants.shp"));  
             restaurantsLayer.Transparency = 200f;  
             restaurantsLayer.ZoomLevelSet.ZoomLevel10.DefaultPointStyle = new PointStyle(new GeoImage(InternalHelper.GetFullPath(@"Images\restaurant.png")));  
             restaurantsLayer.ZoomLevelSet.ZoomLevel10.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;  
             restaurantsLayer.FeatureSource.Projection = wgs84ToMercatorProj4Projection;  
             poiOverlay.Layers.Add("Restaurants", restaurantsLayer);  
 
             ShapeFileFeatureLayer schoolsLayer = new ShapeFileFeatureLayer(InternalHelper.GetFullPath(@"App_Data\POIs\Schools.shp"));  
             schoolsLayer.Transparency = 200f;  
             schoolsLayer.ZoomLevelSet.ZoomLevel10.DefaultPointStyle = new PointStyle(new GeoImage(InternalHelper.GetFullPath(@"Images\school.png")));  
             schoolsLayer.ZoomLevelSet.ZoomLevel10.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;  
             schoolsLayer.FeatureSource.Projection = wgs84ToMercatorProj4Projection;  
             poiOverlay.Layers.Add("Schools", schoolsLayer);  
 
             // Create the Routine Engine.  
             string streetShapeFilePathName = InternalHelper.GetFullPath(@"App_Data\street.shp");  
             string streetRtgFilePathName = Path.ChangeExtension(streetShapeFilePathName, ".rtg");  
 
             RtgRoutingSource routingSource = new RtgRoutingSource(streetRtgFilePathName);  
             FeatureSource featureSource = new ShapeFileFeatureSource(streetShapeFilePathName);  
             featureSource.Projection = wgs84ToMercatorProj4Projection;  
             routingEngine = new RoutingEngine(routingSource, featureSource);  
             routingEngine.GeographyUnit = GeographyUnit.Meter;  
 
             // Initialise categories  
             poiTypes = new Dictionary<string, Collection<string>>();  
             foreach (string layerId in new string[] { "Hotels", "Medical Facilites", "Restaurants", "Schools" })  
             {  
                 poiTypes.Add(layerId, GetPoiSubTypes(poiOverlay, layerId));  
             }  
         }  
 
         [Route("GetCategories")]  
         public string GetCategories()  
         {  
             // Return the categories in JSON to client side.  
             return JsonConvert.SerializeObject(poiTypes);  
         }  
 
         [Route("baselayer/{z}/{x}/{y}")]  
         public HttpResponseMessage GetBaseLayerTile(int z, int x, int y)  
         {  
             return GenerateTile(z, x, y, poiOverlay);  
         }  
 
         [Route("resultlayer/{z}/{x}/{y}")]  
         public HttpResponseMessage GetResultLayerTile(int z, int x, int y)  
         {  
             return GenerateTile(z, x, y, GetResultOverlay());  
         }  
 
         [Route("Search")]  
         [HttpPost]  
         public string Search([FromBody] string parameterString)  
         {  
             Dictionary<string, string> parameters = JsonConvert.DeserializeObject<Dictionary<string, string>>(parameterString);  
             string[] searchPointLatLng = parameters["searchPoint"].Split(',');  
             PointShape searchPoint = InternalHelper.ConvertToSphericalMercator<PointShape>(new PointShape(double.Parse(searchPointLatLng[0]), double.Parse(searchPointLatLng[1])));  
 
             string result = JsonConvert.SerializeObject(new { status = "2", message = "out of restriction area" });  
 
             // check if the clicked point is in valid area (Frisco County)  
             FeatureLayer friscoLayer = (FeatureLayer)poiOverlay.Layers["friscoBoundary"];  
             friscoLayer.Open();  
             if (friscoLayer.QueryTools.GetFeaturesContaining(searchPoint, ReturningColumnsType.NoColumns).Any())  
             {  
                 // Calculate the service area/buffer area and display it on the map  
                 LayerOverlay resultOverlay = GetResultOverlay();  
                 InMemoryFeatureLayer serviceAreaLayer = (InMemoryFeatureLayer)resultOverlay.Layers["serviceArea"];  
                 serviceAreaLayer.Open();  
                 serviceAreaLayer.InternalFeatures.Clear();  
                 if (parameters["searchMode"] == "serviceArea")  
                 {  
                     int drivingTimeInMinutes = Convert.ToInt32(parameters["driveTime"], CultureInfo.InvariantCulture);  
                     serviceAreaLayer.InternalFeatures.Add(new Feature(routingEngine.GenerateServiceArea(searchPoint, new TimeSpan(0, drivingTimeInMinutes, 0), 100, GeographyUnit.Meter)));  
                 }  
                 else  
                 {  
                     DistanceUnit distanceUnit = parameters["distanceUnit"] == "Mile" ? DistanceUnit.Mile : DistanceUnit.Kilometer;  
                     double distanceBuffer = Convert.ToDouble(parameters["distanceBuffer"], CultureInfo.InvariantCulture);  
                     serviceAreaLayer.InternalFeatures.Add(new Feature(searchPoint.Buffer(distanceBuffer, 40, GeographyUnit.Meter, distanceUnit)));  
                 }  
 
                 // Search the Pois in calculated service area and display them on map  
                 InMemoryFeatureLayer highlightFeatureLayer = (InMemoryFeatureLayer)resultOverlay.Layers["HighlightFeatureLayer"];  
                 highlightFeatureLayer.Open();  
                 highlightFeatureLayer.InternalFeatures.Clear();  
 
                 ShapeFileFeatureLayer poiLayer = (ShapeFileFeatureLayer)(poiOverlay.Layers[parameters["category"]);  
                 Collection<Feature> featuresInServiceArea = poiLayer.QueryTools.GetFeaturesWithin(serviceAreaLayer.InternalFeatures[0].GetShape(), ReturningColumnsType.AllColumns);  
                 List<Feature> filteredQueryFeatures = FilterFeaturesByQueryConfiguration(featuresInServiceArea, parameters["category"], parameters["subCategory"].Replace(">~", ">="));  
 
                 if (filteredQueryFeatures.Any())  
                 {  
                     Collection<object> jsonFeatures = new Collection<object>();  
                     foreach (Feature feature in filteredQueryFeatures)  
                     {  
                         highlightFeatureLayer.InternalFeatures.Add(feature);  
                         PointShape latlng = InternalHelper.ConvertToWgs84<PointShape>(feature.GetShape());  
                         jsonFeatures.Add(new { name = feature.ColumnValues["NAME"], point = string.Format("{0},{1}", latlng.Y, latlng.X) });  
                     }  
                     result = JsonConvert.SerializeObject(new { status = "0", message = "has features", features = jsonFeatures });  
                 }  
                 else  
                 {  
                     result = JsonConvert.SerializeObject(new { status = "1", message = "without features" });  
                 }  
             }  
 
             return result;  
         }  
 
         [Route("ClearSearch")]  
         [HttpPost]  
         public void Clear()  
         {  
             LayerOverlay resultOverlay = GetResultOverlay();  
             foreach (Layer layer in resultOverlay.Layers)  
             {  
                 layer.Open();  
                 ((InMemoryFeatureLayer)layer).InternalFeatures.Clear();  
                 layer.Close();  
             }  
         }  
 
         private LayerOverlay GetResultOverlay()  
         {  
             // Create the result overlay and put it into the session.  
             LayerOverlay resultOverlay = HttpContext.Current.Session["resultOverlay"] as LayerOverlay;  
             if (resultOverlay == null)  
             {  
                 resultOverlay = new LayerOverlay();  
 
                 InMemoryFeatureLayer serviceAreaLayer = new InMemoryFeatureLayer();  
                 serviceAreaLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.CreateSimpleAreaStyle(new GeoColor(120, GeoColor.FromHtml("#33a8e1")), GeoColor.FromHtml("#428ce3"), 2, LineDashStyle.Solid);  
                 serviceAreaLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;  
 
                 InMemoryFeatureLayer highlightFeatureLayer = new InMemoryFeatureLayer();  
                 highlightFeatureLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = new PointStyle(new GeoImage(InternalHelper.GetFullPath(@"Images\selectedHalo.png")));  
                 highlightFeatureLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;  
 
                 resultOverlay.Layers.Add("serviceArea", serviceAreaLayer);  
                 resultOverlay.Layers.Add("HighlightFeatureLayer", highlightFeatureLayer);  
 
                 HttpContext.Current.Session["resultOverlay"] = resultOverlay;  
             }  
 
             return resultOverlay;  
         }  
 
         private static Collection<string> GetPoiSubTypes(LayerOverlay queryingOverlay, string poiType)  
         {  
             Collection<string> poiSubTypes = new Collection<string>();  
             poiSubTypes.Add("All");  
 
             string columnName = InternalHelper.GetDbfColumnByPoiType(poiType);  
             if (columnName.Equals("Hotels"))  
             {  
                 poiSubTypes.Add("1 ~ 50");  
                 poiSubTypes.Add("50 ~ 100");  
                 poiSubTypes.Add("100 ~ 150");  
                 poiSubTypes.Add("150 ~ 200");  
                 poiSubTypes.Add("200 ~ 300");  
                 poiSubTypes.Add("300 ~ 400");  
                 poiSubTypes.Add("400 ~ 500");  
                 poiSubTypes.Add(">= 500");  
             }  
             else  
             {  
                 ShapeFileFeatureLayer inMemoryFeatureLayer = (ShapeFileFeatureLayer)queryingOverlay.Layers[poiType];  
                 inMemoryFeatureLayer.Open();  
                 IEnumerable<string> distinctColumnValues = inMemoryFeatureLayer.FeatureSource.GetDistinctColumnValues(columnName).Select(v => v.ColumnValue);  
                 foreach (string distinctColumnValue in distinctColumnValues)  
                 {  
                     poiSubTypes.Add(distinctColumnValue);  
                 }  
             }  
 
             return poiSubTypes;  
         }  
 
         private List<Feature> FilterFeaturesByQueryConfiguration(Collection<Feature> allFeatures, string category, string subCategory)  
         {  
             if (subCategory.Equals("All"))  
             {  
                 return allFeatures.ToList();  
             }  
             else if (!category.Equals("Hotels"))  
             {  
                 return allFeatures.Where(f => f.ColumnValues[InternalHelper.GetDbfColumnByPoiType(category)] == subCategory).ToList();  
             }  
             else  
             {  
                 string queriedColumn = InternalHelper.GetDbfColumnByPoiType(category);  
 
                 List<Feature> queriedPois = new List<Feature>();  
                 foreach (Feature feature in allFeatures)  
                 {  
                     int rooms = int.Parse(feature.ColumnValues[queriedColumn], CultureInfo.InvariantCulture);  
 
                     string[] values = subCategory.Split('~');  
                     if (values.Length >= 2)  
                     {  
                         if (int.Parse(values[0], CultureInfo.InvariantCulture) <= rooms && int.Parse(values[1], CultureInfo.InvariantCulture) >= rooms)  
                         {  
                             queriedPois.Add(feature);  
                         }  
                     }  
                     else if (values.Length == 1)  
                     {  
                         int maxValue = int.Parse(values[0].TrimStart(new[] { '>', '=', ' ' }), CultureInfo.InvariantCulture);  
                         if (rooms > maxValue)  
                         {  
                             queriedPois.Add(feature);  
                         }  
                     }  
                 }  
                 return queriedPois;  
             }  
         }  
 
         private static HttpResponseMessage GenerateTile(int z, int x, int y, LayerOverlay overlay)  
         {  
             using (Bitmap bitmap = new Bitmap(256, 256))  
             {  
                 GdiPlusGeoCanvas geoCanvas = new GdiPlusGeoCanvas();  
                 RectangleShape boundingBox = WebApiExtentHelper.GetBoundingBoxForXyz(x, y, z, GeographyUnit.Meter);  
                 geoCanvas.BeginDrawing(bitmap, boundingBox, GeographyUnit.Meter);  
                 overlay.Draw(geoCanvas);  
                 geoCanvas.EndDrawing();  
 
                 MemoryStream ms = new MemoryStream();  
                 bitmap.Save(ms, ImageFormat.Png);  
                 HttpResponseMessage msg = new HttpResponseMessage(HttpStatusCode.OK);  
                 msg.Content = new ByteArrayContent(ms.ToArray());  
                 msg.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");  
 
                 return msg;  
             }  
         }  
     }  
 }  
 

InternalHelper.cs

 using System;  
 using System.Collections.Generic;  
 using System.IO;  
 using System.Reflection;  
 using ThinkGeo.MapSuite.Core;  
 
 namespace SiteSelection  
 {  
     public static class InternalHelper  
     {  
         private static Dictionary<string, string> poiColumns;  
         private static ManagedProj4Projection projection;  
 
         public static string GetDbfColumnByPoiType(string poiCategory)  
         {  
             if (poiColumns == null)  
             {  
                 poiColumns = new Dictionary<string, string>();  
                 poiColumns.Add("Hotels", "Hotels");  
                 poiColumns.Add("Medical Facilites", "TYPE");  
                 poiColumns.Add("Restaurants", "FoodType");  
                 poiColumns.Add("Schools", "TYPE");  
             }  
 
             return poiColumns[poiCategory];  
         }  
 
         public static string GetFullPath(string fileName)  
         {  
             Uri uri = new Uri(Assembly.GetExecutingAssembly().CodeBase);  
             string rootDirectory = Path.GetDirectoryName(Path.GetDirectoryName(uri.LocalPath));  
             return Path.Combine(rootDirectory, fileName); ;  
         }  
 
         public static T ConvertToWgs84<T>(BaseShape baseShape) where T : BaseShape  
         {  
             InitializeProjection();  
             return projection.ConvertToInternalProjection(baseShape) as T;  
         }  
 
         public static T ConvertToSphericalMercator<T>(BaseShape baseShape) where T : BaseShape  
         {  
             InitializeProjection();  
             return projection.ConvertToExternalProjection(baseShape) as T;  
         }  
 
         private static void InitializeProjection()  
         {  
             if (projection == null)  
             {  
                 projection = new ManagedProj4Projection();  
                 projection.InternalProjectionParametersString = Proj4Projection.GetWgs84ParametersString();  
                 projection.ExternalProjectionParametersString = Proj4Projection.GetSphericalMercatorParametersString();  
                 projection.Open();  
             }  
         }  
     }  
 }  
 

default.htm(leaflet)

 <!DOCTYPE html>  
 <html xmlns="http://www.w3.org/1999/xhtml">  
 <head>  
     <title>Site Selection</title>  
     <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />  
     <meta http-equiv="content-type" content="text/html; charset=utf-8" />  
     <meta name="author" content="ThinkGeo" />  
     <link rel="apple-touch-icon" href="desktop.png" />  
     <meta name="apple-mobile-web-app-title" content="Site Selection" />  
     <link href="favicon.ico" rel="shortcut icon" type="Images/x-icon" />  
     <link href="Content/leaflet.css" rel="stylesheet" />  
     <link href="Content/bootstrap.min.css" rel="stylesheet" />  
     <link href="Content/Site.css" rel="stylesheet" />  
 </head>  
 <body>  
     <div id="map">  
     </div>  
     <div id="message"></div>  
     <div id="loadingImage">  
         <img src="Images/ajax-loader.gif" />  
     </div>  
     <div id="legend">  
         <img src="Images/legend.png" />  
     </div>  
     <div id="left-panel">  
         <div class="panel-header">  
             <span class="title">Result List</span>  
         </div>  
         <div class="panel-content">  
             <div id="div-resultlist">  
                 <table id="result-table" class="table table-triped table-bordered">  
                     <tr>  
                         <td></td>  
                         <td>Name  
                         </td>  
                     </tr>  
                 </table>  
             </div>  
         </div>  
     </div>  
     <div class="centroid">  
         <div id="edit-panel">  
             <div class="edit-panel-header">  
                 <span id="settingTitle">Settings of site selection</span>  
             </div>  
             <div id="div-setting" class="edit-content">  
                 <div class="edit-body">  
                     Highlight points of this type  
                     <select id="sltCategory">  
                     </select>  
                     <select id="sltCategorySubtype">  
                     </select>  
                     Area Type  
                         <select id="sltSearchMode">  
                             <option value="serviceArea">Service Area</option>  
                             <option value="bufferedArea">Buffered Area</option>  
                         </select>  
                     <div id="divService">  
                         <span class="valueLabel">Service Area in</span>  
                         <input type="text" id="tbxServiceArea" class="valueTxt" value="5" /><span class="valueLabel"> Minutes Driving</span>  
                     </div>  
                     <div id="divBuffer" style="display: none;">  
                         <span class="valueLabel">Buffer Distance:</span>  
                         <input type="text" id="tbxDistance" class="valueTxt" value="2" />  
                         <select id="sltDistanceUnit" style="width: 100px;">  
                             <option value="Mile">Mile</option>  
                             <option value="Kilometer">Kilometer</option>  
                         </select>  
                     </div>  
                 </div>  
             </div>  
             <div class="edit-foot">  
                 <a id="btnSettingCancel" href="#" class="btn btn-default" role="button">Cancel</a>  
                 <a id="btnSettingSave" href="#" class="btn btn-primary" role="button">Save</a>  
             </div>  
         </div>  
     </div>  
     <script src="Scripts/jquery-1.11.1.min.js"></script>  
     <script src="Scripts/leaflet.js"></script>  
     <script src="thinkgeo.leaflet.js"></script>  
     <script>  
         var map, searchPoint, resultLayer, markers, searchPointIcon, trackMode = 'plot';  
         var defaultSetting = {  
             lng: -96.809983627817,  
             lat: 33.128303417665,  
             category: 'Restaurants',  
             subCategory: 'All',  
             searchMode: 'serviceArea',  
             driveTime:5  
         };  
 
         $(function () {  
             // Initialize the POI categories and its sub-type categories  
             $.get(L.Util.getRootPath() + "/SiteSelection/GetCategories/", function (response) {  
                 var categoies = JSON.parse(response);  
                 $.each(categoies, function (key) {  
                     $('#sltCategory').append($("<option/>", {  
                         value: key,  
                         text: key  
                     }));  
                 });  
                 $("#sltCategory").change(function () {  
                     var selectValue = $("#sltCategory").val();  
                     var selectedCategories;  
                     if (categoies.hasOwnProperty(selectValue)) {  
                         selectedCategories = categoies[selectValue];  
                     }  
                     $('#sltCategorySubtype').empty();  
                     for (var i = 0; i < selectedCategories.length; i++) {  
                         $('#sltCategorySubtype').append($("<option/>", {  
                             value: selectedCategories[i],  
                             text: selectedCategories[i]  
                         }));  
                     }  
                 });  
                 var setting = defaultSetting;  
                 searchPoint = new L.LatLng(setting.lat, setting.lng);  
                 L.marker([setting.lat,|setting.lng], { icon: searchPointIcon }).addTo(markers);  
 
                 $("#sltCategory").val(setting.category).trigger('change');  
                 $("#sltCategorySubtype").val(setting.subCategory);  
                 $("#sltSearchMode").val(setting.searchMode).trigger('change');  
                 if (setting.driveTime) {  
                     $("#tbxServiceArea").val(setting.driveTime);  
                 }  
                 if (setting.bufferDistance) {  
                     $("#tbxServiceArea").val(setting.bufferDistance);  
                 }  
                 if (setting.sltDistanceUnit) {  
                     $("#tbxServiceArea").val(setting.distanceUnit);  
                 }  
                 applySearch();  
             });  
 
             // Initialize the map.  
             map = L.map('map', {  
                 center: [33.1279394892519,|-96.8008536874563],  
                 zoom: 14  
             });  
             L.control.scale().addTo(map);  
 
             // Add the marker layer for search location.  
             markers = new L.FeatureGroup();  
             map.addLayer(markers);  
 
             searchPointIcon = L.icon({  
                 iconUrl: 'Images/drawPoint.png',  
                 iconSize: [32,|32],  
                 iconAnchor: [16,|32]  
             });  
 
             // Added WorldMapKit Online as the background map.  
             L.tileLayer.wms('http://{s}.thinkgeo.com/CachedWMSServer/WmsServer.axd', {  
                 subdomains: ['worldmapkit1',|'worldmapkit2', 'worldmapkit3', 'worldmapkit4', 'worldmapkit5', 'worldmapkit6'],  
                 layers: 'OSMWorldMapKitLayer',  
                 format: 'image/png',  
                 styles: 'WorldMapKitDefaultStyle',  
                 version: '1.1.1',  
                 attribution: '<a href="http://thinkgeo.com/map-suite-developer-gis/world-map-kit-sdk/">ThinkGeo</a> | &copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors '  
             }).addTo(map);  
 
             // Add POI layer.  
             L.tileLayer(L.Util.getRootPath() + '/SiteSelection/baselayer/{z}/{x}/{y}').addTo(map);  
 
             // Create a layer which requests the tiles from the webapi controller action  
             resultLayer = L.dynamicLayer(L.Util.getRootPath() + '/SiteSelection/resultlayer/{z}/{x}/{y}').addTo(map);  
             resultLayer.on('loading', function () {  
                 $('#loadingImage').show();  
             })  
             resultLayer.on('load', function () {  
                 $('#loadingImage').hide();  
             })  
 
             // Add image controls for pan, plot, settings etc.  
             L.imageButtons({  
                 imgs: [   | {  
                         src: 'Images/pan.png',  
                         id: 'btnPan',  
                         title: 'Pan the map',  
                         callback: function (e) {  
                             trackMode = 'pan';  
 
                             $(map.getContainer()).css("cursor", "pointer");  
                             $('#btnPlot').removeClass('active');  
                             $(e.target).addClass('active');  
                         }  
                     },  
                     {  
                         src: 'Images/plot.png',  
                         id: 'btnPlot',  
                         title: 'Plot a point',  
                         css: 'active',  
                         callback: function (e) {  
                             trackMode = 'plot';  
 
                             $(map.getContainer()).css("cursor", "crosshair");  
                             $('#btnPan').removeClass('active');  
                             $(e.target).addClass('active');  
                         }  
                     },  
                     {  
                         src: 'Images/clear.png',  
                         id: 'btnClear',  
                         title: 'clear',  
                         callback: function () {  
                             $.post(L.Util.getRootPath() + "SiteSelection/ClearSearch", function () {  
                                 searchPoint = null;  
                                 markers.clearLayers();  
                                 resultLayer.redraw();  
                                 // Remove all the lines except the header  
                                 $("#result-table tr:gt(0)").remove();  
                             });  
                         }  
                     },  
                     {  
                         src: 'Images/gear.png',  
                         id: 'btnSetting',  
                         title: 'setting',  
                         callback: function () {  
                             showSettingDlg();  
                         }  
                     }  
                 ]  
             }).addTo(map);  
 
             L.imageButtons({  
                 imgs: [   | {  
                         src: 'Images/more.png',  
                         id: 'btnMore',  
                         title: 'Show Details',  
                         callback: function () {  
                             showResultDlg();  
                         }  
                     }]  
             }).addTo(map);  
 
             // Function for plotting a point on the map and do a query based on the clicked point.  
             $(map.getContainer()).css("cursor", "crosshair");  
             map.on("click", function (e) {  
                 if (trackMode == 'plot') {  
                     if (listViewHidden()) {  
                         searchPoint = e.latlng;  
                         markers.clearLayers();  
 
                         L.marker([e.latlng.lat,|e.latlng.lng], { icon: searchPointIcon }).addTo(markers);  
 
                         applySearch();  
                     }  
                 }  
             });  
 
             $("html").click(function () {  
                 $('#left-panel').animate({  
                     'left': -$('#left-panel').width() + 'px'  
                 });  
             });  
 
             var listViewHidden = function () {  
                 return ($("#left-panel").css("left") != "0px");  
             }  
 
             $("#sltSearchMode").change(function (e) {  
                 if ($("#sltSearchMode").val() == 'bufferedArea') {  
                     $("#divBuffer").show();  
                     $("#divService").hide();  
                 }  
                 else {  
                     $("#divBuffer").hide();  
                     $("#divService").show();  
                 }  
             });  
 
             $("#btnSettingCancel").click(function () {  
                 hideSettingDlg();  
             });  
 
             $("#btnSettingSave").click(function () {  
                 applySearch();  
             });  
 
             var applySearch = function () {  
                 hideSettingDlg();  
                 if (!searchPoint) {  
                     return;  
                 }  
                 var category = $("#sltCategory").val();;  
                 var subCategory = $('#sltCategorySubtype').val().replace(">=", ">~");  
                 var searchMode = $("#sltSearchMode").val();  
 
                 var args = { "category": category, "subCategory": subCategory, "searchMode": searchMode, "searchPoint": searchPoint.lng + "," + searchPoint.lat };  
                 if (searchMode == "serviceArea") {  
                     args["driveTime"] = $("#tbxServiceArea").val();  
                 } else {  
                     args["distanceBuffer"] = $("#tbxDistance").val();  
                     args["distanceUnit"] = $("#sltDistanceUnit").val();  
                 }  
 
                 $.post(L.Util.getRootPath() + "SiteSelection/Search", { //: JSON.stringify(args) }, function (res) {  
                     resultLayer.redraw();  
                     $("#result-table tr:gt(0)").remove();  
 
                     var data = JSON.parse(res);  
                     if (data.status == 2) {  
                         $("#message").html("Please note that this sample map is only able to analyze service areas within the Frisco, TX city limits, <br\>which are indicated by a dashed red line. Click inside that boundary for best results. ");  
                         $("#message").show().delay(5000).fadeOut();  
                     }  
                     if (data.status == 1) {  
                         $("#message").text("No results found.");  
                         $("#message").show().delay(5000).fadeOut();  
                     }  
                     if (data.status == 0) {  
                         bindSearchResult(data.features);  
                     }  
                 });  
             }  
         });  
 
         // Functions for displaying query result to grid table.  
         function bindSearchResult(queryItems) {  
             // Remove all the lines except the header  
             $("#result-table tr:gt(0)").remove();  
             // Display data in the Grid table  
             for (var i = 0; i < queryItems.length; i++) {  
                 var name = queryItems[i].name;  
                 var position = queryItems[i].point;  
                 var newRow = $("<tr>");  
                 newRow.append('<td><a style="width:14px;display:block;"><img alt="Search" title="Zoom to sepcified POI" src="Images/find.png" onclick="zoomToPoi(' + position.split(',')[0] + ',' + position.split(',')[1] + ')" /></a></td>');  
                 newRow.append("<td>" + name + "</td>");  
                 $("#result-table > tbody:last").append(newRow);  
             }  
         }  
 
         function zoomToPoi(lat, lng) {  
             map.setView(L.latLng(lat, lng), 16);  
         }  
 
         /* Setting dialog events*/  
         function showSettingDlg() {  
             this.bgmask = L.DomUtil.create('div', 'bg-mask');  
             $('body').append(this.bgmask);  
             $('#edit-panel').slideToggle("fast");  
         }  
 
         function hideSettingDlg() {  
             if ($('#edit-panel').is(':visible')) {  
                 $('.bg-mask').remove();  
                 $('#edit-panel').slideToggle("fast");  
             }  
         }  
 
         function showResultDlg() {  
             $('#left-panel').animate({  
                 'left': '0px'  
             });  
         }  
     </script>  
 </body>  
 </html>  
 
 

default.htm(openlayers)

 <!DOCTYPE html>  
 <html xmlns="http://www.w3.org/1999/xhtml">  
 <head>  
     <title>Site Selection</title>  
     <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />  
     <meta http-equiv="content-type" content="text/html; charset=utf-8" />  
     <meta name="author" content="ThinkGeo" />  
     <link rel="apple-touch-icon" href="desktop.png" />  
     <meta name="apple-mobile-web-app-title" content="Site Selection" />  
     <link href="favicon.ico" rel="shortcut icon" type="Images/x-icon" />  
     <link href="Content/ol.css" rel="stylesheet" />  
     <link href="Content/bootstrap.min.css" rel="stylesheet" />  
     <link href="Content/thinkgeo.openlayers.css" rel="stylesheet" />  
     <link href="Content/Site.css" rel="stylesheet" />  
 </head>  
 <body>  
     <div id="map">  
     </div>  
     <div id="message"></div>  
     <div id="loadingImage">  
         <img src="Images/ajax-loader.gif" />  
     </div>  
     <div id="legend">  
         <img src="Images/legend.png" />  
     </div>  
     <div id="left-panel">  
         <div class="panel-header">  
             <span class="title">Result List</span>  
         </div>  
         <div class="panel-content">  
             <div id="div-resultlist">  
                 <table id="result-table" class="table table-triped table-bordered">  
                     <tr>  
                         <td></td>  
                         <td>Name  
                         </td>  
                     </tr>  
                 </table>  
             </div>  
         </div>  
     </div>  
     <div class="centroid">  
         <div id="edit-panel">  
             <div class="edit-panel-header">  
                 <span id="settingTitle">Settings of site selection</span>  
             </div>  
             <div id="div-setting" class="edit-content">  
                 Highlight points of this type  
                     <select id="sltCategory">  
                     </select>  
                 <select id="sltCategorySubtype">  
                 </select>  
                 Area Type  
                         <select id="sltSearchMode">  
                             <option value="serviceArea">Service Area</option>  
                             <option value="bufferedArea">Buffered Area</option>  
                         </select>  
                 <div id="divService">  
                     <span class="valueLabel">Service Area in</span>  
                     <input type="text" id="tbxServiceArea" class="valueTxt" value="5" /><span class="valueLabel"> Minutes Driving</span>  
                 </div>  
                 <div id="divBuffer" style="display: none;">  
                     <span class="valueLabel">Buffer Distance:</span>  
                     <input type="text" id="tbxDistance" class="valueTxt" value="2" />  
                     <select id="sltDistanceUnit" style="width: 200px;">  
                         <option value="Mile">Mile</option>  
                         <option value="Kilometer">Kilometer</option>  
                     </select>  
                 </div>  
             </div>  
             <div class="edit-foot">  
                 <a id="btnSettingCancel" href="#" class="btn btn-default" role="button">Cancel</a>  
                 <a id="btnSettingSave" href="#" class="btn btn-primary" role="button">Save</a>  
             </div>  
         </div>  
     </div>  
     <script src="Scripts/jquery-1.11.1.min.js"></script>  
     <script src="Scripts/ol.js"></script>  
     <script src="thinkgeo.openlayers.js"></script>  
     <script>  
         var map, resultLayer, searchPoint, trackMode = 'plot', markerLayer = new ol.layer.Vector({  
             source: new ol.source.Vector({  
                 features: []  
             })  
         });;  
         var markerFeature;  
         var defaultSetting = {  
             lng: -96.809983627817,  
             lat: 33.128303417665,  
             category: 'Restaurants',  
             subCategory: 'All',  
             searchMode: 'serviceArea',  
             driveTime: 5  
         };  
 
         $(function () {  
             // Initialize the POI categories and its sub-type categories  
             $.get(getRootPath() + "/SiteSelection/GetCategories/", function (response) {  
                 var categoies = JSON.parse(response);  
                 $.each(categoies, function (key) {  
                     $('#sltCategory').append($("<option/>", {  
                         value: key,  
                         text: key  
                     }));  
                 });  
                 $("#sltCategory").change(function () {  
                     var selectValue = $("#sltCategory").val();  
                     var selectedCategories;  
                     if (categoies.hasOwnProperty(selectValue)) {  
                         selectedCategories = categoies[selectValue];  
                     }  
                     $('#sltCategorySubtype').empty();  
                     for (var i = 0; i < selectedCategories.length; i++) {  
                         $('#sltCategorySubtype').append($("<option/>", {  
                             value: selectedCategories[i],  
                             text: selectedCategories[i]  
                         }));  
                     }  
                 });  
                 var setting = defaultSetting;  
                 var x = parseFloat(setting.lng);  
                 var y = parseFloat(setting.lat);  
                 searchPoint = ol.proj.transform([x,|y], 'EPSG:4326', 'EPSG:3857');  
                 $("#sltCategory").val(setting.category).trigger('change');  
                 $("#sltCategorySubtype").val(setting.subCategory);  
                 $("#sltSearchMode").val(setting.searchMode).trigger('change');  
                 if (setting.driveTime) {  
                     $("#tbxServiceArea").val(setting.driveTime);  
                 }  
                 if (setting.bufferDistance) {  
                     $("#tbxServiceArea").val(setting.bufferDistance);  
                 }  
                 if (setting.sltDistanceUnit) {  
                     $("#tbxServiceArea").val(setting.distanceUnit);  
                 }  
                 applySearch();  
             });  
 
             // Create the openlayers-map  
             map = new ol.Map({  
                 target: 'map',  
                 controls: ol.control.defaults({ attribution: false }).extend(  
                     [new|ol.control.Attribution({  
                         collapsible: false  
                     })]),  
                 view: new ol.View({  
                     center: [-10775821.740841813,|3912298.129520194],  
                     zoom: 14  
                 })  
             });  
 
             // Add thinkgeo map  
             var worldmapkitlayer = new ol.layer.Tile({  
                 source: new ol.source.TileWMS(({  
                     urls: ['http://worldmapkit1.thinkgeo.com/CachedWMSServer/WmsServer.axd',   | 'http://worldmapkit2.thinkgeo.com/CachedWMSServer/WmsServer.axd',  
                         'http://worldmapkit3.thinkgeo.com/CachedWMSServer/WmsServer.axd',  
                         'http://worldmapkit4.thinkgeo.com/CachedWMSServer/WmsServer.axd',  
                         'http://worldmapkit5.thinkgeo.com/CachedWMSServer/WmsServer.axd',  
                         'http://worldmapkit6.thinkgeo.com/CachedWMSServer/WmsServer.axd'],  
                     params:  
                         {  
                             'LAYERS': 'OSMWorldMapKitLayer',  
                             'VERSION': '1.1.1'  
                         },  
                     attributions: [new|ol.Attribution({  
                         html: '<a href="http://thinkgeo.com/map-suite-developer-gis/world-map-kit-sdk/">ThinkGeo</a> | &copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors <a href="http://www.openstreetmap.org/copyright">ODbL</a>'  
                     })]  
                 }))  
             });  
             map.addLayer(worldmapkitlayer);  
 
             // Add POI layer.  
             map.addLayer(new ol.layer.Tile({  
                 source: new ol.source.XYZ({  
                     url: getRootPath() + "/SiteSelection/baselayer/{z}/{x}/{y}",  
                     maxZoom: 19  
                 })  
             }));  
 
 
             // Create a layer which requests the tiles from the webapi controller action  
             var resultSource = new ol.source.XYZ({  
                 url: getRootPath() + "/SiteSelection/resultlayer/{z}/{x}/{y}",  
                 maxZoom: 19  
             });  
             resultSource.tileLoadFunction = function (imageTile, src) {  
                 imageTile.getImage().src = src + '?t=' + new Date().getTime();;  
             };  
             map.addLayer(new ol.layer.Tile({  
                 source: resultSource  
             }));  
 
             // add marker layer.  
             markerLayer.getSource().clear();  
             markerFeature = new ol.Feature({  
                 geometry: new ol.geom.Point(ol.proj.transform([defaultSetting.lng,|defaultSetting.lat], 'EPSG:4326', 'EPSG:3857'))  
             });  
             markerFeature.setStyle(  
             new ol.style.Style({  
                 image: new ol.style.Icon(({  
                     anchor: [0.5,|32],  
                     anchorXUnits: 'fraction',  
                     anchorYUnits: 'pixels',  
                     opacity: 0.75,  
                     src: 'Images/drawPoint.png'  
                 }))  
             }));  
 
             markerLayer.getSource().addFeature(markerFeature);  
             map.addLayer(markerLayer);  
 
             // Add image controls for pan, plot, settings etc.  
             var imgControls = new app.ImagesControl({  
                 imgs: [   | {  
                         src: 'Images/pan.png',  
                         id: 'btnPan',  
                         title: 'Pan the map',  
                         callback: function (e) {  
                             trackMode = 'pan';  
 
                             $(map.getViewport()).css("cursor", "pointer");  
                             $('#btnPlot').removeClass('active');  
                             $(e.target).addClass('active');  
                         }  
                     },  
                     {  
                         src: 'Images/plot.png',  
                         id: 'btnPlot',  
                         title: 'Plot a point',  
                         css: 'active',  
                         callback: function (e) {  
                             trackMode = 'plot';  
 
                             $(map.getViewport()).css("cursor", "crosshair");  
                             $('#btnPan').removeClass('active');  
                             $(e.target).addClass('active');  
                         }  
                     },  
                     {  
                         src: 'Images/clear.png',  
                         id: 'btnClear',  
                         title: 'clear',  
                         callback: function () {  
                             $.post(getRootPath() + "SiteSelection/ClearSearch", function () {  
                                 markerFeature.setGeometry(new ol.geom.Point([0,0]));  
                                 resultSource.setUrl(getRootPath() + "/SiteSelection/resultlayer/{z}/{x}/{y}");  
                                 // Remove all the lines except the header  
                                 $("#result-table tr:gt(0)").remove();  
                             });  
                         }  
                     },  
                     {  
                         src: 'Images/gear.png',  
                         id: 'btnSetting',  
                         title: 'setting',  
                         callback: function () {  
                             showSettingDlg();  
                         }  
                     },  
                     {  
                         src: 'Images/more.png',  
                         id: 'btnMore',  
                         title: 'Show Details',  
                         callback: function () {  
                             showResultDlg();  
                         }  
                     }  
                 ]  
             });  
             map.addControl(imgControls);  
 
             // Function for plotting a point on the map and do a query based on the clicked point.  
             $(map.getViewport()).css("cursor", "crosshair");  
             map.on("click", function (e) {  
                 if (trackMode == 'plot') {  
                     if (listViewHidden()) {  
                         searchPoint = e.coordinate;  
                         markerFeature.setGeometry(new ol.geom.Point(e.coordinate));  
 
                         applySearch();  
                     }  
                 }  
                 $('#left-panel').animate({  
                     'left': -$('#left-panel').width() + 'px'  
                 });  
             });  
 
             var listViewHidden = function () {  
                 return ($("#left-panel").css("left") != "0px");  
             }  
 
             $("#sltSearchMode").change(function (e) {  
                 if ($("#sltSearchMode").val() == 'bufferedArea') {  
                     $("#divBuffer").show();  
                     $("#divService").hide();  
                 }  
                 else {  
                     $("#divBuffer").hide();  
                     $("#divService").show();  
                 }  
             });  
 
             $("#btnSettingCancel").click(function () {  
                 hideSettingDlg();  
             });  
 
             $("#btnSettingSave").click(function () {  
                 applySearch();  
             });  
 
             var applySearch = function () {  
                 var category = $("#sltCategory").val();  
                 var subCategory = $('#sltCategorySubtype').val().replace(">=", ">~");  
                 var searchMode = $("#sltSearchMode").val();  
 
                 var searchLatlng = ol.proj.transform(searchPoint, 'EPSG:3857', 'EPSG:4326');  
                 var args = { "category": category, "subCategory": subCategory, "searchMode": searchMode, "searchPoint": searchLatlng[0] + "," + searchLatlng[1] };  
                 if (searchMode == "serviceArea") {  
                     args["driveTime"] = $("#tbxServiceArea").val();  
                 } else {  
                     args["distanceBuffer"] = $("#tbxDistance").val();  
                     args["distanceUnit"] = $("#sltDistanceUnit").val();  
                 }  
 
                 $.post(getRootPath() + "SiteSelection/Search", { //: JSON.stringify(args) }, function (res) {  
                     resultSource.setUrl(getRootPath() + "/SiteSelection/resultlayer/{z}/{x}/{y}");  
                     $("#result-table tr:gt(0)").remove();  
                     var data = JSON.parse(res);  
                     if (data.status == 2) {  
                         $("#message").html("Please note that this sample map is only able to analyze service areas within the Frisco, TX city limits, <br\>which are indicated by a dashed red line. Click inside that boundary for best results. ");  
                         $("#message").show().delay(5000).fadeOut();  
                     }  
                     if (data.status == 1) {  
                         $("#message").text("No results found.");  
                         $("#message").show().delay(5000).fadeOut();  
                     }  
                     if (data.status == 0) {  
                         bindSearchResult(data.features);  
                     }  
                 });  
 
                 hideSettingDlg();  
             }  
         });  
 
         /* functions for result panel*/  
         function bindSearchResult(queryItems) {  
             // remove all the lines except the header  
             $("#result-table tr:gt(0)").remove();  
             // Display data in the Grid table  
             for (var i = 0; i < queryItems.length; i++) {  
                 var name = queryItems[i].name;  
                 var position = queryItems[i].point;  
                 var newRow = $("<tr>");  
                 newRow.append('<td><a style="width:14px;height:14px;display:block;"><img alt="Search" title="Zoom to sepcified POI" src="Images/find.png" onclick="zoomToPoi(' + position.split(',')[0] + ',' + position.split(',')[1] + ')" /></a></td>');  
                 newRow.append("<td>" + name + "</td>");  
                 $("#result-table > tbody:last").append(newRow);  
             }  
         }  
 
         function zoomToPoi(lat, lng) {  
             var projectedCenter = ol.proj.transform([lng,|lat], 'EPSG:4326', 'EPSG:3857');  
             map.setView(new ol.View({  
                 center: projectedCenter,  
                 zoom: 16  
             }));  
         }  
 
         /* setting dialog events*/  
         function showSettingDlg() {  
             this.bgmask = document.createElement('div');  
             this.bgmask.id = 'bg-mask';  
             $('body').append(this.bgmask);  
             $('#edit-panel').slideToggle("fast");  
         }  
 
         function hideSettingDlg() {  
             if ($('#edit-panel').is(':visible')) {  
                 $('.bg-mask').remove();  
                 $('#edit-panel').slideToggle("fast");  
             }  
         }  
 
         function showResultDlg() {  
             $('#left-panel').animate({  
                 'left': '0px'  
             });  
         }  
     </script>  
 </body>  
 </html>  
 
 

thinkgeo.openlayers.js

 /**  
  * Define a namespace for the application.  
  */  
 window.app = {};  
 var app = window.app;  
 
 /**  
  * @constructor  
  * @extends {ol.control.Control}  
  * @param {Object=} opt_options Control options.  
  */  
 app.ImagesControl = function (opt_options) {  
     var options = opt_options || {};  
 
     var element = document.createElement('div');  
     element.className = 'img-control ol-unselectable';  
 
     for (var i = 0; i < options.imgs.length; i++) {  
         var img = document.createElement('img');  
         img.id = options.imgs[i].id;  
         img.src = options.imgs[i].src;  
         if (options.imgs[i].css) {  
             img.className = options.imgs[i].css;  
         }  
         img.title = options.imgs[i].title;  
         img.callback = options.imgs[i].callback;  
         img.context = this;  
 
         var handleCallback = function (e) {  
             // prevent #rotate-north anchor from getting appended to the url  
             e.preventDefault();  
             if (this.callback) {  
                 this.callback(e);  
             }  
         };  
 
         img.addEventListener('click', handleCallback, false);  
         img.addEventListener('touchstart', handleCallback, false);  
 
         element.appendChild(img);  
     }  
 
     ol.control.Control.call(this, {  
         element: element,  
         target: options.target  
     });  
 };  
 ol.inherits(app.ImagesControl, ol.control.Control);  
 
 // add get root path method.  
 getRootPath = function () {  
     var pathArray = location.pathname.split('/');  
     var appPath = "/";  
     for (var i = 1; i < pathArray.length - 1; i++) {  
         appPath += pathArray[i] + "/";  
     }  
 
     return appPath === "/" ? "" : appPath;  
 };  
 
source_code_webapieditionsample_siteselection.zip.txt · Last modified: 2015/09/09 03:37 by admin