ThinkGeo Cloud
ThinkGeo UI Controls
ThinkGeo Open Source
Help and Support
External Resources
ThinkGeo Cloud
ThinkGeo UI Controls
ThinkGeo Open Source
Help and Support
External Resources
using System; 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 System.Web.SessionState; using System.Xml.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using ThinkGeo.MapSuite.Core; using ThinkGeo.MapSuite.WebApiEdition; namespace DrawingAndEditing.Controllers { [RoutePrefix("edit")] public class DrawingAndEditingController : ApiController { private static string jsonArrayTemplate = "[{0}]"; [Route("{z}/{x}/{y}")] public HttpResponseMessage GetTile(int z, int x, int y) { // Create the layerOverlay for displaying the map. LayerOverlay layerOverlay = new LayerOverlay(); InMemoryFeatureLayer shapesFeatureLyaer = GetLayer(); if (shapesFeatureLyaer != null && shapesFeatureLyaer.InternalFeatures.Count > 0) { layerOverlay.Layers.Add(shapesFeatureLyaer); } 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); layerOverlay.Draw(geoCanvas); geoCanvas.EndDrawing(); MemoryStream memoryStream = new MemoryStream(); bitmap.Save(memoryStream, ImageFormat.Png); HttpResponseMessage responseMessage = new HttpResponseMessage(HttpStatusCode.OK); responseMessage.Content = new ByteArrayContent(memoryStream.ToArray()); responseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png"); return responseMessage; } } [Route("getshapes")] public string GetShapes() { InMemoryFeatureLayer shapesFeatureLayer = GetLayer(); // Return the shapes in JSON saved on server side to client side. return string.Format(CultureInfo.InvariantCulture, jsonArrayTemplate, string.Join(",", shapesFeatureLayer.InternalFeatures.Select(f => f.GetGeoJson()))); } [Route("saveshapes")] [HttpPost] public void SaveShapes([FromBody] string modifiedShapesInJson) { if (!string.IsNullOrEmpty(modifiedShapesInJson)) { // Parse the JSON. // There are 2 groups of shapes, one is for shapes removed on client side, // and the other is for shapes added on client side. JObject jObject = JObject.Parse(modifiedShapesInJson); InMemoryFeatureLayer shapesFeatureLayer = GetLayer(); shapesFeatureLayer.Open(); // Deal with removed shapes. string[] ids = jObject["removedIds"].ToObject<string[]>(); foreach (var id in ids) { if (shapesFeatureLayer.InternalFeatures.Count > 0) { shapesFeatureLayer.InternalFeatures.Remove(id); } } // Deal with newly added shapes. string featureGeoJsons = jObject["newShapes"].ToString(); foreach (Feature feature in CreateFeaturesFromGeoJsons(featureGeoJsons)) { shapesFeatureLayer.InternalFeatures.Add(feature.Id, feature); } shapesFeatureLayer.Close(); } } private static Collection<Feature> CreateFeaturesFromGeoJsons(string geoJsons) { Collection<Feature> features = new Collection<Feature>(); foreach (JToken item in JArray.Parse(geoJsons)) { Feature feature = null; string geoJson = item.ToString(); if (geoJson.Contains("\"type\": \"Circle\"")) { // Circle is not supported in standard GeoJSON, it's only defined in this sample. feature = CreateCircleFeatureFromGeoJson(geoJson); } else { feature = Feature.CreateFeatureFromGeoJson(geoJson); } if (feature != null && feature.GetWellKnownBinary() != null) { features.Add(feature); } } return features; } private static Feature CreateCircleFeatureFromGeoJson(string geoJson) { dynamic featureEntity = JsonConvert.DeserializeObject(geoJson); dynamic geometryEntity = JsonConvert.DeserializeObject(featureEntity.geometry.ToString()); double x = Convert.ToDouble(geometryEntity.coordinates[0].ToString(), CultureInfo.InvariantCulture); double y = Convert.ToDouble(geometryEntity.coordinates[1].ToString(), CultureInfo.InvariantCulture); double radius = Convert.ToDouble(geometryEntity.radius.ToString(), CultureInfo.InvariantCulture); DistanceUnit distanceUnit = (DistanceUnit)Enum.Parse(typeof(DistanceUnit), geometryEntity.radiusUnit.ToString(), true); EllipseShape circleShape = new EllipseShape(new PointShape(x, y), radius, GeographyUnit.DecimalDegree, distanceUnit); Feature feature = new Feature(circleShape); foreach (var item in featureEntity.properties) { feature.ColumnValues[item.Name] = item.Value.ToString(); } return feature; } // Get layer from the Session so each session has its own test data. private static InMemoryFeatureLayer GetLayer() { IHttpSessionState session = SessionStateUtility.GetHttpSessionStateFromContext(HttpContext.Current); if (session["shapesFeatureLayer"] == null) { InMemoryFeatureLayer shapesFeatureLayer = new InMemoryFeatureLayer(); shapesFeatureLayer.Open(); shapesFeatureLayer.Columns.Add(new FeatureSourceColumn("Name")); shapesFeatureLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.CreateSimpleAreaStyle(GeoColor.FromArgb(100, GeoColor.FromHtml("#676e51")), GeoColor.SimpleColors.Black); shapesFeatureLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyles.CreateSimpleCircleStyle(GeoColor.FromHtml("#2b7a05"), 14, GeoColor.SimpleColors.Black); shapesFeatureLayer.ZoomLevelSet.ZoomLevel01.DefaultLineStyle = LineStyles.CreateSimpleLineStyle(GeoColor.FromHtml("#676e51"), 2, true); shapesFeatureLayer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle = TextStyles.CreateSimpleTextStyle("Name", "Arial", 12, DrawingFontStyles.Bold, GeoColor.StandardColors.Gray, GeoColor.StandardColors.White, 2); shapesFeatureLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; string dataFilePath = GetFullPath(@"App_Data\Data.xml"); XElement xElement = XElement.Load(dataFilePath); foreach (var geometryXElement in xElement.Descendants("Geometry")) { Feature feature = new Feature(geometryXElement.Value); feature.ColumnValues.Add("name", geometryXElement.Attribute("name").Value); shapesFeatureLayer.InternalFeatures.Add(feature.Id, feature); } Proj4Projection proj4 = new Proj4Projection(); proj4.InternalProjectionParametersString = Proj4Projection.GetWgs84ParametersString(); proj4.ExternalProjectionParametersString = Proj4Projection.GetSphericalMercatorParametersString(); shapesFeatureLayer.FeatureSource.Projection = proj4; proj4.Open(); session["shapesFeatureLayer"] = shapesFeatureLayer; } return (InMemoryFeatureLayer)session["shapesFeatureLayer"]; } private static string GetFullPath(string fileName) { Uri uri = new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase); string rootDirectory = Path.GetDirectoryName(Path.GetDirectoryName(uri.LocalPath)); return Path.Combine(rootDirectory, fileName); ; } } }
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Draw edit features</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="Draw edit features" /> <link href="favicon.ico" rel="shortcut icon" type="Images/x-icon" /> <link href="Content/leaflet.css" rel="stylesheet" /> <link href="Content/leaflet.draw.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="loadingImage"> <img src="Images/ajax-loader.gif" /> </div> <div class="centroid"> <div id="dlgName"> <div class="edit-panel-header"> <span>The name of drawn shape</span> </div> <div class="edit-content"> <input type="text" id="txtName" /> <span id="spWarning" class="warning">The name is required.</span> </div> <div class="edit-foot"> <a id="btnSaveName" href="#" class="btn btn-primary" role="button">OK</a> </div> </div> </div> <script src="Scripts/jquery-1.11.1.min.js"></script> <script src="Scripts/leaflet.js"></script> <script src="Scripts/leaflet.draw.js"></script> <script src="thinkgeo.leaflet.js"></script> <script> var drawingLayer, editServerShapes = false; var postData = { removeIds: [], geoJsons: [] }; // initialize the map var map = L.map('map', { center: [33.1451,|-96.8150], zoom: 16 }); // ThinkGeo World 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> | © <a href="http://osm.org/copyright">OpenStreetMap</a> contributors ' }).addTo(map); // layer including the drawn shapes which are saved to server side var shapeLayer = L.dynamicLayer(L.Util.getRootPath() + "/edit/{z}/{x}/{y}"); shapeLayer.on('loading', function () { $('#loadingImage').show(); }) shapeLayer.on('load', function () { $('#loadingImage').hide(); }) shapeLayer.addTo(map); // Initialise the FeatureGroup to save editable layers var drawnItems = L.featureGroup().addTo(map); // Initialise the draw control and pass it the FeatureGroup of editable layers var drawControl = new L.Control.Draw({ edit: { featureGroup: drawnItems } }).addTo(map); // add image buttons for layers, edit, help etc. L.imageButtons({ imgs: [ | { src: 'Images/save.png', id: 'imgSave', title: 'Save to server', callback: function () { editServerShapes = false; drawnItems.eachLayer(function (layer) { var geoJson = layer.toGeoJSON(); if (layer._mRadius) { geoJson.geometry.radius = layer.getRadius(); geoJson.geometry.type = "Circle"; geoJson.geometry.radiusUnit = "Meter"; } geoJson.id = layer.id; geoJson.properties = { 'name': layer.name }; postData.geoJsons.push(geoJson); }, this); // save the drawn features to server side in GeoJson format $.post(L.Util.getRootPath() + '/edit/add', { //: JSON.stringify(postData) }, function (data) { shapeLayer.redraw(); drawnItems.clearLayers(); }); postData.removeIds.length = 0; postData.geoJsons.length = 0; $('#btnStartingEdit').prop("disabled", false); } } ] }).addTo(map); // event after shapes drawn map.on('draw:created', function (e) { drawingLayer = e.layer; drawingLayer.id = L.Util.guid(); drawnItems.addLayer(drawingLayer); showDlg(); }); map.on('draw:deleted', function (e) { var layers = e.layers; layers.eachLayer(function (layer) { postData.removeIds.push(layer.id); }); }); $('.leaflet-draw-edit-edit').click(function (e) { if (!editServerShapes) { editServerShapes = true; $.get(L.Util.getRootPath() + '/edit/getshapes', function (data) { var geoJsons = JSON.parse(data); for (var i = 0; i < geoJsons.length; i++) { var vectorlayer = L.GeoJSON.geometryToLayer(geoJsons[i].geometry); var coordinates = geoJsons[i].geometry.coordinates; var geo; switch (geoJsons[i].geometry.type) { case 'LineString': for (var j = 0; j < coordinates.length; j++) { var tempX = coordinates[j][0]; coordinates[j][0] = coordinates[j][1]; coordinates[j][1] = tempX; } geo = new L.Polyline(coordinates); break; case 'Polygon': for (var j = 0; j < coordinates[0].length; j++) { var tempX = coordinates[0][j][0]; coordinates[0][j][0] = coordinates[0][j][1]; coordinates[0][j][1] = tempX; } var geo = new L.Polygon(coordinates[0]); break; case 'Point': var tempX = coordinates[0]; coordinates[0] = coordinates[1]; coordinates[1] = tempX; geo = new L.Polyline(coordinates); break; } if (geoJsons[i].properties.name) { geo.name = geoJsons[i].properties.name; } geo.setStyle({ color: '#f06eaa' }); geo.id = geoJsons[i].id; postData.removeIds.push(geoJsons[i].id); geo.editing.enable(); drawnItems.addLayer(geo); } map.removeLayer(shapeLayer); }); } }); $('#btnSaveName').click(function () { if ($('#txtName').val() == //) { $('#spWarning').show(); return; } else { $('#spWarning').hide(); } // take the input name or description of the drawn shape if (drawingLayer) { drawingLayer.name = $('#txtName').val(); $('#txtName').val(//); } hideDlg(); }); // show/hide edit dialog in model mode function showDlg() { this.bgmask = L.DomUtil.create('div', 'bg-mask'); $('body').append(this.bgmask); $('#dlgName').slideToggle("fast"); } function hideDlg() { $('.bg-mask').remove(); $('#dlgName').slideToggle("fast"); } </script> </body> </html>
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Draw edit features</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="Draw edit features" /> <link href="favicon.ico" rel="shortcut icon" type="Images/x-icon" /> <link href="Content/bootstrap.min.css" rel="stylesheet" /> <link href="Content/ol.css" rel="stylesheet" /> <link href="Content/Site.css" rel="stylesheet" /> <link href="Content/thinkgeo.openlayers.css" rel="stylesheet" /> </head> <body> <div id="map"> </div> <div id="bg-mask"> </div> <div class="centroid"> <div id="dlgName"> <div class="edit-panel-header"> <span>The name of drawn shape</span> </div> <div class="edit-content"> <input type="text" id="txtName" /> <span id="spWarning" class="warning">The name is required.</span> </div> <div class="edit-foot"> <a id="btnSaveName" href="#" class="btn btn-primary" role="button">OK</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 draw, editServerShapes = false; var postData = { removeIds: [], geoJsons: [] }; var attribution = new ol.control.Attribution({ collapsible: false }); // initialize the map var map = new ol.Map({ target: 'map', controls: ol.control.defaults({ attribution: false }).extend([attribution]), view: new ol.View({ center: [-10777396.5012,|3914579.4368], zoom: 16 }) }); // add image buttons for layers, edit, help etc. var imgControls = new app.ImagesControl({ imgs: [{ | src: 'Images/Point.png', title: 'Draw Point', callback: function () { removeModify(); removeDraw(); removeSelect(); addInteraction('Point'); } }, { src: 'Images/Line.png', title: 'Draw Line', callback: function () { removeModify(); removeDraw(); removeSelect(); addInteraction('LineString'); } }, { src: 'Images/Polygon.png', title: 'Draw Polygon', callback: function () { removeModify(); removeDraw(); removeSelect(); addInteraction('Polygon'); } }, { src: 'Images/Edit.png', title: 'Edit Shape', callback: function () { if (!editServerShapes) { editServerShapes = true; $.get(getRootPath() + '/edit/getshapes', function (data) { var geoJsons = JSON.parse(data); for (var i = 0; i < geoJsons.length; i++) { tempGeoJSON = geoJsons[i]; transfterGeoJSON(tempGeoJSON, getSphericalMercatorVertex); var tempFeature = getFeatureFromGeoJson(tempGeoJSON); featureOverlay.addFeature(tempFeature); postData.removeIds.push(tempFeature.getId()); } tileLayer.setVisible(false); }); removeModify(); removeDraw(); removeSelect(); map.addInteraction(modify); map.addInteraction(select); } } }, { src: 'Images/Delete.png', title: 'Delete Polygon', callback: function () { removeModify(); removeDraw(); removeSelect(); var selectionFeatures = select.getFeatures(); selectionFeatures.on('add', deleteFeature); map.addInteraction(select); } }, { src: 'Images/save.png', id: 'imgSave', title: 'Save to server', callback: function () { var features = featureOverlay.getFeatures().getArray(); var featureLength = features.length; for (var i = 0; i < featureLength; i++) { var tempGeoJSON = getGeoJsonFromFeature(features[i]); transfterGeoJSON(tempGeoJSON, getWgs84Vertex); postData.geoJsons.push(tempGeoJSON); } // save the drawn features to server side in GeoJson format $.post(getRootPath() + '/edit/add', { //: JSON.stringify(postData) }, function (data) { xyzSource.setUrl(getRootPath() + "/edit/{z}/{x}/{y}"); tileLayer.setVisible(true); }); for (var i = featureLength - 1; i > -1; i--) { featureOverlay.removeFeature(features[i]); } postData.removeIds.length = 0; postData.geoJsons.length = 0; removeModify(); removeDraw(); removeSelect(); editServerShapes = false; } } ] }); map.addControl(imgControls); // ThinkGeo World 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> | © <a href="http://osm.org/copyright">OpenStreetMap</a> contributors <a href="http://www.openstreetmap.org/copyright">ODbL</a>' })] })) }); map.addLayer(worldmapkitlayer); // layer including the drawn shapes which are saved to server side var xyzSource = new ol.source.XYZ({ url: getRootPath() + "/edit/{z}/{x}/{y}", maxZoom: 19 }); xyzSource.tileLoadFunction = function (imageTile, src) { imageTile.getImage().src = src + '?t=' + new Date().getTime();; }; var tileLayer = new ol.layer.Tile({ source: xyzSource }) map.addLayer(tileLayer); // Initialise the FeatureGroup to save editable layers var featureOverlay = new ol.FeatureOverlay({ style: new ol.style.Style({ fill: new ol.style.Fill({ color: 'rgba(0, 153, 255, 0.4)' }), stroke: new ol.style.Stroke({ color: '#0099FF', width: 3 }), image: new ol.style.Circle({ radius: 7, fill: new ol.style.Fill({ color: '#0099FF' }) }) }) }); featureOverlay.setMap(map); var select = new ol.interaction.Select({ style: new ol.style.Style({ fill: new ol.style.Fill({ color: 'rgba(240, 110, 170,0.2)' }), stroke: new ol.style.Stroke({ color: 'rgba(240, 110, 170,0.5)', width: 3 }), image: new ol.style.Circle({ radius: 7, fill: new ol.style.Fill({ color: 'rgba(240, 110, 170,0.2)' }) }) }) }); // Initialise the draw control and pass it the FeatureGroup of editable layers var modify = new ol.interaction.Modify({ features: select.getFeatures(), // the SHIFT key must be pressed to delete vertices, so // that new vertices can be drawn at the same position // of existing vertices deleteCondition: function (event) { return ol.events.condition.shiftKeyOnly(event) && ol.events.condition.singleClick(event); } }); var creatingFeature; function addInteraction(drawType) { removeDraw(); draw = new ol.interaction.Draw({ features: featureOverlay.getFeatures(), type: drawType }); draw.on('drawend', function (e) { var id = guid(); e.feature.setId(id); creatingFeature = e.feature; showDlg(); }); map.addInteraction(draw); } function removeDraw() { if (draw) { map.removeInteraction(draw); } } function removeModify() { if (modify) { map.removeInteraction(modify); } } function removeSelect() { if (select) { map.removeInteraction(select); var selectionFeatures = select.getFeatures(); selectionFeatures.un('add', deleteFeature); } } function transfterGeoJSON(geoJSON, transfer) { var coordinates = geoJSON.geometry.coordinates; switch (geoJSON.geometry.type) { case 'LineString': for (var j = 0; j < coordinates.length; j++) { coordinates[j] = transfer(coordinates[j]); } break; case 'Polygon': for (var j = 0; j < coordinates[0].length; j++) { coordinates[0][j] = transfer(coordinates[0][j]); } break; case 'Point': geoJSON.geometry.coordinates = transfer(coordinates); break; } } function getGeoJsonFromFeature(feature) { var geoJSONFomat = new ol.format.GeoJSON(); var geoJSON = geoJSONFomat.writeFeature(feature); var id = feature.getId(); if (id) { geoJSON.id = id; } else { geoJSON.id = guid(); } return geoJSON; } function getFeatureFromGeoJson(geoJSON) { var geoJSONFomat = new ol.format.GeoJSON(); var feature = geoJSONFomat.readFeature(geoJSON); feature.setId(geoJSON.id); return feature; } function getWgs84Vertex(vertex) { return ol.proj.transform(vertex, 'EPSG:3857', 'EPSG:4326'); } function getSphericalMercatorVertex(vertex) { return ol.proj.transform(vertex, 'EPSG:4326', 'EPSG:3857'); } var deleteFeature = function (e) { var features = e.target.getArray(); if (features.length > 0) { var id = features[0].getId(); featureOverlay.removeFeature(features[0]); var selectionFeatures = select.getFeatures(); selectionFeatures.remove(features[0]); postData.removeIds.push(id); } } $('#btnSaveName').click(function () { if ($('#txtName').val() == //) { $('#spWarning').show(); return; } else { $('#spWarning').hide(); } // take the input name or description of the drawn shape if (creatingFeature) { var shapeName = $('#txtName').val(); creatingFeature.setProperties({ name: shapeName }); $('#txtName').val(//); creatingFeature = null; } hideDlg(); }); // show/hide edit dialog in model mode function showDlg() { $('#bg-mask').show(); $('#dlgName').slideToggle("fast"); } function hideDlg() { $('#bg-mask').hide(); $('#dlgName').slideToggle("fast"); } </script> </body> </html>