summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Maps.WP8/MapRenderer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Xamarin.Forms.Maps.WP8/MapRenderer.cs')
-rw-r--r--Xamarin.Forms.Maps.WP8/MapRenderer.cs250
1 files changed, 250 insertions, 0 deletions
diff --git a/Xamarin.Forms.Maps.WP8/MapRenderer.cs b/Xamarin.Forms.Maps.WP8/MapRenderer.cs
new file mode 100644
index 00000000..eaac51d2
--- /dev/null
+++ b/Xamarin.Forms.Maps.WP8/MapRenderer.cs
@@ -0,0 +1,250 @@
+using System;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Device.Location;
+using System.Linq;
+using System.Windows;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Shapes;
+using Windows.Devices.Geolocation;
+using Microsoft.Phone.Maps;
+using Microsoft.Phone.Maps.Controls;
+using Microsoft.Phone.Maps.Toolkit;
+using Xamarin.Forms.Platform.WinPhone;
+
+namespace Xamarin.Forms.Maps.WP8
+{
+ public class
+ MapRenderer : ViewRenderer<Map, Microsoft.Phone.Maps.Controls.Map>
+ {
+ bool _firstZoomLevelChangeFired;
+ MapLayer _pushPinLayer;
+ MapLayer _userLocationLayer;
+
+ protected override void OnElementChanged(ElementChangedEventArgs<Map> e)
+ {
+ base.OnElementChanged(e);
+
+ SetNativeControl(new Microsoft.Phone.Maps.Controls.Map());
+ UpdateMapType();
+
+ Control.Loaded += ControlOnLoaded;
+
+ _pushPinLayer = new MapLayer();
+ Control.Layers.Add(_pushPinLayer);
+
+ _userLocationLayer = new MapLayer();
+ Control.Layers.Add(_userLocationLayer);
+
+ Control.ViewChanged += (s, a) => UpdateVisibleRegion();
+ Control.ZoomLevelChanged += (sender, args) => UpdateVisibleRegion();
+ Control.CenterChanged += (s, a) => UpdateVisibleRegion();
+ //Control.ViewChangeOnFrame += (s, a) => UpdateVisibleRegion ();
+
+ MessagingCenter.Subscribe<Map, MapSpan>(this, "MapMoveToRegion", (s, a) => MoveToRegion(a), Element);
+
+ ((ObservableCollection<Pin>)Element.Pins).CollectionChanged += OnCollectionChanged;
+
+ if (Element.Pins.Any())
+ LoadPins();
+
+ UpdateShowUserLocation();
+ }
+
+ async void UpdateShowUserLocation()
+ {
+ if (Element.IsShowingUser)
+ {
+ var myGeolocator = new Geolocator();
+
+ if (myGeolocator.LocationStatus != PositionStatus.NotAvailable &&
+ myGeolocator.LocationStatus != PositionStatus.Disabled)
+ {
+ var userPosition = await myGeolocator.GetGeopositionAsync();
+ if (userPosition?.Coordinate != null)
+ LoadUserPosition(userPosition.Coordinate, true);
+ }
+ }
+ else if (_userLocationLayer.Count > 0)
+ _userLocationLayer.Clear();
+ }
+
+ void ControlOnLoaded(object sender, RoutedEventArgs routedEventArgs)
+ {
+ MapsSettings.ApplicationContext.ApplicationId = FormsMaps.ApplicationId;
+ MapsSettings.ApplicationContext.AuthenticationToken = FormsMaps.AuthenticationToken;
+ }
+
+ void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+ {
+ switch (e.Action)
+ {
+ case NotifyCollectionChangedAction.Add:
+ foreach (Pin pin in e.NewItems)
+ LoadPin(pin);
+ break;
+ case NotifyCollectionChangedAction.Move:
+ // no matter
+ break;
+ case NotifyCollectionChangedAction.Remove:
+ foreach (Pin pin in e.OldItems)
+ RemovePin(pin);
+ break;
+ case NotifyCollectionChangedAction.Replace:
+ foreach (Pin pin in e.OldItems)
+ RemovePin(pin);
+ foreach (Pin pin in e.NewItems)
+ LoadPin(pin);
+ break;
+ case NotifyCollectionChangedAction.Reset:
+ _pushPinLayer.Clear();
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+
+ void UpdateVisibleRegion()
+ {
+ if (!_firstZoomLevelChangeFired)
+ {
+ MoveToRegion(Element.LastMoveToRegion, MapAnimationKind.None);
+ _firstZoomLevelChangeFired = true;
+ return;
+ }
+
+ var center = new Position(Control.Center.Latitude, Control.Center.Longitude);
+ var topLeft = Control.ConvertViewportPointToGeoCoordinate(new System.Windows.Point(0, 0));
+ var bottomRight =
+ Control.ConvertViewportPointToGeoCoordinate(new System.Windows.Point(Control.ActualWidth, Control.ActualHeight));
+ if (topLeft == null || bottomRight == null)
+ return;
+
+ var boundingRegion = LocationRectangle.CreateBoundingRectangle(topLeft, bottomRight);
+ var result = new MapSpan(center, boundingRegion.HeightInDegrees, boundingRegion.WidthInDegrees);
+ Element.VisibleRegion = result;
+ }
+
+ void LoadPins()
+ {
+ foreach (var pin in Element.Pins)
+ LoadPin(pin);
+ }
+
+ void LoadPin(Pin pin)
+ {
+ var location = new GeoCoordinate(pin.Position.Latitude, pin.Position.Longitude);
+ var pushPin = new Pushpin
+ {
+ Content = pin.Label,
+ PositionOrigin = new System.Windows.Point(0, 1),
+ Tag = pin
+ };
+
+ pushPin.Tap += PinTap;
+
+ var pushPinOverlay = new MapOverlay
+ {
+ Content = pushPin,
+ GeoCoordinate = location,
+ PositionOrigin = new System.Windows.Point(0, 1)
+ };
+ _pushPinLayer.Add(pushPinOverlay);
+ }
+
+ void PinTap(object sender, GestureEventArgs e)
+ {
+ var pushPin = (Pushpin)sender;
+ var pin = (Pin)pushPin.Tag;
+ pin.SendTap();
+ }
+
+ void RemovePin(Pin pin)
+ {
+ var child = _pushPinLayer.FirstOrDefault(p => ((Pushpin)p.Content).Tag == pin);
+ if (child != null)
+ _pushPinLayer.Remove(child);
+ }
+
+ void MoveToRegion(MapSpan span, MapAnimationKind animation = MapAnimationKind.Parabolic)
+ {
+ // FIXME
+ var center = new GeoCoordinate(span.Center.Latitude, span.Center.Longitude);
+ var location = new LocationRectangle(center, span.LongitudeDegrees, span.LatitudeDegrees);
+ Control.SetView(location, animation);
+ }
+
+ public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
+ {
+ return new SizeRequest(new Size(100, 100));
+ }
+
+ protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ base.OnElementPropertyChanged(sender, e);
+
+ if (e.PropertyName == Map.MapTypeProperty.PropertyName)
+ UpdateMapType();
+ if (e.PropertyName == Map.IsShowingUserProperty.PropertyName)
+ UpdateShowUserLocation();
+ }
+
+ void UpdateMapType()
+ {
+ switch (Element.MapType)
+ {
+ case MapType.Street:
+ Control.CartographicMode = MapCartographicMode.Road;
+ break;
+ case MapType.Satellite:
+ Control.CartographicMode = MapCartographicMode.Aerial;
+ break;
+ case MapType.Hybrid:
+ Control.CartographicMode = MapCartographicMode.Hybrid;
+ break;
+ }
+ }
+
+ void LoadUserPosition(Geocoordinate userPosition, bool center = false)
+ {
+ _userLocationLayer.Clear();
+
+ var userCoordinate = new GeoCoordinate
+ (
+ userPosition.Latitude,
+ userPosition.Longitude,
+ userPosition.Altitude ?? double.NaN,
+ userPosition.Accuracy,
+ userPosition.AltitudeAccuracy ?? double.NaN,
+ userPosition.Speed ?? double.NaN,
+ userPosition.Heading ?? double.NaN
+ );
+
+ //make some preety?
+ var userPositionCircle = new Ellipse
+ {
+ Fill = new SolidColorBrush(Colors.Blue),
+ Height = 20,
+ Width = 20,
+ Opacity = 50
+ };
+
+ var userPostionOverlay = new MapOverlay
+ {
+ Content = userPositionCircle,
+ PositionOrigin = new System.Windows.Point(0.5, 0.5),
+ GeoCoordinate = userCoordinate
+ };
+
+ _userLocationLayer.Add(userPostionOverlay);
+
+ if (center)
+ {
+ Control.Center = userCoordinate;
+ Control.ZoomLevel = 13;
+ }
+ }
+ }
+} \ No newline at end of file