Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add onPress for polygons and polylines on iOS and Android #760

Merged
merged 2 commits into from
Nov 10, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
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 @@ -102,6 +102,7 @@ public Object getFeature() {
@Override
public void addToMap(GoogleMap map) {
polygon = map.addPolygon(getPolygonOptions());
polygon.setClickable(true);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.annotations.ReactProp;

import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;

public class AirMapPolygonManager extends ViewGroupManager<AirMapPolygon> {
private final DisplayMetrics metrics;

Expand Down Expand Up @@ -67,4 +72,13 @@ public void setGeodesic(AirMapPolygon view, boolean geodesic) {
public void setZIndex(AirMapPolygon view, float zIndex) {
view.setZIndex(zIndex);
}

@Override
@Nullable
public Map getExportedCustomDirectEventTypeConstants() {
Map map = MapBuilder.of(
"onPress", MapBuilder.of("registrationName", "onPress")
);
return map;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return MapBuilder.of() directly, no need to declare a variable 👍

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public Object getFeature() {
@Override
public void addToMap(GoogleMap map) {
polyline = map.addPolyline(getPolylineOptions());
polyline.setClickable(true);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.annotations.ReactProp;

import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;

public class AirMapPolylineManager extends ViewGroupManager<AirMapPolyline> {
private final DisplayMetrics metrics;

Expand Down Expand Up @@ -62,4 +67,13 @@ public void setGeodesic(AirMapPolyline view, boolean geodesic) {
public void setZIndex(AirMapPolyline view, float zIndex) {
view.setZIndex(zIndex);
}

@Override
@Nullable
public Map getExportedCustomDirectEventTypeConstants() {
Map map = MapBuilder.of(
"onPress", MapBuilder.of("registrationName", "onPress")
);
return map;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.Polygon;
import com.google.android.gms.maps.model.Polyline;

import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -72,6 +74,8 @@ public class AirMapView extends MapView implements GoogleMap.InfoWindowAdapter,

private final List<AirMapFeature> features = new ArrayList<>();
private final Map<Marker, AirMapMarker> markerMap = new HashMap<>();
private final Map<Polyline, AirMapPolyline> polylineMap = new HashMap<>();
private final Map<Polygon, AirMapPolygon> polygonMap = new HashMap<>();
private final ScaleGestureDetector scaleDetector;
private final GestureDetectorCompat gestureDetector;
private final AirMapManager manager;
Expand Down Expand Up @@ -165,6 +169,26 @@ public boolean onMarkerClick(Marker marker) {
}
});

map.setOnPolygonClickListener(new GoogleMap.OnPolygonClickListener() {
@Override
public void onPolygonClick(Polygon polygon) {
WritableMap event;
event = makeClickEventData(polygon.getPoints().get(0));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WritableMap event = makeClickEventData(polygon.getPoints().get(0));

event.putString("action", "polygon-press");
manager.pushEvent(polygonMap.get(polygon), "onPress", event);
}
});

map.setOnPolylineClickListener(new GoogleMap.OnPolylineClickListener() {
@Override
public void onPolylineClick(Polyline polyline) {
WritableMap event;
event = makeClickEventData(polyline.getPoints().get(0));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

event.putString("action", "polyline-press");
manager.pushEvent(polylineMap.get(polyline), "onPress", event);
}
});

map.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
@Override
public void onInfoWindowClick(Marker marker) {
Expand Down Expand Up @@ -381,10 +405,14 @@ public void addFeature(View child, int index) {
AirMapPolyline polylineView = (AirMapPolyline) child;
polylineView.addToMap(map);
features.add(index, polylineView);
Polyline polyline = (Polyline) polylineView.getFeature();
polylineMap.put(polyline, polylineView);
} else if (child instanceof AirMapPolygon) {
AirMapPolygon polygonView = (AirMapPolygon) child;
polygonView.addToMap(map);
features.add(index, polygonView);
Polygon polygon = (Polygon) polygonView.getFeature();
polygonMap.put(polygon, polygonView);
} else if (child instanceof AirMapCircle) {
AirMapCircle circleView = (AirMapCircle) child;
circleView.addToMap(map);
Expand Down
119 changes: 111 additions & 8 deletions ios/AirMaps/AIRMapManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ - (void)takeMapSnapshot:(AIRMap *)mapView
[pin.image drawAtPoint:point];
}
}

for (id <AIRMapSnapshot> overlay in mapView.overlays) {
if ([overlay respondsToSelector:@selector(drawToSnapshot:context:)]) {
[overlay drawToSnapshot:snapshot context:UIGraphicsGetCurrentContext()];
Expand All @@ -308,21 +308,75 @@ - (void)takeMapSnapshot:(AIRMap *)mapView

#pragma mark Gesture Recognizer Handlers

#define MAX_DISTANCE_PX 10.0f
- (void)handleMapTap:(UITapGestureRecognizer *)recognizer {
AIRMap *map = (AIRMap *)recognizer.view;
if (!map.onPress) return;

CGPoint touchPoint = [recognizer locationInView:map];
CLLocationCoordinate2D coord = [map convertPoint:touchPoint toCoordinateFromView:map];
CGPoint tapPoint = [recognizer locationInView:map];
CLLocationCoordinate2D tapCoordinate = [map convertPoint:tapPoint toCoordinateFromView:map];
MKMapPoint mapPoint = MKMapPointForCoordinate(tapCoordinate);
CGPoint mapPointAsCGP = CGPointMake(mapPoint.x, mapPoint.y);

double maxMeters = [self metersFromPixel:MAX_DISTANCE_PX atPoint:tapPoint forMap:map];
float nearestDistance = MAXFLOAT;
AIRMapPolyline *nearestPolyline = nil;

for (id<MKOverlay> overlay in map.overlays) {
if([overlay isKindOfClass:[AIRMapPolygon class]]){
AIRMapPolygon *polygon = (AIRMapPolygon*) overlay;
if (polygon.onPress) {
CGMutablePathRef mpr = CGPathCreateMutable();

for(int i = 0; i < polygon.coordinates.count; i++) {
AIRMapCoordinate *c = polygon.coordinates[i];
MKMapPoint mp = MKMapPointForCoordinate(c.coordinate);
if (i == 0) {
CGPathMoveToPoint(mpr, NULL, mp.x, mp.y);
} else {
CGPathAddLineToPoint(mpr, NULL, mp.x, mp.y);
}
}

if (CGPathContainsPoint(mpr, NULL, mapPointAsCGP, FALSE)) {
id event = @{
@"action": @"polygon-press",
};
polygon.onPress(event);
}

CGPathRelease(mpr);
}
}

if([overlay isKindOfClass:[AIRMapPolyline class]]){
AIRMapPolyline *polyline = (AIRMapPolyline*) overlay;
if (polyline.onPress) {
float distance = [self distanceOfPoint:MKMapPointForCoordinate(tapCoordinate)
toPoly:overlay];
if (distance < nearestDistance) {
nearestDistance = distance;
nearestPolyline = overlay;
}
}
}
}

if (nearestDistance <= maxMeters) {
id event = @{
@"action": @"polyline-press",
};
nearestPolyline.onPress(event);
}

if (!map.onPress) return;
map.onPress(@{
@"coordinate": @{
@"latitude": @(coord.latitude),
@"longitude": @(coord.longitude),
@"latitude": @(tapCoordinate.latitude),
@"longitude": @(tapCoordinate.longitude),
},
@"position": @{
@"x": @(touchPoint.x),
@"y": @(touchPoint.y),
@"x": @(tapPoint.x),
@"y": @(tapPoint.y),
},
});

Expand Down Expand Up @@ -609,4 +663,53 @@ - (void)_emitRegionChangeEvent:(AIRMap *)mapView continuous:(BOOL)continuous
}
}

/** Returns the distance of |pt| to |poly| in meters
*
*
*/
- (double)distanceOfPoint:(MKMapPoint)pt toPoly:(AIRMapPolyline *)poly
{
double distance = MAXFLOAT;
for (int n = 0; n < poly.coordinates.count - 1; n++) {

MKMapPoint ptA = MKMapPointForCoordinate(poly.coordinates[n].coordinate);
MKMapPoint ptB = MKMapPointForCoordinate(poly.coordinates[n + 1].coordinate);

double xDelta = ptB.x - ptA.x;
double yDelta = ptB.y - ptA.y;

if (xDelta == 0.0 && yDelta == 0.0) {
continue;
}

double u = ((pt.x - ptA.x) * xDelta + (pt.y - ptA.y) * yDelta) / (xDelta * xDelta + yDelta * yDelta);
MKMapPoint ptClosest;
if (u < 0.0) {
ptClosest = ptA;
}
else if (u > 1.0) {
ptClosest = ptB;
}
else {
ptClosest = MKMapPointMake(ptA.x + u * xDelta, ptA.y + u * yDelta);
}

distance = MIN(distance, MKMetersBetweenMapPoints(ptClosest, pt));
}

return distance;
}


/** Converts |px| to meters at location |pt| */
- (double)metersFromPixel:(NSUInteger)px atPoint:(CGPoint)pt forMap:(AIRMap *)mapView
{
CGPoint ptB = CGPointMake(pt.x + px, pt.y);

CLLocationCoordinate2D coordA = [mapView convertPoint:pt toCoordinateFromView:mapView];
CLLocationCoordinate2D coordB = [mapView convertPoint:ptB toCoordinateFromView:mapView];

return MKMetersBetweenMapPoints(MKMapPointForCoordinate(coordA), MKMapPointForCoordinate(coordB));
}

@end
1 change: 1 addition & 0 deletions ios/AirMaps/AIRMapPolygon.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
@property (nonatomic, assign) CGLineJoin lineJoin;
@property (nonatomic, assign) CGFloat lineDashPhase;
@property (nonatomic, strong) NSArray <NSNumber *> *lineDashPattern;
@property (nonatomic, copy) RCTBubblingEventBlock onPress;

#pragma mark MKOverlay protocol

Expand Down
5 changes: 1 addition & 4 deletions ios/AirMaps/AIRMapPolygonManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,7 @@ - (UIView *)view
RCT_EXPORT_VIEW_PROPERTY(miterLimit, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(lineDashPhase, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(lineDashPattern, NSArray)
RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)

// NOTE(lmr):
// for now, onPress events for overlays will be left unimplemented. Seems it is possible with some work, but
// it is difficult to achieve in both ios and android so I decided to leave it out.
//RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)

@end
1 change: 1 addition & 0 deletions ios/AirMaps/AIRMapPolyline.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
@property (nonatomic, assign) CGLineJoin lineJoin;
@property (nonatomic, assign) CGFloat lineDashPhase;
@property (nonatomic, strong) NSArray <NSNumber *> *lineDashPattern;
@property (nonatomic, copy) RCTBubblingEventBlock onPress;

#pragma mark MKOverlay protocol

Expand Down
6 changes: 1 addition & 5 deletions ios/AirMaps/AIRMapPolylineManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,6 @@ - (UIView *)view
RCT_EXPORT_VIEW_PROPERTY(miterLimit, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(lineDashPhase, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(lineDashPattern, NSArray)

// NOTE(lmr):
// for now, onPress events for overlays will be left unimplemented. Seems it is possible with some work, but
// it is difficult to achieve in both ios and android so I decided to leave it out.
//RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)

@end