Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[ios, macos] Add shapes annotations select/deselect delegates.
Browse files Browse the repository at this point in the history
  • Loading branch information
fabian-guerra committed Aug 10, 2017
1 parent 5d641f4 commit 4a9edb4
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 3 deletions.
2 changes: 2 additions & 0 deletions include/mbgl/map/map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ class Map : private util::noncopyable {
std::vector<Feature> querySourceFeatures(const std::string& sourceID, const SourceQueryOptions& options = {});

AnnotationIDs queryPointAnnotations(const ScreenBox&);
AnnotationIDs queryShapeAnnotations(const ScreenBox&, const RenderedQueryOptions& options = {});

// Memory
void setSourceTileCacheSize(size_t);
Expand All @@ -213,6 +214,7 @@ class Map : private util::noncopyable {
private:
class Impl;
const std::unique_ptr<Impl> impl;
AnnotationIDs queryAnnotations(const ScreenBox&, const RenderedQueryOptions& options = {});
};

} // namespace mbgl
10 changes: 10 additions & 0 deletions platform/ios/app/MBXViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -1809,4 +1809,14 @@ - (void)mapView:(MGLMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
}
}

- (void)mapView:(MGLMapView *)mapView didSelectShapeAnnotation:(nonnull MGLShape *)shapeAnnotation
{
NSLog(@"Did Select: %f, %f", shapeAnnotation.coordinate.latitude, shapeAnnotation.coordinate.longitude);
}

- (void)mapView:(MGLMapView *)mapView didDeselectShapeAnnotation:(nonnull MGLShape *)shapeAnnotation
{
NSLog(@"Did deselect: %f, %f", shapeAnnotation.coordinate.latitude, shapeAnnotation.coordinate.longitude);
}

