312 lines
7.8 KiB
JavaScript
312 lines
7.8 KiB
JavaScript
import PropTypes from 'prop-types';
|
||
import React from 'react';
|
||
import {
|
||
StyleSheet,
|
||
Platform,
|
||
NativeModules,
|
||
Animated,
|
||
findNodeHandle,
|
||
ViewPropTypes,
|
||
View,
|
||
} from 'react-native';
|
||
|
||
import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';
|
||
import decorateMapComponent, {
|
||
SUPPORTED,
|
||
USES_DEFAULT_IMPLEMENTATION,
|
||
} from './decorateMapComponent';
|
||
|
||
const viewConfig = {
|
||
uiViewClassName: 'AIR<provider>MapMarker',
|
||
validAttributes: {
|
||
coordinate: true,
|
||
},
|
||
};
|
||
|
||
// if ViewPropTypes is not defined fall back to View.propType (to support RN < 0.44)
|
||
const viewPropTypes = ViewPropTypes || View.propTypes;
|
||
|
||
const propTypes = {
|
||
...viewPropTypes,
|
||
|
||
// TODO(lmr): get rid of these?
|
||
identifier: PropTypes.string,
|
||
reuseIdentifier: PropTypes.string,
|
||
|
||
/**
|
||
* The title of the marker. This is only used if the <Marker /> component has no children that
|
||
* are an `<MapView.Callout />`, in which case the default callout behavior will be used, which
|
||
* will show both the `title` and the `description`, if provided.
|
||
*/
|
||
title: PropTypes.string,
|
||
|
||
/**
|
||
* The description of the marker. This is only used if the <Marker /> component has no children
|
||
* that are an `<MapView.Callout />`, in which case the default callout behavior will be used,
|
||
* which will show both the `title` and the `description`, if provided.
|
||
*/
|
||
description: PropTypes.string,
|
||
|
||
/**
|
||
* A custom image to be used as the marker's icon. Only local image resources are allowed to be
|
||
* used.
|
||
*/
|
||
image: PropTypes.any,
|
||
|
||
/**
|
||
* Opacity level of view/image based markers
|
||
*/
|
||
opacity: PropTypes.number,
|
||
|
||
/**
|
||
* If no custom marker view or custom image is provided, the platform default pin will be used,
|
||
* which can be customized by this color. Ignored if a custom marker is being used.
|
||
*/
|
||
pinColor: PropTypes.string,
|
||
|
||
/**
|
||
* The coordinate for the marker.
|
||
*/
|
||
coordinate: PropTypes.shape({
|
||
/**
|
||
* Coordinates for the anchor point of the marker.
|
||
*/
|
||
latitude: PropTypes.number.isRequired,
|
||
longitude: PropTypes.number.isRequired,
|
||
}).isRequired,
|
||
|
||
/**
|
||
* The offset (in points) at which to display the view.
|
||
*
|
||
* By default, the center point of an annotation view is placed at the coordinate point of the
|
||
* associated annotation. You can use this property to reposition the annotation view as
|
||
* needed. This x and y offset values are measured in points. Positive offset values move the
|
||
* annotation view down and to the right, while negative values move it up and to the left.
|
||
*
|
||
* For android, see the `anchor` prop.
|
||
*
|
||
* @platform ios
|
||
*/
|
||
centerOffset: PropTypes.shape({
|
||
/**
|
||
* Offset from the anchor point
|
||
*/
|
||
x: PropTypes.number.isRequired,
|
||
y: PropTypes.number.isRequired,
|
||
}),
|
||
|
||
/**
|
||
* The offset (in points) at which to place the callout bubble.
|
||
*
|
||
* This property determines the additional distance by which to move the callout bubble. When
|
||
* this property is set to (0, 0), the anchor point of the callout bubble is placed on the
|
||
* top-center point of the marker view’s frame. Specifying positive offset values moves the
|
||
* callout bubble down and to the right, while specifying negative values moves it up and to
|
||
* the left.
|
||
*
|
||
* For android, see the `calloutAnchor` prop.
|
||
*
|
||
* @platform ios
|
||
*/
|
||
calloutOffset: PropTypes.shape({
|
||
/**
|
||
* Offset to the callout
|
||
*/
|
||
x: PropTypes.number.isRequired,
|
||
y: PropTypes.number.isRequired,
|
||
}),
|
||
|
||
/**
|
||
* Sets the anchor point for the marker.
|
||
*
|
||
* The anchor specifies the point in the icon image that is anchored to the marker's position
|
||
* on the Earth's surface.
|
||
*
|
||
* The anchor point is specified in the continuous space [0.0, 1.0] x [0.0, 1.0], where (0, 0)
|
||
* is the top-left corner of the image, and (1, 1) is the bottom-right corner. The anchoring
|
||
* point in a W x H image is the nearest discrete grid point in a (W + 1) x (H + 1) grid,
|
||
* obtained by scaling the then rounding. For example, in a 4 x 2 image, the anchor point
|
||
* (0.7, 0.6) resolves to the grid point at (3, 1).
|
||
*
|
||
* For ios, see the `centerOffset` prop.
|
||
*
|
||
* @platform android
|
||
*/
|
||
anchor: PropTypes.shape({
|
||
/**
|
||
* Offset to the callout
|
||
*/
|
||
x: PropTypes.number.isRequired,
|
||
y: PropTypes.number.isRequired,
|
||
}),
|
||
|
||
/**
|
||
* Specifies the point in the marker image at which to anchor the callout when it is displayed.
|
||
* This is specified in the same coordinate system as the anchor. See the `andor` prop for more
|
||
* details.
|
||
*
|
||
* The default is the top middle of the image.
|
||
*
|
||
* For ios, see the `calloutOffset` prop.
|
||
*
|
||
* @platform android
|
||
*/
|
||
calloutAnchor: PropTypes.shape({
|
||
/**
|
||
* Offset to the callout
|
||
*/
|
||
x: PropTypes.number.isRequired,
|
||
y: PropTypes.number.isRequired,
|
||
}),
|
||
|
||
/**
|
||
* Sets whether this marker should be flat against the map true or a billboard facing the
|
||
* camera false.
|
||
*
|
||
* @platform android
|
||
*/
|
||
flat: PropTypes.bool,
|
||
|
||
draggable: PropTypes.bool,
|
||
|
||
/**
|
||
* Sets whether this marker should track view changes true.
|
||
*
|
||
* @platform ios
|
||
*/
|
||
|
||
tracksViewChanges: PropTypes.bool,
|
||
|
||
/**
|
||
* Callback that is called when the user presses on the marker
|
||
*/
|
||
onPress: PropTypes.func,
|
||
|
||
/**
|
||
* Callback that is called when the user selects the marker, before the callout is shown.
|
||
*
|
||
* @platform ios
|
||
*/
|
||
onSelect: PropTypes.func,
|
||
|
||
/**
|
||
* Callback that is called when the marker is deselected, before the callout is hidden.
|
||
*
|
||
* @platform ios
|
||
*/
|
||
onDeselect: PropTypes.func,
|
||
|
||
/**
|
||
* Callback that is called when the user taps the callout view.
|
||
*/
|
||
onCalloutPress: PropTypes.func,
|
||
|
||
/**
|
||
* Callback that is called when the user initiates a drag on this marker (if it is draggable)
|
||
*/
|
||
onDragStart: PropTypes.func,
|
||
|
||
/**
|
||
* Callback called continuously as the marker is dragged
|
||
*/
|
||
onDrag: PropTypes.func,
|
||
|
||
/**
|
||
* Callback that is called when a drag on this marker finishes. This is usually the point you
|
||
* will want to setState on the marker's coordinate again
|
||
*/
|
||
onDragEnd: PropTypes.func,
|
||
};
|
||
|
||
const defaultProps = {
|
||
onPress() {},
|
||
};
|
||
|
||
class MapMarker extends React.Component {
|
||
constructor(props) {
|
||
super(props);
|
||
|
||
this.showCallout = this.showCallout.bind(this);
|
||
this.hideCallout = this.hideCallout.bind(this);
|
||
}
|
||
|
||
setNativeProps(props) {
|
||
this.marker.setNativeProps(props);
|
||
}
|
||
|
||
showCallout() {
|
||
this._runCommand('showCallout', []);
|
||
}
|
||
|
||
hideCallout() {
|
||
this._runCommand('hideCallout', []);
|
||
}
|
||
|
||
_getHandle() {
|
||
return findNodeHandle(this.marker);
|
||
}
|
||
|
||
_runCommand(name, args) {
|
||
switch (Platform.OS) {
|
||
case 'android':
|
||
NativeModules.UIManager.dispatchViewManagerCommand(
|
||
this._getHandle(),
|
||
this.getUIManagerCommand(name),
|
||
args
|
||
);
|
||
break;
|
||
|
||
case 'ios':
|
||
this.getMapManagerCommand(name)(this._getHandle(), ...args);
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
render() {
|
||
let image;
|
||
if (this.props.image) {
|
||
image = resolveAssetSource(this.props.image) || {};
|
||
image = image.uri || this.props.image;
|
||
}
|
||
|
||
const AIRMapMarker = this.getAirComponent();
|
||
|
||
return (
|
||
<AIRMapMarker
|
||
ref={ref => {
|
||
this.marker = ref;
|
||
}}
|
||
{...this.props}
|
||
image={image}
|
||
style={[styles.marker, this.props.style]}
|
||
/>
|
||
);
|
||
}
|
||
}
|
||
|
||
MapMarker.propTypes = propTypes;
|
||
MapMarker.defaultProps = defaultProps;
|
||
MapMarker.viewConfig = viewConfig;
|
||
|
||
const styles = StyleSheet.create({
|
||
marker: {
|
||
position: 'absolute',
|
||
backgroundColor: 'transparent',
|
||
},
|
||
});
|
||
|
||
MapMarker.Animated = Animated.createAnimatedComponent(MapMarker);
|
||
|
||
module.exports = decorateMapComponent(MapMarker, {
|
||
componentType: 'Marker',
|
||
providers: {
|
||
google: {
|
||
ios: SUPPORTED,
|
||
android: USES_DEFAULT_IMPLEMENTATION,
|
||
},
|
||
},
|
||
});
|