import React from 'react'
import PropTypes from 'prop-types'
import olLayerTile from 'ol/layer/Tile'
import olSourceBingMaps from 'ol/source/BingMaps'
import { BasemapOption, BasemapThumbnail, Label } from './styled'
import { connectToContext } from 'Provider'
const DEFAULT_OPTS = {
thumbnail: '',
culture: 'en-us',
imagerySet: 'Aerial',
hidpi: false,
cacheSize: 4096,
maxZoom: 19,
reprojectionErrorThreshold: 0,
wrapX: true
}
/**
* Bing basemap option (requires a Bing key to work properly)
* @component
* @category Basemap
* @since 0.1.0
*/
class BasemapBingMaps extends React.Component {
handleLayersChange = () => {
this.forceUpdate()
}
componentDidMount () {
this.props.map.getLayers().on('change', this.handleLayersChange)
}
componentWillUnmount () {
this.props.map.getLayers().un('change', this.handleLayersChange)
}
onClick = () => {
const { map, layerTypeID, layerID, sourceOpts, onBasemapChanged } = this.props
const opts = { ...DEFAULT_OPTS, ...sourceOpts }
const source = new olSourceBingMaps(opts)
const layer = new olLayerTile({
className: '_ol_kit_basemap_layer',
[layerTypeID]: layerID, // make sure we can identify this layer as a layer that has been created from the ol-kit basemap component.
source
})
const layers = map.getLayers()
const layerArray = layers.getArray()
const hasBasemap = layerTypeID && layerArray.length ? layerArray[0].get(layerTypeID) : false
if (hasBasemap) {
layers.setAt(0, layer)
} else {
layers.insertAt(0, layer)
}
layers.changed() // ol.Collection insertAt and setAt do not trigger a change event so we fire one manually so that we can rerender to display the active and inactive BasemapOptions
onBasemapChanged(layer)
}
render () {
const { translations, thumbnail, map, layerTypeID, layerID } = this.props
const layerArray = map.getLayers().getArray()
const isActive = layerArray.length ? layerArray[0].get(layerTypeID) === layerID : false
return (
<BasemapOption className='_ol_kit_basemapOption' isActive={isActive} onClick={this.onClick}>
<BasemapThumbnail thumbnail={thumbnail} />
<Label>{translations['_ol_kit.BingMaps.title']}</Label>
</BasemapOption>
)
}
}
BasemapBingMaps.propTypes = {
/** reference to Openlayers map object */
map: PropTypes.object.isRequired,
/** A unique string or symbol property name that will be set directly on the layer when it is created with a value containing a string identifying the type of basemap layer (e.g. '_ol_kit_basemap': 'osm'). This property should be a shared ID used to identify individual layers as 'basemap' layers. */
layerTypeID: PropTypes.oneOfType([PropTypes.symbol, PropTypes.string]),
/** An string or symbol ID unique to the layer that this component will create (e.g. 'bingAerial'). */
layerID: PropTypes.oneOfType([PropTypes.symbol, PropTypes.string]),
/** Object with key/value pairs for translated strings */
translations: PropTypes.shape({
'_ol_kit.BingMaps.title': PropTypes.string
}),
/** A string containing an http url or data url to a thumbnail image */
thumbnail: PropTypes.string,
/** A callback that is fired when the basemap layer has been changed. It is called with the updated layer. */
onBasemapChanged: PropTypes.func,
/** The options object that will be used to create the ol/source/BingMaps (https://openlayers.org/en/latest/apidoc/module-ol_source_BingMaps-BingMaps.html) instance for the layer that this component adds to the map. While there are default sourceOpts it is required that an object containing at least a valid BingMaps Maps key is passed down to this component (https://www.microsoft.com/en-us/maps/create-a-bing-maps-key). */
sourceOpts: PropTypes.shape({
key: PropTypes.string.isRequired
}).isRequired
}
BasemapBingMaps.defaultProps = {
onBasemapChanged: () => {},
layerTypeID: '_ol_kit_basemap',
thumbnail: '',
layerID: 'bingAerial'
}
export default connectToContext(BasemapBingMaps)