Skip To Content ArcGIS for Developers Sign In Dashboard

ArcGIS Runtime SDK for .NET

Sketch on map

This code sample is available for these platforms:
View Sample on GitHub

Use the Sketch Editor to edit or sketch a new point, line, or polygon geometry on to a map.

Image of sketch on map

Use case

A field worker could annotate features of interest on a map (via the GUI) such as location of dwellings (marked as points), geological features (polylines), or areas of glaciation (polygons).

How to use the sample

Choose which geometry type to sketch from one of the available buttons. Choose from points, multipoints, polylines, polygons, freehand polylines, and freehand polygons.

Use the control panel to cancel the sketch, undo or redo changes made to the sketch and to save the sketch to the graphics overlay. There is also the option to select a saved graphic and edit its geometry using the Sketch Editor. The graphics overlay can be cleared using the clear all button.

How it works

  1. Use SketchEditor.StartAsync() to start sketching. If editing an existing graphic's geometry, use SketchEditor.StartAsync(graphic.Geometry).
  2. Use the UndoCommand and RedoCommand to undo and redo edits in the sketch.
  3. Use a CompleteCommand to finish the sketch and get the Geometry result. Use the CancelCommand to cancel the sketch.
  4. Create a Graphic for the geometry and add it to the GraphicsOverlay in the map view.

Relevant API

  • Geometry
  • Graphic
  • GraphicsOverlay
  • MapView
  • SketchCreationMode
  • SketchEditor

Tags

draw, edit

Sample Code

<UserControl
    x:Class="ArcGISRuntime.UWP.Samples.SketchOnMap.SketchOnMap"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:esriUI="using:Esri.ArcGISRuntime.UI.Controls">
    <Grid>
        <esriUI:MapView x:Name="MyMapView" />
        <CommandBar OverflowButtonVisibility="Collapsed">
            <AppBarButton AllowFocusOnInteraction="True">
                <AppBarButton.Content>
                    <TextBlock HorizontalAlignment="Center" Text="Draw/Edit" />
                </AppBarButton.Content>
                <AppBarButton.Flyout>
                    <Flyout x:Name="DrawToolsFlyout">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="5" />
                                <RowDefinition Height="35" />
                                <RowDefinition Height="35" />
                                <RowDefinition Height="35" />
                                <RowDefinition />
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition />
                                <ColumnDefinition />
                            </Grid.ColumnDefinitions>
                            <TextBlock
                                Grid.Row="1"
                                Grid.Column="0"
                                HorizontalAlignment="Right"
                                VerticalAlignment="Center"
                                FontSize="12"
                                Text="Sketch shape:" />
                            <ComboBox
                                x:Name="SketchModeComboBox"
                                Grid.Row="1"
                                Grid.Column="1"
                                Margin="2"
                                HorizontalAlignment="Stretch"
                                VerticalAlignment="Center"
                                FontSize="12" />
                            <Button
                                Grid.Row="2"
                                Grid.Column="1"
                                Width="100"
                                Height="30"
                                Margin="2"
                                HorizontalAlignment="Center"
                                VerticalAlignment="Top"
                                Click="DrawButtonClick"
                                Content="Draw"
                                FontSize="12" />
                            <Button
                                x:Name="EditButton"
                                Grid.Row="3"
                                Grid.Column="1"
                                Width="100"
                                Height="30"
                                Margin="2"
                                HorizontalAlignment="Center"
                                VerticalAlignment="Top"
                                Click="EditButtonClick"
                                Content="Edit"
                                FontSize="12"
                                IsEnabled="False" />
                        </Grid>
                    </Flyout>
                </AppBarButton.Flyout>
            </AppBarButton>
            <AppBarButton Command="{Binding UndoCommand}">
                <AppBarButton.Content>
                    <TextBlock HorizontalAlignment="Center" Text="Undo" />
                </AppBarButton.Content>
            </AppBarButton>
            <AppBarButton Command="{Binding RedoCommand}">
                <AppBarButton.Content>
                    <TextBlock HorizontalAlignment="Center" Text="Redo" />
                </AppBarButton.Content>
            </AppBarButton>
            <AppBarButton Command="{Binding CompleteCommand}">
                <AppBarButton.Content>
                    <TextBlock HorizontalAlignment="Center" Text="Complete" />
                </AppBarButton.Content>
            </AppBarButton>
            <AppBarButton x:Name="ClearButton" Click="ClearButtonClick">
                <AppBarButton.Content>
                    <TextBlock HorizontalAlignment="Center" Text="Clear" />
                </AppBarButton.Content>
            </AppBarButton>
        </CommandBar>
    </Grid>
</UserControl>
// Copyright 2017 Esri.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an 
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific 
// language governing permissions and limitations under the License.

using Esri.ArcGISRuntime.Data;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Symbology;
using Esri.ArcGISRuntime.UI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Drawing;
using Windows.UI.Popups;
using Windows.UI.Xaml;

namespace ArcGISRuntime.UWP.Samples.SketchOnMap
{
    [ArcGISRuntime.Samples.Shared.Attributes.Sample(
        name: "Sketch on map",
        category: "GraphicsOverlay",
        description: "Use the Sketch Editor to edit or sketch a new point, line, or polygon geometry on to a map.",
        instructions: "Choose which geometry type to sketch from one of the available buttons. Choose from points, multipoints, polylines, polygons, freehand polylines, and freehand polygons.",
        tags: new[] { "draw", "edit" })]
    public sealed partial class SketchOnMap
    {
        // Graphics overlay to host sketch graphics
        private GraphicsOverlay _sketchOverlay;

