import React, { useState, useEffect } from 'react'
import PropTypes from 'prop-types'
import { connectToContext } from 'Provider'
import { CompassContainer } from './styled'
import { rotateMap } from './utils'
const colors = {
light: {
background: '#ffffff',
arrows: '#4d4d4d',
needleTop: '#e04343',
needleBottom: '#000000'
},
dark: {
background: '#000000',
arrows: '#cccccc',
needleTop: '#e04343',
needleBottom: '#ffffff'
}
}
/**
* A map rotation control
* @component
* @category Controls
* @since 0.1.0
*/
function Compass (props) {
const { map, size, variation } = props
const [radians, setRadians] = useState(map.getView().getRotation())
useEffect(() => {
const listener = () => setRadians(map.getView().getRotation())
map.getView().on('change:rotation', listener)
return function cleanup () {
map.getView().un('change:rotation', listener)
}
}, [map]) // optimization: listeners will only attach/cleanup if the map prop changes
const getRadianOffset = (radians, clockwiseTurn) => {
return clockwiseTurn
? radians + (Math.PI / 8)
: radians - (Math.PI / 8)
}
const rotate = direction => {
const currentRotation = map.getView().getRotation()
const clockwiseTurn = direction === 'right'
// set the rotation to 0 for a north arrow click
const finalRotation = direction === 'north' ? 0 : getRadianOffset(currentRotation, clockwiseTurn)
// animate map
rotateMap(map, finalRotation)
// animate UI
setRadians(finalRotation)
}
const degrees = radians * 57.296 // the number of degrees per radian
return (
<CompassContainer size={size} background={colors[variation].background}>
<svg width={size} height={size} viewBox='0 0 48 48' version='1.1' xmlns='http://www.w3.org/2000/svg'>
<g onClick={() => rotate('left')} transform='translate(8, 11)' id='_ol_kit_rotate_left'>
<path stroke={colors[variation].arrows} strokeWidth='2' strokeLinecap='square' fill='transparent' d='M6.08917588,0.274482759 C2.08917588,3.50525199 0.0891758754,7.27448276 0.0891758754,11.5821751 C0.0891758754,18.0437135 3.5177473,21.2744828 3.5177473,21.2744828'></path>
<polygon fill={colors[variation].arrows} transform='translate(5.838799, 24.192853) rotate(143.000000) translate(-5.838799, -24.192853) ' points='5.93396953 20.6928529 8.83879936 27.636638 2.83879936 27.6928529'></polygon>
</g>
<g onClick={() => rotate('north')} transform={`translate(18.0, 10.0) rotate(${degrees} 6.0 15.0)`} id='_ol_kit_true_north'>
<polygon fill={colors[variation].needleTop} points='5.74325656 0 11.4865131 15.4007427 0 15.4007427'></polygon>
<polygon fill={colors[variation].needleBottom} points='5.74325656 30.8014854 0 15.4007427 11.4865131 15.4007427'></polygon>
</g>
<g onClick={() => rotate('right')} transform='translate(34.500000, 25.500000) scale(-1, 1) translate(-34.500000, -25.500000) translate(29.000000, 11.000000)' id='_ol_kit_rotate_right'>
<path stroke={colors[variation].arrows} strokeWidth='2' strokeLinecap='square' fill='transparent' d='M6.08917588,0.274482759 C2.08917588,3.50525199 0.0891758754,7.27448276 0.0891758754,11.5821751 C0.0891758754,18.0437135 3.5177473,21.2744828 3.5177473,21.2744828'></path>
<polygon fill={colors[variation].arrows} transform='translate(5.838799, 24.192853) rotate(143.000000) translate(-5.838799, -24.192853) ' points='5.93396953 20.6928529 8.83879936 27.636638 2.83879936 27.6928529'></polygon>
</g>
</svg>
</CompassContainer>
)
}
Compass.defaultProps = {
variation: 'light',
size: '45px'
}
Compass.propTypes = {
/** reference to Openlayers map object */
map: PropTypes.object.isRequired,
/** sets the width/height of the compass in a valid CSS unit like px or ems */
size: PropTypes.string,
/** light or dark variation for styling */
variation: PropTypes.oneOf(['light', 'dark'])
}
export default connectToContext(Compass)