import * as React from 'react' ; import { Select } from 'antd' ; const Option = Select . Option ; import OlMap from 'ol/Map' ; import OlView from 'ol/View' ; import _isInteger from 'lodash/isInteger' ; import _isEmpty from 'lodash/isEmpty' ; import _isEqual from 'lodash/isEqual' ; import _isFunction from 'lodash/isFunction' ; import _reverse from 'lodash/reverse' ; import _clone from 'lodash/clone' ; import Logger from '@terrestris/base-util/dist/Logger' ; import MapUtil from '@terrestris/ol-util/dist/MapUtil/MapUtil' ; import { CSS_PREFIX } from '../../constants' ; import './ScaleCombo.less' ; interface DefaultProps { /**
     * A filter function to filter resolutions no options should be created
     */ resolutionsFilter : ( item : any , index ? : number , resolutions ? : number [ ] ) => boolean ; /**
     * Set to false to not listen to the map moveend event.
     */ syncWithMap : boolean ; /**
     * The scales.
     */ scales : number [ ] ; } interface BaseProps { /**
     * An optional CSS class which should be added.
     */ className ? : string ; /**
     * The zoomLevel.
     */ zoomLevel ? : number ; /**
     * The onZoomLevelSelect function. Pass a function if you want something
     * different than the resolution of the passed map.
     */ onZoomLevelSelect ? : ( zoomLevel : string ) => void ; /**
     * The resolutions.
     */ resolutions ? : number [ ] ; /**
     * The map
     */ map : OlMap ; } interface ScaleComboState { /**
     * The zoomLevel.
     */ zoomLevel ? : number ; /**
     * The onZoomLevelSelect function. Pass a function if you want something
     * different than the resolution of the passed map.
     */ onZoomLevelSelect ? : ( zoomLevel : string ) => void ; /**
     * The scales.
     */ scales : number [ ] ; } export type ScaleComboProps = BaseProps & Partial < DefaultProps > ; class extends React . Component class ScaleCombo extends React . Component < ScaleComboProps , ScaleComboState > { /**
     * The default props
     */ static defaultProps = { resolutionsFilter : ( ) => true , scales : [ ] , syncWithMap : true } ; private className = `${ CSS_PREFIX }scalecombo` ; constructs constructor ( props ) { super ( props ) ; param selectedScale const defaultOnZoomLevelSelect = ( selectedScale ) => { const mapView = props . map . getView ( ) ; const calculatedResolution = MapUtil . getResolutionForScale ( selectedScale , mapView . getProjection ( ) . getUnits ( ) ) ; mapView . setResolution ( calculatedResolution ) ; } ; this . state = { zoomLevel : props . zoomLevel || props . map . getView ( ) . getZoom ( ) , onZoomLevelSelect : props . onZoomLevelSelect || defaultOnZoomLevelSelect , scales : props . scales . length > 0 ? props . scales : this . getOptionsFromMap ( ) } ; if ( props . syncWithMap ) { props . map . on ( 'moveend' , this . zoomListener ) ; } } param nextProps param prevState static getDerivedStateFromProps ( nextProps , prevState ) { if ( _isInteger ( nextProps . zoomLevel ) && ! _isEqual ( nextProps . zoomLevel , prevState . zoomLevel ) ) { return { zoomLevel : nextProps . zoomLevel } ; } if ( _isFunction ( nextProps . onZoomLevelSelect ) && ! _isEqual ( nextProps . onZoomLevelSelect , prevState . onZoomLevelSelect ) ) { return { onZoomLevelSelect : nextProps . onZoomLevelSelect } ; } return null ; } param prevProps componentDidUpdate ( prevProps ) { const { map , syncWithMap } = this . props ; if ( ! _isEqual ( syncWithMap , prevProps . syncWithMap ) ) { if ( syncWithMap ) { map . on ( 'moveend' , this . zoomListener ) ; } else { map . un ( 'moveend' , this . zoomListener ) ; } } } param evt private zoomListener = ( evt ) => { const zoom = evt . target . getView ( ) . getZoom ( ) ; let roundZoom = Math . round ( zoom ) ; if ( ! roundZoom ) { roundZoom = 0 ; } this . setState ( { zoomLevel : roundZoom } ) ; } ; function pushScaleOption: Helper function to create a  Option scale component
     * based on a resolution and the  Ol . View param scales param resolution param view pushScale = ( scales , resolution , view ) => { const scale = MapUtil . getScaleForResolution ( resolution , view . getProjection ( ) . getUnits ( ) ) ; const roundScale = MapUtil . roundScale ( scale ) ; if ( scales . includes ( roundScale ) ) { return ; } scales . push ( roundScale ) ; } ; /**
     * Generates the scales to add as  Option to the SelectField based on
     * the given instance of  Ol . Map .
     *
     *  return getOptionsFromMap ( ) { const { map , resolutionsFilter } = this . props ; if ( ! map ) { Logger . warn ( 'Map component not found. Could not initialize options array.' ) ; return [ ] ; } const scales = [ ] ; const view = map . getView ( ) ; const resolutions = view . getResolutions ( ) ; if ( _isEmpty ( resolutions ) ) { for ( let currentZoomLevel = view . getMaxZoom ( ) ; currentZoomLevel >= view . getMinZoom ( ) ; currentZoomLevel -- ) { const resolution = view . getResolutionForZoom ( currentZoomLevel ) ; if ( resolutionsFilter ( resolution ) ) { this . pushScale ( scales , resolution , view ) ; } } } else { const reversedResolutions = _reverse ( _clone ( resolutions ) ) ; reversedResolutions . filter ( resolutionsFilter ) . forEach ( ( resolution ) => { this . pushScale ( scales , resolution , view ) ; } ) ; } return scales ; } param zoom return determineOptionKeyForZoomLevel = ( zoom ) : string | undefined => { if ( ! _isInteger ( zoom ) || ( this . state . scales . length - 1 - zoom ) < 0 ) { return undefined ; } return this . state . scales [ this . state . scales . length - 1 - zoom ] . toString ( ) ; } ; /**
     * The render function.
     */ render ( ) { const { map , className , onZoomLevelSelect : onZoomLevelSelectProp , resolutions , resolutionsFilter , scales : scalesProp , syncWithMap , zoomLevel : zoomLevelProp , ... passThroughProps } = this . props ; const { onZoomLevelSelect , scales , zoomLevel } = this . state ; const finalClassName = className ? `${ className } ${ this . className }` : this . className ; const options = scales . map ( roundScale => { return ( < Option key = { roundScale } value = { roundScale . toString ( ) } > { `1:${ roundScale . toLocaleString ( ) }` } < /Option>); } ) ; return ( < Select showSearch onChange = { onZoomLevelSelect } filterOption = { ( input , option ) => option . key . toString ( ) . startsWith ( input ) } value = { this . determineOptionKeyForZoomLevel ( zoomLevel ) } size = "small" className = { finalClassName } { ... passThroughProps } > { options } < /Select>); } } export default ScaleCombo ;