        public SketchOnMap()
        {
            InitializeComponent();

            // Call a function to set up the map and sketch editor 
            Initialize();
        }

        private void Initialize()
        {
            // Create a light gray canvas map
            Map myMap = new Map(Basemap.CreateLightGrayCanvas());

            // Create graphics overlay to display sketch geometry
            _sketchOverlay = new GraphicsOverlay();
            MyMapView.GraphicsOverlays.Add(_sketchOverlay);

            // Assign the map to the MapView
            MyMapView.Map = myMap;

            // Fill the combo box with choices for the sketch modes (shapes)
            SketchModeComboBox.ItemsSource = System.Enum.GetValues(typeof(SketchCreationMode));
            SketchModeComboBox.SelectedIndex = 0;

            // Set the sketch editor as the page's data context
            DataContext = MyMapView.SketchEditor;
        }

        #region Graphic and symbol helpers
        private Graphic CreateGraphic(Esri.ArcGISRuntime.Geometry.Geometry geometry)
        {
            // Create a graphic to display the specified geometry
            Symbol symbol = null;
            switch (geometry.GeometryType)
            {
                // Symbolize with a fill symbol
                case GeometryType.Envelope:
                case GeometryType.Polygon:
                    {
                        symbol = new SimpleFillSymbol()
                        {
                            Color = Color.Red,
                            Style = SimpleFillSymbolStyle.Solid
                        };
                        break;
                    }
                // Symbolize with a line symbol
                case GeometryType.Polyline:
                    {
                        symbol = new SimpleLineSymbol()
                        {
                            Color = Color.Red,
                            Style = SimpleLineSymbolStyle.Solid,
                            Width = 5d
                        };
                        break;
                    }
                // Symbolize with a marker symbol
                case GeometryType.Point:
                case GeometryType.Multipoint:
                    {

                        symbol = new SimpleMarkerSymbol()
                        {
                            Color = Color.Red,
                            Style = SimpleMarkerSymbolStyle.Circle,
                            Size = 15d
                        };
                        break;
                    }
            }

            // pass back a new graphic with the appropriate symbol
            return new Graphic(geometry, symbol);
        }

        private async Task<Graphic> GetGraphicAsync()
        {
            // Wait for the user to click a location on the map
            MapPoint mapPoint = (MapPoint)await MyMapView.SketchEditor.StartAsync(SketchCreationMode.Point, false);

            // Convert the map point to a screen point
            var screenCoordinate = MyMapView.LocationToScreen(mapPoint);

            // Identify graphics in the graphics overlay using the point
            IReadOnlyList<IdentifyGraphicsOverlayResult> results = await MyMapView.IdentifyGraphicsOverlaysAsync(screenCoordinate, 2, false);

            // If results were found, get the first graphic
            Graphic graphic = null;
            IdentifyGraphicsOverlayResult idResult = results.FirstOrDefault();
            if (idResult != null && idResult.Graphics.Count > 0)
            {
                graphic = idResult.Graphics.FirstOrDefault();
            }

            // Return the graphic (or null if none were found)
            return graphic;
        }
        #endregion

        private async void DrawButtonClick(object sender, RoutedEventArgs e)
        {
            try
            {
                // Set the focus to the map view(close the flyout panel)
                DrawToolsFlyout.Hide();

                // Let the user draw on the map view using the chosen sketch mode
                SketchCreationMode creationMode = (SketchCreationMode)SketchModeComboBox.SelectedItem;
                Esri.ArcGISRuntime.Geometry.Geometry geometry = await MyMapView.SketchEditor.StartAsync(creationMode, true);

                // Create and add a graphic from the geometry the user drew
                Graphic graphic = CreateGraphic(geometry);
                _sketchOverlay.Graphics.Add(graphic);

                // Enable/disable the clear and edit buttons according to whether or not graphics exist in the overlay
                ClearButton.IsEnabled = _sketchOverlay.Graphics.Count > 0;
                EditButton.IsEnabled = _sketchOverlay.Graphics.Count > 0;
            }
            catch (TaskCanceledException)
            {
                // Ignore ... let the user cancel drawing
            }
            catch (Exception ex)
            {
                // Report exceptions
                MessageDialog dialog = new MessageDialog("Error drawing graphic shape: " + ex.Message);
                await dialog.ShowAsync();
            }
        }

        private void ClearButtonClick(object sender, RoutedEventArgs e)
        {
            // Remove all graphics from the graphics overlay
            _sketchOverlay.Graphics.Clear();

            // Cancel any uncompleted sketch
            if (MyMapView.SketchEditor.CancelCommand.CanExecute(null))
            {
                MyMapView.SketchEditor.CancelCommand.Execute(null);
            }

            // Disable buttons that require graphics
            ClearButton.IsEnabled = false;
            EditButton.IsEnabled = false;
        }

        private async void EditButtonClick(object sender, RoutedEventArgs e)
        {
            try
            {
                // Set the focus to the map view(close the flyout panel)
                DrawToolsFlyout.Hide();

                // Allow the user to select a graphic
                Graphic editGraphic = await GetGraphicAsync();
                if (editGraphic == null) { return; }

                // Let the user make changes to the graphic's geometry, await the result (updated geometry)
                Geometry newGeometry = await MyMapView.SketchEditor.StartAsync(editGraphic.Geometry);

                // Display the updated geometry in the graphic
                editGraphic.Geometry = newGeometry;
            }
            catch (TaskCanceledException)
            {
                // Ignore ... let the user cancel editing
            }
            catch (Exception ex)
            {
                // Report exceptions
                MessageDialog dialog = new MessageDialog("Error editing shape: " + ex.Message);
                await dialog.ShowAsync();
            }
        }
    }
}