@end
134 changes: 131 additions & 3 deletions platform/ios/src/MGLMapView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ typedef NS_ENUM(NSUInteger, MGLUserTrackingState) {
/// Mapping from an annotation object to an annotation tag.
typedef std::map<id<MGLAnnotation>, MGLAnnotationTag> MGLAnnotationObjectTagMap;

/// Mapping from a shape annotation object to shape layer id.
typedef std::map<id<MGLAnnotation>, std::string> MGLShapeAnnotationObjectLayerIDMap;

const NSString *MGLLayerIDShapeAnnotation = @"com.mapbox.annotations.shape.";

mbgl::util::UnitBezier MGLUnitBezierForMediaTimingFunction(CAMediaTimingFunction *function)
{
if ( ! function)
Expand Down Expand Up @@ -285,9 +290,11 @@ @implementation MGLMapView

MGLAnnotationTagContextMap _annotationContextsByAnnotationTag;
MGLAnnotationObjectTagMap _annotationTagsByAnnotation;

MGLShapeAnnotationObjectLayerIDMap _shapeAnnotationLayerIDs;

/// Tag of the selected annotation. If the user location annotation is selected, this ivar is set to `MGLAnnotationTagNotFound`.
MGLAnnotationTag _selectedAnnotationTag;
MGLShape *_selectedShapeAnnotation;

BOOL _userLocationAnnotationIsSelected;
/// Size of the rectangle formed by unioning the maximum slop area around every annotation image and annotation image view.
Expand Down Expand Up @@ -468,6 +475,7 @@ - (void)commonInit
_annotationImagesByIdentifier = [NSMutableDictionary dictionary];
_annotationContextsByAnnotationTag = {};
_annotationTagsByAnnotation = {};
_shapeAnnotationLayerIDs = {};
_annotationViewReuseQueueByIdentifier = [NSMutableDictionary dictionary];
_selectedAnnotationTag = MGLAnnotationTagNotFound;
_annotationsNearbyLastTap = {};
Expand Down Expand Up @@ -1483,12 +1491,20 @@ - (void)handleSingleTapGesture:(UITapGestureRecognizer *)singleTap
id<MGLAnnotation>annotation = [self annotationForGestureRecognizer:singleTap persistingResults:YES];
if(annotation)
{
[self deselectShapeAnnotation:_selectedShapeAnnotation];
[self selectAnnotation:annotation animated:YES];
}
else
{
[self deselectAnnotation:self.selectedAnnotation animated:YES];
MGLShape *shapeAnnotation = [self shapeAnnotationForGestureRecognizer:singleTap];
if (shapeAnnotation) {
[self selectShapeAnnotation:shapeAnnotation];
} else {
[self deselectShapeAnnotation:_selectedShapeAnnotation];
}
}

}

/**
Expand Down Expand Up @@ -1861,8 +1877,12 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
if(!self.selectedAnnotation)
{
id<MGLAnnotation>annotation = [self annotationForGestureRecognizer:(UITapGestureRecognizer*)gestureRecognizer persistingResults:NO];
if(!annotation) {
return NO;
if(!annotation && !_selectedShapeAnnotation) {
MGLShape *shapeAnnotation = [self shapeAnnotationForGestureRecognizer:(UITapGestureRecognizer*)gestureRecognizer];
if (!shapeAnnotation) {
return NO;
}

}
}
}
Expand Down Expand Up @@ -3226,6 +3246,8 @@ - (void)addAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations
context.annotation = annotation;
_annotationContextsByAnnotationTag[annotationTag] = context;
_annotationTagsByAnnotation[annotation] = annotationTag;
NSString *layerID = [NSString stringWithFormat:@"%@%u", MGLLayerIDShapeAnnotation, annotationTag];
_shapeAnnotationLayerIDs[annotation] = layerID.UTF8String;

[(NSObject *)annotation addObserver:self forKeyPath:@"coordinates" options:0 context:(void *)(NSUInteger)annotationTag];
}
Expand Down Expand Up @@ -3524,6 +3546,7 @@ - (void)removeAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations

_annotationContextsByAnnotationTag.erase(annotationTag);
_annotationTagsByAnnotation.erase(annotation);
_shapeAnnotationLayerIDs.erase(annotation);

if ([annotation isKindOfClass:[NSObject class]] && ![annotation isKindOfClass:[MGLMultiPoint class]])
{
Expand Down Expand Up @@ -4150,6 +4173,111 @@ - (void)applyIconIdentifier:(NSString *)iconIdentifier toAnnotationsWithImageReu
}
}

#pragma mark - Shape Annotation

- (void)selectShapeAnnotation:(MGLShape *)shapeAnnotation
{
if (!shapeAnnotation) return;

if (shapeAnnotation == _selectedShapeAnnotation) return;

[self deselectShapeAnnotation:_selectedShapeAnnotation];

_selectedShapeAnnotation = shapeAnnotation;

if ([self.delegate respondsToSelector:@selector(mapView:didSelectShapeAnnotation:)])
{
[self.delegate mapView:self didSelectShapeAnnotation:shapeAnnotation];
}
}

- (void)deselectShapeAnnotation:(MGLShape *)shapeAnnotation
{
if (!shapeAnnotation) return;

if (_selectedShapeAnnotation == shapeAnnotation)
{
if ([self.delegate respondsToSelector:@selector(mapView:didDeselectShapeAnnotation:)])
{
[self.delegate mapView:self didDeselectShapeAnnotation:shapeAnnotation];
}
_selectedShapeAnnotation = nil;
}

}

- (MGLShape*)shapeAnnotationForGestureRecognizer:(UITapGestureRecognizer*)singleTap
{
CGPoint tapPoint = [singleTap locationInView:self];
// CGRect queryRect = CGRectInset({ tapPoint, CGSizeZero },
// -_unionedAnnotationRepresentationSize.width,
// -_unionedAnnotationRepresentationSize.height);
// queryRect = CGRectInset(queryRect, -MGLAnnotationImagePaddingForHitTest,
// -MGLAnnotationImagePaddingForHitTest);
//
// NSMutableSet *layerIDs = [NSMutableSet set];
//
// for (const auto &annotation : _shapeAnnotationLayerIDs) {
// const std::string layerID = annotation.second;
// [layerIDs addObject:[NSString stringWithUTF8String:layerID.c_str()]];
// }
//
// NSArray *nearbyFeatures = [self visibleFeaturesInRect:queryRect inStyleLayersWithIdentifiers:layerIDs predicate:nil];
// id<MGLFeature> feature = nearbyFeatures.firstObject;
//
MGLAnnotationTag hitAnnotationTag = [self shapeAnnotationTagAtPoint:tapPoint];

if (hitAnnotationTag != MGLAnnotationTagNotFound) {
id <MGLAnnotation> annotation = [self annotationWithTag:hitAnnotationTag];
NSAssert(annotation, @"Cannot select nonexistent annotation with tag %u", hitAnnotationTag);
if ([annotation isKindOfClass:[MGLShape class]]) {
return (MGLShape *)annotation;
}
}

return nil;
}

- (MGLAnnotationTag)shapeAnnotationTagAtPoint:(CGPoint)point
{
CGRect queryRect = CGRectInset({ point, CGSizeZero },
-_unionedAnnotationRepresentationSize.width,
-_unionedAnnotationRepresentationSize.height);
queryRect = CGRectInset(queryRect, -MGLAnnotationImagePaddingForHitTest,
-MGLAnnotationImagePaddingForHitTest);

std::vector<MGLAnnotationTag> nearbyAnnotations = [self shapeAnnotationTagsInRect:queryRect];

MGLAnnotationTag hitAnnotationTag = MGLAnnotationTagNotFound;

// Choose the first nearby annotation.
if (nearbyAnnotations.size())
{
hitAnnotationTag = nearbyAnnotations.front();
}
return hitAnnotationTag;
}

- (std::vector<MGLAnnotationTag>)shapeAnnotationTagsInRect:(CGRect)rect
{
mbgl::ScreenBox screenBox = {
{ CGRectGetMinX(rect), CGRectGetMinY(rect) },
{ CGRectGetMaxX(rect), CGRectGetMaxY(rect) },
};

mbgl::optional<std::vector<std::string>> optionalLayerIDs;
if (_shapeAnnotationLayerIDs.size()) {
__block std::vector<std::string> layerIDs;
layerIDs.reserve(_shapeAnnotationLayerIDs.size());
for (const auto &annotation : _shapeAnnotationLayerIDs) {
layerIDs.push_back(annotation.second);
}
optionalLayerIDs = layerIDs;
}

return _mbglMap->queryShapeAnnotations(screenBox, { optionalLayerIDs });
}

#pragma mark - User Location -

- (void)validateLocationServices
Expand Down
21 changes: 21 additions & 0 deletions platform/ios/src/MGLMapViewDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,27 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)mapView:(MGLMapView *)mapView didDeselectAnnotation:(id <MGLAnnotation>)annotation;

/**
Tells the delegate that one of its shape annotations was selected.
You can use this method to track changes in the selection state of annotations.
@param mapView The map view containing the annotation.
@param shapeAnnotation The shape annotation that was selected.
*/
- (void)mapView:(MGLMapView *)mapView didSelectShapeAnnotation:(MGLShape *)shapeAnnotation;

/**
Tells the delegate that one of its shape annotations was deselected.
You can use this method to track changes in the selection state of annotations.
@param mapView The map view containing the annotation.
@param shapeAnnotation The shape annotation that was deselected.
*/
- (void)mapView:(MGLMapView *)mapView didDeselectShapeAnnotation:(MGLShape *)shapeAnnotation;

/**
Tells the delegate that one of its annotation views was selected.
Expand Down
9 changes: 9 additions & 0 deletions src/mbgl/map/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,15 @@ std::vector<Feature> Map::querySourceFeatures(const std::string& sourceID, const
AnnotationIDs Map::queryPointAnnotations(const ScreenBox& box) {
RenderedQueryOptions options;
options.layerIDs = {{ AnnotationManager::PointLayerID }};
return queryAnnotations(box, options);
}

AnnotationIDs Map::queryShapeAnnotations(const ScreenBox& box, const RenderedQueryOptions& options) {

return queryAnnotations(box, options);
}

AnnotationIDs Map::queryAnnotations(const ScreenBox& box, const RenderedQueryOptions& options) {
auto features = queryRenderedFeatures(box, options);
std::set<AnnotationID> set;
for (auto &feature : features) {
Expand Down

0 comments on commit 4a9edb4

Please sign in to comment.