Created
June 18, 2018 11:09
-
-
Save kristfal/9b1af1a381c1d57fe8dab1993cb1ad62 to your computer and use it in GitHub Desktop.
Mapbox camera snippets
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const cameraValid = camera => | |
camera && camera.geometry && Array.isArray(camera.geometry.coordinates); | |
// Workaround for Mapbox issue | |
// https://github.com/mapbox/react-native-mapbox-gl/issues/1126 | |
export const enforceIntegerPadding = padding => | |
padding.map(value => parseInt(value, 10)); | |
export const isValidBounds = camera => | |
camera && | |
camera.bounds && | |
Array.isArray(camera.bounds) && | |
Array.isArray(camera.bounds[0]) && | |
Array.isArray(camera.bounds[1]) && | |
isNumeric(camera.bounds[0][0]) && | |
isNumeric(camera.bounds[0][1]) && | |
isNumeric(camera.bounds[1][1]) && | |
isNumeric(camera.bounds[1][1]); | |
export const isCameraChanged = (a, b) => { | |
if (!a || !b) return true; | |
if (a.isInitial) return true; | |
const defaultPropertiesChanged = | |
a.bearing !== b.bearing || | |
a.center[0] !== b.center[0] || | |
a.center[1] !== b.center[1] || | |
a.pitch !== b.pitch || | |
a.zoom !== b.zoom || | |
a.userInitiated !== b.userInitiated; | |
if (!isValidBounds(a) || !isValidBounds(b)) return defaultPropertiesChanged; | |
return ( | |
defaultPropertiesChanged || | |
a.bounds[0][0] !== b.bounds[0][0] || | |
a.bounds[0][1] !== b.bounds[0][1] || | |
a.bounds[1][0] !== b.bounds[1][0] || | |
a.bounds[1][1] !== b.bounds[1][1] | |
); | |
}; | |
export const isInstantCameraChange = (a, b) => { | |
if (!a || !b) return true; | |
if (a.isInstant) return true; | |
const dZ = 7; | |
const dD = 5; | |
if (Math.abs(a.zoom - b.zoom) > dZ) return true; | |
if (Math.abs(a.center[0] - b.center[0]) > dD) return true; | |
if (Math.abs(a.center[1] - b.center[1]) > dD) return true; | |
return false; | |
}; | |
export const isSignificantChange = (nextCamera, camera) => { | |
const coordDelta = SIGNIFICANT_COORDINATE_DELTA; | |
const zoomDelta = SINGIFICANT_ZOOM_DELTA; | |
if (!cameraValid(camera) || !cameraValid(nextCamera)) return true; | |
const deltaLat = | |
Math.abs( | |
nextCamera.geometry.coordinates[1] - camera.geometry.coordinates[1], | |
) > coordDelta; | |
const deltaLng = | |
Math.abs( | |
nextCamera.geometry.coordinates[0] - camera.geometry.coordinates[0], | |
) > coordDelta; | |
const deltaZoom = | |
Math.abs(nextCamera.properties.zoomLevel - camera.properties.zoomLevel) > | |
zoomDelta; | |
return deltaLat || deltaLng || deltaZoom; | |
}; | |
class EmbarkMapMapbox extends PureComponent { | |
static propTypes = { | |
pitchEnabled: PropTypes.bool, | |
rotateEnabled: PropTypes.bool, | |
scrollEnabled: PropTypes.bool, | |
panResponderEnabled: PropTypes.bool, | |
zoomLevel: PropTypes.number, | |
onPress: PropTypes.func, | |
onLongPress: PropTypes.func, | |
onRegionDidChange: PropTypes.func, | |
textureMode: PropTypes.bool, | |
padding: PropTypes.array, | |
minZoomLevel: PropTypes.number, | |
onPanResponderMove: PropTypes.func, | |
onPanResponderRelease: PropTypes.func, | |
style: ViewPropTypes.style, | |
children: PropTypes.node, | |
camera: PropTypes.object, | |
initialCamera: PropTypes.object, | |
onDidFinishLoadingMap: PropTypes.func, | |
onAttribution: PropTypes.func, | |
testID: PropTypes.string, | |
}; | |
static defaultProps = { | |
pitchEnabled: false, | |
rotateEnabled: true, | |
scrollEnabled: true, | |
padding: [15, 15, 174, 15], | |
hitSlop: EMBARK_MAP_HITSLOP, | |
}; | |
constructor() { | |
super(); | |
this.onWillStartLoadingMap = this.onWillStartLoadingMap.bind(this); | |
} | |
componentWillMount() { | |
MapboxGL.setAccessToken(MAPBOX_ACCESSTOKEN); | |
} | |
onWillStartLoadingMap() { | |
const {camera, initialCamera, padding} = this.props; | |
const derivedCamera = initialCamera || camera; | |
this.handleCameraChange( | |
{ | |
...derivedCamera, | |
userInitiated: false, | |
isInstant: true, | |
isInitial: true, | |
}, | |
padding, | |
); | |
} | |
componentWillReceiveProps({camera, padding}) { | |
this.handleCameraChange(camera, padding); | |
} | |
handleCameraChange(camera, padding) { | |
if (!camera) return; | |
const currentCamera = this.props.camera; | |
const changed = isCameraChanged(camera, currentCamera); | |
const instant = isInstantCameraChange(camera, currentCamera); | |
const validBounds = isValidBounds(camera); | |
const duration = instant ? 1 : EMBARK_MAP_ANIMATION_DURATION; | |
if (!changed || camera.userInitiated) return; | |
if (validBounds) { | |
this.setCameraWithBounds(camera, padding, duration); | |
} else { | |
this.setCameraWithCenter(camera, duration); | |
} | |
} | |
setCameraWithBounds(camera, padding, duration) { | |
this.map.fitBounds( | |
camera.bounds[0], | |
camera.bounds[1], | |
enforceIntegerPadding(padding), | |
duration, | |
); | |
} | |
setCameraWithCenter(camera, duration) { | |
this.map.setCamera({ | |
centerCoordinate: camera.center, | |
zoom: camera.zoom, | |
pitch: camera.pitch, | |
heading: camera.bearing, | |
duration, | |
}); | |
} | |
render() { | |
const { | |
pitchEnabled, | |
rotateEnabled, | |
scrollEnabled, | |
textureMode, | |
minZoomLevel, | |
style, | |
onDidFinishLoadingMap, | |
testID, | |
} = this.props; | |
return ( | |
<View style={[styles.wrapper, style]}> | |
<MapboxGL.MapView | |
ref={ref => (this.map = ref)} | |
textureMode={textureMode} | |
attributionEnabled={false} | |
compassEnabled={false} | |
showUserLocation={false} | |
logoEnabled={false} | |
minZoomLevel={minZoomLevel} | |
maxZoomLevel={17} | |
zoomLevel={0} | |
contentInset={[90, 15, 15, 15]} | |
onWillStartLoadingMap={this.onWillStartLoadingMap} | |
style={styles.map} | |
styleURL={API.EMBARK_STYLE_URL} | |
pitchEnabled={pitchEnabled} | |
rotateEnabled={rotateEnabled} | |
scrollEnabled={scrollEnabled} | |
testID={testID} | |
> | |
{this.props.children} | |
</MapboxGL.MapView> | |
</View> | |
); | |
} | |
} | |
export default EmbarkMapMapbox; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment