public static FeatureCollection ToFeatureCollection(this FAnnotation annotation) { var list = new List <Feature>(); if (annotation is PointAnnotation) { var pa = (PointAnnotation)annotation; list.Add(pa.ToFeature()); } else if (annotation is PolylineAnnotation) { var pa = (PolylineAnnotation)annotation; list.Add(pa.ToFeature()); } else if (annotation is MultiPolylineAnnotation) { var pa = (MultiPolylineAnnotation)annotation; list.Add(pa.ToFeature()); } return(FeatureCollection.FromFeatures(list.ToArray())); }
/// <summary> /// This has a problem, if the same pin updates a couple of times a second pin might jump suddenly to the /// 2nd to latest position then smooth animate to the latest position, but I think this is ok logically since /// By the time it's animating its final animation position is not really up to date. /// </summary> /// <param name="pin">Pin.</param> private void animateLocationChange(Pin pin) { #region Simultaneous pin update System.Threading.Tasks.Task.Run(async() => { // If there exist a pin that caused this update if (isPinAnimating) { return; } // Wait for pin position assignment in the same call isPinAnimating = true; // Get all pins with the same key and same flat value (animatable pins) var pinsWithSimilarKey = xMap.pins.Where( (Pin arg) => arg.IsCenterAndFlat == pin.IsCenterAndFlat).ToArray(); Device.BeginInvokeOnMainThread(() => { var geoJsonSource = (GeoJsonSource)nMap.GetSource(mapLockedPinsSourceKey); var visibleMovablePinCount = pinsWithSimilarKey.Count(p => p.isVisible); var currentHeadingCollection = new double[visibleMovablePinCount]; var features = new Feature[visibleMovablePinCount]; // Update the entire frame MapBox.Extensions.MapExtensions.animatePin( (double d) => { System.Threading.Tasks.Task.Run(() => { for (int i = 0; i < visibleMovablePinCount; i++) { var p = pinsWithSimilarKey[i]; Position theCurrentAnimationJump = p.position; double theCurrentHeading = p.heading; // Only update the pin if it is the pin that cause this animation call // OR the if it actually requested for a position update before this current animation has not been finished if (pin == p || p.requestForUpdate) { theCurrentAnimationJump = SphericalUtil.interpolate(p.previousPinPosition, p.position, d); theCurrentHeading = SphericalUtil.computeHeading(p.previousPinPosition, p.position); } currentHeadingCollection[i] = theCurrentHeading; var feature = Feature.FromGeometry( Com.Mapbox.Geojson.Point.FromLngLat(theCurrentAnimationJump.longitude, theCurrentAnimationJump.latitude)); feature.AddStringProperty(MapboxRenderer.pin_image_key, p.image); feature.AddNumberProperty(MapboxRenderer.pin_rotation_key, (Java.Lang.Number)theCurrentHeading); feature.AddNumberProperty(MapboxRenderer.pin_size_key, (Java.Lang.Number)p.imageScaleFactor); feature.AddStringProperty(MapboxRenderer.pin_id_key, p.id); // Add to the new animation frame features[i] = feature; } // Extension method bypass, fromFeatures accepts IList as parameter var featureCollection = FeatureCollection.FromFeatures(features); // Update the entire layer Device.BeginInvokeOnMainThread(() => geoJsonSource.SetGeoJson(featureCollection)); }); }, async(d, b) => { // DO NOT REMOVE, this is essential for the simultaneous pin location update to work await System.Threading.Tasks.Task.Delay(500); isPinAnimating = false; // Stabilize the pins, at this moment all the pins are updated for (int i = 0; i < visibleMovablePinCount; i++) { var p = pinsWithSimilarKey[i]; // To avoid triggering heading property change event p.PropertyChanged -= Pin_PropertyChanged; p.requestForUpdate = false; p.heading = currentHeadingCollection[i]; p.PropertyChanged += Pin_PropertyChanged; } }, 500); }); }); #endregion }
public static FeatureCollection toFeatureCollection(this IEnumerable <Feature> features) { return(FeatureCollection.FromFeatures(features.ToArray())); }