import type { DoorMode , Lift , LiftState , Door } from 'api-client' ; import React from 'react' ; import { LiftState as RmfLiftState } from 'rmf-models' ; import { almostShallowEqual , fromRmfCoords , fromRmfYaw , radiansToDegrees } from '../utils' ; import { DoorMarker as DoorMarker_ } from './door-marker' ; import { useAutoScale } from './hooks' ; import { LiftMarker as LiftMarker_ , LiftMarkerProps , liftMarkerClasses } from './lift-marker' ; import { SVGOverlay , SVGOverlayProps } from './svg-overlay' ; import { viewBoxFromLeafletBounds } from './utils' ; import { withLabel } from './with-label' ; function toDoorMode ( liftState ) { return { value : liftState . door_state } ; } interface BoundedMarkerProps extends Omit < LiftMarkerProps , 'onClick' > { lift : Lift ; onClick ? : ( ev : React . MouseEvent , lift : string ) => void ; } /**
 * Bind a marker to include the lift name in the click event.
 * This is needed to avoid re-rendering all markers when only one of them changes.
 */ function bindMarker ( MarkerComponent ) { return ( { lift , onClick , ... otherProps } ) => { const handleClick = React . useCallback ( ( ev ) => onClick && onClick ( ev , lift . name ) , [ onClick , lift . name ] ) ; return < MarkerComponent onClick = { onClick && handleClick } { ... otherProps } />; } ; } const DoorMarker = React . memo ( DoorMarker_ ) ; const LiftMarker = React . memo ( withLabel ( bindMarker ( LiftMarker_ ) ) , ( prev , next ) => almostShallowEqual ( prev , next , [ 'style' ] ) ) ; export const getLiftModeVariant = ( currentLevel , liftStateMode ? , liftStateFloor ? ) : keyof typeof liftMarkerClasses | undefined => { if ( ! liftStateMode && ! liftStateFloor ) return 'unknown' ; if ( liftStateMode === RmfLiftState . MODE_FIRE ) return 'fire' ; if ( liftStateMode === RmfLiftState . MODE_EMERGENCY ) return 'emergency' ; if ( liftStateMode === RmfLiftState . MODE_OFFLINE ) return 'offLine' ; if ( liftStateFloor === currentLevel ) { if ( liftStateMode === RmfLiftState . MODE_HUMAN ) return 'human' ; if ( liftStateMode === RmfLiftState . MODE_AGV ) return 'onCurrentLevel' ; } else { if ( liftStateMode === RmfLiftState . MODE_HUMAN ) return 'moving' ; if ( liftStateMode === RmfLiftState . MODE_AGV ) return 'moving' ; } if ( liftStateMode === RmfLiftState . MODE_UNKNOWN ) return 'unknown' ; return 'unknown' ; } ; export interface LiftsOverlayProps extends Omit < SVGOverlayProps , 'viewBox' > { currentLevel : string ; lifts : Lift [ ] ; liftStates ? : Record < string , LiftState > ; hideLabels ? : boolean ; onLiftClick ? : ( ev : React . MouseEvent , lift : string ) => void ; } export const LiftsOverlay = ( { lifts , liftStates = { } , hideLabels = false , onLiftClick , currentLevel , ... otherProps } ) : JSX . Element => { const viewBox = viewBoxFromLeafletBounds ( otherProps . bounds ) ; const scale = useAutoScale ( 40 ) ; return ( < SVGOverlay viewBox = { viewBox } { ... otherProps } > { lifts . map ( ( lift ) => { const state = liftStates && liftStates [ lift . name ] ; const pos = fromRmfCoords ( [ lift . ref_x , lift . ref_y ] ) ; return ( < g key = { lift . name } > < LiftMarker lift = { lift } onClick = { onLiftClick } cx = { pos [ 0 ] } cy = { pos [ 1 ] } width = { lift . width } height = { lift . depth } yaw = { radiansToDegrees ( fromRmfYaw ( lift . ref_yaw ) ) } liftState = { state } variant = { getLiftModeVariant ( currentLevel , liftStates [ lift . name ] ?. current_mode , liftStates [ lift . name ] ?. current_floor ) } style = { { transform : `scale(${ scale })` , transformOrigin : `${ pos [ 0 ] }px ${ pos [ 1 ] }px` } } aria - label = { lift . name } labelText = { lift . name } labelSourceX = { pos [ 0 ] } labelSourceY = { pos [ 1 ] } labelSourceRadius = { Math . min ( lift . width / 2 , lift . depth / 2 ) } labelArrowLength = { Math . max ( ( lift . width / 3 ) * scale , ( lift . depth / 3 ) * scale ) } hideLabel = { hideLabels } / > { lift . doors . map ( ( door , idx ) => { const [ x1 , y1 ] = fromRmfCoords ( [ door . v1_x , door . v1_y ] ) ; const [ x2 , y2 ] = fromRmfCoords ( [ door . v2_x , door . v2_y ] ) ; return ( < DoorMarker key = { idx } x1 = { x1 } y1 = { y1 } x2 = { x2 } y2 = { y2 } doorType = { door . door_type } doorMode = { state && toDoorMode ( state ) . value } />); } ) } < /g>); } ) } < /SVGOverlay>); } ; export default LiftsOverlay ;