// Must be true if from new instance of collection private void removeAllPins(bool isFromNewCollection) { if (xMap.pins == null) return; // Get the segregated pin type by flat value to avoid multiple instance of the same pin to be added var mapLockedFeatureCollection = xMap.pins.Where((Pin pin) => pin.IsCenterAndFlat); var normalFeatureCollection = xMap.pins.Where((Pin pin) => !pin.IsCenterAndFlat); var flatPinsSource = (MGLShapeSource)nStyle.SourceWithIdentifier(mapLockedPinsSourceKey); var normalPinsSource = (MGLShapeSource)nStyle.SourceWithIdentifier(normalPinsSourceKey); // Just set to empty pins, this will also refreshes with the latest pin and the old pins removed flatPinsSource.Shape = MGLShapeCollectionFeature.ShapeCollectionWithShapes(mapLockedFeatureCollection.toShapeSourceArray()); normalPinsSource.Shape = MGLShapeCollectionFeature.ShapeCollectionWithShapes(normalFeatureCollection.toShapeSourceArray()); // Usubscribe each pin to change monitoring if (xMap.oldPins != null) { foreach (var pin in xMap.oldPins) pin.PropertyChanged -= Pin_PropertyChanged; xMap.oldPins.CollectionChanged -= Pins_CollectionChanged; } if (isFromNewCollection) xMap.pins.CollectionChanged += Pins_CollectionChanged; // Subcribe each new pin to change monitoring foreach (var pin in xMap.pins) pin.PropertyChanged += Pin_PropertyChanged; }
void DrawPolyline() { var jsonPath = NSBundle.MainBundle.PathForResource("example", "geojson"); NSData data = NSFileManager.DefaultManager.Contents(jsonPath); NSError err; MGLShapeCollectionFeature shapeCollectionFeature = (MGLShapeCollectionFeature)MGLShape.ShapeWithData(data, (uint)NSStringEncoding.UTF8, out err); MGLPolylineFeature polyline = (MGLPolylineFeature)shapeCollectionFeature.Shapes.First(); mapView.AddAnnotation(polyline); }
private void updatePins(Pin pin) { // The image is the type/class key string key = pin.image; // Find a source that has the same image as this pin var uiImage = nStyle.ImageForName(key); // Get all pins with the same flat value var pinsWithSimilarKey = xMap.pins.Where((Pin arg) => arg.IsCenterAndFlat == pin.IsCenterAndFlat); // If there are existing image of the same type the reuse if (uiImage != null) { MGLShapeSource geoJsonSource; // Edit the proper source if (pin.IsCenterAndFlat) geoJsonSource = (MGLShapeSource)nStyle.SourceWithIdentifier(mapLockedPinsSourceKey); else geoJsonSource = (MGLShapeSource)nStyle.SourceWithIdentifier(normalPinsSourceKey); // Refresh entire source when a pin is added to a specific source geoJsonSource.Shape = MGLShapeCollectionFeature.ShapeCollectionWithShapes(pinsWithSimilarKey.toShapeSourceArray()); } }
private void addAllPins() { if (xMap.pins == null) return; // Subscribe all pins to their respective changes foreach (var pin in xMap.pins) pin.PropertyChanged += Pin_PropertyChanged; // Add the mapLocked pins first // Select all pins where it has heading setter activated var mapLockedFeatureCollection = xMap.pins.Where((Pin pin) => pin.IsCenterAndFlat).toShapeSourceArray(); var mapLockedPinSource = (MGLShapeSource)nStyle.SourceWithIdentifier(mapLockedPinsSourceKey); mapLockedPinSource.Shape = MGLShapeCollectionFeature.ShapeCollectionWithShapes(mapLockedFeatureCollection); // Add the normal pins after // Select all pins where it has heading disabled var normalFeatureCollection = xMap.pins.Where((Pin pin) => !pin.IsCenterAndFlat).toShapeSourceArray(); var normalPinSource = (MGLShapeSource)nStyle.SourceWithIdentifier(normalPinsSourceKey); normalPinSource.Shape = MGLShapeCollectionFeature.ShapeCollectionWithShapes(normalFeatureCollection); }
/// <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 = (MGLShapeSource)nStyle.SourceWithIdentifier(mapLockedPinsSourceKey); var visibleMovablePinCount = pinsWithSimilarKey.Count(p => p.isVisible); var currentHeadingCollection = new double[visibleMovablePinCount]; var features = new NSObject[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 = new MGLPointFeature { Coordinate = new CLLocationCoordinate2D(theCurrentAnimationJump.latitude, theCurrentAnimationJump.longitude) }; feature.Attributes = NSDictionary<NSString, NSObject>.FromObjectsAndKeys( new object[] { p.image, theCurrentHeading, p.imageScaleFactor, p.id }, new object[] { MapboxRenderer.pin_image_key, MapboxRenderer.pin_rotation_key, MapboxRenderer.pin_size_key, MapboxRenderer.pin_id_key }); // Add to the new animation frame features[i] = feature; } // Update the entire layer Device.BeginInvokeOnMainThread(() => geoJsonSource.Shape = MGLShapeCollectionFeature.ShapeCollectionWithShapes(features)); }); }, 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 MGLShapeCollectionFeature toShapeCollectionFeature(this IEnumerable <Route> routes) { return(MGLShapeCollectionFeature.ShapeCollectionWithShapes(routes.toFeatureList().ToArray())); }