Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@
<li>
<NavLink class="dropdown-item" href="/Drawing/DrawingToolbarUpdate"> Toolbar update </NavLink>
</li>
<li>
<NavLink class="dropdown-item" href="/Drawing/DrawingManagerLoadData"> Load data to drawing manager </NavLink>
</li>
</ul>
</li>
<NavLink class="nav-link" href="Indoor"> Indoor </NavLink>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
@page "/Drawing/DrawingManagerLoadData"
@rendermode InteractiveServer

@using AzureMapsControl.Components.Atlas
@using AzureMapsControl.Components.Drawing
@using AzureMapsControl.Components.Map


<AzureMap Id="map"
OnReady="MapReady"
EventActivationFlags="MapEventActivationFlags.None().Enable(MapEventType.Ready)" />
<div style="position: absolute; bottom: 10px; left: 10px; z-index: 1;">
<button @onclick="AddRandomShape">Add Random Shape</button>
<button @onclick="ClearShapes">Clear Shapes</button>
</div>


@code {
private DrawingManager? _drawingManager;
private Position _center = new Position(-122.33, 47.6);

public async Task MapReady(MapEventArgs eventArgs)
{
await eventArgs.Map.SetCameraOptionsAsync(options =>
{
options.Zoom = 10;
options.Center = _center;
});
await eventArgs.Map.AddDrawingToolbarAsync(new AzureMapsControl.Components.Drawing.DrawingToolbarOptions
{
Buttons = new[]
{
AzureMapsControl.Components.Drawing.DrawingButton.DrawCircle,
AzureMapsControl.Components.Drawing.DrawingButton.DrawLine,
AzureMapsControl.Components.Drawing.DrawingButton.EditGeometry
},
Position = AzureMapsControl.Components.Controls.ControlPosition.TopRight,
Style = AzureMapsControl.Components.Drawing.DrawingToolbarStyle.Dark
});

var lineString = new AzureMapsControl.Components.Atlas.LineString(new[]
{
new AzureMapsControl.Components.Atlas.Position(-122.27577, 47.55938),
new AzureMapsControl.Components.Atlas.Position(-122.29705, 47.60662),
new AzureMapsControl.Components.Atlas.Position(-122.22358, 47.6367)
});
var shape = new AzureMapsControl.Components.Atlas.Shape<AzureMapsControl.Components.Atlas.LineString>(lineString);
_drawingManager = eventArgs.Map.DrawingManager;
await _drawingManager.AddShapesAsync(new[] { shape });
}

private async Task AddRandomShape()
{
if (_drawingManager == null) return;

var random = new Random();
var shapeType = random.Next(3);
Shape shape;
var numberOfPoints = random.Next(3, 5);
var center = new Position(_center.Longitude + (random.NextDouble()-0.5) * 0.6, _center.Latitude + (random.NextDouble()-0.5) * 0.4);

switch (shapeType)
{
case 0: // Circle
var radius = random.NextDouble() * 2000;
shape = new Shape<Point>(new Point(center), new Dictionary<string, object>
{
{ "subType", "Circle" },
{ "radius", radius }
});
break;
case 1: // Polygon
var polygonPositions = new List<Position>();
for (var i = 0; i < numberOfPoints; i++)
{
polygonPositions.Add(new Position(center.Longitude + (random.NextDouble()-0.5) * 0.1, center.Latitude + (random.NextDouble()-0.5) * 0.1));
}
polygonPositions.Add(polygonPositions[0]);
shape = new Shape<Polygon>(new Polygon(new[] { polygonPositions }));
break;
case 2: // Polyline
var polylinePositions = new List<Position>();
for (var i = 0; i < numberOfPoints; i++)
{
polylinePositions.Add(new Position(center.Longitude + (random.NextDouble()-0.5) * 0.1, center.Latitude + (random.NextDouble()-0.5) * 0.1));
}
shape = new Shape<LineString>(new LineString(polylinePositions));
break;
default:
return;
}

await _drawingManager.AddShapesAsync(new[] { shape });
}

private async Task ClearShapes()
{
if (_drawingManager != null)
{
await _drawingManager.ClearAsync();
}
}
}
151 changes: 151 additions & 0 deletions src/AzureMapsControl.Components/Drawing/DrawingManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
namespace AzureMapsControl.Components.Drawing
{
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

using AzureMapsControl.Components.Atlas;
using AzureMapsControl.Components.Logger;
using AzureMapsControl.Components.Runtime;

using Microsoft.Extensions.Logging;


/// <summary>
/// DrawingManager for the DrawingToolbar
/// </summary>
public sealed class DrawingManager
{
internal IMapJsRuntime JSRuntime { get; set; }
internal ILogger Logger { get; set; }
public bool Disposed { get; private set; }

/// <summary>
/// List of shapes added to the data source
/// </summary>
private List<Shape> _sourceShapes;

/// <summary>
/// Add shapes to the drawing manager data source
/// </summary>
/// <param name="shapes">Shapes to add</param>
/// <returns></returns>
/// <exception cref="Exceptions.ComponentNotAddedToMapException">The control has not been added to the map</exception>
/// <exception cref="Exceptions.ComponentDisposedException">The control has already been disposed</exception>
public async ValueTask AddShapesAsync(IEnumerable<Shape> shapes)
{
if (shapes == null || !shapes.Any())
{
return;
}

EnsureJsRuntimeExists();
EnsureNotDisposed();

if (_sourceShapes == null)
{
_sourceShapes = new List<Shape>();
}

var lineStrings = shapes.OfType<Shape<LineString>>();
if (lineStrings.Any())
{
Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{lineStrings.Count()} linestrings will be added");
await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), lineStrings);
}

var multiLineStrings = shapes.OfType<Shape<MultiLineString>>();
if (multiLineStrings.Any())
{
Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{multiLineStrings.Count()} multilinestrings will be added");
await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), multiLineStrings);
}

