import turfDistance from '@turf/distance' ; import turfCircle from '@turf/circle' ; import { Feature , GeoJSON , Position } from 'geojson' ; const DRAW_CIRCLE_RADIUS = 'draw-circle-radius' ; export const DRAW_CIRCLE_RADIUS_LABEL_STYLE = { id : 'gl-draw-radius-label' , type : 'symbol' , filter : [ '==' , 'meta' , DRAW_CIRCLE_RADIUS ] , layout : { 'text-anchor' : 'right' , 'text-field' : '{radiusLabel}' , 'text-size' : 16 , 'text-offset' : [ - 1 , 0 ] , 'text-ignore-placement' : true , 'text-allow-overlap' : true , } , paint : { 'text-color' : '#fbb03b' , 'text-halo-color' : 'rgba(0, 0, 0, 1)' , 'text-halo-width' : 2 , } , } ; export interface DrawCircleProperties { center : Position ; radiusKm : number ; } type DrawCircleState = { circle : { properties : Omit < DrawCircleProperties , 'center' > & { center : Position | null ; edge : Position | null ; radiusKm : number ; } ; id : string | number ; incomingCoords : ( coords : unknown [ ] ) => void ; toGeoJSON : ( ) => GeoJSON ; } ; } ; type MouseEvent = { lngLat : { lng : number ; lat : number ; } ; } ; export const DrawCircle = { onSetup ( ) { const circle = this . newFeature ( { type : 'Feature' , properties : { center : null , edge : null , radiusKm : 0 , } , geometry : { type : 'Polygon' , coordinates : [ [ ] ] , } , } ) ; this . addFeature ( circle ) ; this . clearSelectedFeatures ( ) ; this . updateUIClasses ( { mouse : 'add' } ) ; this . setActionableState ( { trash : true , } ) ; return { circle , } ; } , onKeyUp ( state , e ) { if ( e . keyCode === 27 ) { state . circle . properties . center = null ; state . circle . properties . radiusKm = 0 ; state . circle . incomingCoords ( [ [ ] ] ) ; } } , onClick ( state , e ) { if ( ! state . circle . properties . center ) { state . circle . properties . center = [ e . lngLat . lng , e . lngLat . lat ] ; } else { this . updateUIClasses ( { mouse : 'pointer' } ) ; state . circle . properties . radiusKm = turfDistance ( state . circle . properties . center , [ e . lngLat . lng , e . lngLat . lat , ] ) ; this . changeMode ( 'simple_select' , { featuresId : state . circle . id } ) ; } } , onMouseMove ( state , e ) { if ( ! state . circle . properties . center ) { return ; } const mouseLocation = [ e . lngLat . lng , e . lngLat . lat ] ; state . circle . properties . edge = mouseLocation ; state . circle . properties . radiusKm = turfDistance ( state . circle . properties . center , mouseLocation ) ; const newCircleFeature = turfCircle ( state . circle . properties . center , state . circle . properties . radiusKm ) ; state . circle . incomingCoords ( newCircleFeature . geometry . coordinates ) ; } , onStop ( state ) { this . updateUIClasses ( { mouse : 'none' } ) ; this . activateUIButton ( ) ; if ( this . getFeature ( state . circle . id ) === undefined ) return ; if ( state . circle . properties . center && state . circle . properties . radiusKm > 0 ) { this . map . fire ( 'draw.create' , { features : [ state . circle . toGeoJSON ( ) ] , } ) ; } else { this . deleteFeature ( [ state . circle . id ] , { silent : true } ) ; this . changeMode ( 'simple_select' , { } , { silent : true } ) ; } } , toDisplayFeatures ( state , geojson , display ) { if ( ! state . circle . properties . center || ! state . circle . properties . edge ) { return null ; } geojson . properties ! . active = 'true' ; let radiusLabel = '' ; if ( state . circle . properties . radiusKm <= 1 ) { radiusLabel = `${ Math . round ( state . circle . properties . radiusKm * 1000 ) } m` ; } else if ( state . circle . properties . radiusKm <= 10 ) { radiusLabel = `${ state . circle . properties . radiusKm . toFixed ( 1 ) } km` ; } else { radiusLabel = `${ Math . round ( state . circle . properties . radiusKm ) } km` ; } display ( { type : 'Feature' , properties : { meta : DRAW_CIRCLE_RADIUS , parent : state . circle . id , radiusLabel , active : 'false' , } , geometry : { type : 'Point' , coordinates : state . circle . properties . edge , } , } ) ; display ( { type : 'Feature' , properties : { meta : 'draw-circle-radius-line' , parent : state . circle . id , active : 'true' , } , geometry : { type : 'LineString' , coordinates : [ state . circle . properties . center , state . circle . properties . edge ] , } , } ) ; display ( geojson ) ; } , onTrash ( state ) { this . deleteFeature ( [ state . circle . id ] , { silent : true } ) ; this . changeMode ( 'simple_select' ) ; } , } ;