var multiPoints = shapes.OfType<Shape<MultiPoint>>();
if (multiPoints.Any())
{
Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{multiPoints.Count()} multipoints will be added");
await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), multiPoints);
}

var multiPolygons = shapes.OfType<Shape<MultiPolygon>>();
if (multiPolygons.Any())
{
Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{multiPolygons.Count()} multipolygons will be added");
await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), multiPolygons);
}

var points = shapes.OfType<Shape<Point>>();
if (points.Any())
{
Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{points.Count()} points will be added");
await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), points);
}

var polygons = shapes.OfType<Shape<Polygon>>();
if (polygons.Any())
{
Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{polygons.Count()} polygons will be added");
await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), polygons);
}

var routePoints = shapes.OfType<Shape<RoutePoint>>();
if (routePoints.Any())
{
Logger?.LogAzureMapsControlDebug(AzureMapLogEvent.Source_AddAsync, $"{routePoints.Count()} route points will be added");
await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.AddShapes.ToDrawingNamespace(), routePoints);
}

_sourceShapes.AddRange(shapes);
}

/// <summary>
/// Clear the drawing manager source
/// </summary>
/// <returns></returns>
/// <exception cref="Exceptions.ComponentNotAddedToMapException">The control has not been added to the map</exception>
/// <exception cref="Exceptions.ComponentDisposedException">The control has already been disposed</exception>
public async ValueTask ClearAsync()
{
Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Source_ClearAsync, "Clearing drawing manager source");

EnsureJsRuntimeExists();
EnsureNotDisposed();

_sourceShapes = null;
await JSRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Source.Clear.ToDrawingNamespace());
}

/// <summary>
/// Mark the control as disposed
/// </summary>
/// <returns></returns>
/// <exception cref="Exceptions.ComponentNotAddedToMapException">The control has not been added to the map</exception>
/// <exception cref="Exceptions.ComponentDisposedException">The control has already been disposed</exception>
internal void Dispose()
{
Logger?.LogAzureMapsControlInfo(AzureMapLogEvent.Source_DisposeAsync, "DrawingManager - Dispose");

EnsureJsRuntimeExists();
EnsureNotDisposed();

Disposed = true;
}

private void EnsureJsRuntimeExists()
{
if (JSRuntime is null)
{
throw new Exceptions.ComponentNotAddedToMapException();
}
}

private void EnsureNotDisposed()
{
if (Disposed)
{
throw new Exceptions.ComponentDisposedException();
}
}
}
}
8 changes: 8 additions & 0 deletions src/AzureMapsControl.Components/Map/Map.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ public sealed class Map

public DrawingToolbarOptions DrawingToolbarOptions { get; internal set; }

public DrawingManager DrawingManager { get; internal set; }

public IEnumerable<Control> Controls => _controls;

public IEnumerable<Layer> Layers => _layers;
Expand Down Expand Up @@ -352,6 +354,10 @@ await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Drawing.AddDrawin
Events = drawingToolbarOptions.Events?.EnabledEvents
},
DotNetObjectReference.Create(_drawingToolbarEventInvokeHelper));
DrawingManager = new DrawingManager() {
JSRuntime = _jsRuntime,
Logger = _logger
};
}
}

Expand Down Expand Up @@ -394,6 +400,8 @@ public async ValueTask RemoveDrawingToolbarAsync()
{
await _jsRuntime.InvokeVoidAsync(Constants.JsConstants.Methods.Drawing.RemoveDrawingToolbar.ToDrawingNamespace());
DrawingToolbarOptions = null;
DrawingManager?.Dispose();
DrawingManager = null;
}
}

Expand Down
11 changes: 11 additions & 0 deletions src/AzureMapsControl.Components/typescript/drawing/drawing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import * as azmaps from 'azure-maps-control';
import { EventHelper } from '../events/event-helper';
import { Core } from '../core/core';
import { DrawingEventArgs } from './drawing-event-args';
import { Shape } from '../geometries/geometry';
import { GeometryBuilder } from '../geometries/geometry-builder';

export class Drawing {

Expand Down Expand Up @@ -96,4 +98,13 @@ export class Drawing {
});
}

public static addShapes(shapes: Shape[]): void {
const mapsShapes = shapes.map(shape => GeometryBuilder.buildShape(shape));
this._drawingManager.getSource().add(mapsShapes);
}

public static clear(): void {
this._drawingManager.getSource().clear();
}

}
Loading
Loading